crypto: replace ToECDSAPub with error-checking func UnmarshalPubkey (#16932)
ToECDSAPub was unsafe because it returned a non-nil key with nil X, Y in case of invalid input. This change replaces ToECDSAPub with UnmarshalPubkey across the codebase.
This commit is contained in:
parent
85cd64df0e
commit
0255951587
@ -140,8 +140,8 @@ func processArgs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *asymmetricMode && len(*argPub) > 0 {
|
if *asymmetricMode && len(*argPub) > 0 {
|
||||||
pub = crypto.ToECDSAPub(common.FromHex(*argPub))
|
var err error
|
||||||
if !isKeyValid(pub) {
|
if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil {
|
||||||
utils.Fatalf("invalid public key")
|
utils.Fatalf("invalid public key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,10 +321,6 @@ func startServer() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isKeyValid(k *ecdsa.PublicKey) bool {
|
|
||||||
return k.X != nil && k.Y != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func configureNode() {
|
func configureNode() {
|
||||||
var err error
|
var err error
|
||||||
var p2pAccept bool
|
var p2pAccept bool
|
||||||
@ -340,9 +336,8 @@ func configureNode() {
|
|||||||
if b == nil {
|
if b == nil {
|
||||||
utils.Fatalf("Error: can not convert hexadecimal string")
|
utils.Fatalf("Error: can not convert hexadecimal string")
|
||||||
}
|
}
|
||||||
pub = crypto.ToECDSAPub(b)
|
if pub, err = crypto.UnmarshalPubkey(b); err != nil {
|
||||||
if !isKeyValid(pub) {
|
utils.Fatalf("Error: invalid peer public key")
|
||||||
utils.Fatalf("Error: invalid public key")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,8 @@ var (
|
|||||||
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
|
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errInvalidPubkey = errors.New("invalid secp256k1 public key")
|
||||||
|
|
||||||
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||||
func Keccak256(data ...[]byte) []byte {
|
func Keccak256(data ...[]byte) []byte {
|
||||||
d := sha3.NewKeccak256()
|
d := sha3.NewKeccak256()
|
||||||
@ -122,12 +124,13 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte {
|
|||||||
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
|
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
|
// UnmarshalPubkey converts bytes to a secp256k1 public key.
|
||||||
if len(pub) == 0 {
|
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
x, y := elliptic.Unmarshal(S256(), pub)
|
x, y := elliptic.Unmarshal(S256(), pub)
|
||||||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}
|
if x == nil {
|
||||||
|
return nil, errInvalidPubkey
|
||||||
|
}
|
||||||
|
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
||||||
|
@ -23,9 +23,11 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
|
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
|
||||||
@ -56,6 +58,33 @@ func BenchmarkSha3(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalPubkey(t *testing.T) {
|
||||||
|
key, err := UnmarshalPubkey(nil)
|
||||||
|
if err != errInvalidPubkey || key != nil {
|
||||||
|
t.Fatalf("expected error, got %v, %v", err, key)
|
||||||
|
}
|
||||||
|
key, err = UnmarshalPubkey([]byte{1, 2, 3})
|
||||||
|
if err != errInvalidPubkey || key != nil {
|
||||||
|
t.Fatalf("expected error, got %v, %v", err, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
enc, _ = hex.DecodeString("04760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d")
|
||||||
|
dec = &ecdsa.PublicKey{
|
||||||
|
Curve: S256(),
|
||||||
|
X: hexutil.MustDecodeBig("0x760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1"),
|
||||||
|
Y: hexutil.MustDecodeBig("0xb01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
key, err = UnmarshalPubkey(enc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(key, dec) {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSign(t *testing.T) {
|
func TestSign(t *testing.T) {
|
||||||
key, _ := HexToECDSA(testPrivHex)
|
key, _ := HexToECDSA(testPrivHex)
|
||||||
addr := common.HexToAddress(testAddrHex)
|
addr := common.HexToAddress(testAddrHex)
|
||||||
@ -69,7 +98,7 @@ func TestSign(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ECRecover error: %s", err)
|
t.Errorf("ECRecover error: %s", err)
|
||||||
}
|
}
|
||||||
pubKey := ToECDSAPub(recoveredPub)
|
pubKey, _ := UnmarshalPubkey(recoveredPub)
|
||||||
recoveredAddr := PubkeyToAddress(*pubKey)
|
recoveredAddr := PubkeyToAddress(*pubKey)
|
||||||
if addr != recoveredAddr {
|
if addr != recoveredAddr {
|
||||||
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)
|
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)
|
||||||
|
@ -461,13 +461,11 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt
|
|||||||
}
|
}
|
||||||
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||||
|
|
||||||
rpk, err := crypto.Ecrecover(signHash(data), sig)
|
rpk, err := crypto.SigToPub(signHash(data), sig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
pubKey := crypto.ToECDSAPub(rpk)
|
return crypto.PubkeyToAddress(*rpk), nil
|
||||||
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
|
|
||||||
return recoveredAddr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
|
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
|
||||||
|
@ -528,9 +528,9 @@ func importPublicKey(pubKey []byte) (*ecies.PublicKey, error) {
|
|||||||
return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
|
return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
|
||||||
}
|
}
|
||||||
// TODO: fewer pointless conversions
|
// TODO: fewer pointless conversions
|
||||||
pub := crypto.ToECDSAPub(pubKey65)
|
pub, err := crypto.UnmarshalPubkey(pubKey65)
|
||||||
if pub.X == nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid public key")
|
return nil, err
|
||||||
}
|
}
|
||||||
return ecies.ImportECDSAPublic(pub), nil
|
return ecies.ImportECDSAPublic(pub), nil
|
||||||
}
|
}
|
||||||
|
@ -432,13 +432,11 @@ func (api *SignerAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (c
|
|||||||
}
|
}
|
||||||
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||||
hash, _ := SignHash(data)
|
hash, _ := SignHash(data)
|
||||||
rpk, err := crypto.Ecrecover(hash, sig)
|
rpk, err := crypto.SigToPub(hash, sig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
pubKey := crypto.ToECDSAPub(rpk)
|
return crypto.PubkeyToAddress(*rpk), nil
|
||||||
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
|
|
||||||
return recoveredAddr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignHash is a helper function that calculates a hash for the given message that can be
|
// SignHash is a helper function that calculates a hash for the given message that can be
|
||||||
|
@ -19,6 +19,7 @@ package swap
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
@ -134,6 +135,11 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
|||||||
out *chequebook.Outbox
|
out *chequebook.Outbox
|
||||||
)
|
)
|
||||||
|
|
||||||
|
remotekey, err := crypto.UnmarshalPubkey(common.FromHex(remote.PublicKey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid remote public key")
|
||||||
|
}
|
||||||
|
|
||||||
// check if remote chequebook is valid
|
// check if remote chequebook is valid
|
||||||
// insolvent chequebooks suicide so will signal as invalid
|
// insolvent chequebooks suicide so will signal as invalid
|
||||||
// TODO: monitoring a chequebooks events
|
// TODO: monitoring a chequebooks events
|
||||||
@ -142,7 +148,7 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
|||||||
log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
|
log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
|
||||||
} else {
|
} else {
|
||||||
// remote contract valid, create inbox
|
// remote contract valid, create inbox
|
||||||
in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, crypto.ToECDSAPub(common.FromHex(remote.PublicKey)), backend)
|
in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, remotekey, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
|
log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
|
||||||
}
|
}
|
||||||
|
@ -252,8 +252,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
|||||||
|
|
||||||
// Set asymmetric key that is used to encrypt the message
|
// Set asymmetric key that is used to encrypt the message
|
||||||
if pubKeyGiven {
|
if pubKeyGiven {
|
||||||
params.Dst = crypto.ToECDSAPub(req.PublicKey)
|
if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
|
||||||
if !ValidatePublicKey(params.Dst) {
|
|
||||||
return false, ErrInvalidPublicKey
|
return false, ErrInvalidPublicKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,8 +328,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(crit.Sig) > 0 {
|
if len(crit.Sig) > 0 {
|
||||||
filter.Src = crypto.ToECDSAPub(crit.Sig)
|
if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
|
||||||
if !ValidatePublicKey(filter.Src) {
|
|
||||||
return nil, ErrInvalidSigningPubKey
|
return nil, ErrInvalidSigningPubKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -513,8 +511,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(req.Sig) > 0 {
|
if len(req.Sig) > 0 {
|
||||||
src = crypto.ToECDSAPub(req.Sig)
|
if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
|
||||||
if !ValidatePublicKey(src) {
|
|
||||||
return "", ErrInvalidSigningPubKey
|
return "", ErrInvalidSigningPubKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,8 +272,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil.
|
|||||||
|
|
||||||
// Set asymmetric key that is used to encrypt the message
|
// Set asymmetric key that is used to encrypt the message
|
||||||
if pubKeyGiven {
|
if pubKeyGiven {
|
||||||
params.Dst = crypto.ToECDSAPub(req.PublicKey)
|
if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
|
||||||
if !ValidatePublicKey(params.Dst) {
|
|
||||||
return nil, ErrInvalidPublicKey
|
return nil, ErrInvalidPublicKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,8 +359,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(crit.Sig) > 0 {
|
if len(crit.Sig) > 0 {
|
||||||
filter.Src = crypto.ToECDSAPub(crit.Sig)
|
if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
|
||||||
if !ValidatePublicKey(filter.Src) {
|
|
||||||
return nil, ErrInvalidSigningPubKey
|
return nil, ErrInvalidSigningPubKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -544,8 +542,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(req.Sig) > 0 {
|
if len(req.Sig) > 0 {
|
||||||
src = crypto.ToECDSAPub(req.Sig)
|
if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
|
||||||
if !ValidatePublicKey(src) {
|
|
||||||
return "", ErrInvalidSigningPubKey
|
return "", ErrInvalidSigningPubKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user