From c7af8bd3ced6140a0dc408f4f897effc32867b35 Mon Sep 17 00:00:00 2001 From: Ruby Martin Date: Mon, 27 Jul 2026 15:35:26 -0600 Subject: [PATCH 1/3] prevent uninitialized scalar variable issue --- tests/api/test_coding.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/api/test_coding.c b/tests/api/test_coding.c index a7f06b8235..64aa65f65b 100644 --- a/tests/api/test_coding.c +++ b/tests/api/test_coding.c @@ -330,18 +330,22 @@ int test_wc_Base64_EncodeDecisionCoverage(void) byte enc[128]; word32 i; int nlCount = 0; + + XMEMSET(enc, 0, sizeof(enc)); for (i = 0; i < (word32)sizeof(in48); i++) in48[i] = (byte)(i + 1); outLen = (word32)sizeof(enc); ExpectIntEQ(Base64_Encode(in48, (word32)sizeof(in48), enc, &outLen), 0); - for (i = 0; i < outLen; i++) { - if (enc[i] == '\n') - nlCount++; + if (EXPECT_SUCCESS()) { + for (i = 0; i < outLen; i++) { + if (enc[i] == '\n') + nlCount++; + } + /* exactly one (trailing) newline -- none inserted mid-stream */ + ExpectIntEQ(nlCount, 1); + ExpectIntEQ(enc[outLen - 1], '\n'); } - /* exactly one (trailing) newline -- none inserted mid-stream */ - ExpectIntEQ(nlCount, 1); - ExpectIntEQ(enc[outLen - 1], '\n'); } /* --- force a BUFFER_E from CEscape() inside the *main* while loop From 44f582afe1f67e4ded4fa1d67bd564519884862e Mon Sep 17 00:00:00 2001 From: Ruby Martin Date: Tue, 28 Jul 2026 15:29:32 -0600 Subject: [PATCH 2/3] Lock globalRng before access if HAVE_GLOBAL_RNG and OPENSSL_EXTRA are defined prevent potential deadlock --- src/ssl_sess.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/ssl_sess.c b/src/ssl_sess.c index cfc5eb4813..5ec882b76f 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -2165,13 +2165,37 @@ void AddSession(WOLFSSL* ssl) if (ssl->rng != NULL) rng = ssl->rng; #if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA) - else if (initGlobalRNG == 1 || wolfSSL_RAND_Init() == WOLFSSL_SUCCESS) { + else if (initGlobalRNG == 1 || + wolfSSL_RAND_Init() == WOLFSSL_SUCCESS) { rng = &globalRNG; } + if (rng == &globalRNG) { + if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + return; + } + /* The above access requires initGlobalRNG recheck now + * that we have the lock. */ + if (initGlobalRNG == 0) { + wc_UnLockMutex(&globalRNGMutex); + return; + } + } #endif if (wc_RNG_GenerateBlock(rng, ssl->session->altSessionID, - ID_LEN) != 0) + ID_LEN) != 0) { +#if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA) + if (rng == &globalRNG) { + wc_UnLockMutex(&globalRNGMutex); + } +#endif return; + } +#if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA) + if (rng == &globalRNG) { + wc_UnLockMutex(&globalRNGMutex); + } +#endif ssl->session->haveAltSessionID = 1; id = ssl->session->altSessionID; idSz = ID_LEN; From 460f447fec03dcd3365f4a65d5a0bcee969d6f00 Mon Sep 17 00:00:00 2001 From: Ruby Martin Date: Tue, 28 Jul 2026 17:06:18 -0600 Subject: [PATCH 3/3] cap derLen at largest valid DER size Test oversized DER is rejected before allocation --- src/pk_rsa.c | 6 +++++ tests/api.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/pk_rsa.c b/src/pk_rsa.c index 63ab70abd2..b029fcc405 100644 --- a/src/pk_rsa.c +++ b/src/pk_rsa.c @@ -651,6 +651,12 @@ static int wolfssl_read_der_bio(WOLFSSL_BIO* bio, unsigned char** out) WOLFSSL_ERROR_MSG("DER SEQUENCE decode failed"); err = 1; } + /* Cap at 8x the maximum modulus size, leaves headroom for the full + * private key encoding. */ + if ((!err) && (derLen > RSA_MAX_SIZE)) { + WOLFSSL_ERROR_MSG("DER length too large"); + err = 1; + } /* Allocate a buffer to read DER data into. */ if ((!err) && ((der = (unsigned char*)XMALLOC((size_t)derLen, bio->heap, DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) { diff --git a/tests/api.c b/tests/api.c index 14f10ca874..ef4c18214c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -20491,6 +20491,68 @@ static int test_wolfSSL_d2i_PrivateKeys_bio(void) } #endif /* OPENSSL_ALL || (WOLFSSL_ASIO && !NO_RSA) */ +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_NO_MALLOC) && \ + !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) +/* Counts and refuses allocations >= big_alloc_threshold, to observe the + * oversized DER allocation in wolfssl_read_der_bio(). */ +static size_t big_alloc_threshold = 0; /* 0 = disabled */ +static int big_alloc_attempts = 0; + +static void* big_malloc_cb(size_t size) +{ + if (big_alloc_threshold != 0 && size >= big_alloc_threshold) { + big_alloc_attempts++; + return NULL; /* refuse; records the attempt */ + } + return malloc(size); +} +#endif /* memory-hook guards */ + +/* Oversized-DER cap in wolfssl_read_der_bio(): a SEQUENCE far over the cap must + * be rejected before allocation. NULL alone doesn't prove it (uncapped returns + * NULL too), so refuse large allocations and assert none was attempted. */ +static int test_wolfSSL_d2i_RSAPrivateKey_bio_oversized(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_NO_MALLOC) && \ + !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) + /* SEQUENCE, canonical 4-byte length 0x01000000 (16 MB), over the cap. + * Must be canonical -- 0x00FFFFFF is rejected by the parser first. */ + static const unsigned char hugeSeq[] = + { 0x30, 0x84, 0x01, 0x00, 0x00, 0x00 }; + BIO* bio = NULL; + RSA* rsa = NULL; + wolfSSL_Malloc_cb prev_mc = NULL; + wolfSSL_Free_cb prev_fc = NULL; + wolfSSL_Realloc_cb prev_rc = NULL; + int allocators_set = 0; + + ExpectIntEQ(wolfSSL_GetAllocators(&prev_mc, &prev_fc, &prev_rc), 0); + ExpectIntEQ(wolfSSL_SetAllocators(big_malloc_cb, prev_fc, prev_rc), 0); + if (EXPECT_SUCCESS()) + allocators_set = 1; + + ExpectNotNull(bio = BIO_new(BIO_s_mem())); + ExpectIntGT(BIO_write(bio, hugeSeq, (int)sizeof(hugeSeq)), 0); + + big_alloc_attempts = 0; + big_alloc_threshold = 0x10000; + ExpectNull(d2i_RSAPrivateKey_bio(bio, &rsa)); + big_alloc_threshold = 0; + + ExpectIntEQ(big_alloc_attempts, 0); + + BIO_free(bio); + RSA_free(rsa); + + if (allocators_set) + (void)wolfSSL_SetAllocators(prev_mc, prev_fc, prev_rc); +#endif + return EXPECT_RESULT(); +} + #endif /* !NO_BIO */ @@ -38233,6 +38295,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_d2i_PrivateKeys_bio), #endif /* !NO_BIO */ #endif +#ifndef NO_BIO + TEST_DECL(test_wolfSSL_d2i_RSAPrivateKey_bio_oversized), +#endif /* !NO_BIO */ #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)