Move TLS 1.3 KDF functions into the FIPS module. Change-Id: I32a40a73f96e029ac9096af826d15b22d9dcad28 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58745 Auto-Submit: Adam Langley <agl@google.com> Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c index 8dcc415..3b51e2f 100644 --- a/crypto/fipsmodule/self_check/self_check.c +++ b/crypto/fipsmodule/self_check/self_check.c
@@ -946,6 +946,46 @@ goto err; } + // TLS v1.3: derives a dummy client-early-traffic secret. + static const uint8_t kTLS13Secret[32] = { + 0x02, 0x4a, 0x0d, 0x80, 0xf3, 0x57, 0xf2, 0x49, 0x9a, 0x12, 0x44, + 0xda, 0xc2, 0x6d, 0xab, 0x66, 0xfc, 0x13, 0xed, 0x85, 0xfc, 0xa7, + 0x1d, 0xac, 0xe1, 0x46, 0x21, 0x11, 0x19, 0x52, 0x58, 0x74, + }; + static const uint8_t kTLS13Salt[16] = { + 0x54, 0x61, 0x11, 0x36, 0x75, 0x91, 0xf0, 0xf8, + 0x92, 0xec, 0x70, 0xbd, 0x78, 0x2a, 0xef, 0x61, + }; + static const uint8_t kTLS13Label[] = "c e traffic"; + static const uint8_t kTLS13ClientHelloHash[32] = { + 0x1d, 0xe8, 0x67, 0xed, 0x93, 0x6a, 0x73, 0x65, 0x9b, 0x05, 0xcf, + 0x8a, 0x22, 0x77, 0xb7, 0x37, 0x29, 0xf2, 0x44, 0x94, 0x81, 0x6a, + 0x83, 0x33, 0x7f, 0x09, 0xbb, 0x6c, 0xc2, 0x6f, 0x48, 0x9c, + }; + static const uint8_t kTLS13ExpandLabelOutput[32] = { + 0x62, 0x91, 0x52, 0x90, 0x2e, 0xc9, 0xcf, 0x9c, 0x5f, 0x1e, 0x0a, + 0xb7, 0x00, 0x33, 0x42, 0x24, 0xc4, 0xe3, 0xba, 0x01, 0x40, 0x32, + 0x06, 0xab, 0x09, 0x23, 0x8a, 0xdd, 0x01, 0xa4, 0x05, 0xcd, + }; + uint8_t tls13_extract_output[32]; + size_t tls13_extract_output_len; + uint8_t tls13_expand_label_output[32]; + if (!HKDF_extract(tls13_extract_output, &tls13_extract_output_len, + EVP_sha256(), kTLS13Secret, sizeof(kTLS13Secret), + kTLS13Salt, sizeof(kTLS13Salt)) || + tls13_extract_output_len != sizeof(tls13_extract_output) || + !CRYPTO_tls13_hkdf_expand_label( + tls13_expand_label_output, sizeof(tls13_expand_label_output), + EVP_sha256(), tls13_extract_output, sizeof(tls13_extract_output), + kTLS13Label, sizeof(kTLS13Label) - 1, kTLS13ClientHelloHash, + sizeof(kTLS13ClientHelloHash)) || + !check_test(kTLS13ExpandLabelOutput, tls13_expand_label_output, + sizeof(kTLS13ExpandLabelOutput), + "CRYPTO_tls13_hkdf_expand_label")) { + fprintf(stderr, "TLSv1.3 KDF failed.\n"); + goto err; + } + // HKDF static const uint8_t kHKDFSecret[32] = { 0x68, 0x67, 0x85, 0x04, 0xb9, 0xb3, 0xad, 0xd1, 0x7d, 0x59, 0x67,
diff --git a/crypto/fipsmodule/tls/internal.h b/crypto/fipsmodule/tls/internal.h index ef642a6..535b7eb 100644 --- a/crypto/fipsmodule/tls/internal.h +++ b/crypto/fipsmodule/tls/internal.h
@@ -31,6 +31,14 @@ const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len); +// CRYPTO_tls13_hkdf_expand_label computes the TLS 1.3 KDF function of the same +// name. See https://www.rfc-editor.org/rfc/rfc8446#section-7.1. +OPENSSL_EXPORT int CRYPTO_tls13_hkdf_expand_label( + uint8_t *out, size_t out_len, const EVP_MD *digest, // + const uint8_t *secret, size_t secret_len, // + const uint8_t *label, size_t label_len, // + const uint8_t *hash, size_t hash_len); + #if defined(__cplusplus) }
diff --git a/crypto/fipsmodule/tls/kdf.c b/crypto/fipsmodule/tls/kdf.c index 046cb52..9c6cfaf 100644 --- a/crypto/fipsmodule/tls/kdf.c +++ b/crypto/fipsmodule/tls/kdf.c
@@ -52,6 +52,7 @@ #include <assert.h> +#include <openssl/bytestring.h> #include <openssl/digest.h> #include <openssl/hmac.h> #include <openssl/mem.h> @@ -176,3 +177,34 @@ } return ret; } + +int CRYPTO_tls13_hkdf_expand_label(uint8_t *out, size_t out_len, + const EVP_MD *digest, // + const uint8_t *secret, size_t secret_len, + const uint8_t *label, size_t label_len, + const uint8_t *hash, size_t hash_len) { + static const uint8_t kProtocolLabel[] = "tls13 "; + CBB cbb, child; + uint8_t *hkdf_label = NULL; + size_t hkdf_label_len; + + CBB_zero(&cbb); + if (!CBB_init(&cbb, 2 + 1 + sizeof(kProtocolLabel) - 1 + label_len + 1 + + hash_len) || + !CBB_add_u16(&cbb, out_len) || + !CBB_add_u8_length_prefixed(&cbb, &child) || + !CBB_add_bytes(&child, kProtocolLabel, sizeof(kProtocolLabel) - 1) || + !CBB_add_bytes(&child, label, label_len) || + !CBB_add_u8_length_prefixed(&cbb, &child) || + !CBB_add_bytes(&child, hash, hash_len) || + !CBB_finish(&cbb, &hkdf_label, &hkdf_label_len)) { + CBB_cleanup(&cbb); + return 0; + } + + const int ret = HKDF_expand(out, out_len, digest, secret, secret_len, + hkdf_label, hkdf_label_len); + OPENSSL_free(hkdf_label); + return ret; +} +
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc index ad023ef..3de10f4 100644 --- a/ssl/tls13_enc.cc +++ b/ssl/tls13_enc.cc
@@ -27,6 +27,7 @@ #include <openssl/hmac.h> #include <openssl/mem.h> +#include "../crypto/fipsmodule/tls/internal.h" #include "../crypto/internal.h" #include "internal.h" @@ -95,27 +96,10 @@ Span<const uint8_t> secret, Span<const char> label, Span<const uint8_t> hash) { - Span<const char> protocol_label = label_to_span("tls13 "); - ScopedCBB cbb; - CBB child; - Array<uint8_t> hkdf_label; - if (!CBB_init(cbb.get(), 2 + 1 + protocol_label.size() + label.size() + 1 + - hash.size()) || - !CBB_add_u16(cbb.get(), out.size()) || - !CBB_add_u8_length_prefixed(cbb.get(), &child) || - !CBB_add_bytes(&child, - reinterpret_cast<const uint8_t *>(protocol_label.data()), - protocol_label.size()) || - !CBB_add_bytes(&child, reinterpret_cast<const uint8_t *>(label.data()), - label.size()) || - !CBB_add_u8_length_prefixed(cbb.get(), &child) || - !CBB_add_bytes(&child, hash.data(), hash.size()) || - !CBBFinishArray(cbb.get(), &hkdf_label)) { - return false; - } - - return HKDF_expand(out.data(), out.size(), digest, secret.data(), - secret.size(), hkdf_label.data(), hkdf_label.size()); + return CRYPTO_tls13_hkdf_expand_label( + out.data(), out.size(), digest, secret.data(), secret.size(), + reinterpret_cast<const uint8_t *>(label.data()), label.size(), + hash.data(), hash.size()) == 1; } static const char kTLS13LabelDerived[] = "derived";
diff --git a/util/fipstools/acvp/ACVP.md b/util/fipstools/acvp/ACVP.md index d3578e2..61c6f88 100644 --- a/util/fipstools/acvp/ACVP.md +++ b/util/fipstools/acvp/ACVP.md
@@ -77,6 +77,8 @@ | ECDSA/sigVer | Curve name, hash name, message, X, Y, R, S | Single-byte validity flag | | FFDH | p, q, g, peer public key, local private key (or empty), local public key (or empty) | Local public key, shared key | | HKDF/<HASH> | key, salt, info, num output bytes | Key | +| HKDFExtract | secret, salt | Key | +| HKDFExpandLabel | Output length, secret, label, transcript hash | Key | | HMAC-SHA-1 | Value to hash, key | Digest | | HMAC-SHA2-224 | Value to hash, key | Digest | | HMAC-SHA2-256 | Value to hash, key | Digest |
diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go index 48d7083..b496982 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go
@@ -107,6 +107,7 @@ "hmacDRBG": &drbg{"hmacDRBG", map[string]bool{"SHA-1": true, "SHA2-224": true, "SHA2-256": true, "SHA2-384": true, "SHA2-512": true}}, "KDF": &kdfPrimitive{}, "KDA": &hkdf{}, + "TLS-v1.3": &tls13{}, "CMAC-AES": &keyedMACPrimitive{"CMAC-AES"}, "RSA": &rsa{}, "kdf-components": &tlsKDF{},
diff --git a/util/fipstools/acvp/acvptool/subprocess/tls13.go b/util/fipstools/acvp/acvptool/subprocess/tls13.go new file mode 100644 index 0000000..b8b6e51 --- /dev/null +++ b/util/fipstools/acvp/acvptool/subprocess/tls13.go
@@ -0,0 +1,240 @@ +// Copyright (c) 2023, Google Inc. +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +package subprocess + +import ( + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "encoding/json" + "fmt" +) + +// The following structures reflect the JSON of TLS 1.3 tests. See +// https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html + +type tls13TestVectorSet struct { + Groups []tls13TestGroup `json:"testGroups"` +} + +type tls13TestGroup struct { + ID uint64 `json:"tgId"` + HashFunc string `json:"hmacAlg"` + Tests []tls13Test `json:"tests"` +} + +type tls13Test struct { + ID uint64 `json:"tcId"` + // Although ACVP refers to these as client and server randoms, these + // fields are misnamed and really contain portions of the handshake + // transcript. Concatenated in order, they give the transcript up to + // the named message. In case of HelloRetryRequest, ClientHelloHex + // includes up to the second ClientHello. + ClientHelloHex string `json:"helloClientRandom"` + ServerHelloHex string `json:"helloServerRandom"` + ServerFinishedHex string `json:"finishedServerRandom"` + ClientFinishedHex string `json:"finishedClientRandom"` + DHEInputHex string `json:"dhe"` + PSKInputHex string `json:"psk"` +} + +type tls13TestGroupResponse struct { + ID uint64 `json:"tgId"` + Tests []tls13TestResponse `json:"tests"` +} + +type tls13TestResponse struct { + ID uint64 `json:"tcId"` + ClientEarlyTrafficSecretHex string `json:"clientEarlyTrafficSecret"` + EarlyExporterMasterSecretHex string `json:"earlyExporterMasterSecret"` + ClientHandshakeTrafficSecretHex string `json:"clientHandshakeTrafficSecret"` + ServerHandshakeTrafficSecretHex string `json:"serverHandshakeTrafficSecret"` + ClientApplicationTrafficSecretHex string `json:"clientApplicationTrafficSecret"` + ServerApplicationTrafficSecretHex string `json:"serverApplicationTrafficSecret"` + ExporterMasterSecretHex string `json:"exporterMasterSecret"` + ResumptionMasterSecretHex string `json:"resumptionMasterSecret"` +} + +type tls13 struct{} + +func (k *tls13) Process(vectorSet []byte, m Transactable) (interface{}, error) { + var parsed tls13TestVectorSet + if err := json.Unmarshal(vectorSet, &parsed); err != nil { + return nil, err + } + + var respGroups []tls13TestGroupResponse + for _, group := range parsed.Groups { + groupResp := tls13TestGroupResponse{ID: group.ID} + + for _, test := range group.Tests { + testResp := tls13TestResponse{ID: test.ID} + + clientHello, err := hex.DecodeString(test.ClientHelloHex) + if err != nil { + return nil, err + } + serverHello, err := hex.DecodeString(test.ServerHelloHex) + if err != nil { + return nil, err + } + serverFinished, err := hex.DecodeString(test.ServerFinishedHex) + if err != nil { + return nil, err + } + clientFinished, err := hex.DecodeString(test.ClientFinishedHex) + if err != nil { + return nil, err + } + + // See https://www.rfc-editor.org/rfc/rfc8446#section-7.1 + var hashLen int + var emptyHash []byte + switch group.HashFunc { + case "SHA2-256": + hashLen = 256 / 8 + digest := sha256.Sum256(nil) + emptyHash = digest[:] + case "SHA2-384": + hashLen = 384 / 8 + digest := sha512.Sum384(nil) + emptyHash = digest[:] + default: + return nil, fmt.Errorf("hash function %q is not supported for TLS v1.3", group.HashFunc) + } + hashLenBytes := uint32le(uint32(hashLen)) + + psk, err := hex.DecodeString(test.PSKInputHex) + if err != nil { + return nil, err + } + if len(psk) == 0 { + psk = make([]byte, hashLen) + } + + dhe, err := hex.DecodeString(test.DHEInputHex) + if err != nil { + return nil, err + } + if len(dhe) == 0 { + dhe = make([]byte, hashLen) + } + + zeros := make([]byte, hashLen) + earlySecret, err := m.Transact("HKDFExtract/"+group.HashFunc, 1, psk, zeros) + if err != nil { + return nil, fmt.Errorf("HKDFExtract operation failed: %s", err) + } + + hashedToClientHello, err := m.Transact(group.HashFunc, 1, clientHello) + if err != nil { + return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) + } + hashedToServerHello, err := m.Transact(group.HashFunc, 1, concat(clientHello, serverHello)) + if err != nil { + return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) + } + hashedToServerFinished, err := m.Transact(group.HashFunc, 1, concat(clientHello, serverHello, serverFinished)) + if err != nil { + return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) + } + hashedMessages, err := m.Transact(group.HashFunc, 1, concat(clientHello, serverHello, serverFinished, clientFinished)) + if err != nil { + return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) + } + + clientEarlyTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, earlySecret[0], []byte("c e traffic"), hashedToClientHello[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.ClientEarlyTrafficSecretHex = hex.EncodeToString(clientEarlyTrafficSecret[0]) + + earlyExporter, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, earlySecret[0], []byte("e exp master"), hashedToClientHello[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.EarlyExporterMasterSecretHex = hex.EncodeToString(earlyExporter[0]) + + derivedSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, earlySecret[0], []byte("derived"), emptyHash[:]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + + handshakeSecret, err := m.Transact("HKDFExtract/"+group.HashFunc, 1, dhe, derivedSecret[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExtract operation failed: %s", err) + } + + clientHandshakeTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, handshakeSecret[0], []byte("c hs traffic"), hashedToServerHello[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.ClientHandshakeTrafficSecretHex = hex.EncodeToString(clientHandshakeTrafficSecret[0]) + + serverHandshakeTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, handshakeSecret[0], []byte("s hs traffic"), hashedToServerHello[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.ServerHandshakeTrafficSecretHex = hex.EncodeToString(serverHandshakeTrafficSecret[0]) + + derivedSecret, err = m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, handshakeSecret[0], []byte("derived"), emptyHash[:]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + + masterSecret, err := m.Transact("HKDFExtract/"+group.HashFunc, 1, zeros, derivedSecret[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExtract operation failed: %s", err) + } + + clientAppTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("c ap traffic"), hashedToServerFinished[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.ClientApplicationTrafficSecretHex = hex.EncodeToString(clientAppTrafficSecret[0]) + + serverAppTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("s ap traffic"), hashedToServerFinished[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.ServerApplicationTrafficSecretHex = hex.EncodeToString(serverAppTrafficSecret[0]) + + exporterSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("exp master"), hashedToServerFinished[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.ExporterMasterSecretHex = hex.EncodeToString(exporterSecret[0]) + + resumptionSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("res master"), hashedMessages[0]) + if err != nil { + return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) + } + testResp.ResumptionMasterSecretHex = hex.EncodeToString(resumptionSecret[0]) + + groupResp.Tests = append(groupResp.Tests, testResp) + } + respGroups = append(respGroups, groupResp) + } + + return respGroups, nil +} + +func concat(slices ...[]byte) []byte { + var ret []byte + for _, slice := range slices { + ret = append(ret, slice...) + } + return ret +}
diff --git a/util/fipstools/acvp/acvptool/test/expected/TLS13.bz2 b/util/fipstools/acvp/acvptool/test/expected/TLS13.bz2 new file mode 100644 index 0000000..7693c5f --- /dev/null +++ b/util/fipstools/acvp/acvptool/test/expected/TLS13.bz2 Binary files differ
diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json index 36fdaad..3e7dbd0 100644 --- a/util/fipstools/acvp/acvptool/test/tests.json +++ b/util/fipstools/acvp/acvptool/test/tests.json
@@ -30,5 +30,6 @@ {"Wrapper": "modulewrapper", "In": "vectors/SHA2-224.bz2", "Out": "expected/SHA2-224.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/SHA2-256.bz2", "Out": "expected/SHA2-256.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/SHA2-384.bz2", "Out": "expected/SHA2-384.bz2"}, -{"Wrapper": "modulewrapper", "In": "vectors/SHA2-512.bz2", "Out": "expected/SHA2-512.bz2"} +{"Wrapper": "modulewrapper", "In": "vectors/SHA2-512.bz2", "Out": "expected/SHA2-512.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/TLS13.bz2", "Out": "expected/TLS13.bz2"} ]
diff --git a/util/fipstools/acvp/acvptool/test/vectors/TLS13.bz2 b/util/fipstools/acvp/acvptool/test/vectors/TLS13.bz2 new file mode 100644 index 0000000..7e8ea08 --- /dev/null +++ b/util/fipstools/acvp/acvptool/test/vectors/TLS13.bz2 Binary files differ
diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 5c4f9b0..85622c1 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -914,6 +914,20 @@ "increment": 8 } ] + }, + { + "algorithm": "TLS-v1.3", + "mode": "KDF", + "revision": "RFC8446", + "hmacAlg": [ + "SHA2-256", + "SHA2-384" + ], + "runningMode": [ + "DHE", + "PSK", + "PSK-DHE" + ] } ])"; return write_reply({Span<const uint8_t>( @@ -1484,6 +1498,49 @@ return write_reply({out}); } +template <const EVP_MD *HashFunc()> +static bool HKDFExtract(const Span<const uint8_t> args[], + ReplyCallback write_reply) { + const EVP_MD *const md = HashFunc(); + const auto secret = args[0]; + const auto salt = args[1]; + + std::vector<uint8_t> out(EVP_MD_size(md)); + size_t out_len; + if (!HKDF_extract(out.data(), &out_len, md, secret.data(), secret.size(), + salt.data(), salt.size())) { + return false; + } + assert(out_len == out.size()); + return write_reply({out}); +} + +template <const EVP_MD *HashFunc()> +static bool HKDFExpandLabel(const Span<const uint8_t> args[], + ReplyCallback write_reply) { + const EVP_MD *const md = HashFunc(); + const auto out_len_bytes = args[0]; + const auto secret = args[1]; + const auto label = args[2]; + const auto hash = args[3]; + + if (out_len_bytes.size() != sizeof(uint32_t)) { + return false; + } + const uint32_t out_len = CRYPTO_load_u32_le(out_len_bytes.data()); + if (out_len > (1 << 24)) { + return false; + } + + std::vector<uint8_t> out(out_len); + if (!CRYPTO_tls13_hkdf_expand_label(out.data(), out_len, md, secret.data(), + secret.size(), label.data(), label.size(), + hash.data(), hash.size())) { + return false; + } + return write_reply({out}); +} + template <bool WithReseed> static bool DRBG(const Span<const uint8_t> args[], ReplyCallback write_reply) { const auto out_len_bytes = args[0]; @@ -2029,6 +2086,10 @@ {"HKDF/SHA2-384", 4, HKDF<EVP_sha384>}, {"HKDF/SHA2-512", 4, HKDF<EVP_sha512>}, {"HKDF/SHA2-512/256", 4, HKDF<EVP_sha512_256>}, + {"HKDFExpandLabel/SHA2-256", 4, HKDFExpandLabel<EVP_sha256>}, + {"HKDFExpandLabel/SHA2-384", 4, HKDFExpandLabel<EVP_sha384>}, + {"HKDFExtract/SHA2-256", 2, HKDFExtract<EVP_sha256>}, + {"HKDFExtract/SHA2-384", 2, HKDFExtract<EVP_sha384>}, {"HMAC-SHA-1", 2, HMAC<EVP_sha1>}, {"HMAC-SHA2-224", 2, HMAC<EVP_sha224>}, {"HMAC-SHA2-256", 2, HMAC<EVP_sha256>},
diff --git a/util/fipstools/break-kat.go b/util/fipstools/break-kat.go index ed29bb3..c412d0e 100644 --- a/util/fipstools/break-kat.go +++ b/util/fipstools/break-kat.go
@@ -26,6 +26,7 @@ "SHA-256": "ff3b857da7236a2baa0f396b51522217", "SHA-512": "212512f8d2ad8322781c6c4d69a9daa1", "TLS-KDF": "abc3657b094c7628a0b282996fe75a75f4984fd94d4ecc2fcf53a2c469a3f731", + "TLS13-KDF": "024a0d80f357f2499a1244dac26dab66fc13ed85fca71dace146211119525874", "RSA-sign": "d2b56e53306f720d7929d8708bf46f1c22300305582b115bedcac722d8aa5ab2", "RSA-verify": "abe2cbc13d6bd39d48db5334ddbf8d070a93bdcb104e2cc5d0ee486ee295f6b31bda126c41890b98b73e70e6b65d82f95c663121755a90744c8d1c21148a1960be0eca446e9ff497f1345c537ef8119b9a4398e95c5c6de2b1c955905c5299d8ce7a3b6ab76380d9babdd15f610237e1f3f2aa1c1f1e770b62fbb596381b2ebdd77ecef9c90d4c92f7b6b05fed2936285fa94826e62055322a33b6f04c74ce69e5d8d737fb838b79d2d48e3daf71387531882531a95ac964d02ea413bf85952982bbc089527daff5b845c9a0f4d14ef1956d9c3acae882d12da66da0f35794f5ee32232333517db9315232a183b991654dbea41615345c885325926744a53915", "ECDSA-sign": "1e35930be860d0942ca7bbd6f6ded87f157e4de24f81ed4b875c0e018e89a81f",