@@ -21,6 +21,7 @@ package fipstest
21
21
import (
22
22
"bufio"
23
23
"bytes"
24
+ "crypto/elliptic"
24
25
"crypto/internal/cryptotest"
25
26
"crypto/internal/fips140"
26
27
"crypto/internal/fips140/ecdsa"
@@ -32,12 +33,14 @@ import (
32
33
"crypto/internal/fips140/sha256"
33
34
"crypto/internal/fips140/sha3"
34
35
"crypto/internal/fips140/sha512"
36
+ "crypto/rand"
35
37
_ "embed"
36
38
"encoding/binary"
37
39
"errors"
38
40
"fmt"
39
41
"internal/testenv"
40
42
"io"
43
+ "math/big"
41
44
"os"
42
45
"path/filepath"
43
46
"strings"
85
88
// https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2
86
89
// EDDSA algorithm capabilities:
87
90
// https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7
91
+ // ECDSA algorithm capabilities:
92
+ // https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#section-7
88
93
//go:embed acvp_capabilities.json
89
94
capabilitiesJson []byte
90
95
@@ -151,6 +156,11 @@ var (
151
156
"EDDSA/keyVer" : cmdEddsaKeyVerAft (),
152
157
"EDDSA/sigGen" : cmdEddsaSigGenAftBft (),
153
158
"EDDSA/sigVer" : cmdEddsaSigVerAft (),
159
+
160
+ "ECDSA/keyGen" : cmdEcdsaKeyGenAft (),
161
+ "ECDSA/keyVer" : cmdEcdsaKeyVerAft (),
162
+ "ECDSA/sigGen" : cmdEcdsaSigGenAft (),
163
+ "ECDSA/sigVer" : cmdEcdsaSigVerAft (),
154
164
}
155
165
)
156
166
@@ -526,6 +536,208 @@ func cmdEddsaSigVerAft() command {
526
536
}
527
537
}
528
538
539
+ func cmdEcdsaKeyGenAft () command {
540
+ return command {
541
+ requiredArgs : 1 , // Curve name
542
+ handler : func (args [][]byte ) ([][]byte , error ) {
543
+ curve , err := lookupCurve (string (args [0 ]))
544
+ if err != nil {
545
+ return nil , err
546
+ }
547
+
548
+ var sk * ecdsa.PrivateKey
549
+ switch curve .Params () {
550
+ case elliptic .P224 ().Params ():
551
+ sk , err = ecdsa .GenerateKey (ecdsa .P224 (), rand .Reader )
552
+ case elliptic .P256 ().Params ():
553
+ sk , err = ecdsa .GenerateKey (ecdsa .P256 (), rand .Reader )
554
+ case elliptic .P384 ().Params ():
555
+ sk , err = ecdsa .GenerateKey (ecdsa .P384 (), rand .Reader )
556
+ case elliptic .P521 ().Params ():
557
+ sk , err = ecdsa .GenerateKey (ecdsa .P521 (), rand .Reader )
558
+ default :
559
+ return nil , fmt .Errorf ("unsupported curve: %v" , curve )
560
+ }
561
+
562
+ if err != nil {
563
+ return nil , err
564
+ }
565
+
566
+ pubBytes := sk .PublicKey ().Bytes ()
567
+ byteLen := (curve .Params ().BitSize + 7 ) / 8
568
+
569
+ return [][]byte {
570
+ sk .Bytes (),
571
+ pubBytes [1 : 1 + byteLen ],
572
+ pubBytes [1 + byteLen :],
573
+ }, nil
574
+ },
575
+ }
576
+ }
577
+
578
+ func cmdEcdsaKeyVerAft () command {
579
+ return command {
580
+ requiredArgs : 3 , // Curve name, X, Y
581
+ handler : func (args [][]byte ) ([][]byte , error ) {
582
+ curve , err := lookupCurve (string (args [0 ]))
583
+ if err != nil {
584
+ return nil , err
585
+ }
586
+
587
+ x := new (big.Int ).SetBytes (args [1 ])
588
+ y := new (big.Int ).SetBytes (args [2 ])
589
+
590
+ if curve .IsOnCurve (x , y ) {
591
+ return [][]byte {{1 }}, nil
592
+ }
593
+
594
+ return [][]byte {{0 }}, nil
595
+ },
596
+ }
597
+ }
598
+
599
+ // pointFromAffine is used to convert the PublicKey to a nistec SetBytes input.
600
+ // Duplicated from crypto/ecdsa.go's pointFromAffine.
601
+ func pointFromAffine (curve elliptic.Curve , x , y * big.Int ) ([]byte , error ) {
602
+ bitSize := curve .Params ().BitSize
603
+ // Reject values that would not get correctly encoded.
604
+ if x .Sign () < 0 || y .Sign () < 0 {
605
+ return nil , errors .New ("negative coordinate" )
606
+ }
607
+ if x .BitLen () > bitSize || y .BitLen () > bitSize {
608
+ return nil , errors .New ("overflowing coordinate" )
609
+ }
610
+ // Encode the coordinates and let SetBytes reject invalid points.
611
+ byteLen := (bitSize + 7 ) / 8
612
+ buf := make ([]byte , 1 + 2 * byteLen )
613
+ buf [0 ] = 4 // uncompressed point
614
+ x .FillBytes (buf [1 : 1 + byteLen ])
615
+ y .FillBytes (buf [1 + byteLen : 1 + 2 * byteLen ])
616
+ return buf , nil
617
+ }
618
+
619
+ func signEcdsa [P ecdsa.Point [P ], H fips140.Hash ](c * ecdsa.Curve [P ], h func () H , q []byte , sk []byte , digest []byte ) (* ecdsa.Signature , error ) {
620
+ priv , err := ecdsa .NewPrivateKey (c , sk , q )
621
+ if err != nil {
622
+ return nil , fmt .Errorf ("invalid private key: %w" , err )
623
+ }
624
+
625
+ sig , err := ecdsa .Sign (c , h , priv , rand .Reader , digest )
626
+ if err != nil {
627
+ return nil , fmt .Errorf ("signing failed: %w" , err )
628
+ }
629
+
630
+ return sig , nil
631
+ }
632
+
633
+ func cmdEcdsaSigGenAft () command {
634
+ return command {
635
+ requiredArgs : 4 , // Curve name, private key, hash name, message
636
+ handler : func (args [][]byte ) ([][]byte , error ) {
637
+ curve , err := lookupCurve (string (args [0 ]))
638
+ if err != nil {
639
+ return nil , err
640
+ }
641
+
642
+ sk := args [1 ]
643
+
644
+ newH , err := lookupHash (string (args [2 ]))
645
+ if err != nil {
646
+ return nil , err
647
+ }
648
+
649
+ msg := args [3 ]
650
+ hashFunc := newH ()
651
+ hashFunc .Write (msg )
652
+ digest := hashFunc .Sum (nil )
653
+
654
+ d := new (big.Int ).SetBytes (sk )
655
+ x , y := curve .ScalarBaseMult (d .Bytes ())
656
+ q , err := pointFromAffine (curve , x , y )
657
+ if err != nil {
658
+ return nil , err
659
+ }
660
+
661
+ var sig * ecdsa.Signature
662
+ switch curve .Params () {
663
+ case elliptic .P224 ().Params ():
664
+ sig , err = signEcdsa (ecdsa .P224 (), newH , q , sk , digest )
665
+ case elliptic .P256 ().Params ():
666
+ sig , err = signEcdsa (ecdsa .P256 (), newH , q , sk , digest )
667
+ case elliptic .P384 ().Params ():
668
+ sig , err = signEcdsa (ecdsa .P384 (), newH , q , sk , digest )
669
+ case elliptic .P521 ().Params ():
670
+ sig , err = signEcdsa (ecdsa .P521 (), newH , q , sk , digest )
671
+ default :
672
+ return nil , fmt .Errorf ("unsupported curve: %v" , curve )
673
+ }
674
+ if err != nil {
675
+ return nil , err
676
+ }
677
+
678
+ return [][]byte {sig .R , sig .S }, nil
679
+ },
680
+ }
681
+ }
682
+
683
+ func cmdEcdsaSigVerAft () command {
684
+ return command {
685
+ requiredArgs : 7 , // Curve name, hash name, message, X, Y, R, S
686
+ handler : func (args [][]byte ) ([][]byte , error ) {
687
+ curve , err := lookupCurve (string (args [0 ]))
688
+ if err != nil {
689
+ return nil , err
690
+ }
691
+
692
+ newH , err := lookupHash (string (args [1 ]))
693
+ if err != nil {
694
+ return nil , err
695
+ }
696
+
697
+ msg := args [2 ]
698
+ hashFunc := newH ()
699
+ hashFunc .Write (msg )
700
+ digest := hashFunc .Sum (nil )
701
+
702
+ x , y := args [3 ], args [4 ]
703
+ q , err := pointFromAffine (curve , new (big.Int ).SetBytes (x ), new (big.Int ).SetBytes (y ))
704
+ if err != nil {
705
+ return nil , fmt .Errorf ("invalid x/y coordinates: %v" , err )
706
+ }
707
+
708
+ signature := & ecdsa.Signature {R : args [5 ], S : args [6 ]}
709
+
710
+ switch curve .Params () {
711
+ case elliptic .P224 ().Params ():
712
+ err = verifyEcdsa (ecdsa .P224 (), q , digest , signature )
713
+ case elliptic .P256 ().Params ():
714
+ err = verifyEcdsa (ecdsa .P256 (), q , digest , signature )
715
+ case elliptic .P384 ().Params ():
716
+ err = verifyEcdsa (ecdsa .P384 (), q , digest , signature )
717
+ case elliptic .P521 ().Params ():
718
+ err = verifyEcdsa (ecdsa .P521 (), q , digest , signature )
719
+ default :
720
+ return nil , fmt .Errorf ("unsupported curve: %v" , curve )
721
+ }
722
+
723
+ if err == nil {
724
+ return [][]byte {{1 }}, nil
725
+ }
726
+
727
+ return [][]byte {{0 }}, nil
728
+ },
729
+ }
730
+ }
731
+
732
+ func verifyEcdsa [P ecdsa.Point [P ]](c * ecdsa.Curve [P ], q []byte , digest []byte , sig * ecdsa.Signature ) error {
733
+ pub , err := ecdsa .NewPublicKey (c , q )
734
+ if err != nil {
735
+ return fmt .Errorf ("invalid public key: %w" , err )
736
+ }
737
+
738
+ return ecdsa .Verify (c , pub , digest , sig )
739
+ }
740
+
529
741
func lookupHash (name string ) (func () fips140.Hash , error ) {
530
742
var h func () fips140.Hash
531
743
@@ -714,6 +926,25 @@ func cmdHmacDrbgAft(h func() fips140.Hash) command {
714
926
}
715
927
}
716
928
929
+ func lookupCurve (name string ) (elliptic.Curve , error ) {
930
+ var c elliptic.Curve
931
+
932
+ switch name {
933
+ case "P-224" :
934
+ c = elliptic .P224 ()
935
+ case "P-256" :
936
+ c = elliptic .P256 ()
937
+ case "P-384" :
938
+ c = elliptic .P384 ()
939
+ case "P-521" :
940
+ c = elliptic .P521 ()
941
+ default :
942
+ return nil , fmt .Errorf ("unknown curve name: %q" , name )
943
+ }
944
+
945
+ return c , nil
946
+ }
947
+
717
948
func TestACVP (t * testing.T ) {
718
949
testenv .SkipIfShortAndSlow (t )
719
950
0 commit comments