Skip to content

Commit 8d11806

Browse files
authored
Merge pull request #144 from golang/master
[pull] master from golang:master
2 parents 7f276b1 + fb60d8c commit 8d11806

2 files changed

Lines changed: 159 additions & 2 deletions

File tree

src/crypto/mldsa/mldsa_fips140v1.26.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,16 @@ var errInvalidSignerOpts = errors.New("mldsa: invalid SignerOpts")
103103
//
104104
// [pre-hashed μ message representative]: https://www.rfc-editor.org/rfc/rfc9881.html#externalmu
105105
func (sk *PrivateKey) Sign(_ io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
106+
if sk.k == (mldsa.PrivateKey{}) {
107+
return nil, errors.New("mldsa: zero private key")
108+
}
106109
if opts == nil {
107110
opts = &Options{}
108111
}
109112
switch opts.HashFunc() {
110113
case 0:
111114
var context string
112-
if opts, ok := opts.(*Options); ok {
115+
if opts, ok := opts.(*Options); ok && opts != nil {
113116
context = opts.Context
114117
}
115118
return mldsa.Sign(&sk.k, message, context)
@@ -123,13 +126,16 @@ func (sk *PrivateKey) Sign(_ io.Reader, message []byte, opts crypto.SignerOpts)
123126
// SignDeterministic works like [PrivateKey.Sign], but the signature is
124127
// deterministic.
125128
func (sk *PrivateKey) SignDeterministic(message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
129+
if sk.k == (mldsa.PrivateKey{}) {
130+
return nil, errors.New("mldsa: zero private key")
131+
}
126132
if opts == nil {
127133
opts = &Options{}
128134
}
129135
switch opts.HashFunc() {
130136
case 0:
131137
var context string
132-
if opts, ok := opts.(*Options); ok {
138+
if opts, ok := opts.(*Options); ok && opts != nil {
133139
context = opts.Context
134140
}
135141
return mldsa.SignDeterministic(&sk.k, message, context)
@@ -210,6 +216,9 @@ func Verify(pk *PublicKey, message []byte, signature []byte, opts *Options) erro
210216
if pk == nil {
211217
return errors.New("mldsa: nil public key")
212218
}
219+
if pk.p == (mldsa.PublicKey{}) {
220+
return errors.New("mldsa: zero public key")
221+
}
213222
if opts == nil {
214223
opts = &Options{}
215224
}

src/crypto/mldsa/mldsa_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,154 @@ func TestInvalidSize(t *testing.T) {
593593
}
594594
}
595595

596+
func TestUninitialized(t *testing.T) {
597+
t.Run("Verify", func(t *testing.T) {
598+
msg := []byte("attacker-controlled message")
599+
sig := make([]byte, MLDSA44SignatureSize)
600+
601+
cases := []struct {
602+
name string
603+
fn func() error
604+
}{
605+
{"empty signature/nil opts", func() error {
606+
var pk PublicKey
607+
return Verify(&pk, msg, nil, nil)
608+
}},
609+
{"empty signature/empty opts", func() error {
610+
var pk PublicKey
611+
return Verify(&pk, msg, nil, &Options{})
612+
}},
613+
{"zero length signature", func() error {
614+
var pk PublicKey
615+
return Verify(&pk, msg, []byte{}, nil)
616+
}},
617+
{"full length signature", func() error {
618+
var pk PublicKey
619+
return Verify(&pk, msg, sig, nil)
620+
}},
621+
{"full length signature/with context", func() error {
622+
var pk PublicKey
623+
return Verify(&pk, msg, sig, &Options{Context: "ctx"})
624+
}},
625+
}
626+
for _, c := range cases {
627+
t.Run(c.name, func(t *testing.T) {
628+
err, panicked := call(c.fn)
629+
if panicked != nil {
630+
t.Errorf("Verify panicked: %v", panicked)
631+
}
632+
if err == nil {
633+
t.Error("Verify accepted uninitialized PublicKey, want error")
634+
}
635+
})
636+
}
637+
})
638+
639+
signFuncs := []struct {
640+
name string
641+
sign func(sk *PrivateKey, msg []byte, opts crypto.SignerOpts) ([]byte, error)
642+
}{
643+
{"Sign", func(sk *PrivateKey, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
644+
return sk.Sign(nil, msg, opts)
645+
}},
646+
{"SignDeterministic", func(sk *PrivateKey, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
647+
return sk.SignDeterministic(msg, opts)
648+
}},
649+
}
650+
for _, f := range signFuncs {
651+
t.Run(f.name, func(t *testing.T) {
652+
msg := []byte("message")
653+
654+
cases := []struct {
655+
name string
656+
fn func() error
657+
}{
658+
{"nil opts", func() error {
659+
var sk PrivateKey
660+
_, err := sk.Sign(nil, msg, nil)
661+
return err
662+
}},
663+
{"empty opts", func() error {
664+
var sk PrivateKey
665+
_, err := sk.Sign(nil, msg, &Options{})
666+
return err
667+
}},
668+
{"typed nil opts", func() error {
669+
var sk PrivateKey
670+
_, err := sk.Sign(nil, msg, (*Options)(nil))
671+
return err
672+
}},
673+
{"mu opts", func() error {
674+
var sk PrivateKey
675+
_, err := sk.Sign(nil, msg, muOptions{})
676+
return err
677+
}},
678+
}
679+
for _, c := range cases {
680+
t.Run(c.name, func(t *testing.T) {
681+
err, panicked := call(c.fn)
682+
if panicked != nil {
683+
t.Errorf("panicked: %v", panicked)
684+
}
685+
if err == nil {
686+
t.Error("accepted zero-value PrivateKey, want error")
687+
}
688+
})
689+
}
690+
})
691+
}
692+
693+
t.Run("TypedNilOptions", func(t *testing.T) {
694+
sk, err := GenerateKey(MLDSA44())
695+
if err != nil {
696+
t.Fatal(err)
697+
}
698+
msg := []byte("message")
699+
700+
t.Run("SignDeterministic", func(t *testing.T) {
701+
want, err := sk.SignDeterministic(msg, nil)
702+
if err != nil {
703+
t.Fatalf("SignDeterministic(nil opts): %v", err)
704+
}
705+
var got []byte
706+
_, panicked := call(func() (err error) {
707+
got, err = sk.SignDeterministic(msg, (*Options)(nil))
708+
return err
709+
})
710+
if panicked != nil {
711+
t.Fatalf("SignDeterministic(typed-nil opts) panicked: %v", panicked)
712+
}
713+
if !bytes.Equal(got, want) {
714+
t.Error("SignDeterministic(typed-nil opts) != SignDeterministic(nil opts)")
715+
}
716+
})
717+
718+
t.Run("Sign", func(t *testing.T) {
719+
var sig []byte
720+
_, panicked := call(func() (err error) {
721+
sig, err = sk.Sign(nil, msg, (*Options)(nil))
722+
return err
723+
})
724+
if panicked != nil {
725+
t.Fatalf("Sign(typed-nil opts) panicked: %v", panicked)
726+
}
727+
if err := Verify(sk.PublicKey(), msg, sig, nil); err != nil {
728+
t.Errorf("signature made with typed-nil opts does not verify under empty context: %v", err)
729+
}
730+
})
731+
})
732+
}
733+
734+
func call(fn func() error) (err error, panicked any) {
735+
defer func() { panicked = recover() }()
736+
err = fn()
737+
return err, nil
738+
}
739+
740+
type muOptions struct{}
741+
742+
func (muOptions) HashFunc() crypto.Hash { return crypto.MLDSAMu }
743+
596744
func BenchmarkSign(b *testing.B) {
597745
// Signing works by rejection sampling, which introduces massive variance in
598746
// individual signing times. To get stable but correct results, we benchmark

0 commit comments

Comments
 (0)