From 2add69303ec20700f7d67a02e61f82be792c73bb Mon Sep 17 00:00:00 2001 From: Dory Date: Wed, 11 Sep 2024 01:36:31 -0700 Subject: [PATCH] Add back crypto.Signer support for ECDSA signing keys (#227) Currently only PubKeyAlgoRSA supports crypto.Signer. x/crypto/openpgp originally had support for ECDSA external crypto.Signer. This change adds that back. --- openpgp/packet/signature.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/openpgp/packet/signature.go b/openpgp/packet/signature.go index 90097951d..b76488423 100644 --- a/openpgp/packet/signature.go +++ b/openpgp/packet/signature.go @@ -5,9 +5,11 @@ package packet import ( + "math/big" "bytes" "crypto" "crypto/dsa" + "encoding/asn1" "encoding/binary" "hash" "io" @@ -927,8 +929,16 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e sig.DSASigS = new(encoding.MPI).SetBig(s) } case PubKeyAlgoECDSA: - sk := priv.PrivateKey.(*ecdsa.PrivateKey) - r, s, err := ecdsa.Sign(config.Random(), sk, digest) + var r, s *big.Int + if sk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok { + r, s, err = ecdsa.Sign(config.Random(), sk, digest) + } else { + var b []byte + b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) + if err == nil { + r, s, err = unwrapECDSASig(b) + } + } if err == nil { sig.ECDSASigR = new(encoding.MPI).SetBig(r) @@ -960,6 +970,18 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e return } +// unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA signature. +func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { + var ecsdaSig struct { + R, S *big.Int + } + _, err = asn1.Unmarshal(b, &ecsdaSig) + if err != nil { + return + } + return ecsdaSig.R, ecsdaSig.S, nil +} + // SignUserId computes a signature from priv, asserting that pub is a valid // key for the identity id. On success, the signature is stored in sig. Call // Serialize to write it out.