From a09ec82b9be71508bb5ac7b0ea1b198271ee1403 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 26 Aug 2026 15:28:38 +0200 Subject: [PATCH] tls13: factor the record key expansion out of DeriveTls13Keys The second half of DeriveTls13Keys() - the "key"/"iv" labels, the provision computation and the four Tls13DeriveKey() calls, plus Dtls13DeriveSnKeys() - is the expansion of a pair of traffic secrets into the record keys. It is reachable only through a full secret derivation, so a caller that already holds the secrets cannot use it. - add Tls13DeriveRecordKeys(), which expands the traffic secrets in ssl->clientSecret/serverSecret into ssl->keys and derives the DTLS 1.3 record number key; it owns the key_dig buffer and its zeroization - DeriveTls13Keys() keeps the secret derivation, the store gate and the DTLS 1.3 epoch bookkeeping, and no longer allocates key_dig when store is 0 No functional change. --- src/tls13.c | 171 +++++++++++++++++++++++++-------------------- wolfssl/internal.h | 1 + 2 files changed, 97 insertions(+), 75 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 1322d76df5..acc72f00ee 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1510,6 +1510,101 @@ static const byte writeKeyLabel[WRITE_KEY_LABEL_SZ+1] = "key"; /* The label to use when deriving IVs. */ static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1] = "iv"; +/* Expand the traffic secrets held in ssl->clientSecret/serverSecret into the + * record layer key and IV of ssl->keys, and, for DTLS 1.3, into the record + * number key. RFC 8446 Section 7.3 and RFC 9147 Section 4.2.3. + * + * ssl The SSL/TLS object. + * provision PROVISION_CLIENT, PROVISION_SERVER or both, naming the + * direction(s) whose secret is expanded. + * returns 0 on success, otherwise failure. + */ +int Tls13DeriveRecordKeys(WOLFSSL* ssl, int provision) +{ + int ret = 0; + int i = 0; + WC_DECLARE_VAR(key_dig, byte, MAX_PRF_DIG, 0); + + WC_ALLOC_VAR_EX(key_dig, byte, MAX_PRF_DIG, ssl->heap, + DYNAMIC_TYPE_DIGEST, return MEMORY_E); + +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(key_dig, 0xff, MAX_PRF_DIG); + wc_MemZero_Add("Tls13DeriveRecordKeys key_dig", key_dig, MAX_PRF_DIG); +#endif + + /* Key data = client key | server key | client IV | server IV */ + + if (provision & PROVISION_CLIENT) { + /* Derive the client key. */ + WOLFSSL_MSG("Derive Client Key"); + ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, + ssl->clientSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0, + WOLFSSL_CLIENT_END); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + } + + if (provision & PROVISION_SERVER) { + /* Derive the server key. */ + WOLFSSL_MSG("Derive Server Key"); + ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, + ssl->serverSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0, + WOLFSSL_SERVER_END); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + } + + if (provision & PROVISION_CLIENT) { + /* Derive the client IV. */ + WOLFSSL_MSG("Derive Client IV"); + ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->clientSecret, writeIVLabel, + WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0, + WOLFSSL_CLIENT_END); + if (ret != 0) + goto end; + i += ssl->specs.iv_size; + } + + if (provision & PROVISION_SERVER) { + /* Derive the server IV. */ + WOLFSSL_MSG("Derive Server IV"); + ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->serverSecret, writeIVLabel, + WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0, + WOLFSSL_SERVER_END); + if (ret != 0) + goto end; + /* Server IV is the last key material written to key_dig, so i is not + * advanced here; the whole buffer is zeroed at end regardless. */ + } + + /* Store keys and IVs but don't activate them. */ + ret = StoreKeys(ssl, key_dig, provision); + +#ifdef WOLFSSL_DTLS13 + if (ret == 0 && ssl->options.dtls) + ret = Dtls13DeriveSnKeys(ssl, provision); +#endif + +end: + /* Zero the whole key_dig buffer (not just the i bytes derived) so no + * key-schedule material can linger in the unused tail. */ + ForceZero(key_dig, MAX_PRF_DIG); +#ifdef WOLFSSL_SMALL_STACK + XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); +#elif defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(key_dig, MAX_PRF_DIG); +#endif + + return ret; +} + /* Derive the keys and IVs for TLS v1.3. * * ssl The SSL/TLS object. @@ -1533,8 +1628,6 @@ static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1] = "iv"; int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) { int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); /* Assume failure */ - int i = 0; - WC_DECLARE_VAR(key_dig, byte, MAX_PRF_DIG, 0); int provision; #if defined(WOLFSSL_RENESAS_TSIP_TLS) @@ -1545,14 +1638,6 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); /* Assume failure */ #endif - WC_ALLOC_VAR_EX(key_dig, byte, MAX_PRF_DIG, ssl->heap, - DYNAMIC_TYPE_DIGEST, return MEMORY_E); - -#ifdef WOLFSSL_CHECK_MEM_ZERO - XMEMSET(key_dig, 0xff, MAX_PRF_DIG); - wc_MemZero_Add("DeriveTls13Keys key_dig", key_dig, MAX_PRF_DIG); -#endif - if (side == ENCRYPT_AND_DECRYPT_SIDE) { provision = PROVISION_CLIENT_SERVER; } @@ -1638,59 +1723,7 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) if (!store) goto end; - /* Key data = client key | server key | client IV | server IV */ - - if (provision & PROVISION_CLIENT) { - /* Derive the client key. */ - WOLFSSL_MSG("Derive Client Key"); - ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, - ssl->clientSecret, writeKeyLabel, - WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0, - WOLFSSL_CLIENT_END); - if (ret != 0) - goto end; - i += ssl->specs.key_size; - } - - if (provision & PROVISION_SERVER) { - /* Derive the server key. */ - WOLFSSL_MSG("Derive Server Key"); - ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, - ssl->serverSecret, writeKeyLabel, - WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0, - WOLFSSL_SERVER_END); - if (ret != 0) - goto end; - i += ssl->specs.key_size; - } - - if (provision & PROVISION_CLIENT) { - /* Derive the client IV. */ - WOLFSSL_MSG("Derive Client IV"); - ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, - ssl->clientSecret, writeIVLabel, - WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0, - WOLFSSL_CLIENT_END); - if (ret != 0) - goto end; - i += ssl->specs.iv_size; - } - - if (provision & PROVISION_SERVER) { - /* Derive the server IV. */ - WOLFSSL_MSG("Derive Server IV"); - ret = Tls13DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, - ssl->serverSecret, writeIVLabel, - WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0, - WOLFSSL_SERVER_END); - if (ret != 0) - goto end; - /* Server IV is the last key material written to key_dig, so i is not - * advanced here; the whole buffer is zeroed at end regardless. */ - } - - /* Store keys and IVs but don't activate them. */ - ret = StoreKeys(ssl, key_dig, provision); + ret = Tls13DeriveRecordKeys(ssl, provision); #ifdef WOLFSSL_DTLS13 if (ret != 0) @@ -1698,9 +1731,6 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) if (ssl->options.dtls) { w64wrapper epochNumber; - ret = Dtls13DeriveSnKeys(ssl, provision); - if (ret != 0) - goto end; switch (secret) { case early_data_key: @@ -1738,15 +1768,6 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) #endif /* WOLFSSL_DTLS13 */ end: - /* Zero the whole key_dig buffer (not just the i bytes derived) so no - * key-schedule material can linger in the unused tail. */ - ForceZero(key_dig, MAX_PRF_DIG); -#ifdef WOLFSSL_SMALL_STACK - XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); -#elif defined(WOLFSSL_CHECK_MEM_ZERO) - wc_MemZero_Check(key_dig, MAX_PRF_DIG); -#endif - if (ret != 0) { WOLFSSL_ERROR_VERBOSE(ret); } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index ebc0e7b524..335606649a 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4083,6 +4083,7 @@ WOLFSSL_LOCAL int DeriveHandshakeSecret(WOLFSSL* ssl); #define DeriveTls13Keys wolfSSL_DeriveTls13Keys #endif WOLFSSL_TEST_VIS int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store); +WOLFSSL_LOCAL int Tls13DeriveRecordKeys(WOLFSSL* ssl, int provision); WOLFSSL_LOCAL int DeriveMasterSecret(WOLFSSL* ssl); WOLFSSL_LOCAL int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret); WOLFSSL_LOCAL int DeriveResumptionSecret(WOLFSSL* ssl, byte* key);