Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions openpgp/packet/private_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ import (
"bytes"
"crypto"
"crypto/dsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"fmt"
"hash"
"io"
"math/big"
mathrand "math/rand"
"testing"
"time"

"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
pgped25519 "github.com/ProtonMail/go-crypto/openpgp/ed25519"
"github.com/ProtonMail/go-crypto/openpgp/eddsa"
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
Expand Down Expand Up @@ -449,6 +452,86 @@ func TestEdDSASignerPrivateKeyRandomizeFast(t *testing.T) {
}
}

type externalEd25519Signer struct {
priv ed25519.PrivateKey
err error
}

func (s *externalEd25519Signer) Public() crypto.PublicKey {
return s.priv.Public()
}

func (s *externalEd25519Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
if s.err != nil {
return nil, s.err
}
if opts.HashFunc() != crypto.Hash(0) {
return nil, fmt.Errorf("ed25519 signs the message itself, got hash %v", opts.HashFunc())
}
return s.priv.Sign(rand, digest, opts)
}

func signAndVerifyWithExternalSigner(t *testing.T, priv *PrivateKey, sig *Signature) {
t.Helper()
msg := make([]byte, maxMessageLength)
rand.Read(msg)

h, err := populateHash(sig.Hash, msg)
if err != nil {
t.Fatal(err)
}
if err := sig.Sign(h, priv, nil); err != nil {
t.Fatal(err)
}

if h, err = populateHash(sig.Hash, msg); err != nil {
t.Fatal(err)
}
if err := priv.VerifySignature(h, sig); err != nil {
t.Fatal(err)
}
}

func TestExternalEdDSASignerPrivateKeyRandomizeFast(t *testing.T) {
pub, stdPriv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
eddsaPub := eddsa.NewPublicKey(ecc.NewEd25519())
eddsaPub.X = pub

priv := &PrivateKey{
PublicKey: *NewEdDSAPublicKey(time.Now(), eddsaPub),
PrivateKey: &externalEd25519Signer{priv: stdPriv},
}
sig := &Signature{
Version: 4,
PubKeyAlgo: PubKeyAlgoEdDSA,
Hash: crypto.SHA256,
}
signAndVerifyWithExternalSigner(t, priv, sig)
}

func TestExternalEd25519SignerPrivateKeyRandomizeFast(t *testing.T) {
pub, stdPriv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
pgpPub := pgped25519.NewPublicKey()
pgpPub.Point = pub

priv := &PrivateKey{
PublicKey: *NewEd25519PublicKey(time.Now(), pgpPub),
PrivateKey: &externalEd25519Signer{priv: stdPriv},
}
sig := &Signature{
Version: 4,
PubKeyAlgo: PubKeyAlgoEd25519,
Hash: crypto.SHA256,
}
signAndVerifyWithExternalSigner(t, priv, sig)
}

// Tests correctness when encrypting an EdDSA private key with a password.
func TestEncryptDecryptEdDSAPrivateKeyRandomizeFast(t *testing.T) {
password := make([]byte, 20)
Expand Down
78 changes: 61 additions & 17 deletions openpgp/packet/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,8 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
// supports both *rsa.PrivateKey and crypto.Signer
sigdata, err := priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash)
var sigdata []byte
sigdata, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash)
if err == nil {
sig.RSASignature = encoding.NewMPI(sigdata)
}
Expand All @@ -1006,7 +1007,8 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
if len(digest) > subgroupSize {
digest = digest[:subgroupSize]
}
r, s, err := dsa.Sign(config.Random(), dsaPriv, digest)
var r, s *big.Int
r, s, err = dsa.Sign(config.Random(), dsaPriv, digest)
if err == nil {
sig.DSASigR = new(encoding.MPI).SetBig(r)
sig.DSASigS = new(encoding.MPI).SetBig(s)
Expand All @@ -1028,30 +1030,71 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
sig.ECDSASigS = new(encoding.MPI).SetBig(s)
}
case PubKeyAlgoEdDSA:
sk := priv.PrivateKey.(*eddsa.PrivateKey)
r, s, err := eddsa.Sign(sk, digest)
if err == nil {
sig.EdDSASigR = encoding.NewMPI(r)
sig.EdDSASigS = encoding.NewMPI(s)
if sk, ok := priv.PrivateKey.(*eddsa.PrivateKey); ok {
var r, s []byte
r, s, err = eddsa.Sign(sk, digest)
if err == nil {
sig.EdDSASigR = encoding.NewMPI(r)
sig.EdDSASigS = encoding.NewMPI(s)
}
} else {
// Pure EdDSA, digest is message to sign
pub := priv.PublicKey.PublicKey.(*eddsa.PublicKey)
var b []byte
b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, crypto.Hash(0))
if err == nil {
if len(b) != 2*len(pub.X) {
err = errors.InvalidArgumentError("signer returned an eddsa signature of unexpected length")
} else {
r, s := pub.GetCurve().MarshalSignature(b)
sig.EdDSASigR = encoding.NewMPI(r)
sig.EdDSASigS = encoding.NewMPI(s)
}
}
}
case PubKeyAlgoEd25519:
sk := priv.PrivateKey.(*ed25519.PrivateKey)
signature, err := ed25519.Sign(sk, digest)
if err == nil {
sig.EdSig = signature
if sk, ok := priv.PrivateKey.(*ed25519.PrivateKey); ok {
var signature []byte
signature, err = ed25519.Sign(sk, digest)
if err == nil {
sig.EdSig = signature
}
} else {
var b []byte
b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, crypto.Hash(0))
if err == nil {
if len(b) != ed25519.SignatureSize {
err = errors.InvalidArgumentError("signer returned an ed25519 signature of unexpected length")
} else {
sig.EdSig = b
}
}
}
case PubKeyAlgoEd448:
sk := priv.PrivateKey.(*ed448.PrivateKey)
signature, err := ed448.Sign(sk, digest)
if err == nil {
sig.EdSig = signature
if sk, ok := priv.PrivateKey.(*ed448.PrivateKey); ok {
var signature []byte
signature, err = ed448.Sign(sk, digest)
if err == nil {
sig.EdSig = signature
}
} else {
var b []byte
b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, crypto.Hash(0))
if err == nil {
if len(b) != ed448.SignatureSize {
err = errors.InvalidArgumentError("signer returned an ed448 signature of unexpected length")
} else {
sig.EdSig = b
}
}
}
case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448:
if sig.Version != 6 {
return errors.StructuralError("cannot use MldsaEdDsa on a non-v6 signature")
}
sk := priv.PrivateKey.(*mldsa_eddsa.PrivateKey)
dSig, ecSig, err := mldsa_eddsa.Sign(sk, digest)
var dSig, ecSig []byte
dSig, ecSig, err = mldsa_eddsa.Sign(sk, digest)

if err == nil {
sig.MldsaSig = dSig
Expand All @@ -1062,7 +1105,8 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
return errors.StructuralError("cannot use SLH-DSA on a non-v6 signature")
}
sk := priv.PrivateKey.(*slhdsa.PrivateKey)
dSig, err := slhdsa.Sign(sk, digest)
var dSig []byte
dSig, err = slhdsa.Sign(sk, digest)

if err == nil {
sig.SlhdsaSig = dSig
Expand Down