@@ -12,6 +12,7 @@ import (
1212 "encoding/json"
1313 "fmt"
1414 "io"
15+ "math/big"
1516 "net/http"
1617 "time"
1718)
@@ -86,10 +87,13 @@ func (c *CryptoProvider) signMessage(privateKeyBytes []byte, message []byte) ([]
8687
8788 digest := sha512.Sum384(message)
8889 curve := elliptic.P384()
89- privateKey, err := ecdsa.ParseRawPrivateKey(curve, privateKeyBytes)
90+
91+ // Parse the raw private key (compatible with Go 1.24)
92+ privateKey, err := parseRawPrivateKey(curve, privateKeyBytes)
9093 if err != nil {
9194 return nil, fmt.Errorf("failed to parse ECDSA private key: %w", err)
9295 }
96+
9397 r, s, err := ecdsa.Sign(rand.Reader, privateKey, digest[:])
9498 if err != nil {
9599 return nil, fmt.Errorf("failed to sign message: %w", err)
@@ -101,6 +105,38 @@ func (c *CryptoProvider) signMessage(privateKeyBytes []byte, message []byte) ([]
101105 }
102106}
103107
108+ // parseRawPrivateKey parses a raw ECDSA private key from bytes.
109+ // This mimics crypto/ecdsa.ParseRawPrivateKey from Go 1.25+ for compatibility with Go 1.24.
110+ func parseRawPrivateKey(curve elliptic.Curve, privateKeyBytes []byte) (*ecdsa.PrivateKey, error) {
111+ if curve == nil {
112+ return nil, fmt.Errorf("nil curve")
113+ }
114+
115+ // Only standard NIST curves supported
116+ switch curve {
117+ case elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521():
118+ // ok
119+ default:
120+ return nil, fmt.Errorf("unsupported curve")
121+ }
122+
123+ d := new(big.Int).SetBytes(privateKeyBytes)
124+ params := curve.Params()
125+ if d.Sign() <= 0 || d.Cmp(params.N) >= 0 {
126+ return nil, fmt.Errorf("invalid private scalar")
127+ }
128+
129+ x, y := curve.ScalarBaseMult(d.Bytes())
130+ return &ecdsa.PrivateKey{
131+ PublicKey: ecdsa.PublicKey{
132+ Curve: curve,
133+ X: x,
134+ Y: y,
135+ },
136+ D: d,
137+ }, nil
138+ }
139+
104140// NeedsLogin always returns false for cryptographic auth since no interactive login is needed
105141func (c *CryptoProvider) NeedsLogin() bool {
106142 return false
0 commit comments