From bc8a9fa7c263db4f589f6a141c106acce3af5532 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:28:35 -0700 Subject: [PATCH 01/17] Refactor wolfSSL_EVP_DigestUpdate into a chunked function so sizes above word32 max are handled correctly. (F-7103) --- wolfcrypt/src/evp.c | 76 +++++++++++++++++++++++++++++-------------- wolfssl/openssl/evp.h | 2 +- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index ca0ccdd7432..880411a1ece 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -5002,22 +5002,6 @@ static int wolfSSL_evp_digest_pk_init(WOLFSSL_EVP_MD_CTX *ctx, return WOLFSSL_SUCCESS; } -/* Update an EVP_DigestSign/Verify operation. - * Update a digest for RSA and ECC keys, or HMAC for HMAC key. - */ -static int wolfssl_evp_digest_pk_update(WOLFSSL_EVP_MD_CTX *ctx, - const void *d, unsigned int cnt) -{ - if (ctx->isHMAC) { - if (wc_HmacUpdate(&ctx->hash.hmac, (const byte *)d, cnt) != 0) - return WOLFSSL_FAILURE; - - return WOLFSSL_SUCCESS; - } - else - return wolfSSL_EVP_DigestUpdate(ctx, d, cnt); -} - /* Finalize an EVP_DigestSign/Verify operation - common part only. * Finalize a digest for RSA and ECC keys, or HMAC for HMAC key. * Copies the digest so that you can keep updating. @@ -5160,14 +5144,14 @@ int wolfSSL_EVP_DigestSignInit(WOLFSSL_EVP_MD_CTX *ctx, int wolfSSL_EVP_DigestSignUpdate(WOLFSSL_EVP_MD_CTX *ctx, const void *d, - unsigned int cnt) + size_t cnt) { WOLFSSL_ENTER("EVP_DigestSignUpdate"); if (ctx == NULL || d == NULL) return WOLFSSL_FAILURE; - return wolfssl_evp_digest_pk_update(ctx, d, cnt); + return wolfSSL_EVP_DigestUpdate(ctx, d, cnt); } int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig, @@ -5286,7 +5270,7 @@ int wolfSSL_EVP_DigestSign(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sigret, if (sigret != NULL) { if (tbs == NULL) return WOLFSSL_FAILURE; - if (wolfSSL_EVP_DigestSignUpdate(ctx, tbs, (unsigned int)tbslen) + if (wolfSSL_EVP_DigestSignUpdate(ctx, tbs, tbslen) != WOLFSSL_SUCCESS) return WOLFSSL_FAILURE; } @@ -5316,7 +5300,7 @@ int wolfSSL_EVP_DigestVerifyUpdate(WOLFSSL_EVP_MD_CTX *ctx, const void *d, if (ctx == NULL || d == NULL) return WOLFSSL_FAILURE; - return wolfssl_evp_digest_pk_update(ctx, d, (unsigned int)cnt); + return wolfSSL_EVP_DigestUpdate(ctx, d, cnt); } @@ -11817,15 +11801,14 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) return ret; } - /* WOLFSSL_SUCCESS on ok, WOLFSSL_FAILURE on failure */ - int wolfSSL_EVP_DigestUpdate(WOLFSSL_EVP_MD_CTX* ctx, const void* data, - size_t sz) + /* Update the digest with at most a word32 of data. + * WOLFSSL_SUCCESS on ok, WOLFSSL_FAILURE on failure */ + static int wolfssl_evp_digest_update_chunk(WOLFSSL_EVP_MD_CTX* ctx, + const void* data, word32 sz) { int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); enum wc_HashType macType; - WOLFSSL_ENTER("EVP_DigestUpdate"); - macType = EvpMd2MacType(wolfSSL_EVP_MD_CTX_md(ctx)); switch (macType) { case WC_HASH_TYPE_MD4: @@ -11984,6 +11967,49 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) return ret; } + /* WOLFSSL_SUCCESS on ok, WOLFSSL_FAILURE on failure */ + int wolfSSL_EVP_DigestUpdate(WOLFSSL_EVP_MD_CTX* ctx, const void* data, + size_t sz) + { + int ret; + + WOLFSSL_ENTER("EVP_DigestUpdate"); + + if (ctx == NULL) + return WOLFSSL_FAILURE; + + /* The underlying update functions take a word32 length. Feed the data + * in chunks so the whole of sz is hashed instead of sz mod 2^32. + * Detect the narrowing by round-tripping rather than comparing against + * a constant, so this holds for any width of size_t. */ + do { + word32 chunk = (word32)sz; + if ((size_t)chunk != sz) + chunk = WC_MAX_UINT_OF(word32); + + #ifndef NO_HMAC + if (ctx->isHMAC) { + if (wc_HmacUpdate(&ctx->hash.hmac, (const byte*)data, + chunk) != 0) { + return WOLFSSL_FAILURE; + } + } + else + #endif + { + /* pass the sub-call's code through, e.g. NOT_COMPILED_IN */ + ret = wolfssl_evp_digest_update_chunk(ctx, data, chunk); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + + data = (const byte*)data + chunk; + sz -= chunk; + } while (sz > 0); + + return WOLFSSL_SUCCESS; + } + /* WOLFSSL_SUCCESS on ok */ static int wolfSSL_EVP_DigestFinal_Common(WOLFSSL_EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s, enum wc_HashType macType) diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 26cc0261b5d..c525e3a9c17 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -869,7 +869,7 @@ WOLFSSL_API int wolfSSL_EVP_DigestFinal_ex(WOLFSSL_EVP_MD_CTX* ctx, WOLFSSL_API int wolfSSL_EVP_DigestFinalXOF(WOLFSSL_EVP_MD_CTX* ctx, unsigned char* md, size_t sz); WOLFSSL_API int wolfSSL_EVP_DigestSignUpdate(WOLFSSL_EVP_MD_CTX *ctx, - const void *d, unsigned int cnt); + const void *d, size_t cnt); WOLFSSL_API int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig, size_t *siglen); WOLFSSL_API int wolfSSL_EVP_DigestSign(WOLFSSL_EVP_MD_CTX *ctx, From 50c9ecb78b6fd3c0c0404a174aff06ba3aa56813 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:32:07 -0700 Subject: [PATCH 02/17] Always use new key in wc_ecc_decrypt to avoid freeing passed in key. (F-7105) --- doc/dox_comments/header_files/ecc.h | 13 +++-- tests/api/test_ecc.c | 73 +++++++++++++++++++++++++++++ tests/api/test_ecc.h | 2 + wolfcrypt/src/ecc.c | 15 ++---- 4 files changed, 88 insertions(+), 15 deletions(-) diff --git a/doc/dox_comments/header_files/ecc.h b/doc/dox_comments/header_files/ecc.h index 74b39375288..8920d61c0f1 100644 --- a/doc/dox_comments/header_files/ecc.h +++ b/doc/dox_comments/header_files/ecc.h @@ -2267,9 +2267,9 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg, the encryption type specified by ctx. \return 0 Returned upon successfully decrypting the input message - \return BAD_FUNC_ARG Returned if privKey, pubKey, msg, msgSz, out, - or outSz are NULL, or the ctx object specifies an unsupported - encryption type + \return BAD_FUNC_ARG Returned if privKey, msg, msgSz, out, or outSz + are NULL (or pubKey is NULL when built with WOLFSSL_ECIES_OLD), or + the ctx object specifies an unsupported encryption type \return BAD_ENC_STATE_E Returned if the ctx object given is in a state that is not appropriate for decryption \return BUFFER_E Returned if the supplied output buffer is too @@ -2282,8 +2282,11 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg, \param privKey pointer to the ecc_key object containing the private key to use for decryption - \param pubKey pointer to the ecc_key object containing the public - key of the peer with whom one wishes to communicate + \param pubKey only used when built with WOLFSSL_ECIES_OLD: pointer to + the ecc_key object containing the public key of the peer with whom one + wishes to communicate. In the default message format the sender's + ephemeral public key is read from the start of msg instead and pubKey + is ignored (it may be NULL and is left unmodified) \param msg pointer to the buffer holding the ciphertext to decrypt \param msgSz size of the buffer to decrypt \param out pointer to the buffer in which to store the decrypted plaintext diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index f841b71421d..e43a20f69f2 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -2008,6 +2008,79 @@ int test_wc_ecc_encryptDecrypt(void) return EXPECT_RESULT(); } /* END test_wc_ecc_encryptDecrypt */ +/* + * In the default ECIES message format the sender's ephemeral public key is + * carried in the message, so wc_ecc_decrypt() must not free or overwrite a + * caller-supplied pubKey object. Confirm the object is byte-for-byte preserved + * across a decrypt. + */ +int test_wc_ecc_decrypt_pubkey_preserved(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \ + !defined(WOLFSSL_ECIES_OLD) && defined(HAVE_ECC_KEY_EXPORT) && \ + defined(HAVE_ECC_KEY_IMPORT) && \ + (defined(HAVE_AES_CBC) || \ + (defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \ + defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128) + ecc_key cliKey; + ecc_key srvKey; + ecc_key pubKey; + WC_RNG rng; + const char* msg = "EccBlock Size 16"; + word32 msgSz = (word32)XSTRLEN("EccBlock Size 16"); + byte out[KEY20 * 2 + 1 + (sizeof("EccBlock Size 16") - 1) + + WC_SHA256_DIGEST_SIZE]; + word32 outSz = (word32)sizeof(out); + byte plain[sizeof("EccBlock Size 16")]; + word32 plainSz = (word32)sizeof(plain); + byte before[ECC_BUFSIZE]; + byte after[ECC_BUFSIZE]; + word32 beforeSz = (word32)sizeof(before); + word32 afterSz = (word32)sizeof(after); + + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(&cliKey, 0, sizeof(cliKey)); + XMEMSET(&srvKey, 0, sizeof(srvKey)); + XMEMSET(&pubKey, 0, sizeof(pubKey)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_ecc_init(&cliKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, KEY20, &cliKey), 0); + ExpectIntEQ(wc_ecc_init(&srvKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, KEY20, &srvKey), 0); + ExpectIntEQ(wc_ecc_init(&pubKey), 0); + /* Load a public key distinct from the sender's ephemeral (embedded in the + * message) so that overwriting pubKey would be detectable. */ + ExpectIntEQ(wc_ecc_export_x963(&srvKey, before, &beforeSz), 0); + ExpectIntEQ(wc_ecc_import_x963(before, beforeSz, &pubKey), 0); + +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \ + !defined(HAVE_SELFTEST) + ExpectIntEQ(wc_ecc_set_rng(&srvKey, &rng), 0); + ExpectIntEQ(wc_ecc_set_rng(&cliKey, &rng), 0); +#endif + + ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, (byte*)msg, msgSz, out, + &outSz, NULL), 0); + ExpectIntEQ(wc_ecc_decrypt(&srvKey, &pubKey, out, outSz, plain, &plainSz, + NULL), 0); + ExpectIntEQ(XMEMCMP(msg, plain, msgSz), 0); + + /* the caller's pubKey object must be unchanged after the decrypt */ + ExpectIntEQ(wc_ecc_export_x963(&pubKey, after, &afterSz), 0); + ExpectIntEQ(afterSz, beforeSz); + ExpectIntEQ(XMEMCMP(before, after, beforeSz), 0); + + wc_ecc_free(&pubKey); + wc_ecc_free(&srvKey); + wc_ecc_free(&cliKey); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} /* END test_wc_ecc_decrypt_pubkey_preserved */ + /* * Testing ECIES with the AES-256-GCM DEM. Exercises, each with its own * single-use client/server ctx pair: diff --git a/tests/api/test_ecc.h b/tests/api/test_ecc.h index acaa4bb349b..d3928b009a4 100644 --- a/tests/api/test_ecc.h +++ b/tests/api/test_ecc.h @@ -56,6 +56,7 @@ int test_wc_ecc_ctx_set_peer_salt(void); int test_wc_ecc_ctx_set_info(void); int test_wc_ecc_ctx_getters(void); int test_wc_ecc_encryptDecrypt(void); +int test_wc_ecc_decrypt_pubkey_preserved(void); int test_wc_ecc_ecies_gcm(void); int test_wc_ecc_ecies_gcm_no_rng(void); int test_wc_ecc_ecies_cryptocb(void); @@ -109,6 +110,7 @@ int test_wc_EccDecisionCoverage4(void); TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_set_info), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_getters), \ TEST_DECL_GROUP("ecc", test_wc_ecc_encryptDecrypt), \ + TEST_DECL_GROUP("ecc", test_wc_ecc_decrypt_pubkey_preserved), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm_no_rng), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_cryptocb), \ diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 0cc84908060..7ff9a46b2cd 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -16484,17 +16484,12 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, #endif #ifndef WOLFSSL_ECIES_OLD - if (pubKey == NULL) { - WC_ALLOC_VAR_EX(peerKey, ecc_key, 1, ctx->heap, - DYNAMIC_TYPE_ECC_BUFFER, ret=MEMORY_E); - pubKey = peerKey; - } - else { - /* if a public key was passed in we should free it here before init - * and import */ - wc_ecc_free(pubKey); - } + /* The ephemeral public key comes from the message; parse it into the + * local key object so a caller-supplied pubKey is left untouched. */ + WC_ALLOC_VAR_EX(peerKey, ecc_key, 1, ctx->heap, + DYNAMIC_TYPE_ECC_BUFFER, ret=MEMORY_E); if (ret == 0) { + pubKey = peerKey; ret = wc_ecc_init_ex(pubKey, privKey->heap, INVALID_DEVID); } if (ret == 0) { From 878d558c2c0e1fe96299254fffe6cb5bdfddfe24 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:34:35 -0700 Subject: [PATCH 03/17] Zero out the digest in SHA256/512 generation functions. (F-7135) --- wolfcrypt/src/random.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 55d23d2e6e5..a174d777cda 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1485,6 +1485,7 @@ static WARN_UNUSED_RESULT int Hash_gen(DRBG_internal* drbg, byte* out, XMEMCPY(data, V, DRBG_SEED_LEN); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("Hash_gen data", data, DRBG_SEED_LEN); + wc_MemZero_Add("Hash_gen digest", digest, WC_SHA256_DIGEST_SIZE); #endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -1525,9 +1526,11 @@ static WARN_UNUSED_RESULT int Hash_gen(DRBG_internal* drbg, byte* out, } } ForceZero(data, DRBG_SEED_LEN); + ForceZero(digest, WC_SHA256_DIGEST_SIZE); #if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(data, DRBG_SEED_LEN); + wc_MemZero_Check(digest, WC_SHA256_DIGEST_SIZE); #endif #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -2152,6 +2155,7 @@ static WARN_UNUSED_RESULT int Hash512_gen(DRBG_SHA512_internal* drbg, XMEMCPY(data, V, DRBG_SHA512_SEED_LEN); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("Hash512_gen data", data, DRBG_SHA512_SEED_LEN); + wc_MemZero_Add("Hash512_gen digest", digest, WC_SHA512_DIGEST_SIZE); #endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -2191,9 +2195,11 @@ static WARN_UNUSED_RESULT int Hash512_gen(DRBG_SHA512_internal* drbg, } } ForceZero(data, DRBG_SHA512_SEED_LEN); + ForceZero(digest, WC_SHA512_DIGEST_SIZE); #if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(data, DRBG_SHA512_SEED_LEN); + wc_MemZero_Check(digest, WC_SHA512_DIGEST_SIZE); #endif #ifndef WOLFSSL_SMALL_STACK_CACHE From 07a546459ccf9e0838a0fe9710776ea18779632f Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:36:02 -0700 Subject: [PATCH 04/17] Zero out SRP user and key when overwriting them. (F-7400) --- wolfcrypt/src/srp.c | 14 ++++++++++++++ wolfcrypt/test/test.c | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/wolfcrypt/src/srp.c b/wolfcrypt/src/srp.c index 44c48d45ef0..13d70e545ea 100644 --- a/wolfcrypt/src/srp.c +++ b/wolfcrypt/src/srp.c @@ -326,6 +326,13 @@ int wc_SrpSetUsername(Srp* srp, const byte* username, word32 size) if (!srp || !username) return BAD_FUNC_ARG; + if (srp->user) { + ForceZero(srp->user, srp->userSz); + XFREE(srp->user, srp->heap, DYNAMIC_TYPE_SRP); + srp->user = NULL; + srp->userSz = 0; + } + /* +1 for NULL char */ srp->user = (byte*)XMALLOC(size + 1, srp->heap, DYNAMIC_TYPE_SRP); if (srp->user == NULL) @@ -676,6 +683,13 @@ static int wc_SrpSetKey(Srp* srp, byte* secret, word32 size) XMEMSET(digest, 0, SRP_MAX_DIGEST_SIZE); + if (srp->key) { + ForceZero(srp->key, srp->keySz); + XFREE(srp->key, srp->heap, DYNAMIC_TYPE_SRP); + srp->key = NULL; + srp->keySz = 0; + } + srp->key = (byte*)XMALLOC(2 * (word32)digestSz, srp->heap, DYNAMIC_TYPE_SRP); if (srp->key == NULL) return MEMORY_E; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 0c1e4e44544..3b162d00153 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -40789,6 +40789,14 @@ static wc_test_ret_t srp_test_digest(SrpType dgstType) if (!r) r = wc_SrpVerifyPeersProof(cli, serverProof, serverProofSz); + /* Regression: a second wc_SrpSetUsername()/wc_SrpComputeKey() must release + * (and, for the key, zeroise) the buffer from the first call rather than + * leaking it. The exchange above is already verified; these repeat calls + * exercise the overwrite path so ASan flags a leak if it regresses. */ + if (!r) r = wc_SrpSetUsername(cli, username, usernameSz); + if (!r) r = wc_SrpComputeKey(cli, clientPubKey, clientPubKeySz, + serverPubKey, serverPubKeySz); + /* Negative test: corrupted proof must be rejected with SRP_VERIFY_E. */ if (!r) { int rNeg; From bde5e2f2d0d61648ef3a2f615fd84bb498a4bed9 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:39:37 -0700 Subject: [PATCH 05/17] Use subtraction-based comparison in EVP fillBuff. (F-7446) --- wolfcrypt/src/evp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 880411a1ece..3cd9e8b395c 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -594,7 +594,7 @@ static int fillBuff(WOLFSSL_EVP_CIPHER_CTX *ctx, const unsigned char *in, int sz if (sz > 0) { int fill; - if ((sz+ctx->bufUsed) > ctx->block_size) { + if (sz > ctx->block_size - ctx->bufUsed) { fill = ctx->block_size - ctx->bufUsed; } else { fill = sz; From b334acb134b452bb8da7aa404ebfdbf1398d93b7 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:40:53 -0700 Subject: [PATCH 06/17] Correct decOidSz in wc_ecc_get_curve_id_from_oid. (F-7623) --- tests/api/test_ecc.c | 19 +++++++++++++++++++ wolfcrypt/src/ecc.c | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index e43a20f69f2..db2478e0777 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -3391,6 +3391,25 @@ int test_wc_ecc_get_curve_id_from_oid(void) ExpectIntEQ(wc_ecc_get_curve_id_from_oid(oid, 0), ECC_CURVE_INVALID); /* Good Case */ ExpectIntEQ(wc_ecc_get_curve_id_from_oid(oid, len), ECC_SECP256R1); + +#ifdef HAVE_OID_DECODING + { + /* An OID with more sub-identifiers than the internal decode array can + * hold must be rejected, not decoded past the end of that array. The + * first byte decodes to two arcs and every following byte to one, so + * MAX_OID_SZ bytes yield well over the MAX_OID_SZ/2 element capacity. + * Run under ASan to catch a regression. */ + byte longOid[MAX_OID_SZ]; + word32 i; + + longOid[0] = 0x2A; + for (i = 1; i < (word32)sizeof(longOid); i++) + longOid[i] = 0x01; + + ExpectIntEQ(wc_ecc_get_curve_id_from_oid(longOid, sizeof(longOid)), + WC_NO_ERR_TRACE(BUFFER_E)); + } +#endif #endif return EXPECT_RESULT(); } /* END test_wc_ecc_get_curve_id_from_oid */ diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 7ff9a46b2cd..29babb06e95 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4672,7 +4672,8 @@ int wc_ecc_get_curve_id_from_oid(const byte* oid, word32 len) return BAD_FUNC_ARG; #ifdef HAVE_OID_DECODING - decOidSz = (word32)sizeof(decOid); + /* in elements, not bytes */ + decOidSz = (word32)(sizeof(decOid) / sizeof(decOid[0])); ret = DecodeObjectId(oid, len, decOid, &decOidSz); if (ret != 0) { return ret; From 23438233d16970c525e37c6e4ea413ea172d1700 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:44:47 -0700 Subject: [PATCH 07/17] Avoid clamping in EncodeAttributes when attribute size exceeds capacity. (F-7624) --- wolfcrypt/src/pkcs7.c | 8 ++- wolfcrypt/test/test.c | 124 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 9040d3422fd..017f8416258 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1894,16 +1894,18 @@ static int EncodeAttributes(EncodedAttrib* ea, int eaSz, PKCS7Attrib* attribs, int attribsSz) { int i; - int maxSz; word32 allAttribsSz = 0; if (eaSz < 0 || attribsSz < 0) { return BAD_FUNC_ARG; } - maxSz = (int)min((word32)eaSz, (word32)attribsSz); + /* every attribute must fit in the output array; do not silently drop */ + if (attribsSz > eaSz) { + return BUFFER_E; + } - for (i = 0; i < maxSz; i++) + for (i = 0; i < attribsSz; i++) { word32 attribSz = 0; word32 boundSz = 0; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 3b162d00153..2ba9e14edf5 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -79565,6 +79565,123 @@ static wc_test_ret_t pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCer return ret; } +#if !defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_128) +/* Boundary test for the fixed-size auth/unauth attribute arrays in + * wc_PKCS7_EncodeAuthEnvelopedData(): filling them to capacity must encode, + * while requesting one attribute more than fits must fail cleanly instead of + * writing past the arrays. Run under ASan to catch a regression. */ +static wc_test_ret_t pkcs7_authenv_attribs_boundary_test(byte* rsaCert, + word32 rsaCertSz, byte* rsaPrivKey, word32 rsaPrivKeySz) +{ + wc_test_ret_t ret = 0; + wc_PKCS7* pkcs7 = NULL; + byte* enveloped = NULL; + int envSz; + byte content[] = "authenv attribs boundary test"; + + /* eight distinct, well-formed attribute TLVs (OID + PrintableString) */ + static const byte oid0[] = { 0x06,0x03, 0x55,0x04,0x03 }; + static const byte oid1[] = { 0x06,0x03, 0x55,0x04,0x04 }; + static const byte oid2[] = { 0x06,0x03, 0x55,0x04,0x05 }; + static const byte oid3[] = { 0x06,0x03, 0x55,0x04,0x06 }; + static const byte oid4[] = { 0x06,0x03, 0x55,0x04,0x07 }; + static const byte oid5[] = { 0x06,0x03, 0x55,0x04,0x08 }; + static const byte oid6[] = { 0x06,0x03, 0x55,0x04,0x09 }; + static const byte oid7[] = { 0x06,0x03, 0x55,0x04,0x0a }; + static const byte val[] = { 0x13,0x01, 0x30 }; + PKCS7Attrib attribs[8] = { + { oid0, sizeof(oid0), val, sizeof(val) }, + { oid1, sizeof(oid1), val, sizeof(val) }, + { oid2, sizeof(oid2), val, sizeof(val) }, + { oid3, sizeof(oid3), val, sizeof(val) }, + { oid4, sizeof(oid4), val, sizeof(val) }, + { oid5, sizeof(oid5), val, sizeof(val) }, + { oid6, sizeof(oid6), val, sizeof(val) }, + { oid7, sizeof(oid7), val, sizeof(val) } + }; + + enveloped = (byte*)XMALLOC(PKCS7_BUF_SIZE, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (enveloped == NULL) + return WC_TEST_RET_ENC_ERRNO; + + /* contentOID == DATA so no contentType attribute is auto-added; all + * MAX_AUTH_ATTRIBS_SZ slots are available to the user attributes. */ + + /* exactly MAX_AUTH_ATTRIBS_SZ authenticated attributes: must encode */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->authAttribs = attribs; + pkcs7->authAttribsSz = MAX_AUTH_ATTRIBS_SZ; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz <= 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); + + /* one more authenticated attribute than fits: must fail, not overrun */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->authAttribs = attribs; + pkcs7->authAttribsSz = MAX_AUTH_ATTRIBS_SZ + 1; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz >= 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + /* one more unauthenticated attribute than fits: must fail, not overrun */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->unauthAttribs = attribs; + pkcs7->unauthAttribsSz = MAX_UNAUTH_ATTRIBS_SZ + 1; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz >= 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + ret = 0; + +out: + if (pkcs7 != NULL) + wc_PKCS7_Free(pkcs7); + XFREE(enveloped, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} +#endif /* RSA + AESGCM + keywrap + AES128 */ + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs7authenveloped_test(void) { wc_test_ret_t ret = 0; @@ -79642,6 +79759,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs7authenveloped_test(void) eccCert, (word32)eccCertSz, eccPrivKey, (word32)eccPrivKeySz); +#if !defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_128) + if (ret == 0) + ret = pkcs7_authenv_attribs_boundary_test(rsaCert, (word32)rsaCertSz, + rsaPrivKey, (word32)rsaPrivKeySz); +#endif + #ifndef NO_RSA XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); From 3c54695d53900d8d23ba56d18168cb06e3bf42da Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:53:59 -0700 Subject: [PATCH 08/17] Clear hash in EVP_CIPHER_MD_CTX_copy_ex before all possible returns. (F-8166) --- wolfcrypt/src/evp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 3cd9e8b395c..5007eedd814 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -6262,14 +6262,15 @@ void wolfSSL_EVP_init(void) WOLFSSL_ENTER("EVP_CIPHER_MD_CTX_copy_ex"); wolfSSL_EVP_MD_CTX_cleanup(out); XMEMCPY(out, in, sizeof(WOLFSSL_EVP_MD_CTX)); + /* Zero hash context after shallow copy to prevent shared sub-pointers + * with src, even if the pctx allocation below fails. The hash Copy + * function will perform the proper deep copy. */ + XMEMSET(&out->hash, 0, sizeof(out->hash)); if (in->pctx != NULL) { out->pctx = wolfSSL_EVP_PKEY_CTX_new(in->pctx->pkey, NULL); if (out->pctx == NULL) return WOLFSSL_FAILURE; } - /* Zero hash context after shallow copy to prevent shared sub-pointers - * with src. The hash Copy function will perform the proper deep copy. */ - XMEMSET(&out->hash, 0, sizeof(out->hash)); return wolfSSL_EVP_MD_Copy_Hasher(out, (WOLFSSL_EVP_MD_CTX*)in); } #ifndef NO_AES From 6851003490b683c14ee08bbbaeeb7b1e38913b30 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 14 Aug 2026 17:54:54 -0700 Subject: [PATCH 09/17] Correct size documentation for wc_AesCfb1Encrypt and wc_AesCfb1Decrypt (bits not bytes). (F-9329) --- wolfcrypt/src/aes.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index f7aa53f9eb1..fcad0d7bf53 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -17410,7 +17410,8 @@ static WARN_UNUSED_RESULT int wc_AesFeedbackCFB1( * out buffer to hold result of encryption (must be at least as large as input * buffer) * in buffer to encrypt (packed to left, i.e. 101 is 0x90) - * sz size of input buffer in bits (0x1 would be size of 1 and 0xFF size of 8) + * sz number of bits to process, e.g. 1 processes one bit and 8 one byte; + * in and out must hold at least (sz + 7) / 8 bytes * * returns 0 on success and negative values on failure */ @@ -17441,8 +17442,9 @@ int wc_AesCfb8Encrypt(Aes* aes, byte* out, const byte* in, word32 sz) * aes structure holding key to use for encryption * out buffer to hold result of encryption (must be at least as large as input * buffer) - * in buffer to encrypt - * sz size of input buffer in bits (0x1 would be size of 1 and 0xFF size of 8) + * in buffer to decrypt (packed to left, i.e. 101 is 0x90) + * sz number of bits to process, e.g. 1 processes one bit and 8 one byte; + * in and out must hold at least (sz + 7) / 8 bytes * * returns 0 on success and negative values on failure */ From 208bf80be5ac34317287636a46e48028ce0f40cc Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 17 Aug 2026 10:17:08 -0700 Subject: [PATCH 10/17] Code review feedback --- wolfcrypt/src/evp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 5007eedd814..b182c986c68 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -11976,8 +11976,10 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) WOLFSSL_ENTER("EVP_DigestUpdate"); - if (ctx == NULL) + if (ctx == NULL || data == NULL) return WOLFSSL_FAILURE; + if (sz == 0) + return WOLFSSL_SUCCESS; /* The underlying update functions take a word32 length. Feed the data * in chunks so the whole of sz is hashed instead of sz mod 2^32. From ec2e05c29be649b03cb648396cb57951f4e74a1d Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 17 Aug 2026 10:55:03 -0700 Subject: [PATCH 11/17] Correct ordering of added EVP_DigestUpdate checks to match OpenSSL's behavior. --- wolfcrypt/src/evp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index b182c986c68..d63d7925e66 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -11976,10 +11976,14 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) WOLFSSL_ENTER("EVP_DigestUpdate"); - if (ctx == NULL || data == NULL) + if (ctx == NULL) return WOLFSSL_FAILURE; + /* A NULL buffer with nothing to hash is a valid no-op, as in + * wc_ShaUpdate(); a NULL buffer with data to hash is not. */ if (sz == 0) return WOLFSSL_SUCCESS; + if (data == NULL) + return WOLFSSL_FAILURE; /* The underlying update functions take a word32 length. Feed the data * in chunks so the whole of sz is hashed instead of sz mod 2^32. From 63bb10b5e2ed8d26e8eb808eb914c620d586d406 Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 18 Aug 2026 15:10:44 -0700 Subject: [PATCH 12/17] Fix failing test --- tests/api/test_ecc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index db2478e0777..2e7c737b7a5 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -2029,8 +2029,14 @@ int test_wc_ecc_decrypt_pubkey_preserved(void) WC_RNG rng; const char* msg = "EccBlock Size 16"; word32 msgSz = (word32)XSTRLEN("EccBlock Size 16"); +#ifdef WOLFSSL_ECIES_GEN_IV + /* GEN_IV mode carries the nonce in the message as well */ + byte out[KEY20 * 2 + 1 + AES_BLOCK_SIZE + + (sizeof("EccBlock Size 16") - 1) + WC_SHA256_DIGEST_SIZE]; +#else byte out[KEY20 * 2 + 1 + (sizeof("EccBlock Size 16") - 1) + WC_SHA256_DIGEST_SIZE]; +#endif word32 outSz = (word32)sizeof(out); byte plain[sizeof("EccBlock Size 16")]; word32 plainSz = (word32)sizeof(plain); From e1a0915127ee2719cb3f329a6c1016fd7e4bf5bf Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 21 Aug 2026 10:41:13 -0700 Subject: [PATCH 13/17] Code review feedback --- tests/api/test_ecc.c | 23 ++++++--- tests/api/test_pkcs7.c | 113 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_pkcs7.h | 3 ++ wolfcrypt/src/random.c | 9 ++++ wolfcrypt/test/test.c | 69 ++++++++++++++++--------- 5 files changed, 185 insertions(+), 32 deletions(-) diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index 2e7c737b7a5..0e3ce3d58e6 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -2079,6 +2079,14 @@ int test_wc_ecc_decrypt_pubkey_preserved(void) ExpectIntEQ(afterSz, beforeSz); ExpectIntEQ(XMEMCMP(before, after, beforeSz), 0); + /* pubKey is optional in this format: NULL must decrypt too */ + XMEMSET(plain, 0, sizeof(plain)); + plainSz = (word32)sizeof(plain); + ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain, &plainSz, + NULL), 0); + ExpectIntEQ(plainSz, msgSz); + ExpectIntEQ(XMEMCMP(msg, plain, msgSz), 0); + wc_ecc_free(&pubKey); wc_ecc_free(&srvKey); wc_ecc_free(&cliKey); @@ -3400,20 +3408,19 @@ int test_wc_ecc_get_curve_id_from_oid(void) #ifdef HAVE_OID_DECODING { - /* An OID with more sub-identifiers than the internal decode array can - * hold must be rejected, not decoded past the end of that array. The - * first byte decodes to two arcs and every following byte to one, so - * MAX_OID_SZ bytes yield well over the MAX_OID_SZ/2 element capacity. - * Run under ASan to catch a regression. */ - byte longOid[MAX_OID_SZ]; + /* Length must stay just over the array's element capacity but under + * MAX_OID_SZ, or a byte-sized limit would also accept it. */ + #define ECC_OID_ELEMS (MAX_OID_SZ / (int)sizeof(word16)) + byte longOid[ECC_OID_ELEMS + 3]; word32 i; - longOid[0] = 0x2A; + longOid[0] = 0x2A; /* two arcs */ for (i = 1; i < (word32)sizeof(longOid); i++) - longOid[i] = 0x01; + longOid[i] = 0x01; /* one arc each */ ExpectIntEQ(wc_ecc_get_curve_id_from_oid(longOid, sizeof(longOid)), WC_NO_ERR_TRACE(BUFFER_E)); + #undef ECC_OID_ELEMS } #endif #endif diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 33edd70075f..3f9cca090c0 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -5475,6 +5475,119 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) return EXPECT_RESULT(); } /* END test_wc_PKCS7_EncodeDecodeEnvelopedData() */ +/* + * The BER streaming encoder encrypts the content one 4096-byte octet chunk at a + * time into a working buffer, and the final chunk additionally carries the + * block cipher pad. Content that is an exact multiple of the chunk length makes + * that last chunk the largest one the buffer has to hold. Round-trip such sizes. + */ +int test_wc_PKCS7_stream_encode_chunk_boundary(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_AES) && \ + defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256) && \ + defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM) + /* multiples of the encoder's private BER_OCTET_LENGTH (4096) */ + static const word32 contentSizes[] = { 4096, 8192 }; + word32 i; + #if defined(USE_CERT_BUFFERS_2048) + byte cert[sizeof(client_cert_der_2048)]; + byte key[sizeof(client_key_der_2048)]; + word32 certSz = (word32)sizeof(cert); + word32 keySz = (word32)sizeof(key); + + XMEMCPY(cert, client_cert_der_2048, certSz); + XMEMCPY(key, client_key_der_2048, keySz); + #elif defined(USE_CERT_BUFFERS_1024) + byte cert[sizeof(client_cert_der_1024)]; + byte key[sizeof(client_key_der_1024)]; + word32 certSz = (word32)sizeof(cert); + word32 keySz = (word32)sizeof(key); + + XMEMCPY(cert, client_cert_der_1024, certSz); + XMEMCPY(key, client_key_der_1024, keySz); + #else + byte cert[ONEK_BUF]; + byte key[ONEK_BUF]; + word32 certSz = 0; + word32 keySz = 0; + XFILE fp = XBADFILE; + + ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != + XBADFILE); + ExpectIntGT(certSz = (word32)XFREAD(cert, 1, sizeof(cert), fp), 0); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } + ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != + XBADFILE); + ExpectIntGT(keySz = (word32)XFREAD(key, 1, sizeof(key), fp), 0); + if (fp != XBADFILE) + XFCLOSE(fp); + #endif + + for (i = 0; i < (word32)XELEM_CNT(contentSizes); i++) { + PKCS7* pkcs7 = NULL; + byte* content = NULL; + byte* ber = NULL; + byte* plain = NULL; + word32 contentSz = contentSizes[i]; + word32 berBufSz = contentSz + FOURK_BUF; + int encSz = 0; + word32 j; + + ExpectNotNull(content = (byte*)XMALLOC(contentSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(ber = (byte*)XMALLOC(berBufSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(plain = (byte*)XMALLOC(contentSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (content != NULL) { + for (j = 0; j < contentSz; j++) + content[j] = (byte)j; + } + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); + if (pkcs7 != NULL) { + pkcs7->content = content; + pkcs7->contentSz = contentSz; + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES256CBCb; + pkcs7->privateKey = key; + pkcs7->privateKeySz = keySz; + } + ExpectIntEQ(wc_PKCS7_SetStreamMode(pkcs7, 1, NULL, NULL, NULL), 0); + ExpectIntGT((encSz = wc_PKCS7_EncodeEnvelopedData(pkcs7, ber, + berBufSz)), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + /* 8192 is encode-only: a final segment above BER_OCTET_LENGTH does + * not decode, which is a separate pre-existing decoder limit */ + if (encSz > 0 && contentSz == 4096) { + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); + if (pkcs7 != NULL) { + pkcs7->privateKey = key; + pkcs7->privateKeySz = keySz; + } + ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, ber, (word32)encSz, + plain, contentSz), (int)contentSz); + ExpectIntEQ(XMEMCMP(plain, content, contentSz), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + } + + XFREE(content, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(ber, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_stream_encode_chunk_boundary() */ + #if defined(HAVE_PKCS7) && defined(HAVE_ECC) && defined(HAVE_X963_KDF) && \ !defined(NO_SHA256) && defined(WOLFSSL_AES_256) && defined(HAVE_AES_CBC) diff --git a/tests/api/test_pkcs7.h b/tests/api/test_pkcs7.h index b1958d84d0c..e4794d616aa 100644 --- a/tests/api/test_pkcs7.h +++ b/tests/api/test_pkcs7.h @@ -61,6 +61,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void); int test_wc_PKCS7_IndefiniteRecipientSet(void); int test_wc_PKCS7_SetAESKeyWrapUnwrapCb(void); int test_wc_PKCS7_MultipleRecipients(void); +int test_wc_PKCS7_stream_encode_chunk_boundary(void); int test_wc_PKCS7_GetEnvelopedDataKariRid(void); int test_wc_PKCS7_EncodeEncryptedData(void); int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void); @@ -168,6 +169,8 @@ int test_wc_PKCS7_VerifySignedData_NoDigestParams(void); TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeDecodeEnvelopedData), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_IndefiniteRecipientSet), \ + TEST_DECL_GROUP("pkcs7_ed", \ + test_wc_PKCS7_stream_encode_chunk_boundary), \ TEST_PKCS7_RSA_PSS_ED_DECL \ TEST_PKCS7_KTRI_BADRSAPAD_DECL \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \ diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index a174d777cda..971c700070a 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1485,7 +1485,10 @@ static WARN_UNUSED_RESULT int Hash_gen(DRBG_internal* drbg, byte* out, XMEMCPY(data, V, DRBG_SEED_LEN); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("Hash_gen data", data, DRBG_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE + /* cached digest is the caller's drbg->digest_scratch, already registered */ wc_MemZero_Add("Hash_gen digest", digest, WC_SHA256_DIGEST_SIZE); +#endif #endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -1530,8 +1533,10 @@ static WARN_UNUSED_RESULT int Hash_gen(DRBG_internal* drbg, byte* out, #if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(data, DRBG_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE wc_MemZero_Check(digest, WC_SHA256_DIGEST_SIZE); #endif +#endif #ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); @@ -2155,7 +2160,9 @@ static WARN_UNUSED_RESULT int Hash512_gen(DRBG_SHA512_internal* drbg, XMEMCPY(data, V, DRBG_SHA512_SEED_LEN); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("Hash512_gen data", data, DRBG_SHA512_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE wc_MemZero_Add("Hash512_gen digest", digest, WC_SHA512_DIGEST_SIZE); +#endif #endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -2199,8 +2206,10 @@ static WARN_UNUSED_RESULT int Hash512_gen(DRBG_SHA512_internal* drbg, #if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(data, DRBG_SHA512_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE wc_MemZero_Check(digest, WC_SHA512_DIGEST_SIZE); #endif +#endif #ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 2ba9e14edf5..01e257ad6ba 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -79580,26 +79580,26 @@ static wc_test_ret_t pkcs7_authenv_attribs_boundary_test(byte* rsaCert, int envSz; byte content[] = "authenv attribs boundary test"; - /* eight distinct, well-formed attribute TLVs (OID + PrintableString) */ - static const byte oid0[] = { 0x06,0x03, 0x55,0x04,0x03 }; - static const byte oid1[] = { 0x06,0x03, 0x55,0x04,0x04 }; - static const byte oid2[] = { 0x06,0x03, 0x55,0x04,0x05 }; - static const byte oid3[] = { 0x06,0x03, 0x55,0x04,0x06 }; - static const byte oid4[] = { 0x06,0x03, 0x55,0x04,0x07 }; - static const byte oid5[] = { 0x06,0x03, 0x55,0x04,0x08 }; - static const byte oid6[] = { 0x06,0x03, 0x55,0x04,0x09 }; - static const byte oid7[] = { 0x06,0x03, 0x55,0x04,0x0a }; - static const byte val[] = { 0x13,0x01, 0x30 }; - PKCS7Attrib attribs[8] = { - { oid0, sizeof(oid0), val, sizeof(val) }, - { oid1, sizeof(oid1), val, sizeof(val) }, - { oid2, sizeof(oid2), val, sizeof(val) }, - { oid3, sizeof(oid3), val, sizeof(val) }, - { oid4, sizeof(oid4), val, sizeof(val) }, - { oid5, sizeof(oid5), val, sizeof(val) }, - { oid6, sizeof(oid6), val, sizeof(val) }, - { oid7, sizeof(oid7), val, sizeof(val) } - }; + /* one past either capacity, so the over-capacity cases stay in bounds */ +#if MAX_AUTH_ATTRIBS_SZ > MAX_UNAUTH_ATTRIBS_SZ + #define PKCS7_AE_ATTRIB_CNT (MAX_AUTH_ATTRIBS_SZ + 1) +#else + #define PKCS7_AE_ATTRIB_CNT (MAX_UNAUTH_ATTRIBS_SZ + 1) +#endif + static const byte val[] = { 0x13,0x01, 0x30 }; + byte oids[PKCS7_AE_ATTRIB_CNT][5]; + PKCS7Attrib attribs[PKCS7_AE_ATTRIB_CNT]; + word32 i; + + for (i = 0; i < (word32)PKCS7_AE_ATTRIB_CNT; i++) { + oids[i][0] = 0x06; oids[i][1] = 0x03; + oids[i][2] = 0x55; oids[i][3] = 0x04; + oids[i][4] = (byte)(0x03 + i); + attribs[i].oid = oids[i]; + attribs[i].oidSz = (word32)sizeof(oids[i]); + attribs[i].value = val; + attribs[i].valueSz = (word32)sizeof(val); + } enveloped = (byte*)XMALLOC(PKCS7_BUF_SIZE, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (enveloped == NULL) @@ -79647,8 +79647,8 @@ static wc_test_ret_t pkcs7_authenv_attribs_boundary_test(byte* rsaCert, envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); wc_PKCS7_Free(pkcs7); pkcs7 = NULL; - if (envSz >= 0) - ERROR_OUT(WC_TEST_RET_ENC_NC, out); + if (envSz != WC_NO_ERR_TRACE(BUFFER_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); /* one more unauthenticated attribute than fits: must fail, not overrun */ pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); @@ -79668,8 +79668,29 @@ static wc_test_ret_t pkcs7_authenv_attribs_boundary_test(byte* rsaCert, envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); wc_PKCS7_Free(pkcs7); pkcs7 = NULL; - if (envSz >= 0) - ERROR_OUT(WC_TEST_RET_ENC_NC, out); + if (envSz != WC_NO_ERR_TRACE(BUFFER_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); + + /* non-DATA contentOID adds a contentType attrib, leaving one slot fewer */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = FIRMWARE_PKG_DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->authAttribs = attribs; + pkcs7->authAttribsSz = MAX_AUTH_ATTRIBS_SZ; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz != WC_NO_ERR_TRACE(BUFFER_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); ret = 0; From 2f4ad074ee4dcfd0f8460c28b9571822828f2352 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 21 Aug 2026 17:34:27 -0700 Subject: [PATCH 14/17] Fix wc_PKCS7_EncodeContentStream for sizes above BER_OCTET_LENGTH --- tests/api/test_pkcs7.c | 6 +++--- wolfcrypt/src/pkcs7.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 3f9cca090c0..9686660b1f8 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -5564,9 +5564,9 @@ int test_wc_PKCS7_stream_encode_chunk_boundary(void) wc_PKCS7_Free(pkcs7); pkcs7 = NULL; - /* 8192 is encode-only: a final segment above BER_OCTET_LENGTH does - * not decode, which is a separate pre-existing decoder limit */ - if (encSz > 0 && contentSz == 4096) { + /* decode back: a mis-sized or mis-split chunk shows up as corrupt + * plaintext or a parse failure */ + if (encSz > 0) { ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); if (pkcs7 != NULL) { diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 017f8416258..b87b2433236 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -3528,8 +3528,22 @@ static int wc_PKCS7_EncodeContentStream(wc_PKCS7* pkcs7, ESD* esd, void* aes, idx += (word32)padSz; } + /* The pad can push the tail past a full chunk. StreamOctetString(), + * which sized the output, never emits more than BER_OCTET_LENGTH per + * octet string, so split here to match it. */ + if (ret == 0 && idx > BER_OCTET_LENGTH) { + ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType, aes, + encContentOut, contentData, BER_OCTET_LENGTH, out, + &outIdx, esd); + if (ret == 0) { + idx -= BER_OCTET_LENGTH; + XMEMMOVE(contentData, contentData + BER_OCTET_LENGTH, idx); + } + } + /* encrypt and flush out remainder of content data */ - ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType, aes, + if (ret == 0) + ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType, aes, encContentOut, contentData, (int)idx, out, &outIdx, esd); if (ret == 0) { if (cipherType == WC_CIPHER_NONE && esd && From 2c0f460f8f7587517891b7af5023d01e5bf61b54 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 28 Aug 2026 12:23:04 -0700 Subject: [PATCH 15/17] Fix undersized buffers and incorrect read lengths for the file read case in unit tests. --- tests/api/test_ossl_p7p12.c | 9 +++---- tests/api/test_pkcs7.c | 54 ++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/tests/api/test_ossl_p7p12.c b/tests/api/test_ossl_p7p12.c index 58cfa90d9d0..4cc99c3bb31 100644 --- a/tests/api/test_ossl_p7p12.c +++ b/tests/api/test_ossl_p7p12.c @@ -1045,7 +1045,8 @@ int test_wolfSSL_PEM_write_bio_PKCS7(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; @@ -1053,8 +1054,7 @@ int test_wolfSSL_PEM_write_bio_PKCS7(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -1062,8 +1062,7 @@ int test_wolfSSL_PEM_write_bio_PKCS7(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 9686660b1f8..6d1015219b4 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -127,14 +127,14 @@ int test_wc_PKCS7_InitWithCert(void) XMEMSET(cert, 0, certSz); XMEMCPY(cert, client_cert_der_1024, sizeof_client_cert_der_1024); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; XFILE fp = XBADFILE; int certSz; ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -288,15 +288,15 @@ int test_wc_PKCS7_InitWithCert_guardrails(void) XMEMSET(cert, 0, sizeof(cert)); XMEMCPY(cert, client_cert_der_1024, sizeof_client_cert_der_1024); #else - byte cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + byte cert[TWOK_BUF]; XFILE fp = XBADFILE; int tmpCertSz; word32 certSz = 0; ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(tmpCertSz = (int)XFREAD(cert, 1, - sizeof_client_cert_der_1024, fp), 0); + ExpectIntGT(tmpCertSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); certSz = (word32)tmpCertSz; if (fp != XBADFILE) XFCLOSE(fp); @@ -368,7 +368,8 @@ int test_wc_PKCS7_EncodeData(void) XMEMCPY(cert, client_cert_der_1024, certSz); XMEMCPY(key, client_key_der_1024, keySz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; @@ -376,8 +377,7 @@ int test_wc_PKCS7_EncodeData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -385,8 +385,7 @@ int test_wc_PKCS7_EncodeData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -511,7 +510,8 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz, #else { XFILE fp; - byte keyBuf[ONEK_BUF]; + /* key file is larger than ONEK_BUF */ + byte keyBuf[TWOK_BUF]; int keySz; fp = XFOPEN("./certs/client-key.der", "rb"); @@ -713,7 +713,7 @@ int test_wc_PKCS7_EncodeSignedData(void) XMEMCPY(cert, client_cert_der_2048, certSz); #elif defined(USE_CERT_BUFFERS_1024) byte key[sizeof_client_key_der_1024]; - byte cert[sizeof(sizeof_client_cert_der_1024)]; + byte cert[sizeof_client_cert_der_1024]; word32 keySz = (word32)sizeof(key); word32 certSz = (word32)sizeof(cert); XMEMSET(key, 0, keySz); @@ -721,7 +721,8 @@ int test_wc_PKCS7_EncodeSignedData(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; @@ -729,8 +730,7 @@ int test_wc_PKCS7_EncodeSignedData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -738,8 +738,7 @@ int test_wc_PKCS7_EncodeSignedData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -1078,7 +1077,8 @@ int test_wc_PKCS7_EncodeSignedData_SKID(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - byte cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + byte cert[TWOK_BUF]; byte key[ONEK_BUF]; word32 certSz = 0; word32 keySz = 0; @@ -1813,7 +1813,7 @@ int test_wc_PKCS7_EncodeSignedData_ex(void) XMEMCPY(cert, client_cert_der_2048, certSz); #elif defined(USE_CERT_BUFFERS_1024) byte key[sizeof_client_key_der_1024]; - byte cert[sizeof(sizeof_client_cert_der_1024)]; + byte cert[sizeof_client_cert_der_1024]; word32 keySz = (word32)sizeof(key); word32 certSz = (word32)sizeof(cert); XMEMSET(key, 0, keySz); @@ -1821,16 +1821,16 @@ int test_wc_PKCS7_EncodeSignedData_ex(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; int keySz; - ExpectTure((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != + ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -1838,8 +1838,7 @@ int test_wc_PKCS7_EncodeSignedData_ex(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -5507,7 +5506,8 @@ int test_wc_PKCS7_stream_encode_chunk_boundary(void) XMEMCPY(cert, client_cert_der_1024, certSz); XMEMCPY(key, client_key_der_1024, keySz); #else - byte cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + byte cert[TWOK_BUF]; byte key[ONEK_BUF]; word32 certSz = 0; word32 keySz = 0; From 3bfdf354bc0c7e7e7c879653a773002d78d0c83f Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 2 Oct 2026 14:29:54 -0700 Subject: [PATCH 16/17] Avoid suppressing errors from wc_rng_bank_checkin in wc_rng_bank_reseed_range. (F-7414) --- wolfcrypt/src/rng_bank.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index 32fa40464a8..f8346d74e17 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -2540,11 +2540,8 @@ WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, "for DRBG #%d returned %d.", n, ret); #endif (void)wc_rng_bank_checkin(bank, &drbg); - if ((ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E)) || - (ret == WC_NO_ERR_TRACE(INTERRUPTED_E))) - { + if (ret != 0) goto out; - } ret = WC_CHECK_FOR_INTR_SIGNALS(); if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) goto out; From 592c478e01fed7143a6b9a8e9a121517f6ffbdcc Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 2 Oct 2026 16:11:44 -0700 Subject: [PATCH 17/17] Code review feedback: Preserve error return code and continue running rather than exiting early in wc_rng_bank_reseed_range. --- wolfcrypt/src/rng_bank.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index f8346d74e17..532cb15e3a1 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -2330,6 +2330,7 @@ WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, { int n; int ret; + int first_ret = 0; time_t ts1 = 0; #ifdef WC_RNG_BANK_DEFAULT_SUPPORT int bank_is_default = 0; @@ -2540,9 +2541,19 @@ WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, "for DRBG #%d returned %d.", n, ret); #endif (void)wc_rng_bank_checkin(bank, &drbg); - if (ret != 0) + if ((ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E)) || + (ret == WC_NO_ERR_TRACE(INTERRUPTED_E))) + { goto out; + } + /* reseed the rest of the bank, keeping the first error seen for + * the return value */ + if ((ret != 0) && (first_ret == 0)) + first_ret = ret; + ret = WC_CHECK_FOR_INTR_SIGNALS(); + if ((ret != 0) && (first_ret == 0)) + first_ret = ret; if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) goto out; WC_RELAX_LONG_LOOP(); @@ -2560,6 +2571,9 @@ WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, out: + if (first_ret != 0) + ret = first_ret; + #ifdef WC_RNG_BANK_DEFAULT_SUPPORT if (bank_is_default) (void)wc_rng_bank_default_checkin(&bank);