core/types: fix panic on invalid signature length #33647 (#1979)

Replace panic with error return in decodeSignature to prevent crashes on
invalid inputs, and update callers to propagate the error.

Co-authored-by: DeFi Junkie <deffie.jnkiee@gmail.com>
This commit is contained in:
Daniel Liu 2026-01-27 11:25:23 +08:00 committed by GitHub
parent 105044559b
commit ab39386242
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 50 additions and 10 deletions

View file

@ -217,7 +217,10 @@ func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 {
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
}
R, S, _ = decodeSignature(sig)
R, S, _, err = decodeSignature(sig)
if err != nil {
return nil, nil, nil, err
}
V = big.NewInt(int64(sig[64]))
return R, S, V, nil
}
@ -284,7 +287,10 @@ func (s londonSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
return nil, nil, nil, ErrInvalidChainId
}
R, S, _ = decodeSignature(sig)
R, S, _, err = decodeSignature(sig)
if err != nil {
return nil, nil, nil, err
}
V = big.NewInt(int64(sig[64]))
return R, S, V, nil
}
@ -355,7 +361,10 @@ func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *bi
if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
return nil, nil, nil, ErrInvalidChainId
}
R, S, _ = decodeSignature(sig)
R, S, _, err = decodeSignature(sig)
if err != nil {
return nil, nil, nil, err
}
V = big.NewInt(int64(sig[64]))
default:
return nil, nil, nil, ErrTxTypeNotSupported
@ -440,7 +449,10 @@ func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
if tx.Type() != LegacyTxType {
return nil, nil, nil, ErrTxTypeNotSupported
}
R, S, V = decodeSignature(sig)
R, S, V, err = decodeSignature(sig)
if err != nil {
return nil, nil, nil, err
}
if s.chainId.Sign() != 0 {
V = big.NewInt(int64(sig[64] + 35))
V.Add(V, s.chainIdMul)
@ -514,8 +526,8 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *
if tx.Type() != LegacyTxType {
return nil, nil, nil, ErrTxTypeNotSupported
}
r, s, v = decodeSignature(sig)
return r, s, v, nil
r, s, v, err = decodeSignature(sig)
return r, s, v, err
}
// Hash returns the hash to be signed by the sender.
@ -531,14 +543,14 @@ func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
})
}
func decodeSignature(sig []byte) (r, s, v *big.Int) {
func decodeSignature(sig []byte) (r, s, v *big.Int, err error) {
if len(sig) != crypto.SignatureLength {
panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength))
return nil, nil, nil, fmt.Errorf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength)
}
r = new(big.Int).SetBytes(sig[:32])
s = new(big.Int).SetBytes(sig[32:64])
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
return r, s, v
return r, s, v, nil
}
func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {

View file

@ -135,3 +135,28 @@ func TestChainId(t *testing.T) {
t.Error("expected no error")
}
}
func TestSignatureValuesError(t *testing.T) {
// 1. Setup a valid transaction
tx := NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil)
signer := HomesteadSigner{}
// 2. Call WithSignature with invalid length sig (not 65 bytes)
invalidSig := make([]byte, 64)
func() {
defer func() {
if r := recover(); r != nil {
t.Fatalf("Panicked for invalid signature length, expected error: %v", r)
}
}()
_, err := tx.WithSignature(signer, invalidSig)
if err == nil {
t.Fatal("Expected error for invalid signature length, got nil")
} else {
// This is just a sanity check to ensure we got an error,
// the exact error message is verified in unit tests elsewhere if needed.
t.Logf("Got expected error: %v", err)
}
}()
}

View file

@ -94,7 +94,10 @@ func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAutho
if err != nil {
return SetCodeAuthorization{}, err
}
r, s, _ := decodeSignature(sig)
r, s, _, err := decodeSignature(sig)
if err != nil {
return SetCodeAuthorization{}, err
}
return SetCodeAuthorization{
ChainID: auth.ChainID,
Address: auth.Address,