From d6ed06cf156127660b34e52c2353d93c4d0b7a4d Mon Sep 17 00:00:00 2001 From: kt <45947799+kanywst@users.noreply.github.com> Date: Thu, 5 Mar 2026 23:46:03 +0900 Subject: [PATCH] internal/providers/aws: Refactor deprecated crypto/elliptic APIs to crypto/ecdh (#8395) Following SA1019 deprecation warnings in Go 1.21+, the legacy curve.ScalarBaseMult and curve.IsOnCurve calls for NIST curves (like P256) are substituted with their crypto/ecdh standard equivalents. Tests continue to parse and verify AWS V4a signatures equivalently under the new module constraints. Signed-off-by: kanywst --- internal/providers/aws/crypto/ecc.go | 59 +++++++++++++++++++++++++-- internal/providers/aws/signing_v4a.go | 14 ++++++- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/internal/providers/aws/crypto/ecc.go b/internal/providers/aws/crypto/ecc.go index 12679a15be..f93261a809 100644 --- a/internal/providers/aws/crypto/ecc.go +++ b/internal/providers/aws/crypto/ecc.go @@ -2,6 +2,7 @@ package crypto import ( "bytes" + "crypto/ecdh" "crypto/ecdsa" "crypto/elliptic" "crypto/hmac" @@ -27,27 +28,77 @@ func ECDSAKey(curve elliptic.Curve, d []byte) *ecdsa.PrivateKey { // ECDSAKeyFromPoint takes the given elliptic curve and point and returns the // private and public keypair func ECDSAKeyFromPoint(curve elliptic.Curve, d *big.Int) *ecdsa.PrivateKey { - pX, pY := curve.ScalarBaseMult(d.Bytes()) + dBytes := make([]byte, (curve.Params().BitSize+7)/8) + d.FillBytes(dBytes) privKey := &ecdsa.PrivateKey{ PublicKey: ecdsa.PublicKey{ Curve: curve, - X: pX, - Y: pY, }, D: d, } + var pubBytes []byte + switch curve { + case elliptic.P256(): + if ecdhPriv, err := ecdh.P256().NewPrivateKey(dBytes); err == nil { + pubBytes = ecdhPriv.PublicKey().Bytes() + } + case elliptic.P384(): + if ecdhPriv, err := ecdh.P384().NewPrivateKey(dBytes); err == nil { + pubBytes = ecdhPriv.PublicKey().Bytes() + } + case elliptic.P521(): + if ecdhPriv, err := ecdh.P521().NewPrivateKey(dBytes); err == nil { + pubBytes = ecdhPriv.PublicKey().Bytes() + } + } + + if len(pubBytes) > 0 { + byteLen := (curve.Params().BitSize + 7) / 8 + privKey.X = new(big.Int).SetBytes(pubBytes[1 : 1+byteLen]) + privKey.Y = new(big.Int).SetBytes(pubBytes[1+byteLen:]) + } else { + panic(fmt.Sprintf("unsupported curve or invalid private key: %v", curve)) + } + return privKey } +// mathIntToBytes writes val as a big-endian, fixed-length byte slice into out, +// zero-padding on the left when val.Bytes() is shorter than out. This satisfies +// the uncompressed SEC 1 encoding (0x04 || X || Y) expected by crypto/ecdh's +// NewPublicKey: https://pkg.go.dev/crypto/ecdh#Curve.NewPublicKey +func mathIntToBytes(val *big.Int, out []byte) { + valBytes := val.Bytes() + copy(out[len(out)-len(valBytes):], valBytes) +} + // ECDSAPublicKey takes the provide curve and (x, y) coordinates and returns // *ecdsa.PublicKey. Returns an error if the given points are not on the curve. func ECDSAPublicKey(curve elliptic.Curve, x, y []byte) (*ecdsa.PublicKey, error) { xPoint := (&big.Int{}).SetBytes(x) yPoint := (&big.Int{}).SetBytes(y) - if !curve.IsOnCurve(xPoint, yPoint) { + byteLen := (curve.Params().BitSize + 7) / 8 + buf := make([]byte, 1+2*byteLen) + buf[0] = 4 // uncompressed point + mathIntToBytes(xPoint, buf[1:1+byteLen]) + mathIntToBytes(yPoint, buf[1+byteLen:]) + + var err error + switch curve { + case elliptic.P256(): + _, err = ecdh.P256().NewPublicKey(buf) + case elliptic.P384(): + _, err = ecdh.P384().NewPublicKey(buf) + case elliptic.P521(): + _, err = ecdh.P521().NewPublicKey(buf) + default: + err = fmt.Errorf("unsupported curve for ECDSA: %v", curve) + } + + if err != nil { return nil, fmt.Errorf("point(%v, %v) is not on the given curve", xPoint.String(), yPoint.String()) } diff --git a/internal/providers/aws/signing_v4a.go b/internal/providers/aws/signing_v4a.go index 8f6d760e82..db20eddc9d 100644 --- a/internal/providers/aws/signing_v4a.go +++ b/internal/providers/aws/signing_v4a.go @@ -4,6 +4,7 @@ package aws import ( "bytes" "crypto" + "crypto/ecdh" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" @@ -115,7 +116,18 @@ func deriveKeyFromAccessKeyPair(accessKey, secretKey string) (*ecdsa.PrivateKey, priv := new(ecdsa.PrivateKey) priv.PublicKey.Curve = p256 priv.D = d - priv.PublicKey.X, priv.PublicKey.Y = p256.ScalarBaseMult(d.Bytes()) + + dBytes := make([]byte, 32) + d.FillBytes(dBytes) + + ecdhPriv, err := ecdh.P256().NewPrivateKey(dBytes) + if err != nil { + return nil, err + } + pubBytes := ecdhPriv.PublicKey().Bytes() + + priv.PublicKey.X = new(big.Int).SetBytes(pubBytes[1:33]) + priv.PublicKey.Y = new(big.Int).SetBytes(pubBytes[33:]) return priv, nil }