Merge pull request #10304 from JeremiahM37/fenrir-2

Zero DH keys, tighten SSL APIs, harden TLS extensions
This commit is contained in:
David Garske
2026-05-07 14:51:28 -07:00
committed by GitHub
16 changed files with 200 additions and 19 deletions
+3
View File
@@ -8669,6 +8669,9 @@ void FreeKeyExchange(WOLFSSL* ssl)
{
/* Cleanup signature buffer */
if (ssl->buffers.sig.buffer) {
/* May transiently hold the client's DH private exponent in the
* TLS 1.2 diffie_hellman_kea / dhe_psk_kea paths. */
ForceZero(ssl->buffers.sig.buffer, ssl->buffers.sig.length);
XFREE(ssl->buffers.sig.buffer, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
ssl->buffers.sig.buffer = NULL;
ssl->buffers.sig.length = 0;
+10 -3
View File
@@ -4743,6 +4743,7 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
int ret = 1;
word32 pubSz = 0;
word32 privSz = 0;
word32 privAllocSz = 0;
int localRng = 0;
WC_RNG* rng = NULL;
WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
@@ -4792,9 +4793,12 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
else {
privSz = pubSz;
}
/* Allocate public and private key arrays. */
/* Allocate public and private key arrays. Preserve the allocation
* size because wc_DhGenerateKeyPair updates privSz in-place. */
privAllocSz = privSz;
pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
priv = (unsigned char*)XMALLOC(privAllocSz, NULL,
DYNAMIC_TYPE_PRIVATE_KEY);
if (pub == NULL || priv == NULL) {
WOLFSSL_ERROR_MSG("Unable to malloc memory");
ret = 0;
@@ -4846,7 +4850,10 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
}
/* Dispose of allocated data. */
XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
if (priv != NULL) {
ForceZero(priv, privAllocSz);
XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
}
return ret;
}
+6 -2
View File
@@ -2459,11 +2459,15 @@ static void FreeSetupKeysArgs(WOLFSSL* ssl, void* pArgs)
args->key->type = WC_PK_TYPE_NONE;
args->key->initPriv = 0; args->key->initPub = 0;
/* Scrub the raw DH private exponent (and any other key material
* embedded in the union) before release. wc_FreeDhKey above only
* clears the mp_int DhKey, not the separate privKey byte array.
* Use ForceZero (rather than XMEMSET) so the wipe cannot be
* elided by the optimizer. */
ForceZero(args->key, sizeof(*args->key));
#ifdef WOLFSSL_ASYNC_CRYPT
XFREE(args->key, NULL, DYNAMIC_TYPE_SNIFFER_KEY);
args->key = NULL;
#else
XMEMSET(args->key, 0, sizeof(args->key));
#endif
}
+14 -4
View File
@@ -10152,11 +10152,21 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
#ifdef WOLFSSL_DTLS
ssl->options.dtlsStateful = 0;
#endif
#ifdef WOLFSSL_TLS13
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
ssl->options.noPskDheKe = 0;
#ifdef HAVE_SUPPORTED_CURVES
ssl->options.onlyPskDheKe = 0;
#endif
if (ssl->ctx != NULL) {
ssl->options.noPskDheKe = ssl->ctx->noPskDheKe;
#ifdef HAVE_SUPPORTED_CURVES
ssl->options.onlyPskDheKe = ssl->ctx->onlyPskDheKe;
#endif
}
else {
ssl->options.noPskDheKe = 0;
#ifdef HAVE_SUPPORTED_CURVES
ssl->options.onlyPskDheKe = 0;
#endif
}
#endif
#endif
#ifdef HAVE_SESSION_TICKET
#ifdef WOLFSSL_TLS13
+10 -2
View File
@@ -2722,11 +2722,19 @@ void wolfSSL_DES_ncbc_encrypt(const unsigned char* input, unsigned char* output,
int enc)
{
unsigned char tmp[DES_IV_SIZE];
/* Calculate length to a multiple of block size. */
size_t offset = (size_t)length;
size_t offset;
WOLFSSL_ENTER("wolfSSL_DES_ncbc_encrypt");
/* Zero/negative length: no block to derive an IV from. The offset math
* below would underflow for length == 0, yielding a wild-pointer read. */
if (length <= 0) {
WOLFSSL_LEAVE("wolfSSL_DES_ncbc_encrypt", 0);
return;
}
/* Calculate length to a multiple of block size. */
offset = (size_t)length;
offset = (offset + DES_BLOCK_SIZE - 1) / DES_BLOCK_SIZE;
offset *= DES_BLOCK_SIZE;
offset -= DES_BLOCK_SIZE;
+7 -4
View File
@@ -5513,10 +5513,13 @@ int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
ret = 1;
}
#else
/* OpenSSL's implementation of this API does not require loading the
* system CA cert directory. Allow skipping this without erroring out.
*/
ret = 1;
/* No source available: SSL_CERT_DIR/SSL_CERT_FILE not set and
* WOLFSSL_SYS_CA_CERTS not compiled in. Returning success would be
* fail-open since no trust anchors were loaded. */
WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths: no CA source "
"available (build without WOLFSSL_SYS_CA_CERTS and no "
"SSL_CERT_DIR/SSL_CERT_FILE env)");
ret = WOLFSSL_FAILURE;
#endif
}
+4
View File
@@ -1598,8 +1598,12 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
#if !defined(OPENSSL_EXTRA) || !defined(WOLFSSL_ERROR_CODE_OPENSSL)
return WOLFSSL_FAILURE; /* session timed out */
#else /* defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) */
/* Return success for OpenSSL compatibility but do not carry the
* expired session's version/cipher into ssl state, which would
* otherwise pin the ClientHello to stale values. */
WOLFSSL_MSG("Session is expired but return success for "
"OpenSSL compatibility");
return WOLFSSL_SUCCESS;
#endif
}
ssl->options.resuming = 1;
+28 -2
View File
@@ -9063,6 +9063,9 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
if (WOLFSSL_NAMED_GROUP_IS_FFDHE(current->group)) {
#ifndef NO_DH
wc_FreeDhKey((DhKey*)current->key);
if (current->privKey != NULL && current->privKeyLen > 0) {
ForceZero(current->privKey, current->privKeyLen);
}
#endif
}
else if (current->group == WOLFSSL_ECC_X25519) {
@@ -17369,8 +17372,8 @@ static word16 TLSX_GetMinSize_Server(const word16 *type)
/** Parses a buffer of TLS extensions. */
int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
Suites *suites)
WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
byte msgType, Suites *suites)
{
int ret = 0;
word16 offset = 0;
@@ -17992,6 +17995,20 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
#ifdef WOLFSSL_SRTP
case TLSX_USE_SRTP:
WOLFSSL_MSG("Use SRTP extension received");
#if defined(WOLFSSL_TLS13)
if (IsAtLeastTLSv1_3(ssl->version)) {
if (msgType != client_hello &&
msgType != encrypted_extensions)
return EXT_NOT_ALLOWED;
}
else
#endif
{
if (msgType != client_hello &&
msgType != server_hello)
return EXT_NOT_ALLOWED;
}
ret = SRTP_PARSE(ssl, input + offset, size, isRequest);
break;
#endif
@@ -18086,6 +18103,15 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
case TLSX_ECH:
WOLFSSL_MSG("ECH extension received");
if (!IsAtLeastTLSv1_3(ssl->version))
break;
if (msgType != client_hello &&
msgType != encrypted_extensions &&
msgType != hello_retry_request) {
return EXT_NOT_ALLOWED;
}
ret = ECH_PARSE(ssl, input + offset, size, msgType);
break;
case TLSXT_ECH_OUTER_EXTENSIONS: