From b10d60dd4e1330fe73d821f0d891b543aba965fb Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 21 Jul 2026 17:13:18 -0700 Subject: [PATCH 1/5] Free existing x509 cert before calling InitX509 in DecodeToX509 and wolfSSL_get_peer_certificate. --- src/ssl_api_cert.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c index 5809d3faa2..669a1fe111 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -2721,8 +2721,13 @@ int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk) InitDecodedCert(cert, (byte*)in, (word32)len, NULL); if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL, NULL)) == 0) { /* Check if x509 was not previously initialized by wolfSSL_X509_new() */ - if (x509->dynamicMemory != TRUE) + if (x509->dynamicMemory != TRUE) { + /* A non-dynamic x509 (e.g. ssl->peerCert) may already hold + * decoded contents. InitX509 only zeroes the pointers, so free + * the existing allocations first to avoid orphaning them. */ + FreeX509(x509); InitX509(x509, 0, NULL); + } ret = CopyDecodedToX509(x509, cert); } FreeDecodedCert(cert); @@ -2755,6 +2760,10 @@ int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk) ret = wolfSSL_X509_dup(&ssl->peerCert); #ifdef SESSION_CERTS else if (ssl->session->chain.count > 0) { + /* Re-decoding into ssl->peerCert would orphan any contents it + * already holds (e.g. the handshake's copy). Free them first. */ + FreeX509(&ssl->peerCert); + InitX509(&ssl->peerCert, 0, ssl->heap); if (DecodeToX509(&ssl->peerCert, ssl->session->chain.certs[0].buffer, ssl->session->chain.certs[0].length) == 0) { From e19fa3e9bfeba460702ab77f8c35e4e85a2bb194 Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 21 Jul 2026 17:52:31 -0700 Subject: [PATCH 2/5] Mutex the suite allocation in InitSSL to avoid a race between two threads. --- src/internal.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/internal.c b/src/internal.c index 5914aa4203..717814f623 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8271,13 +8271,32 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) } #endif + /* Lazily allocating and deriving ctx->suites mutates shared CTX state. + * A CTX is commonly configured once and then shared by many threads + * that each call wolfSSL_new(), so guard the check and initialization + * with the CTX mutex. Without it, two threads can both observe + * ctx->suites == NULL and both allocate, leaking the Suites that loses + * the race. */ + ret = wolfSSL_RefWithMutexLock(&ctx->ref); + if (ret != 0) { + WOLFSSL_MSG("Failed to lock CTX mutex for suites init"); + return ret; + } if (ctx->suites == NULL) { - /* suites */ ret = AllocateCtxSuites(ctx); - if (ret != 0) - return ret; - InitSSL_CTX_Suites(ctx); + if (ret == 0) + InitSSL_CTX_Suites(ctx); + } + if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0) { + WOLFSSL_MSG("Failed to unlock CTX mutex after suites init"); + /* A stuck lock would deadlock the up_ref in SetSSL_CTX() below, so + * surface it as an error. Keep any earlier suites-init error, as + * that is the more meaningful failure. */ + if (ret == 0) + ret = BAD_MUTEX_E; } + if (ret != 0) + return ret; #ifdef OPENSSL_ALL ssl->suitesStack = NULL; #endif From cdffb4104d8638d90224dc974131142afc001d6a Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 21 Jul 2026 18:03:47 -0700 Subject: [PATCH 3/5] Zeroize the pKey struct at the beginning of AllocKey to avoid issues on failure and free. --- src/internal.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/internal.c b/src/internal.c index 717814f623..81a1fd97e7 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8651,6 +8651,12 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) return MEMORY_E; } + /* Zero the allocation before initializing. XMALLOC does not clear memory, + * and the key-specific init below may fail before it has zeroed/initialized + * the structure's members. Starting from all-zero makes any partial-init + * failure safe to free. */ + XMEMSET(*pKey, 0, sz); + /* Initialize key */ switch (type) { #ifndef NO_RSA From 8ed1f2c88ce4043e1715f2eeafe61d6c5f08242c Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 22 Jul 2026 10:30:41 -0700 Subject: [PATCH 4/5] Code review feedback --- src/ssl_api_cert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c index 669a1fe111..ec5584e0d0 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -2726,7 +2726,7 @@ int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk) * decoded contents. InitX509 only zeroes the pointers, so free * the existing allocations first to avoid orphaning them. */ FreeX509(x509); - InitX509(x509, 0, NULL); + InitX509(x509, 0, x509->heap); } ret = CopyDecodedToX509(x509, cert); } From 4b1f57527a0fa7e10f684ac9201101c94efc095d Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 23 Jul 2026 13:01:58 -0700 Subject: [PATCH 5/5] Code review feedback. --- src/ssl.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 47d731221f..30ef0f3189 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -8472,13 +8472,6 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) if (ssl->ctx == ctx) return ssl->ctx; - if (ctx->suites == NULL) { - /* suites */ - if (AllocateCtxSuites(ctx) != 0) - return NULL; - InitSSL_CTX_Suites(ctx); - } - wolfSSL_RefWithMutexInc(&ctx->ref, &ret); #ifdef WOLFSSL_REFCNT_ERROR_RETURN if (ret != 0) { @@ -8489,6 +8482,14 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) #else (void)ret; #endif + + if (ctx->suites == NULL) { + /* suites */ + if (AllocateCtxSuites(ctx) != 0) + return NULL; + InitSSL_CTX_Suites(ctx); + } + if (ssl->ctx != NULL) wolfSSL_CTX_free(ssl->ctx); ssl->ctx = ctx;