{"algorithm":"TLS-v1.3","mode":"KDF","revision":"RFC8446","hmacAlg":["SHA2-256","SHA2-384"],"runningMode":["DHE","PSK","PSK-DHE"]},
{"algorithm":"kdf-components","mode":"ssh","revision":"1.0","hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512"],"cipher":["AES-128","AES-192","AES-256"]},
- {"algorithm":"KAS-ECC-SSC","revision":"Sp800-56Ar3","scheme":{"ephemeralUnified":{"kasRole":["initiator","responder"]},"staticUnified":{"kasRole":["initiator","responder"]}},"domainParameterGenerationMethods":["P-224","P-256","P-384","P-521"]}
+ {"algorithm":"KAS-ECC-SSC","revision":"Sp800-56Ar3","scheme":{"ephemeralUnified":{"kasRole":["initiator","responder"]},"staticUnified":{"kasRole":["initiator","responder"]}},"domainParameterGenerationMethods":["P-224","P-256","P-384","P-521"]},
+
+ {"algorithm":"KDF","revision":"1.0","capabilities":[{"kdfMode":"counter","macMode":["CMAC-AES128","CMAC-AES192","CMAC-AES256"],"supportedLengths":[256],"fixedDataOrder":["before fixed data"],"counterLength":[16]}]}
]
// https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html#section-7.3
// HMAC DRBG and CTR DRBG algorithm capabilities:
// https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2
+ // KDF-Counter algorithm capabilities:
+ // https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html#section-7.3
//go:embed acvp_capabilities.json
capabilitiesJson []byte
"ctrDRBG/AES-256": cmdCtrDrbgAft(),
"ctrDRBG-reseed/AES-256": cmdCtrDrbgReseedAft(),
+
+ "KDF-counter": cmdKdfCounterAft(),
}
)
return (*[48]byte)(input), nil
}
+func cmdKdfCounterAft() command {
+ return command{
+ requiredArgs: 5, // Number output bytes, PRF name, counter location string, key, number of counter bits
+ handler: func(args [][]byte) ([][]byte, error) {
+ outputBytes := binary.LittleEndian.Uint32(args[0])
+ prf := args[1]
+ counterLocation := args[2]
+ key := args[3]
+ counterBits := binary.LittleEndian.Uint32(args[4])
+
+ if outputBytes != 32 {
+ return nil, fmt.Errorf("KDF received unsupported output length %d bytes", outputBytes)
+ }
+ if !bytes.Equal(prf, []byte("CMAC-AES128")) && !bytes.Equal(prf, []byte("CMAC-AES192")) && !bytes.Equal(prf, []byte("CMAC-AES256")) {
+ return nil, fmt.Errorf("KDF received unsupported PRF %q", string(prf))
+ }
+ if !bytes.Equal(counterLocation, []byte("before fixed data")) {
+ return nil, fmt.Errorf("KDF received unsupported counter location %q", string(counterLocation))
+ }
+ // The spec doesn't describe the "deferred" property for a KDF counterMode test case.
+ // BoringSSL's acvptool sends an empty key when deferred=true, but with the capabilities
+ // we register all test cases ahve deferred=false and provide a key from the populated
+ // keyIn property.
+ if len(key) == 0 {
+ return nil, errors.New("deferred test cases are not supported")
+ }
+ if counterBits != 16 {
+ return nil, fmt.Errorf("KDF received unsupported counter length %d", counterBits)
+ }
+
+ block, err := aes.New(key)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create cipher: %v", err)
+ }
+ kdf := gcm.NewCounterKDF(block)
+
+ var label byte
+ var context [12]byte
+ rand.Reader.Read(context[:])
+
+ result := kdf.DeriveKey(label, context)
+
+ fixedData := make([]byte, 1+1+12) // 1 byte label, 1 null byte, 12 bytes context.
+ fixedData[0] = label
+ copy(fixedData[2:], context[:])
+
+ return [][]byte{key, fixedData, result[:]}, nil
+ },
+ }
+}
+
func TestACVP(t *testing.T) {
testenv.SkipIfShortAndSlow(t)