From 480344d4fa03319efa29cdca41f051c41f5bf95a Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Thu, 13 Apr 2023 02:09:12 +0000 Subject: [PATCH] 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 Reviewed-by: David Benjamin Commit-Queue: David Benjamin --- crypto/fipsmodule/self_check/self_check.c | 40 +++ crypto/fipsmodule/tls/internal.h | 8 + crypto/fipsmodule/tls/kdf.c | 32 +++ ssl/tls13_enc.cc | 26 +- util/fipstools/acvp/ACVP.md | 2 + .../acvp/acvptool/subprocess/subprocess.go | 1 + .../acvp/acvptool/subprocess/tls13.go | 240 ++++++++++++++++++ .../acvp/acvptool/test/expected/TLS13.bz2 | Bin 0 -> 4044 bytes util/fipstools/acvp/acvptool/test/tests.json | 3 +- .../acvp/acvptool/test/vectors/TLS13.bz2 | Bin 0 -> 2556 bytes .../acvp/modulewrapper/modulewrapper.cc | 61 +++++ util/fipstools/break-kat.go | 1 + 12 files changed, 392 insertions(+), 22 deletions(-) create mode 100644 util/fipstools/acvp/acvptool/subprocess/tls13.go create mode 100644 util/fipstools/acvp/acvptool/test/expected/TLS13.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/vectors/TLS13.bz2 diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c index 8dcc41524..3b51e2fe2 100644 --- a/crypto/fipsmodule/self_check/self_check.c +++ b/crypto/fipsmodule/self_check/self_check.c @@ -946,6 +946,46 @@ static int boringssl_self_test_fast(void) { 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 ef642a6cd..535b7ebe6 100644 --- a/crypto/fipsmodule/tls/internal.h +++ b/crypto/fipsmodule/tls/internal.h @@ -31,6 +31,14 @@ OPENSSL_EXPORT int CRYPTO_tls1_prf(const EVP_MD *digest, 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 046cb526a..9c6cfaf03 100644 --- a/crypto/fipsmodule/tls/kdf.c +++ b/crypto/fipsmodule/tls/kdf.c @@ -52,6 +52,7 @@ #include +#include #include #include #include @@ -176,3 +177,34 @@ end: } 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 ad023ef8e..3de10f480 100644 --- a/ssl/tls13_enc.cc +++ b/ssl/tls13_enc.cc @@ -27,6 +27,7 @@ #include #include +#include "../crypto/fipsmodule/tls/internal.h" #include "../crypto/internal.h" #include "internal.h" @@ -95,27 +96,10 @@ static bool hkdf_expand_label(Span out, const EVP_MD *digest, Span secret, Span label, Span hash) { - Span protocol_label = label_to_span("tls13 "); - ScopedCBB cbb; - CBB child; - Array 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(protocol_label.data()), - protocol_label.size()) || - !CBB_add_bytes(&child, reinterpret_cast(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(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 d3578e206..61c6f884b 100644 --- a/util/fipstools/acvp/ACVP.md +++ b/util/fipstools/acvp/ACVP.md @@ -77,6 +77,8 @@ The other commands are as follows. (Note that you only need to implement the com | 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 48d708315..b496982e7 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go @@ -107,6 +107,7 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess "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 000000000..b8b6e51a5 --- /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 0000000000000000000000000000000000000000..7693c5f6c0e3a5cb63b68f5e47df2ebae36ad789 GIT binary patch literal 4044 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 literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json index 36fdaad00..3e7dbd0c3 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 0000000000000000000000000000000000000000..7e8ea080b1dc8f6a63f159456edc7f1e0fc1eaad GIT binary patch literal 2556 zcmV*T4*^jL0KkKS$N|DSO5!QUw~CmPzV3;Kki-{FYn(fU<;obH;#gZ0EtjV zR46G5riP~g1yk}!^Hb3@Pf!7-O#lD@07X4C#K4-BNMvZx111m|GzLM;0$>Ed044we zU;sr=z$QjXB%m??0BF-jngATYCICzT0$>0p00JbbiIil+RC<}H9!NA~XvoksW~Iua zc;FH^aO%k*8a3<3A2%+}US2^sz)a$2671xXNi7>m0x$ux&yjYNPy=Fun?zQE-CMJK zvR1f86L|ZBs7r6va(P#kUT_q z$c`v(yUVWX(hVWAirt8X9q6_p+&eO>Y(3B8ahyi^tz%LFg5qeT)D2%Vv) zZ6}0o_rk(Ee3>q)gHYm~>vUNKV8@*D7nt=q^7IEGzTZ$cQi1Jys|lsjTD&BWvx#OH zqn?wl7k%1Vf+i;H3dC&VP_Lk9Nf~(SV#urZ5f?7GPMN8q+RnSON z8f}+bM)&kt$D8vyur5GdzF;T`0LaCVw&rNlP2_f7-IX${IsA@CR#7a2A;y95Rz36RA+(WbsT=o!rD2fU)5szI?L zn5eWg);2IbOn2-Wk}ue6BaMhW$D9Oj<$suu5==IEP=e> zId~9no$YlWOcrs0R$OEnSJ;coGkv68dg$w30-2Z+8DgC>t?Ce-Ixv?Ub@BnQJR$DyBd%}7#NoRbUgcxJ26nXq&dcwV`XolXKigf##6sdOGyIg)Ffh>{ymJvEhMkuqi*$dRO2m2FpV7my_h zg@)oW+;1aW?*z@Pi^T>oWXT9MEw)sRUz5R5iP>{lcY76tIvLalC%`Z#5#YTPso?t= zZICI8+-43H9FAOD%a3|ylR8Gey~?WeHnhZ>WzOpo^)@{S#gQpf*=)Lvmr=dlyrgG( zio-dZYKR=gOy;r0xf+wd8GGh93N1n7_Bp<{iNN=6{7pgLj!J^G!dk>qojctW#@!VR zk&@nYm!P$t!;L3}({s0}X>KId+DinH5Dw#WPG!weM2Hh0r6P87xk?;g3Mg-nr6Wpbj#}KHh-J*)Xo5q){{i4B&$BJ*bUEJUy(nc) zFC*9jUq^2)K=7B(HCC<4rk*aZ+Cb^RoIn&rI+?PEZasqy`OqWQwk;u+_*P~-Ocm5f zfx{$2I>i{4bsm^ZRP8meMWzfResXEDr<1U|%yE76(31IkV%z~=Rvvj8XF-7*<+aUf z4uUOWZsD~;NbZr2&r4l(7Sryll=_a? zL#0CPu!yx{;2(kj)FBN!_j>NK2~jH0@i4dm z5f--NA!;)Un&}rOSqhb)y%QZ0-X_%*C$ZI`+~)Si^n4H#{7ge*PC-Mkl4%H{+5jvf zl1RbMSOdl|H7ro~JS2h{8yi^iCB)dSGzvU?luPy;P!)6BGy?W&CI@r5-uDr%l#Z8} z^~mAz(Q1oU_FHWPB#vtqc7ujzxYCq&Pba#a2sy}RF9qjr#9;}~MGprljMp3rRNMw6 zPWy%+Ns}coM8~uSWUOaCtuHov;}>Z+e0CnVHjssz3v>mghn=C+FKpaz9=o}gVS9d{ z5ePjI9CC0$0iXu=wL4I_%_eQ2Lz#C;-gdF^HgyD|<2(W$ppK$*sc;l~e%n1kp>ec8 zVt~b@H@EwJdT7urO5}9;JQA*imasy!Vgn9w-)?y{<;{KqcyAKX={B78M1+Kd3m0bm zf>0g>JzL?zWI+h3En3d zpE8fyB?4+wDE0uHU*PK!9#uPhex-mXh$RAP6ws*-Y`~X^V3~xjA=(LOC9q2YD$zVa zEp5mNh4w7Z&L%w|n1W^myATsnnzP?z0Wt}kNC~V<3;{3%@O+VR0W!Fo`7t;Ner*ew z6FE~S4jguga3+r}ifS`x6xdq1P-@Uf4PK|5g11k3y5TO?rklRl6)Xg{^3H)UJH+55 Sf>j|u;_gVN3K9<-U`qgWYOfan literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 5c4f9b0a8..85622c19c 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -914,6 +914,20 @@ static bool GetConfig(const Span args[], ReplyCallback write_repl "increment": 8 } ] + }, + { + "algorithm": "TLS-v1.3", + "mode": "KDF", + "revision": "RFC8446", + "hmacAlg": [ + "SHA2-256", + "SHA2-384" + ], + "runningMode": [ + "DHE", + "PSK", + "PSK-DHE" + ] } ])"; return write_reply({Span( @@ -1484,6 +1498,49 @@ static bool HKDF(const Span args[], ReplyCallback write_reply) { return write_reply({out}); } +template +static bool HKDFExtract(const Span args[], + ReplyCallback write_reply) { + const EVP_MD *const md = HashFunc(); + const auto secret = args[0]; + const auto salt = args[1]; + + std::vector 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 +static bool HKDFExpandLabel(const Span 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 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 static bool DRBG(const Span args[], ReplyCallback write_reply) { const auto out_len_bytes = args[0]; @@ -2029,6 +2086,10 @@ static constexpr struct { {"HKDF/SHA2-384", 4, HKDF}, {"HKDF/SHA2-512", 4, HKDF}, {"HKDF/SHA2-512/256", 4, HKDF}, + {"HKDFExpandLabel/SHA2-256", 4, HKDFExpandLabel}, + {"HKDFExpandLabel/SHA2-384", 4, HKDFExpandLabel}, + {"HKDFExtract/SHA2-256", 2, HKDFExtract}, + {"HKDFExtract/SHA2-384", 2, HKDFExtract}, {"HMAC-SHA-1", 2, HMAC}, {"HMAC-SHA2-224", 2, HMAC}, {"HMAC-SHA2-256", 2, HMAC}, diff --git a/util/fipstools/break-kat.go b/util/fipstools/break-kat.go index ed29bb3a4..c412d0e28 100644 --- a/util/fipstools/break-kat.go +++ b/util/fipstools/break-kat.go @@ -26,6 +26,7 @@ var ( "SHA-256": "ff3b857da7236a2baa0f396b51522217", "SHA-512": "212512f8d2ad8322781c6c4d69a9daa1", "TLS-KDF": "abc3657b094c7628a0b282996fe75a75f4984fd94d4ecc2fcf53a2c469a3f731", + "TLS13-KDF": "024a0d80f357f2499a1244dac26dab66fc13ed85fca71dace146211119525874", "RSA-sign": "d2b56e53306f720d7929d8708bf46f1c22300305582b115bedcac722d8aa5ab2", "RSA-verify": "abe2cbc13d6bd39d48db5334ddbf8d070a93bdcb104e2cc5d0ee486ee295f6b31bda126c41890b98b73e70e6b65d82f95c663121755a90744c8d1c21148a1960be0eca446e9ff497f1345c537ef8119b9a4398e95c5c6de2b1c955905c5299d8ce7a3b6ab76380d9babdd15f610237e1f3f2aa1c1f1e770b62fbb596381b2ebdd77ecef9c90d4c92f7b6b05fed2936285fa94826e62055322a33b6f04c74ce69e5d8d737fb838b79d2d48e3daf71387531882531a95ac964d02ea413bf85952982bbc089527daff5b845c9a0f4d14ef1956d9c3acae882d12da66da0f35794f5ee32232333517db9315232a183b991654dbea41615345c885325926744a53915", "ECDSA-sign": "1e35930be860d0942ca7bbd6f6ded87f157e4de24f81ed4b875c0e018e89a81f",