@@ -26,6 +26,7 @@ import (
26
26
"crypto/internal/fips140"
27
27
"crypto/internal/fips140/aes"
28
28
"crypto/internal/fips140/aes/gcm"
29
+ "crypto/internal/fips140/ecdh"
29
30
"crypto/internal/fips140/ecdsa"
30
31
"crypto/internal/fips140/ed25519"
31
32
"crypto/internal/fips140/edwards25519"
@@ -123,6 +124,8 @@ var (
123
124
// https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html#section-7.2
124
125
// SSH KDF algorithm capabilities:
125
126
// https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#section-7.2
127
+ // ECDH algorithm capabilities:
128
+ // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html
126
129
//go:embed acvp_capabilities.json
127
130
capabilitiesJson []byte
128
131
@@ -251,6 +254,11 @@ var (
251
254
"SSHKDF/SHA2-384/server" : cmdSshKdfAft (func () fips140.Hash { return sha512 .New384 () }, ssh .ServerKeys ),
252
255
"SSHKDF/SHA2-512/client" : cmdSshKdfAft (func () fips140.Hash { return sha512 .New () }, ssh .ClientKeys ),
253
256
"SSHKDF/SHA2-512/server" : cmdSshKdfAft (func () fips140.Hash { return sha512 .New () }, ssh .ServerKeys ),
257
+
258
+ "ECDH/P-224" : cmdEcdhAftVal (ecdh .P224 ()),
259
+ "ECDH/P-256" : cmdEcdhAftVal (ecdh .P256 ()),
260
+ "ECDH/P-384" : cmdEcdhAftVal (ecdh .P384 ()),
261
+ "ECDH/P-521" : cmdEcdhAftVal (ecdh .P521 ()),
254
262
}
255
263
)
256
264
@@ -1413,6 +1421,45 @@ func cmdSshKdfAft(hFunc func() fips140.Hash, direction ssh.Direction) command {
1413
1421
}
1414
1422
}
1415
1423
1424
+ func cmdEcdhAftVal [P ecdh.Point [P ]](curve * ecdh.Curve [P ]) command {
1425
+ return command {
1426
+ requiredArgs : 3 , // X, Y, private key (empty for Val type tests)
1427
+ handler : func (args [][]byte ) ([][]byte , error ) {
1428
+ peerX := args [0 ]
1429
+ peerY := args [1 ]
1430
+ rawSk := args [2 ]
1431
+
1432
+ uncompressedPk := append ([]byte {4 }, append (peerX , peerY ... )... ) // 4 for uncompressed point format
1433
+ pk , err := ecdh .NewPublicKey (curve , uncompressedPk )
1434
+ if err != nil {
1435
+ return nil , fmt .Errorf ("invalid peer public key x,y: %v" , err )
1436
+ }
1437
+
1438
+ var sk * ecdh.PrivateKey
1439
+ if len (rawSk ) > 0 {
1440
+ sk , err = ecdh .NewPrivateKey (curve , rawSk )
1441
+ } else {
1442
+ sk , err = ecdh .GenerateKey (curve , rand .Reader )
1443
+ }
1444
+ if err != nil {
1445
+ return nil , fmt .Errorf ("private key error: %v" , err )
1446
+ }
1447
+
1448
+ pubBytes := sk .PublicKey ().Bytes ()
1449
+ coordLen := (len (pubBytes ) - 1 ) / 2
1450
+ x := pubBytes [1 : 1 + coordLen ]
1451
+ y := pubBytes [1 + coordLen :]
1452
+
1453
+ secret , err := ecdh .ECDH (curve , sk , pk )
1454
+ if err != nil {
1455
+ return nil , fmt .Errorf ("key agreement failed: %v" , err )
1456
+ }
1457
+
1458
+ return [][]byte {x , y , secret }, nil
1459
+ },
1460
+ }
1461
+ }
1462
+
1416
1463
func TestACVP (t * testing.T ) {
1417
1464
testenv .SkipIfShortAndSlow (t )
1418
1465
0 commit comments