From 9a4e7578d5eb502e1d8eb7b83a910ea3114912c2 Mon Sep 17 00:00:00 2001 From: Moreno Ambrosin Date: Wed, 20 Nov 2024 05:18:44 -0800 Subject: [PATCH] Use `ecdsa.{SignASN1,VerifyASN1}` in `subtle.{ECDSASigner,ECDSAVerifier}` This avoids using the legacy `ecdsa.Sign` [1] for DER encoded signatures -- this is still used for the IEEE_P1363 encoding, and `ecdsa.Verify` [2]. The `crypto/ecdsa` package is moving away from using `math/big` [3]. [1] https://github.com/golang/go/blob/fe7d97d0322c283462b38c0f53bc340b642fe1cb/src/crypto/ecdsa/ecdsa_legacy.go#L59 [2] https://github.com/golang/go/blob/fe7d97d0322c283462b38c0f53bc340b642fe1cb/src/crypto/ecdsa/ecdsa_legacy.go#L135 [3] https://github.com/golang/go/commit/08f2091ce0817346458d2ae984ccea77817cd516 PiperOrigin-RevId: 698354627 Change-Id: I3b83575d614a65127f480a41cf90d76288444f4c --- signature/subtle/ecdsa_signer.go | 30 ++++++++++++++++++++---------- signature/subtle/ecdsa_verifier.go | 28 +++++++++++++++++++--------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/signature/subtle/ecdsa_signer.go b/signature/subtle/ecdsa_signer.go index ecc20a6..64b9e13 100644 --- a/signature/subtle/ecdsa_signer.go +++ b/signature/subtle/ecdsa_signer.go @@ -69,15 +69,25 @@ func (e *ECDSASigner) Sign(data []byte) ([]byte, error) { if err != nil { return nil, err } - r, s, err := ecdsa.Sign(rand.Reader, e.privateKey, hashed) - if err != nil { - return nil, fmt.Errorf("ecdsa_signer: signing failed: %s", err) - } - // format the signature - sig := NewECDSASignature(r, s) - ret, err := sig.EncodeECDSASignature(e.encoding, e.privateKey.PublicKey.Curve.Params().Name) - if err != nil { - return nil, fmt.Errorf("ecdsa_signer: signing failed: %s", err) + var signatureBytes []byte + switch e.encoding { + case "IEEE_P1363": + r, s, err := ecdsa.Sign(rand.Reader, e.privateKey, hashed) + if err != nil { + return nil, err + } + sig := NewECDSASignature(r, s) + signatureBytes, err = sig.EncodeECDSASignature(e.encoding, e.privateKey.PublicKey.Curve.Params().Name) + if err != nil { + return nil, fmt.Errorf("ecdsa_signer: signing failed: %s", err) + } + case "DER": + signatureBytes, err = ecdsa.SignASN1(rand.Reader, e.privateKey, hashed) + if err != nil { + return nil, fmt.Errorf("ecdsa_signer: signing failed: %s", err) + } + default: + return nil, fmt.Errorf("ecdsa_signer: unsupported encoding: %s", e.encoding) } - return ret, nil + return signatureBytes, nil } diff --git a/signature/subtle/ecdsa_verifier.go b/signature/subtle/ecdsa_verifier.go index 70784bc..87a90bb 100644 --- a/signature/subtle/ecdsa_verifier.go +++ b/signature/subtle/ecdsa_verifier.go @@ -21,11 +21,10 @@ import ( "hash" "math/big" + internalecdsa "github.com/tink-crypto/tink-go/v2/internal/signature/ecdsa" "github.com/tink-crypto/tink-go/v2/subtle" ) -var errInvalidECDSASignature = errors.New("ecdsa_verifier: invalid signature") - // ECDSAVerifier is an implementation of Verifier for ECDSA. // At the moment, the implementation only accepts signatures with strict DER encoding. type ECDSAVerifier struct { @@ -67,17 +66,28 @@ func NewECDSAVerifierFromPublicKey(hashAlg string, encoding string, publicKey *e // Verify verifies whether the given signature is valid for the given data. // It returns an error if the signature is not valid; nil otherwise. func (e *ECDSAVerifier) Verify(signatureBytes, data []byte) error { - signature, err := DecodeECDSASignature(signatureBytes, e.encoding) - if err != nil { - return fmt.Errorf("ecdsa_verifier: %s", err) - } hashed, err := subtle.ComputeHash(e.hashFunc, data) if err != nil { return err } - valid := ecdsa.Verify(e.publicKey, hashed, signature.R, signature.S) - if !valid { - return errInvalidECDSASignature + var asn1Signature []byte + switch e.encoding { + case "DER": + asn1Signature = signatureBytes + case "IEEE_P1363": + decodedSig, err := internalecdsa.IEEEP1363Decode(signatureBytes) + if err != nil { + return err + } + asn1Signature, err = internalecdsa.ASN1Encode(decodedSig) + if err != nil { + return err + } + default: + return fmt.Errorf("ecdsa: unsupported encoding: %s", e.encoding) + } + if ok := ecdsa.VerifyASN1(e.publicKey, hashed, asn1Signature); !ok { + return fmt.Errorf("ecdsa_verifier: invalid signature") } return nil }