From cd3e81a656f2fd07ad2fa6d475a2cdf726e7bfa4 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:56:55 -0600 Subject: [PATCH 01/18] src/ssl_load.c: in ProcessBufferCert(), check ctx for nullness before accessing ctx->verifyNone (fixes -Wnull-dereference reported by multi-test dtls-no-rsa-no-dh after merge of 36e66eb763). --- src/ssl_load.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssl_load.c b/src/ssl_load.c index 5b995f013..34f328d13 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -2064,7 +2064,7 @@ static int ProcessBufferCert(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der) } /* Don't check if no SSL object verification is disabled for SSL * context. */ - else if ((ssl == NULL) && ctx->verifyNone) { + else if ((ssl == NULL) && (ctx != NULL) && ctx->verifyNone) { checkKeySz = 0; } From 2802e2d82b2c950357180f1b5221410a08541603 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:57:18 -0600 Subject: [PATCH 02/18] =?UTF-8?q?wolfcrypt/src/rsa.c:=20in=20RsaUnPad=5FOA?= =?UTF-8?q?EP(),=20refactor=20volatile-based=20constant=20time=20mitigatio?= =?UTF-8?q?n=20to=20fix=20"using=20value=20of=20assignment=20with=20?= =?UTF-8?q?=E2=80=98volatile=E2=80=99-qualified=20left=20operand=20is=20de?= =?UTF-8?q?precated=20[-Werror=3Dvolatile]"=20(new=20warning=20from=20gcc-?= =?UTF-8?q?16.0.0=5Fp20251207,=20not=20reported=20by=20gcc-16.0.0=5Fp20251?= =?UTF-8?q?116-r1).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wolfcrypt/src/rsa.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 5e7a98ccd..02ed7eeee 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -1538,7 +1538,7 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, byte* optLabel, word32 labelLen, void* heap) { word32 hLen; - volatile int ret; + int ret; byte h[WC_MAX_DIGEST_SIZE]; /* max digest size */ word32 idx; word32 i; @@ -1573,8 +1573,9 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, #endif /* find seedMask value */ - if ((ret = RsaMGF(mgf, (byte*)(pkcsBlock + (hLen + 1)), - pkcsBlockLen - hLen - 1, tmp, hLen, heap)) != 0) { + ret = RsaMGF(mgf, (byte*)(pkcsBlock + (hLen + 1)), + pkcsBlockLen - hLen - 1, tmp, hLen, heap); + if (ret != 0) { WC_FREE_VAR_EX(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); return ret; } @@ -1583,8 +1584,8 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, xorbuf(tmp, pkcsBlock + 1, hLen); /* get dbMask value */ - if ((ret = RsaMGF(mgf, tmp, hLen, tmp + hLen, - pkcsBlockLen - hLen - 1, heap)) != 0) { + ret = RsaMGF(mgf, tmp, hLen, tmp + hLen, pkcsBlockLen - hLen - 1, heap); + if (ret != 0) { ForceZero(tmp, hLen); #ifdef WOLFSSL_SMALL_STACK XFREE(tmp, NULL, DYNAMIC_TYPE_RSA_BUFFER); @@ -1616,7 +1617,8 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, } /* create hash of label for comparison with hash sent */ - if ((ret = wc_Hash(hType, optLabel, labelLen, h, hLen)) != 0) { + ret = wc_Hash(hType, optLabel, labelLen, h, hLen); + if (ret != 0) { return ret; } @@ -1626,13 +1628,14 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, Attackers should not be able to get error condition from the timing of these checks. */ - ret = 0; - ret |= ConstantCompare(pkcsBlock + hLen + 1, h, (int)hLen); - ret += pkcsBlock[idx++] ^ 0x01; /* separator value is 0x01 */ - ret += pkcsBlock[0] ^ 0x00; /* Y, the first value, should be 0 */ + { + volatile int c = ConstantCompare(pkcsBlock + hLen + 1, h, (int)hLen); + c = c + (pkcsBlock[idx++] ^ 0x01); /* separator value is 0x01 */ + c = c + (pkcsBlock[0] ^ 0x00); /* Y, the first value, should be 0 */ - /* Return 0 data length on error. */ - idx = ctMaskSelWord32(ctMaskEq(ret, 0), idx, pkcsBlockLen); + /* Return 0 data length on error. */ + idx = ctMaskSelWord32(ctMaskEq(c, 0), idx, pkcsBlockLen); + } /* adjust pointer to correct location in array and return size of M */ *output = (byte*)(pkcsBlock + idx); From 918b6973bd78f7e4776df344309c5dd0e7309b84 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:57:28 -0600 Subject: [PATCH 03/18] tests/api.c: in test_wolfSSL_dtls_stateless_HashWOLFSSL(), when WOLFSSL_SMALL_STACK_CACHE, omit ssl->hsHashes from the comparison (init-time heap pointers destabilize its bit signature). --- tests/api.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/api.c b/tests/api.c index 631675c24..e4bb7d560 100644 --- a/tests/api.c +++ b/tests/api.c @@ -32566,8 +32566,10 @@ static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl) wc_HashAlg hash; const TLSX* exts = ssl->extensions; WOLFSSL sslCopy; /* Use a copy to omit certain fields */ +#ifndef WOLFSSL_SMALL_STACK_CACHE HS_Hashes* hsHashes = ssl->hsHashes; /* Is re-allocated in * InitHandshakeHashes */ +#endif XMEMCPY(&sslCopy, ssl, sizeof(*ssl)); XMEMSET(hashBuf, 0, sizeof(hashBuf)); @@ -32614,9 +32616,17 @@ static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl) AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)sslCopy.suites, sizeof(struct Suites)), 0); } + +#ifdef WOLFSSL_SMALL_STACK_CACHE + /* with WOLFSSL_SMALL_STACK_CACHE, the SHA-2 objects always differ after + * initialization because of cached W and (for SHA512) X buffers. + */ +#else /* Hash hsHashes */ AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)hsHashes, sizeof(*hsHashes)), 0); +#endif + AssertIntEQ(wc_HashFinal(&hash, hashType, hashBuf), 0); AssertIntEQ(wc_HashFree(&hash, hashType), 0); From dc0fe803a5a05d35761afa8f6c0c35677a90b912 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:57:46 -0600 Subject: [PATCH 04/18] src/internal.c: in InitHandshakeHashesAndCopy(), don't call InitHandshakeHashes(), to avoid leaking in the later wc_FooCopy() operation. --- src/internal.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/internal.c b/src/internal.c index 0517f1b4c..272d3ec37 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7344,36 +7344,37 @@ int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source, HS_Hashes** destination) { int ret; - HS_Hashes* tmpHashes; if (source == NULL) return BAD_FUNC_ARG; - /* save the original so we can put it back afterward */ - tmpHashes = ssl->hsHashes; - ssl->hsHashes = *destination; + /* Note we can't call InitHandshakeHashes() here, because the copy methods + * overwrite the entire dest low level hash struct. With some hashes and + * settings (e.g. SHA-2 hashes with WOLFSSL_SMALL_STACK_CACHE), internal + * scratch buffers are preallocated at init and will leak if overwritten. + */ - ret = InitHandshakeHashes(ssl); - if (ret != 0) { - WOLFSSL_MSG_EX("InitHandshakeHashes failed. err = %d", ret); - ssl->hsHashes = tmpHashes; /* restore hsHashes pointer to original - * before returning */ - return ret; + /* allocate handshake hashes */ + *destination = (HS_Hashes*)XMALLOC(sizeof(HS_Hashes), ssl->heap, + DYNAMIC_TYPE_HASHES); + if (*destination == NULL) { + WOLFSSL_MSG("HS_Hashes Memory error"); + return MEMORY_E; } - - *destination = ssl->hsHashes; - ssl->hsHashes = tmpHashes; + XMEMSET(*destination, 0, sizeof(HS_Hashes)); /* now copy the source contents to the destination */ + ret = 0; #ifndef NO_OLD_TLS #ifndef NO_SHA - ret = wc_ShaCopy(&source->hashSha, &(*destination)->hashSha); + if (ret == 0) + ret = wc_ShaCopy(&source->hashSha, &(*destination)->hashSha); #endif #ifndef NO_MD5 if (ret == 0) ret = wc_Md5Copy(&source->hashMd5, &(*destination)->hashMd5); #endif - #endif /* !NO_OLD_TLS */ +#endif /* !NO_OLD_TLS */ #ifndef NO_SHA256 if (ret == 0) ret = wc_Sha256Copy(&source->hashSha256, From 15fcf7095fa108cd53f7ab36c2822c69bb63d4e7 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:58:08 -0600 Subject: [PATCH 05/18] linuxkm/lkcapi_{dh,ecdh,ecdsa,rsa,aes}_glue.c: when LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG, don't "#error Config conflict" if explicit LINUXKM_LKCAPI_DONT_REGISTER_foo is defined for the missing algorithm. --- linuxkm/lkcapi_aes_glue.c | 17 +++++++++++------ linuxkm/lkcapi_dh_glue.c | 8 ++++++-- linuxkm/lkcapi_ecdh_glue.c | 4 +++- linuxkm/lkcapi_ecdsa_glue.c | 4 +++- linuxkm/lkcapi_rsa_glue.c | 5 +++-- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/linuxkm/lkcapi_aes_glue.c b/linuxkm/lkcapi_aes_glue.c index 7cf99b07b..44e107cdc 100644 --- a/linuxkm/lkcapi_aes_glue.c +++ b/linuxkm/lkcapi_aes_glue.c @@ -121,7 +121,8 @@ #define LINUXKM_LKCAPI_REGISTER_AESCBC #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_CBC) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_CBC) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESCBC) #error Config conflict: target kernel has CONFIG_CRYPTO_CBC, but module is missing HAVE_AES_CBC. #endif #undef LINUXKM_LKCAPI_REGISTER_AESCBC @@ -151,7 +152,8 @@ #define LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_GCM) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_GCM) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESGCM) #error Config conflict: target kernel has CONFIG_CRYPTO_GCM, but module is missing HAVE_AESGCM. #endif #undef LINUXKM_LKCAPI_REGISTER_AESGCM @@ -166,8 +168,9 @@ #define LINUXKM_LKCAPI_REGISTER_AESXTS #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_XTS) - #error Config conflict: target kernel has CONFIG_CRYPTO_GCM, but module is missing WOLFSSL_AES_XTS. + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_XTS) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESXTS) + #error Config conflict: target kernel has CONFIG_CRYPTO_XTS, but module is missing WOLFSSL_AES_XTS. #endif #undef LINUXKM_LKCAPI_REGISTER_AESXTS #endif @@ -180,7 +183,8 @@ #define LINUXKM_LKCAPI_REGISTER_AESCTR #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_CTR) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_CTR) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESCTR) #error Config conflict: target kernel has CONFIG_CRYPTO_CTR, but module is missing WOLFSSL_AES_COUNTER. #endif #undef LINUXKM_LKCAPI_REGISTER_AESCTR @@ -204,7 +208,8 @@ #define LINUXKM_LKCAPI_REGISTER_AESECB #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECB) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECB) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESECB) #error Config conflict: target kernel has CONFIG_CRYPTO_ECB, but module is missing HAVE_AES_ECB. #endif #undef LINUXKM_LKCAPI_REGISTER_AESECB diff --git a/linuxkm/lkcapi_dh_glue.c b/linuxkm/lkcapi_dh_glue.c index 8b3ff0ce5..10cd9cf5e 100644 --- a/linuxkm/lkcapi_dh_glue.c +++ b/linuxkm/lkcapi_dh_glue.c @@ -58,7 +58,10 @@ #undef LINUXKM_LKCAPI_REGISTER_DH #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) && \ + !(defined(RHEL_MAJOR) && \ + ((RHEL_MAJOR > 9) || ((RHEL_MAJOR == 9) && (RHEL_MINOR >= 5)))) + /* Support for FFDHE was added in kernel 5.18, and generic DH support * pre-5.18 used a different binary format for the secret (an additional * slot for q). @@ -73,7 +76,8 @@ #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && \ (defined(CONFIG_CRYPTO_DH) || defined(CONFIG_CRYPTO_DH_RFC7919_GROUPS)) && \ - !defined(LINUXKM_LKCAPI_REGISTER_DH) + !defined(LINUXKM_LKCAPI_REGISTER_DH) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_DH) #error Config conflict: target kernel has CONFIG_CRYPTO_DH and/or \ _DH_RFC7919_GROUPS, but module is missing LINUXKM_LKCAPI_REGISTER_DH. #endif diff --git a/linuxkm/lkcapi_ecdh_glue.c b/linuxkm/lkcapi_ecdh_glue.c index 86231183d..e4a5d717b 100644 --- a/linuxkm/lkcapi_ecdh_glue.c +++ b/linuxkm/lkcapi_ecdh_glue.c @@ -43,7 +43,8 @@ /* currently incompatible with kernel 5.12 or earlier. */ #undef LINUXKM_LKCAPI_REGISTER_ECDH - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDH) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDH) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ECDH) #error Config conflict: missing implementation forces off LINUXKM_LKCAPI_REGISTER_ECDH. #endif #endif @@ -51,6 +52,7 @@ #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && \ defined(CONFIG_CRYPTO_ECDH) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ECDH) && \ !defined(LINUXKM_LKCAPI_REGISTER_ECDH) #error Config conflict: target kernel has CONFIG_CRYPTO_ECDH, but module is missing LINUXKM_LKCAPI_REGISTER_ECDH. #endif diff --git a/linuxkm/lkcapi_ecdsa_glue.c b/linuxkm/lkcapi_ecdsa_glue.c index 92d38dfd2..63d2ec9d9 100644 --- a/linuxkm/lkcapi_ecdsa_glue.c +++ b/linuxkm/lkcapi_ecdsa_glue.c @@ -64,13 +64,15 @@ #undef LINUXKM_LKCAPI_REGISTER_ECDSA #endif /* LINUXKM_LKCAPI_REGISTER_ECDSA */ - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDSA) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDSA) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ECDSA) #error Config conflict: missing implementation forces off LINUXKM_LKCAPI_REGISTER_ECDSA. #endif #endif #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && \ defined(CONFIG_CRYPTO_ECDSA) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ECDSA) && \ !defined(LINUXKM_LKCAPI_REGISTER_ECDSA) #error Config conflict: target kernel has CONFIG_CRYPTO_ECDSA, but module is missing LINUXKM_LKCAPI_REGISTER_ECDSA. #endif diff --git a/linuxkm/lkcapi_rsa_glue.c b/linuxkm/lkcapi_rsa_glue.c index 0902af41f..97862409a 100644 --- a/linuxkm/lkcapi_rsa_glue.c +++ b/linuxkm/lkcapi_rsa_glue.c @@ -63,7 +63,8 @@ #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && \ defined(CONFIG_CRYPTO_RSA) && \ - !defined(LINUXKM_LKCAPI_REGISTER_RSA) + !defined(LINUXKM_LKCAPI_REGISTER_RSA) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_RSA) #error Config conflict: target kernel has CONFIG_CRYPTO_RSA, but module is missing LINUXKM_LKCAPI_REGISTER_RSA. #endif @@ -71,7 +72,7 @@ #if defined(WOLFSSL_RSA_VERIFY_ONLY) || \ defined(WOLFSSL_RSA_PUBLIC_ONLY) - #error LINUXKM_LKCAPI_REGISTER_RSA and RSA_VERIFY_ONLY not supported + #error LINUXKM_LKCAPI_REGISTER_RSA with RSA_VERIFY_ONLY/WOLFSSL_RSA_PUBLIC_ONLY not supported #endif /* WOLFSSL_RSA_VERIFY_ONLY || WOLFSSL_RSA_PUBLIC_ONLY */ #ifdef WC_RSA_NO_PADDING From 8e03d0523c72d5a30bf6e778cb7006b298460f0b Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:58:36 -0600 Subject: [PATCH 06/18] wolfssl/test.h: add missing wc_HmacFree()s in myMacEncryptCb(), myDecryptVerifyCb(), myEncryptMacCb(), myVerifyDecryptCb(). --- wolfssl/test.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wolfssl/test.h b/wolfssl/test.h index f67b02919..56dd88aa8 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -2830,7 +2830,7 @@ static WC_INLINE int myMacEncryptCb(WOLFSSL* ssl, unsigned char* macOut, ret = wc_HmacFinal(&hmac, macOut); if (ret != 0) return ret; - + wc_HmacFree(&hmac); /* encrypt setup on first time */ if (encCtx->keySetup == 0) { @@ -2959,6 +2959,7 @@ static WC_INLINE int myDecryptVerifyCb(WOLFSSL* ssl, ret = wc_HmacFinal(&hmac, verify); if (ret != 0) return ret; + wc_HmacFree(&hmac); if (XMEMCMP(verify, decOut + decSz - digestSz - pad - padByte, (size_t) digestSz) != 0) { @@ -3041,7 +3042,9 @@ static WC_INLINE int myEncryptMacCb(WOLFSSL* ssl, unsigned char* macOut, ret = wc_HmacUpdate(&hmac, encOut, encSz); if (ret != 0) return ret; - return wc_HmacFinal(&hmac, macOut); + ret = wc_HmacFinal(&hmac, macOut); + wc_HmacFree(&hmac); + return ret; } @@ -3088,6 +3091,7 @@ static WC_INLINE int myVerifyDecryptCb(WOLFSSL* ssl, ret = wc_HmacFinal(&hmac, verify); if (ret != 0) return ret; + wc_HmacFree(&hmac); if (XMEMCMP(verify, decOut + decSz, (size_t) digestSz) != 0) { printf("myDecryptVerify verify failed\n"); From 8090817c110f0fb0ddacb6337674bad556c897a4 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:58:56 -0600 Subject: [PATCH 07/18] configure.ac: when KERNEL_MODE_DEFAULTS, set ENABLED_SMALL_STACK_CACHE_DEFAULT=yes regardless of FIPS/version. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index afef3fc59..be23c49ae 100644 --- a/configure.ac +++ b/configure.ac @@ -7512,7 +7512,7 @@ then fi # Small Stack - Cache on object -if test "$KERNEL_MODE_DEFAULTS" = "yes" && (test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -ge 6) +if test "$KERNEL_MODE_DEFAULTS" = "yes" then ENABLED_SMALL_STACK_CACHE_DEFAULT=yes else From 50b51adc938348841dcf386c90aec09432869c1b Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:59:11 -0600 Subject: [PATCH 08/18] wolfcrypt/src/hmac.c and wolfssl/wolfcrypt/hmac.h: implement WOLFSSL_API wc_HmacCopy(), and remove the WOLFSSL_HMAC_COPY_HASH gate on HmacKeyCopyHash(). --- wolfcrypt/src/hmac.c | 17 +++++++++++++++-- wolfssl/wolfcrypt/hmac.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index e7e23387f..f50c235e1 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -248,7 +248,6 @@ int _InitHmac(Hmac* hmac, int type, void* heap) return ret; } -#ifdef WOLFSSL_HMAC_COPY_HASH static int HmacKeyCopyHash(byte macType, wc_HmacHash* src, wc_HmacHash* dst) { int ret = 0; @@ -323,7 +322,21 @@ static int HmacKeyCopyHash(byte macType, wc_HmacHash* src, wc_HmacHash* dst) return ret; } -#endif + +int wc_HmacCopy(Hmac* src, Hmac* dst) { + int ret; + + if ((src == NULL) || (dst == NULL)) + return BAD_FUNC_ARG; + + XMEMCPY(dst, src, sizeof(*dst)); + + ret = HmacKeyCopyHash(src->macType, &src->hash, &dst->hash); + + if (ret != 0) + XMEMSET(dst, 0, sizeof(*dst)); + return ret; +} static int HmacKeyHashUpdate(byte macType, wc_HmacHash* hash, byte* pad) { diff --git a/wolfssl/wolfcrypt/hmac.h b/wolfssl/wolfcrypt/hmac.h index 326ed4a52..92392dc41 100644 --- a/wolfssl/wolfcrypt/hmac.h +++ b/wolfssl/wolfcrypt/hmac.h @@ -190,6 +190,7 @@ WOLFSSL_API int wc_HmacInit_Id(Hmac* hmac, byte* id, int len, void* heap, WOLFSSL_API int wc_HmacInit_Label(Hmac* hmac, const char* label, void* heap, int devId); #endif +WOLFSSL_API int wc_HmacCopy(Hmac* src, Hmac* dst); WOLFSSL_API void wc_HmacFree(Hmac* hmac); WOLFSSL_API int wolfSSL_GetHmacMaxSize(void); From 38b675ef68ae57127285ef33cc66c68ed9fcdd50 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:59:28 -0600 Subject: [PATCH 09/18] linuxkm/lkcapi_sha_glue.c: * as for other glue families, when LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG, don't "#error Config conflict" if explicit LINUXKM_LKCAPI_DONT_REGISTER_foo is defined for the missing algorithm; * in km_hmac_init(), use wc_HmacCopy() to copy p_ctx->wc_hmac to t_ctx->wc_hmac; * in get_drbg(), when tfm == crypto_default_rng, only migrate_disable() and local_bh_disable() if preempt_count() == 0, i.e. if not in already in an uninterruptible context; * add can_spin argument to get_drbg_n() -- wc_linuxkm_drbg_seed() can_spin, wc_mix_pool_bytes() !can_spin, and wc_crng_reseed() can_spin; * add compile-time assert that WOLFSSL_SMALL_STACK_CACHE is defined if LINUXKM_DRBG_GET_RANDOM_BYTES; .wolfssl_known_macro_extras: add CONFIG_CRYPTO_DRBG. --- linuxkm/lkcapi_sha_glue.c | 80 +++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index ef14524a4..f11e61cc0 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -176,7 +176,8 @@ #define LINUXKM_LKCAPI_DONT_REGISTER_SHA3_512_HMAC #endif -#if defined(NO_HMAC) && defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_HMAC) +#if defined(NO_HMAC) && defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_HMAC) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_HMAC_ALL) #error Config conflict: target kernel has CONFIG_CRYPTO_HMAC, but module has NO_HMAC #endif @@ -196,7 +197,8 @@ #define LINUXKM_LKCAPI_REGISTER_SHA1_HMAC #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA1) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA1) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_SHA1) #error Config conflict: target kernel has CONFIG_CRYPTO_SHA1, but module has NO_SHA #endif @@ -220,7 +222,8 @@ #define LINUXKM_LKCAPI_REGISTER_SHA2_224_HMAC #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA256) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA256) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_SHA2_224) #error Config conflict: target kernel has CONFIG_CRYPTO_SHA256, but module is missing WOLFSSL_SHA224 #endif @@ -244,7 +247,8 @@ #define LINUXKM_LKCAPI_REGISTER_SHA2_256_HMAC #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA256) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA256) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_SHA2_256) #error Config conflict: target kernel has CONFIG_CRYPTO_SHA256, but module has NO_SHA256 #endif @@ -268,7 +272,8 @@ #define LINUXKM_LKCAPI_REGISTER_SHA2_384_HMAC #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA512) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA512) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_SHA2_384) #error Config conflict: target kernel has CONFIG_CRYPTO_SHA512, but module is missing WOLFSSL_SHA384 #endif @@ -292,7 +297,8 @@ #define LINUXKM_LKCAPI_REGISTER_SHA2_512_HMAC #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA512) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA512) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_SHA2_512) #error Config conflict: target kernel has CONFIG_CRYPTO_SHA512, but module is missing WOLFSSL_SHA512 #endif @@ -345,7 +351,8 @@ #endif #endif #else - #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA3) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_SHA3) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_SHA3) #error Config conflict: target kernel has CONFIG_CRYPTO_SHA3, but module is missing WOLFSSL_SHA3 #endif @@ -379,6 +386,10 @@ #endif /* setup for LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT is in linuxkm_wc_port.h */ #else + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_DRBG) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_HASH_DRBG) + #error Config conflict: target kernel has CONFIG_CRYPTO_SHA3, but module is missing WOLFSSL_SHA3 + #endif #undef LINUXKM_LKCAPI_REGISTER_HASH_DRBG #endif @@ -757,6 +768,7 @@ WC_MAYBE_UNUSED static void km_hmac_exit_tfm(struct crypto_shash *tfm) } WC_MAYBE_UNUSED static int km_hmac_init(struct shash_desc *desc) { + int ret; struct km_sha_hmac_state *t_ctx = (struct km_sha_hmac_state *)shash_desc_ctx(desc); struct km_sha_hmac_pstate *p_ctx = (struct km_sha_hmac_pstate *)crypto_shash_ctx(desc->tfm); @@ -764,34 +776,12 @@ WC_MAYBE_UNUSED static int km_hmac_init(struct shash_desc *desc) { if (! t_ctx->wc_hmac) return -ENOMEM; - XMEMCPY(t_ctx->wc_hmac, &p_ctx->wc_hmac, sizeof *t_ctx->wc_hmac); - -#ifdef WOLFSSL_SMALL_STACK_CACHE - /* The cached W buffer from the persistent ctx can't be used because it - * would be double-freed, first by km_hmac_free_tstate(), then by - * km_hmac_exit_tfm(). - */ - switch (t_ctx->wc_hmac->macType) { - - #ifndef NO_SHA256 - case WC_SHA256: - #ifdef WOLFSSL_SHA224 - case WC_SHA224: - #endif - t_ctx->wc_hmac->hash.sha256.W = NULL; - break; - #endif /* WOLFSSL_SHA256 */ - - #ifdef WOLFSSL_SHA512 - case WC_SHA512: - #ifdef WOLFSSL_SHA384 - case WC_SHA384: - #endif - t_ctx->wc_hmac->hash.sha512.W = NULL; - break; - #endif /* WOLFSSL_SHA512 */ + ret = wc_HmacCopy(&p_ctx->wc_hmac, t_ctx->wc_hmac); + if (ret != 0) { + free(t_ctx->wc_hmac); + t_ctx->wc_hmac = NULL; + return -EINVAL; } -#endif /* WOLFSSL_SMALL_STACK_CACHE */ return 0; } @@ -1073,7 +1063,7 @@ static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) { return NULL; } - if (tfm == crypto_default_rng) { + if ((tfm == crypto_default_rng) && (preempt_count() == 0)) { #if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) migrate_disable(); /* this actually makes irq_count() nonzero, so that * DISABLE_VECTOR_REGISTERS() is superfluous, but @@ -1108,14 +1098,14 @@ static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) { * caller can't sleep and the requested DRBG is busy, it returns immediately -- * this avoids priority inversions and deadlocks. */ -static inline struct wc_rng_inst *get_drbg_n(struct wc_linuxkm_drbg_ctx *ctx, int n) { +static inline struct wc_rng_inst *get_drbg_n(struct wc_linuxkm_drbg_ctx *ctx, int n, int can_spin) { int can_sleep = (preempt_count() == 0); for (;;) { int expected = 0; if (likely(__atomic_compare_exchange_n(&ctx->rngs[n].lock, &expected, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))) return &ctx->rngs[n]; - if (can_sleep) { + if (can_sleep && can_spin) { if (signal_pending(current)) return NULL; cond_resched(); @@ -1242,7 +1232,7 @@ static int wc_linuxkm_drbg_seed(struct crypto_rng *tfm, * up, to assure they can't possibly phase-lock to each other. */ for (n = ctx->n_rngs - 1; n >= 0; --n) { - struct wc_rng_inst *drbg = get_drbg_n(ctx, n); + struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 1); if (! drbg) { ret = -EINTR; @@ -1313,6 +1303,14 @@ static int wc_linuxkm_drbg_loaded = 0; #ifdef LINUXKM_DRBG_GET_RANDOM_BYTES +#ifndef WOLFSSL_SMALL_STACK_CACHE + /* WOLFSSL_SMALL_STACK_CACHE eliminates post-init heap allocations in SHA-2 + * and the Hash DRBG, fixing circular call dependencies between + * get_random_u32() from kernel heap and wolfCrypt DRBG. + */ + #error LINUXKM_DRBG_GET_RANDOM_BYTES requires WOLFSSL_SMALL_STACK_CACHE. +#endif + #if !(defined(HAVE_ENTROPY_MEMUSE) || defined(HAVE_INTEL_RDSEED) || \ defined(HAVE_AMD_RDSEED) || defined(WC_LINUXKM_RDSEED_IN_GLUE_LAYER)) #error LINUXKM_DRBG_GET_RANDOM_BYTES requires a native or intrinsic entropy source. @@ -1491,11 +1489,11 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) { return -EFAULT; for (n = ctx->n_rngs - 1; n >= 0; --n) { - struct wc_rng_inst *drbg = get_drbg_n(ctx, n); + struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 0); int V_offset; if (! drbg) - return -EINTR; + continue; for (i = 0, V_offset = 0; i < len; ++i) { ((struct DRBG_internal *)drbg->rng.drbg)->V[V_offset++] += ((byte *)buf)[i]; @@ -1523,7 +1521,7 @@ static int wc_crng_reseed(void) { return -EFAULT; for (n = ctx->n_rngs - 1; n >= 0; --n) { - struct wc_rng_inst *drbg = get_drbg_n(ctx, n); + struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 1); if (! drbg) return -EINTR; From 1e38a1011e722e84e8b87b510ef36d5c7098e645 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 16:59:42 -0600 Subject: [PATCH 10/18] wolfcrypt/src/wolfentropy.c: in wc_Entropy_Get(): * use a bss segment allocation for noise, to avoid a heap allocation (access is already mutex-protected), and * in the loop, WC_CHECK_FOR_INTR_SIGNALS() and WC_RELAX_LONG_LOOP(). --- wolfcrypt/src/wolfentropy.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/wolfcrypt/src/wolfentropy.c b/wolfcrypt/src/wolfentropy.c index 46eeeb3cf..9fe47109d 100644 --- a/wolfcrypt/src/wolfentropy.c +++ b/wolfcrypt/src/wolfentropy.c @@ -735,13 +735,10 @@ static wolfSSL_Mutex entropy_mutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(entropy_mute int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len) { int ret = 0; - WC_DECLARE_VAR(noise, byte, MAX_NOISE_CNT, 0); /* Noise length is the number of 8 byte samples required to get the bits of * entropy requested. */ int noise_len = (bits + ENTROPY_EXTRA) / ENTROPY_MIN; - - WC_ALLOC_VAR_EX(noise, byte, MAX_NOISE_CNT, NULL, DYNAMIC_TYPE_TMP_BUFFER, - return MEMORY_E); + static byte noise[MAX_NOISE_CNT]; /* Lock the mutex as collection uses globals. */ if ((ret == 0) && (wc_LockMutex(&entropy_mutex) != 0)) { @@ -790,6 +787,12 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len) entropy += entropy_len; len -= entropy_len; } + if (ret == 0) { + ret = WC_CHECK_FOR_INTR_SIGNALS(); + } + if (ret == 0) { + WC_RELAX_LONG_LOOP(); + } } #ifdef ENTROPY_MEMUSE_THREADED @@ -802,8 +805,6 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len) wc_UnLockMutex(&entropy_mutex); } - WC_FREE_VAR_EX(noise, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; } From 525266c467f2b547f6ce620c3ad4e02bde081c99 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 17:00:24 -0600 Subject: [PATCH 11/18] wolfssl/wolfcrypt/mem_track.h and wolfcrypt/src/memory.c: add WOLFSSL_API extern memoryStats *wc_MemStats_Ptr, set by InitMemoryTracker() and cleared by CleanupMemoryTracker(), allowing public access to the memory statistics. tests/unit.c: at end of unit_test(), when WOLFSSL_TRACK_MEMORY, explicitly wolfSSL_Cleanup() then check and error if wc_MemStats_Ptr->currentBytes > 0. --- tests/unit.c | 11 +++++++++++ wolfcrypt/src/memory.c | 5 +++++ wolfssl/wolfcrypt/mem_track.h | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/tests/unit.c b/tests/unit.c index 5ccb92ebf..72c51f4ec 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -324,6 +324,17 @@ exit: err_sys("Failed to free netRandom context"); #endif /* HAVE_WNR */ +#ifdef WOLFSSL_TRACK_MEMORY + if (ret == 0) { + (void)wolfSSL_Cleanup(); + if (wc_MemStats_Ptr->currentBytes > 0) + { + fprintf(stderr, "WOLFSSL_TRACK_MEMORY: currentBytes after cleanup is %ld\n", wc_MemStats_Ptr->currentBytes); + ret = MEMORY_E; + } + } +#endif + if (ret == 0) { puts("\nunit_test: Success for all configured tests."); fflush(stdout); diff --git a/wolfcrypt/src/memory.c b/wolfcrypt/src/memory.c index 4d17bfbfe..8cf3a64d0 100644 --- a/wolfcrypt/src/memory.c +++ b/wolfcrypt/src/memory.c @@ -521,6 +521,11 @@ void* wolfSSL_Realloc(void *ptr, size_t size) } #endif /* WOLFSSL_STATIC_MEMORY */ +#ifdef WOLFSSL_TRACK_MEMORY +#include +WOLFSSL_API memoryStats *wc_MemStats_Ptr; +#endif + #ifdef WOLFSSL_STATIC_MEMORY struct wc_Memory { diff --git a/wolfssl/wolfcrypt/mem_track.h b/wolfssl/wolfcrypt/mem_track.h index c04c74662..300c41cc0 100644 --- a/wolfssl/wolfcrypt/mem_track.h +++ b/wolfssl/wolfcrypt/mem_track.h @@ -133,6 +133,7 @@ typedef struct memoryList { static memoryStats ourMemStats; +WOLFSSL_API extern memoryStats *wc_MemStats_Ptr; #ifdef DO_MEM_LIST #include @@ -384,6 +385,8 @@ static WC_INLINE int InitMemoryTracker(void) #endif } + wc_MemStats_Ptr = &ourMemStats; + return ret; } @@ -427,6 +430,7 @@ static WC_INLINE void ShowMemoryTracker(void) static WC_INLINE int CleanupMemoryTracker(void) { + wc_MemStats_Ptr = NULL; /* restore default allocators */ return wolfSSL_SetAllocators(mfDefault, ffDefault, rfDefault); } From 2b289318559ed99579852764273db541bae6d9da Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 17:01:36 -0600 Subject: [PATCH 12/18] wolfcrypt/src/sha256.c and wolfcrypt/src/sha512.c: in WOLFSSL_SMALL_STACK_CACHE builds, allocate shafoo->W at init or context copy time, rather than in the transform function. for the SHA512 family, allocate additional space in W for "buffer" in wc_Sha512Transform(). --- wolfcrypt/src/sha256.c | 42 +++++++++++++++++++++++++--------- wolfcrypt/src/sha512.c | 51 ++++++++++++++++++++++++++++++------------ 2 files changed, 68 insertions(+), 25 deletions(-) diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index 59b10eace..690af7564 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -678,7 +678,10 @@ static int InitSha256(wc_Sha256* sha256) sha256->devCtx = NULL; #endif #ifdef WOLFSSL_SMALL_STACK_CACHE - sha256->W = NULL; + sha256->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, + sha256->heap, DYNAMIC_TYPE_DIGEST); + if (sha256->W == NULL) + return MEMORY_E; #endif ret = InitSha256(sha256); @@ -1163,7 +1166,10 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, } #endif #ifdef WOLFSSL_SMALL_STACK_CACHE - sha256->W = NULL; + sha256->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, + sha256->heap, DYNAMIC_TYPE_DIGEST); + if (sha256->W == NULL) + return MEMORY_E; #endif #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA256) @@ -1244,13 +1250,8 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, #if defined(WOLFSSL_SMALL_STACK_CACHE) && !defined(WOLFSSL_NO_MALLOC) word32* W = sha256->W; - if (W == NULL) { - W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, - sha256->heap, DYNAMIC_TYPE_DIGEST); - if (W == NULL) - return MEMORY_E; - sha256->W = W; - } + if (W == NULL) + return BAD_FUNC_ARG; #elif defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) word32* W; W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, @@ -2065,6 +2066,15 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, { int ret = 0; +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (sha224->W == NULL) { + sha224->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, + sha224->heap, DYNAMIC_TYPE_DIGEST); + if (sha224->W == NULL) + return MEMORY_E; + } +#endif + sha224->digest[0] = 0xc1059ed8; sha224->digest[1] = 0x367cd507; sha224->digest[2] = 0x3070dd17; @@ -2575,7 +2585,12 @@ int wc_Sha224_Grow(wc_Sha224* sha224, const byte* in, int inSz) XMEMCPY(dst, src, sizeof(wc_Sha224)); #ifdef WOLFSSL_SMALL_STACK_CACHE - dst->W = NULL; + dst->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, + dst->heap, DYNAMIC_TYPE_DIGEST); + if (dst->W == NULL) { + XMEMSET(dst, 0, sizeof(wc_Sha224)); + return MEMORY_E; + } #endif #if defined(WOLFSSL_SILABS_SE_ACCEL) && defined(WOLFSSL_SILABS_SE_ACCEL_3) @@ -2727,7 +2742,12 @@ int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) #endif #ifdef WOLFSSL_SMALL_STACK_CACHE - dst->W = NULL; + dst->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, + dst->heap, DYNAMIC_TYPE_DIGEST); + if (dst->W == NULL) { + XMEMSET(dst, 0, sizeof(wc_Sha256)); + return MEMORY_E; + } #endif #if defined(WOLFSSL_SILABS_SE_ACCEL) && defined(WOLFSSL_SILABS_SE_ACCEL_3) diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index ceabdc2b8..cf67478b2 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -870,7 +870,10 @@ static int InitSha512_Family(wc_Sha512* sha512, void* heap, int devId, sha512->heap = heap; #ifdef WOLFSSL_SMALL_STACK_CACHE - sha512->W = NULL; + sha512->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE, + sha512->heap, DYNAMIC_TYPE_DIGEST); + if (sha512->W == NULL) + return MEMORY_E; #endif #ifdef WOLF_CRYPTO_CB sha512->devId = devId; @@ -1031,14 +1034,10 @@ static int _Transform_Sha512(wc_Sha512* sha512) word32 j; word64 T[8]; -#ifdef WOLFSSL_SMALL_STACK_CACHE +#if defined(WOLFSSL_SMALL_STACK_CACHE) word64* W = sha512->W; - if (W == NULL) { - W = (word64*)XMALLOC(sizeof(word64) * 16, sha512->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (W == NULL) - return MEMORY_E; - sha512->W = W; - } + if (W == NULL) + return BAD_FUNC_ARG; #elif defined(WOLFSSL_SMALL_STACK) word64* W; W = (word64*) XMALLOC(sizeof(word64) * 16, sha512->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1646,7 +1645,7 @@ void wc_Sha512Free(wc_Sha512* sha512) #ifdef WOLFSSL_SMALL_STACK_CACHE if (sha512->W != NULL) { - ForceZero(sha512->W, sizeof(word64) * 16); + ForceZero(sha512->W, (sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE); XFREE(sha512->W, sha512->heap, DYNAMIC_TYPE_TMP_BUFFER); sha512->W = NULL; } @@ -1699,7 +1698,12 @@ int wc_Sha512Transform(wc_Sha512* sha, const unsigned char* data) return BAD_FUNC_ARG; } -#ifdef WOLFSSL_SMALL_STACK + +#if defined(WOLFSSL_SMALL_STACK_CACHE) + if (sha->W == NULL) + return BAD_FUNC_ARG; + buffer = sha->W + 16; +#elif defined(WOLFSSL_SMALL_STACK) buffer = (word64*)XMALLOC(WC_SHA512_BLOCK_SIZE, sha->heap, DYNAMIC_TYPE_TMP_BUFFER); if (buffer == NULL) @@ -1733,7 +1737,7 @@ int wc_Sha512Transform(wc_Sha512* sha, const unsigned char* data) XMEMCPY(sha->buffer, buffer, WC_SHA512_BLOCK_SIZE); #endif -#ifdef WOLFSSL_SMALL_STACK +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) ForceZero(buffer, WC_SHA512_BLOCK_SIZE); XFREE(buffer, sha->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -1867,6 +1871,15 @@ static int InitSha384(wc_Sha384* sha384) return BAD_FUNC_ARG; } +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (sha384->W == NULL) { + sha384->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE, + sha384->heap, DYNAMIC_TYPE_DIGEST); + if (sha384->W == NULL) + return MEMORY_E; + } +#endif + sha384->digest[0] = W64LIT(0xcbbb9d5dc1059ed8); sha384->digest[1] = W64LIT(0x629a292a367cd507); sha384->digest[2] = W64LIT(0x9159015a3070dd17); @@ -2106,7 +2119,7 @@ void wc_Sha384Free(wc_Sha384* sha384) #ifdef WOLFSSL_SMALL_STACK_CACHE if (sha384->W != NULL) { - ForceZero(sha384->W, sizeof(word64) * 16); + ForceZero(sha384->W, (sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE); XFREE(sha384->W, sha384->heap, DYNAMIC_TYPE_TMP_BUFFER); sha384->W = NULL; } @@ -2219,7 +2232,12 @@ int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst) XMEMCPY(dst, src, sizeof(wc_Sha512)); #ifdef WOLFSSL_SMALL_STACK_CACHE - dst->W = NULL; + dst->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE, + dst->heap, DYNAMIC_TYPE_DIGEST); + if (dst->W == NULL) { + XMEMSET(dst, 0, sizeof(wc_Sha512)); + return MEMORY_E; + } #endif #if defined(WOLFSSL_SILABS_SE_ACCEL) && defined(WOLFSSL_SILABS_SE_ACCEL_3) && \ @@ -2649,7 +2667,12 @@ int wc_Sha384Copy(wc_Sha384* src, wc_Sha384* dst) XMEMCPY(dst, src, sizeof(wc_Sha384)); #ifdef WOLFSSL_SMALL_STACK_CACHE - dst->W = NULL; + dst->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA384_BLOCK_SIZE, + dst->heap, DYNAMIC_TYPE_DIGEST); + if (dst->W == NULL) { + XMEMSET(dst, 0, sizeof(wc_Sha384)); + return MEMORY_E; + } #endif #if defined(WOLFSSL_SILABS_SE_ACCEL) && defined(WOLFSSL_SILABS_SE_ACCEL_3) && \ From 8bd0fb0e4bebecb5b81267d62691252b6870d712 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 17:01:54 -0600 Subject: [PATCH 13/18] wolfcrypt/src/random.c and wolfssl/wolfcrypt/random.h: refactor WOLFSSL_SMALL_STACK_CACHE support to eliminate all heap calls after init and before cleanup. * add DRBG_internal.{seed_scratch,digest_scratch} * add WC_RNG.{drbg_scratch,health_check_scratch,newSeed_buf} * refactor to implement new WOLFSSL_SMALL_STACK_CACHE dynamics: * wc_RNG_HealthTestLocal() * Hash_df() * Hash_gen() * Hash_DRBG_Generate() * Hash_DRBG_Instantiate() * _InitRng() * PollAndReSeed() * wc_FreeRng() * wc_RNG_HealthTest_ex_internal() * wc_RNG_HealthTest_ex() * wc_RNG_HealthTestLocal() * refactor out WOLFSSL_KERNEL_MODE gates (now all WOLFSSL_SMALL_STACK_CACHE) --- wolfcrypt/src/random.c | 354 ++++++++++++++++++++++++++++--------- wolfssl/wolfcrypt/random.h | 10 +- 2 files changed, 276 insertions(+), 88 deletions(-) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index ba8192e04..34e7c5487 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -345,7 +345,8 @@ enum { typedef struct DRBG_internal DRBG_internal; -static int wc_RNG_HealthTestLocal(int reseed, void* heap, int devId); +static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, + int devId); /* Hash Derivation Function */ /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ @@ -363,7 +364,9 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, #else wc_Sha256 sha[1]; #endif -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_KERNEL_MODE) +#if defined(WOLFSSL_SMALL_STACK_CACHE) + byte* digest = drbg->digest_scratch; +#elif defined(WOLFSSL_SMALL_STACK) byte* digest; #else byte digest[WC_SHA256_DIGEST_SIZE]; @@ -373,7 +376,7 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, return DRBG_FAILURE; } -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_KERNEL_MODE) +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) digest = (byte*)XMALLOC(WC_SHA256_DIGEST_SIZE, drbg->heap, DYNAMIC_TYPE_DIGEST); if (digest == NULL) @@ -434,7 +437,7 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, ForceZero(digest, WC_SHA256_DIGEST_SIZE); -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_KERNEL_MODE) +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); #endif @@ -451,8 +454,12 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz return DRBG_FAILURE; } +#ifdef WOLFSSL_SMALL_STACK_CACHE + newV = drbg->seed_scratch; +#else WC_ALLOC_VAR_EX(newV, byte, DRBG_SEED_LEN, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); +#endif XMEMSET(newV, 0, DRBG_SEED_LEN); ret = Hash_df(drbg, newV, DRBG_SEED_LEN, drbgReseed, @@ -468,7 +475,9 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz drbg->reseedCtr = 1; } +#ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(newV, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif return ret; } @@ -505,26 +514,27 @@ static WC_INLINE void array_add_one(byte* data, word32 dataSz) static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) { int ret = DRBG_FAILURE; -#ifdef WOLFSSL_SMALL_STACK - byte* data; - byte* digest; -#else - byte data[DRBG_SEED_LEN]; - byte digest[WC_SHA256_DIGEST_SIZE]; -#endif word32 i; word32 len; -#ifdef WOLFSSL_SMALL_STACK_CACHE +#if defined(WOLFSSL_SMALL_STACK_CACHE) wc_Sha256* sha = &drbg->sha256; + byte* data = drbg->seed_scratch; + byte* digest = drbg->digest_scratch; +#elif defined(WOLFSSL_SMALL_STACK) + wc_Sha256 sha[1]; + byte* data = NULL; + byte* digest = NULL; #else wc_Sha256 sha[1]; + byte data[DRBG_SEED_LEN]; + byte digest[WC_SHA256_DIGEST_SIZE]; #endif if (drbg == NULL) { return DRBG_FAILURE; } -#ifdef WOLFSSL_SMALL_STACK +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) data = (byte*)XMALLOC(DRBG_SEED_LEN, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); digest = (byte*)XMALLOC(WC_SHA256_DIGEST_SIZE, drbg->heap, DYNAMIC_TYPE_DIGEST); @@ -582,8 +592,10 @@ static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) } ForceZero(data, DRBG_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); WC_FREE_VAR_EX(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } @@ -639,7 +651,9 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) return DRBG_NEED_RESEED; } else { - #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_KERNEL_MODE) + #if defined(WOLFSSL_SMALL_STACK_CACHE) + byte* digest = drbg->digest_scratch; + #elif defined(WOLFSSL_SMALL_STACK) byte* digest = (byte*)XMALLOC(WC_SHA256_DIGEST_SIZE, drbg->heap, DYNAMIC_TYPE_DIGEST); if (digest == NULL) @@ -688,7 +702,7 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) drbg->reseedCtr++; } ForceZero(digest, WC_SHA256_DIGEST_SIZE); - #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_KERNEL_MODE) + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); #endif } @@ -696,12 +710,34 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash_DRBG_Init(DRBG_internal* drbg, const byte* seed, word32 seedSz, + const byte* nonce, word32 nonceSz) +{ + if (seed == NULL) + return DRBG_FAILURE; + + if (Hash_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz, + nonce, nonceSz) == DRBG_SUCCESS && + Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, + sizeof(drbg->V), NULL, 0) == DRBG_SUCCESS) { + + drbg->reseedCtr = 1; + return DRBG_SUCCESS; + } + else { + return DRBG_FAILURE; + } +} + /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 seedSz, const byte* nonce, word32 nonceSz, void* heap, int devId) { +#ifdef WOLFSSL_SMALL_STACK_CACHE int ret = DRBG_FAILURE; +#endif XMEMSET(drbg, 0, sizeof(DRBG_internal)); drbg->heap = heap; @@ -721,16 +757,10 @@ static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 s return ret; #endif - if (Hash_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz, - nonce, nonceSz) == DRBG_SUCCESS && - Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, - sizeof(drbg->V), NULL, 0) == DRBG_SUCCESS) { - - drbg->reseedCtr = 1; - ret = DRBG_SUCCESS; - } - - return ret; + if (seed == NULL) + return 0; + else + return Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz); } /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ @@ -785,6 +815,15 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, int ret = 0; #ifdef HAVE_HASHDRBG word32 seedSz = SEED_SZ + SEED_BLOCK_SZ; + #ifdef WOLFSSL_SMALL_STACK + byte* seed = NULL; + #else + byte seed[MAX_SEED_SZ]; + #endif + int drbg_instantiated = 0; +#ifdef WOLFSSL_SMALL_STACK_CACHE + int drbg_scratch_instantiated = 0; +#endif #endif (void)nonce; @@ -795,6 +834,8 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, if (nonce == NULL && nonceSz != 0) return BAD_FUNC_ARG; + XMEMSET(rng, 0, sizeof(*rng)); + #ifdef WOLFSSL_HEAP_TEST rng->heap = (void*)WOLFSSL_HEAP_TEST; (void)heap; @@ -816,6 +857,9 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #ifdef HAVE_HASHDRBG /* init the DBRG to known values */ rng->drbg = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + rng->drbg_scratch = NULL; + #endif rng->status = DRBG_NOT_INIT; #endif @@ -867,45 +911,91 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, seedSz = MAX_SEED_SZ; } - ret = wc_RNG_HealthTestLocal(0, rng->heap, devId); - if (ret != 0) { - #if defined(DEBUG_WOLFSSL) - WOLFSSL_MSG_EX("wc_RNG_HealthTestLocal failed err = %d", ret); - #endif - ret = DRBG_CONT_FAILURE; - } - else { - #ifndef WOLFSSL_SMALL_STACK - byte seed[MAX_SEED_SZ]; - #else - byte* seed = (byte*)XMALLOC(MAX_SEED_SZ, rng->heap, - DYNAMIC_TYPE_SEED); - if (seed == NULL) - return MEMORY_E; - #endif - #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) - rng->drbg = - (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap, - DYNAMIC_TYPE_RNG); - if (rng->drbg == NULL) { + rng->drbg = + (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap, + DYNAMIC_TYPE_RNG); + if (rng->drbg == NULL) { #if defined(DEBUG_WOLFSSL) + WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", + sizeof(DRBG_internal)); + #endif + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } +#else + rng->drbg = (struct DRBG*)&rng->drbg_data; +#endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */ + +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (ret == 0) { + rng->drbg_scratch = + (DRBG_internal *)XMALLOC(sizeof(DRBG_internal), rng->heap, + DYNAMIC_TYPE_RNG); + if (rng->drbg_scratch == NULL) { +#if defined(DEBUG_WOLFSSL) WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", sizeof(DRBG_internal)); - #endif +#endif ret = MEMORY_E; rng->status = DRBG_FAILED; } -#else - rng->drbg = (struct DRBG*)&rng->drbg_data; -#endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */ + } - if (ret != 0) { -#if defined(DEBUG_WOLFSSL) - WOLFSSL_MSG_EX("_InitRng failed. err = %d", ret); -#endif + if (ret == 0) { + ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg_scratch, + NULL /* seed */, 0, NULL /* nonce */, 0, rng->heap, devId); + if (ret == 0) + drbg_scratch_instantiated = 1; + } + + if (ret == 0) { + rng->health_check_scratch = + (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (rng->health_check_scratch == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; } - else { + } + + if (ret == 0) { + rng->newSeed_buf = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, + DYNAMIC_TYPE_SEED); + if (rng->newSeed_buf == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + + if (ret == 0) { + ret = wc_RNG_HealthTestLocal(rng, 0, rng->heap, devId); + if (ret != 0) { + #if defined(DEBUG_WOLFSSL) + WOLFSSL_MSG_EX("wc_RNG_HealthTestLocal failed err = %d", ret); + #endif + ret = DRBG_CONT_FAILURE; + } + } + + #ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + seed = (byte*)XMALLOC(MAX_SEED_SZ, rng->heap, + DYNAMIC_TYPE_SEED); + if (seed == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } + #endif + + if (ret != 0) { +#if defined(DEBUG_WOLFSSL) + WOLFSSL_MSG_EX("_InitRng failed. err = %d", ret); +#endif + } + else { #ifdef WC_RNG_SEED_CB if (seedCb == NULL) { ret = DRBG_NO_SEED_CB; @@ -938,18 +1028,37 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg, seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, nonce, nonceSz, rng->heap, devId); + if (ret == 0) + drbg_instantiated = 1; + } /* ret == 0 */ - if (ret != DRBG_SUCCESS) { - #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) - XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG); - #endif - rng->drbg = NULL; - } - } /* ret == 0 */ - + #ifdef WOLFSSL_SMALL_STACK + if (seed) + #endif + { ForceZero(seed, seedSz); - WC_FREE_VAR_EX(seed, rng->heap, DYNAMIC_TYPE_SEED); - } /* else swc_RNG_HealthTestLocal was successful */ + } + WC_FREE_VAR_EX(seed, rng->heap, DYNAMIC_TYPE_SEED); + + if (ret != DRBG_SUCCESS) { + if (drbg_instantiated) + (void)Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg); + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG); + #endif + rng->drbg = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch = NULL; + XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); + rng->newSeed_buf = NULL; + if (drbg_scratch_instantiated) + (void)Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch); + XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg_scratch = NULL; + #endif + } + /* else swc_RNG_HealthTestLocal was successful */ if (ret == DRBG_SUCCESS) { #ifdef WOLFSSL_CHECK_MEM_ZERO @@ -1068,14 +1177,17 @@ static int PollAndReSeed(WC_RNG* rng) #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) devId = rng->devId; #endif - if (wc_RNG_HealthTestLocal(1, rng->heap, devId) == 0) { - #ifndef WOLFSSL_SMALL_STACK - byte newSeed[SEED_SZ + SEED_BLOCK_SZ]; + if (wc_RNG_HealthTestLocal(rng, 1, rng->heap, devId) == 0) { + #if defined(WOLFSSL_SMALL_STACK_CACHE) + byte* newSeed = rng->newSeed_buf; ret = DRBG_SUCCESS; - #else + #elif defined(WOLFSSL_SMALL_STACK) byte* newSeed = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, DYNAMIC_TYPE_SEED); ret = (newSeed == NULL) ? MEMORY_E : DRBG_SUCCESS; + #else + byte newSeed[SEED_SZ + SEED_BLOCK_SZ]; + ret = DRBG_SUCCESS; #endif if (ret == DRBG_SUCCESS) { #ifdef WC_RNG_SEED_CB @@ -1101,7 +1213,7 @@ static int PollAndReSeed(WC_RNG* rng) if (ret == DRBG_SUCCESS) ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, newSeed + SEED_BLOCK_SZ, SEED_SZ); - #ifdef WOLFSSL_SMALL_STACK + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) if (newSeed != NULL) { ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); } @@ -1247,6 +1359,19 @@ int wc_FreeRng(WC_RNG* rng) rng->drbg = NULL; } + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (rng->drbg_scratch != NULL) { + if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch) != DRBG_SUCCESS) + ret = RNG_FAILURE_E; + XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg_scratch = NULL; + } + XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->health_check_scratch = NULL; + XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_RNG); + rng->newSeed_buf = NULL; + #endif + rng->status = DRBG_NOT_INIT; #endif /* HAVE_HASHDRBG */ @@ -1271,17 +1396,14 @@ int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz, } -int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, +static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg, + int reseed, const byte* nonce, word32 nonceSz, const byte* seedA, word32 seedASz, const byte* seedB, word32 seedBSz, byte* output, word32 outputSz, void* heap, int devId) { int ret = -1; - DRBG_internal* drbg; -#ifndef WOLFSSL_SMALL_STACK - DRBG_internal drbg_var; -#endif if (seedA == NULL || output == NULL) { return BAD_FUNC_ARG; @@ -1295,20 +1417,18 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, return ret; } -#ifdef WOLFSSL_SMALL_STACK - drbg = (DRBG_internal*)XMALLOC(sizeof(DRBG_internal), heap, - DYNAMIC_TYPE_RNG); - if (drbg == NULL) { - return MEMORY_E; +#ifdef WOLFSSL_SMALL_STACK_CACHE + (void)heap; (void)devId; + + if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz) != 0) { + goto exit_rng_ht; } #else - drbg = &drbg_var; -#endif - if (Hash_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, heap, devId) != 0) { goto exit_rng_ht; } +#endif if (reseed) { if (Hash_DRBG_Reseed(drbg, seedB, seedBSz) != 0) { @@ -1334,11 +1454,51 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, exit_rng_ht: +#ifndef WOLFSSL_SMALL_STACK_CACHE /* This is safe to call even if Hash_DRBG_Instantiate fails */ if (Hash_DRBG_Uninstantiate(drbg) != 0) { ret = -1; } +#endif + return ret; +} + +int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret = -1; + DRBG_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_internal drbg_var; +#endif + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_internal*)XMALLOC(sizeof(DRBG_internal), heap, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + +#ifdef WOLFSSL_SMALL_STACK_CACHE + ret = Hash_DRBG_Instantiate(drbg, + NULL /* seed */, 0, NULL /* nonce */, 0, heap, devId); + if (ret == 0) +#endif + { + ret = wc_RNG_HealthTest_ex_internal( + drbg, reseed, nonce, nonceSz, seedA, seedASz, + seedB, seedBSz, output, outputSz, heap, devId); +#ifdef WOLFSSL_SMALL_STACK_CACHE + Hash_DRBG_Uninstantiate(drbg); +#endif + } WC_FREE_VAR_EX(drbg, heap, DYNAMIC_TYPE_RNG); return ret; @@ -1395,13 +1555,30 @@ const FLASH_QUALIFIER byte outputB_data[] = { }; -static int wc_RNG_HealthTestLocal(int reseed, void* heap, int devId) +static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, + int devId) { int ret = 0; +#ifdef WOLFSSL_SMALL_STACK_CACHE + byte *check = rng->health_check_scratch; + DRBG_internal* drbg = (DRBG_internal *)rng->drbg_scratch; +#else WC_DECLARE_VAR(check, byte, RNG_HEALTH_TEST_CHECK_SIZE, 0); + WC_DECLARE_VAR(drbg, DRBG_internal, 1, 0); + + (void)rng; WC_ALLOC_VAR_EX(check, byte, RNG_HEALTH_TEST_CHECK_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); + WC_ALLOC_VAR_EX(drbg, DRBG_internal, sizeof(DRBG_internal), heap, + DYNAMIC_TYPE_TMP_BUFFER, WC_DO_NOTHING); + #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + if (drbg == NULL) { + WC_FREE_VAR_EX(check, heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + #endif +#endif if (reseed) { #ifdef WOLFSSL_USE_FLASHMEM @@ -1427,7 +1604,7 @@ static int wc_RNG_HealthTestLocal(int reseed, void* heap, int devId) const byte* reseedSeedA = reseedSeedA_data; const byte* outputA = outputA_data; #endif - ret = wc_RNG_HealthTest_ex(1, NULL, 0, + ret = wc_RNG_HealthTest_ex_internal(drbg, 1, NULL, 0, seedA, sizeof(seedA_data), reseedSeedA, sizeof(reseedSeedA_data), check, RNG_HEALTH_TEST_CHECK_SIZE, @@ -1470,7 +1647,7 @@ static int wc_RNG_HealthTestLocal(int reseed, void* heap, int devId) WOLFSSL_MSG_EX("sizeof(seedB_data) = %d", (int)sizeof(outputB_data)); #endif - ret = wc_RNG_HealthTest_ex(0, NULL, 0, + ret = wc_RNG_HealthTest_ex_internal(drbg, 0, NULL, 0, seedB, sizeof(seedB_data), NULL, 0, check, RNG_HEALTH_TEST_CHECK_SIZE, @@ -1496,7 +1673,7 @@ static int wc_RNG_HealthTestLocal(int reseed, void* heap, int devId) * just concatenates them. The pivot point between seed and nonce is * byte 32, feed them into the health test separately. */ if (ret == 0) { - ret = wc_RNG_HealthTest_ex(0, + ret = wc_RNG_HealthTest_ex_internal(drbg, 0, seedB + 32, sizeof(seedB_data) - 32, seedB, 32, NULL, 0, @@ -1515,7 +1692,10 @@ static int wc_RNG_HealthTestLocal(int reseed, void* heap, int devId) #endif } +#ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(check, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(drbg, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif return ret; } diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index 3445937f5..93890fe9a 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -177,6 +177,8 @@ struct DRBG_internal { #endif #ifdef WOLFSSL_SMALL_STACK_CACHE wc_Sha256 sha256; + byte seed_scratch[DRBG_SEED_LEN]; + byte digest_scratch[WC_SHA256_DIGEST_SIZE]; #endif }; #endif @@ -191,8 +193,14 @@ struct WC_RNG { #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) struct DRBG_internal drbg_data; #endif - byte status; +#ifdef WOLFSSL_SMALL_STACK_CACHE + /* Scratch buffer slots -- everything is preallocated by _InitRng(). */ + struct DRBG_internal *drbg_scratch; + byte *health_check_scratch; + byte *newSeed_buf; #endif + byte status; +#endif /* HAVE_HASHDRBG */ #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) pid_t pid; #endif From fb82bdbc355ed25149e5c69412a3d9c5dd4ed5a4 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 17:02:09 -0600 Subject: [PATCH 14/18] wolfcrypt/test/test.c: * in wolfcrypt_test_main(), when WOLFSSL_TRACK_MEMORY, check and error if wc_MemStats_Ptr->currentBytes > 0; * don't call the hash initialization APIs for hash structs that are later copied over with the hash copy API (sha224_test(), sha256_test(), sha512_test(), etc) * in hash_test(), either wc_HashNew() or wc_HashInit(), not both (fixes leaks); * in hmac_*_test(), add test coverage for wc_HmacCopy(); * in _rng_test(), when WOLFSSL_TRACK_MEMORY && WOLFSSL_SMALL_STACK_CACHE, check that wc_MemStats_Ptr->totalAllocs doesn't increase when wc_RNG_GenerateBlock() is called, and if HAVE_HASHDRBG) && !CUSTOM_RAND_GENERATE_BLOCK, check that forcing a reseed doesn't result in an increase. * add missing context cleanups in openSSL_evpMD_test(). --- wolfcrypt/test/test.c | 352 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 306 insertions(+), 46 deletions(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ee4b3e4f8..8ae657436 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -3111,6 +3111,14 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ } #endif +#ifdef WOLFSSL_TRACK_MEMORY + if (wc_MemStats_Ptr && (wc_MemStats_Ptr->currentBytes > 0) && + (args.return_code == 0)) + { + args.return_code = WC_TEST_RET_ENC_EC(MEMORY_E); + } +#endif + #if defined(WOLFSSL_ESPIDF) /* ESP_LOGI to print takes up a lot less memory than printf */ ESP_LOGI(ESPIDF_TAG, "Exiting main with return code: % d\n", @@ -4734,11 +4742,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha224_test(void) ret = wc_InitSha224_ex(&sha, HEAP_HINT, devId); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = wc_InitSha224_ex(&shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha224Free(&sha); - return WC_TEST_RET_ENC_EC(ret); - } + XMEMSET(&shaCopy, 0, sizeof(shaCopy)); for (i = 0; i < times; ++i) { ret = wc_Sha224Update(&sha, (byte*)test_sha[i].input, @@ -4846,19 +4850,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha256_test(void) return WC_TEST_RET_ENC_EC(ret); #endif - ret = wc_InitSha256_ex(&shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha256Free(&sha); - return WC_TEST_RET_ENC_EC(ret); - } -#ifndef NO_WOLFSSL_SHA256_INTERLEAVE - ret = wc_InitSha256_ex(&i_shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha256Free(&sha); - wc_Sha256Free(&i_sha); - return WC_TEST_RET_ENC_EC(ret); - } -#endif + XMEMSET(&shaCopy, 0, sizeof(shaCopy)); for (i = 0; i < times; ++i) { ret = wc_Sha256Update(&sha, (byte*)test_sha[i].input, @@ -5085,18 +5077,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha512_test(void) return WC_TEST_RET_ENC_EC(ret); #endif - ret = wc_InitSha512_ex(&shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha512Free(&sha); - return WC_TEST_RET_ENC_EC(ret); - } + XMEMSET(&shaCopy, 0, sizeof(shaCopy)); #ifndef NO_WOLFSSL_SHA512_INTERLEAVE - ret = wc_InitSha512_ex(&i_shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha512Free(&sha); - wc_Sha512Free(&i_sha); - return WC_TEST_RET_ENC_EC(ret); - } + XMEMSET(&i_shaCopy, 0, sizeof(i_shaCopy)); #endif for (i = 0; i < times; ++i) { @@ -5296,11 +5279,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha512_224_test(void) ret = wc_InitSha512_224_ex(&sha, HEAP_HINT, devId); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = wc_InitSha512_224_ex(&shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha512_224Free(&sha); - return WC_TEST_RET_ENC_EC(ret); - } + XMEMSET(&shaCopy, 0, sizeof(shaCopy)); for (i = 0; i < times; ++i) { ret = wc_Sha512_224Update(&sha, (byte*)test_sha[i].input, @@ -5449,11 +5428,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha512_256_test(void) ret = wc_InitSha512_256_ex(&sha, HEAP_HINT, devId); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = wc_InitSha512_256_ex(&shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha512_256Free(&sha); - return WC_TEST_RET_ENC_EC(ret); - } + XMEMSET(&shaCopy, 0, sizeof(shaCopy)); for (i = 0; i < times; ++i) { ret = wc_Sha512_256Update(&sha, (byte*)test_sha[i].input, @@ -5586,11 +5561,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha384_test(void) ret = wc_InitSha384_ex(&sha, HEAP_HINT, devId); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - ret = wc_InitSha384_ex(&shaCopy, HEAP_HINT, devId); - if (ret != 0) { - wc_Sha384Free(&sha); - return WC_TEST_RET_ENC_EC(ret); - } + + XMEMSET(&shaCopy, 0, sizeof(shaCopy)); for (i = 0; i < times; ++i) { ret = wc_Sha384Update(&sha, (byte*)test_sha[i].input, @@ -7149,17 +7121,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hash_test(void) if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(BAD_FUNC_ARG), out); } -#endif +#else ret = wc_HashInit(hash, typesGood[i]); if (ret != exp_ret) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); +#endif ret = wc_HashUpdate(hash, typesGood[i], data, sizeof(data)); if (ret != exp_ret) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); ret = wc_HashFinal(hash, typesGood[i], out); if (ret != exp_ret) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); - wc_HashFree(hash, typesGood[i]); + ret = wc_HashFree(hash, typesGood[i]); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_I(i), out); digestSz = wc_HashGetDigestSize(typesGood[i]); if (exp_ret == 0 && digestSz < 0) @@ -7407,6 +7382,9 @@ out: WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_md5_test(void) { Hmac hmac; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_DECLARE_VAR(hmac_copy, Hmac, 1, HEAP_HINT); +#endif byte hash[WC_MD5_DIGEST_SIZE]; const char* keys[]= @@ -7462,6 +7440,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_md5_test(void) test_hmac[2] = c; test_hmac[3] = d; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_ALLOC_VAR_EX(hmac_copy, Hmac, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); +#endif + for (i = 0; i < times; ++i) { #if defined(HAVE_FIPS) || defined(HAVE_CAVIUM) if (i == 1) { @@ -7477,6 +7460,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_md5_test(void) (word32)XSTRLEN(keys[i])); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacCopy(&hmac, hmac_copy); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); +#endif + ret = wc_HmacUpdate(&hmac, (byte*)test_hmac[i].input, (word32)test_hmac[i].inLen); if (ret != 0) @@ -7489,8 +7479,27 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_md5_test(void) return WC_TEST_RET_ENC_I(i); wc_HmacFree(&hmac); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacUpdate(hmac_copy, (byte*)test_hmac[i].input, + (word32)test_hmac[i].inLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_HmacFinal(hmac_copy, hash); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(hash, test_hmac[i].output, WC_MD5_DIGEST_SIZE) != 0) + return WC_TEST_RET_ENC_I(i); + + wc_HmacFree(hmac_copy); +#endif } +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_FREE_VAR_EX(hmac_copy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(6,0,0) if ((ret = wc_HmacSizeByType(WC_MD5)) != WC_MD5_DIGEST_SIZE) return WC_TEST_RET_ENC_EC(ret); @@ -7504,6 +7513,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_md5_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha_test(void) { Hmac hmac; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_DECLARE_VAR(hmac_copy, Hmac, 1, HEAP_HINT); +#endif byte hash[WC_SHA_DIGEST_SIZE]; const char* keys[]= @@ -7565,6 +7577,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha_test(void) test_hmac[2] = c; test_hmac[3] = d; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_ALLOC_VAR_EX(hmac_copy, Hmac, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); +#endif + for (i = 0; i < times; ++i) { #if defined(HAVE_CAVIUM) || (defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0)) if (i == 1) @@ -7587,6 +7604,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha_test(void) #endif if (ret != 0) return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacCopy(&hmac, hmac_copy); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); +#endif + ret = wc_HmacUpdate(&hmac, (byte*)test_hmac[i].input, (word32)test_hmac[i].inLen); if (ret != 0) @@ -7599,8 +7623,27 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha_test(void) return WC_TEST_RET_ENC_I(i); wc_HmacFree(&hmac); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacUpdate(hmac_copy, (byte*)test_hmac[i].input, + (word32)test_hmac[i].inLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_HmacFinal(hmac_copy, hash); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(hash, test_hmac[i].output, WC_SHA_DIGEST_SIZE) != 0) + return WC_TEST_RET_ENC_I(i); + + wc_HmacFree(hmac_copy); +#endif } +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_FREE_VAR_EX(hmac_copy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(6,0,0) if ((ret = wc_HmacSizeByType(WC_SHA)) != WC_SHA_DIGEST_SIZE) return WC_TEST_RET_ENC_EC(ret); @@ -7615,6 +7658,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha224_test(void) { Hmac hmac; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_DECLARE_VAR(hmac_copy, Hmac, 1, HEAP_HINT); +#endif byte hash[WC_SHA224_DIGEST_SIZE]; const char* keys[]= @@ -7674,6 +7720,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha224_test(void) test_hmac[2] = c; test_hmac[3] = d; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_ALLOC_VAR_EX(hmac_copy, Hmac, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); +#endif + for (i = 0; i < times; ++i) { #if defined(HAVE_FIPS) || defined(HAVE_CAVIUM) if (i == 1) @@ -7687,6 +7738,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha224_test(void) (word32)XSTRLEN(keys[i])); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacCopy(&hmac, hmac_copy); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); +#endif + ret = wc_HmacUpdate(&hmac, (byte*)test_hmac[i].input, (word32)test_hmac[i].inLen); if (ret != 0) @@ -7699,8 +7757,27 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha224_test(void) return WC_TEST_RET_ENC_I(i); wc_HmacFree(&hmac); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacUpdate(hmac_copy, (byte*)test_hmac[i].input, + (word32)test_hmac[i].inLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_HmacFinal(hmac_copy, hash); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(hash, test_hmac[i].output, WC_SHA224_DIGEST_SIZE) != 0) + return WC_TEST_RET_ENC_I(i); + + wc_HmacFree(hmac_copy); +#endif } +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_FREE_VAR_EX(hmac_copy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(6,0,0) if ((ret = wc_HmacSizeByType(WC_SHA224)) != WC_SHA224_DIGEST_SIZE) return WC_TEST_RET_ENC_EC(ret); @@ -7715,6 +7792,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha224_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha256_test(void) { Hmac hmac; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_DECLARE_VAR(hmac_copy, Hmac, 1, HEAP_HINT); +#endif byte hash[WC_SHA256_DIGEST_SIZE]; const char* keys[]= @@ -7789,6 +7869,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha256_test(void) test_hmac[3] = d; test_hmac[4] = e; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_ALLOC_VAR_EX(hmac_copy, Hmac, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); +#endif + for (i = 0; i < times; ++i) { #if defined(HAVE_FIPS) || defined(HAVE_CAVIUM) if (i == 1) @@ -7806,6 +7891,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha256_test(void) (word32)XSTRLEN(keys[i])); if (ret != 0) return WC_TEST_RET_ENC_I(i); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacCopy(&hmac, hmac_copy); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); +#endif + if (test_hmac[i].input != NULL) { ret = wc_HmacUpdate(&hmac, (byte*)test_hmac[i].input, (word32)test_hmac[i].inLen); @@ -7820,8 +7912,29 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha256_test(void) return WC_TEST_RET_ENC_I(i); wc_HmacFree(&hmac); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + if (test_hmac[i].input != NULL) { + ret = wc_HmacUpdate(hmac_copy, (byte*)test_hmac[i].input, + (word32)test_hmac[i].inLen); + if (ret != 0) + return WC_TEST_RET_ENC_I(i); + } + ret = wc_HmacFinal(hmac_copy, hash); + if (ret != 0) + return WC_TEST_RET_ENC_I(i); + + if (XMEMCMP(hash, test_hmac[i].output, WC_SHA256_DIGEST_SIZE) != 0) + return WC_TEST_RET_ENC_I(i); + + wc_HmacFree(hmac_copy); +#endif } +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_FREE_VAR_EX(hmac_copy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(6,0,0) if ((ret = wc_HmacSizeByType(WC_SHA256)) != WC_SHA256_DIGEST_SIZE) return WC_TEST_RET_ENC_EC(ret); @@ -7846,6 +7959,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha256_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha384_test(void) { Hmac hmac; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_DECLARE_VAR(hmac_copy, Hmac, 1, HEAP_HINT); +#endif byte hash[WC_SHA384_DIGEST_SIZE]; const char* keys[]= @@ -7914,6 +8030,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha384_test(void) test_hmac[2] = c; test_hmac[3] = d; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_ALLOC_VAR_EX(hmac_copy, Hmac, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); +#endif + for (i = 0; i < times; ++i) { #if defined(HAVE_FIPS) if (i == 1) @@ -7927,6 +8048,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha384_test(void) (word32)XSTRLEN(keys[i])); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacCopy(&hmac, hmac_copy); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); +#endif + ret = wc_HmacUpdate(&hmac, (byte*)test_hmac[i].input, (word32)test_hmac[i].inLen); if (ret != 0) @@ -7939,8 +8067,27 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha384_test(void) return WC_TEST_RET_ENC_I(i); wc_HmacFree(&hmac); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacUpdate(hmac_copy, (byte*)test_hmac[i].input, + (word32)test_hmac[i].inLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_HmacFinal(hmac_copy, hash); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(hash, test_hmac[i].output, WC_SHA384_DIGEST_SIZE) != 0) + return WC_TEST_RET_ENC_I(i); + + wc_HmacFree(hmac_copy); +#endif } +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_FREE_VAR_EX(hmac_copy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(6,0,0) if ((ret = wc_HmacSizeByType(WC_SHA384)) != WC_SHA384_DIGEST_SIZE) return WC_TEST_RET_ENC_EC(ret); @@ -7955,6 +8102,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha384_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha512_test(void) { Hmac hmac; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_DECLARE_VAR(hmac_copy, Hmac, 1, HEAP_HINT); +#endif byte hash[WC_SHA512_DIGEST_SIZE]; const char* keys[]= @@ -8027,6 +8177,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha512_test(void) test_hmac[2] = c; test_hmac[3] = d; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_ALLOC_VAR_EX(hmac_copy, Hmac, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); +#endif + for (i = 0; i < times; ++i) { #if defined(HAVE_FIPS) if (i == 1) @@ -8040,6 +8195,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha512_test(void) (word32)XSTRLEN(keys[i])); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacCopy(&hmac, hmac_copy); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); +#endif + ret = wc_HmacUpdate(&hmac, (byte*)test_hmac[i].input, (word32)test_hmac[i].inLen); if (ret != 0) @@ -8052,8 +8214,27 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha512_test(void) return WC_TEST_RET_ENC_I(i); wc_HmacFree(&hmac); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacUpdate(hmac_copy, (byte*)test_hmac[i].input, + (word32)test_hmac[i].inLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_HmacFinal(hmac_copy, hash); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(hash, test_hmac[i].output, WC_SHA512_DIGEST_SIZE) != 0) + return WC_TEST_RET_ENC_I(i); + + wc_HmacFree(hmac_copy); +#endif } +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_FREE_VAR_EX(hmac_copy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(6,0,0) if ((ret = wc_HmacSizeByType(WC_SHA512)) != WC_SHA512_DIGEST_SIZE) return WC_TEST_RET_ENC_EC(ret); @@ -8070,6 +8251,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha512_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha3_test(void) { Hmac hmac; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_DECLARE_VAR(hmac_copy, Hmac, 1, HEAP_HINT); +#endif byte hash[WC_SHA3_512_DIGEST_SIZE]; const char* key[4] = @@ -8197,6 +8381,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha3_test(void) int ret; WOLFSSL_ENTER("hmac_sha3_test"); +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_ALLOC_VAR_EX(hmac_copy, Hmac, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); +#endif + #ifdef HAVE_FIPS /* FIPS requires a minimum length for HMAC keys, and "Jefe" is too * short. Skip it in FIPS builds. */ @@ -8211,6 +8400,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha3_test(void) (word32)XSTRLEN(key[i])); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacCopy(&hmac, hmac_copy); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); +#endif + ret = wc_HmacUpdate(&hmac, (byte*)input[i], (word32)XSTRLEN(input[i])); if (ret != 0) @@ -8223,6 +8419,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha3_test(void) wc_HmacFree(&hmac); +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + ret = wc_HmacUpdate(hmac_copy, (byte*)input[i], + (word32)XSTRLEN(input[i])); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_HmacFinal(hmac_copy, hash); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (XMEMCMP(hash, output[(i*jMax) + j], (size_t)hashSz[j]) != 0) + return WC_TEST_RET_ENC_NC; + + wc_HmacFree(hmac_copy); +#endif + if (i > 0) continue; @@ -8234,6 +8444,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha3_test(void) } } +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + WC_FREE_VAR_EX(hmac_copy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return 0; } #endif @@ -19452,6 +19666,9 @@ static wc_test_ret_t _rng_test(WC_RNG* rng) byte block[32]; wc_test_ret_t ret; int i; +#if defined(WOLFSSL_TRACK_MEMORY) && defined(WOLFSSL_SMALL_STACK_CACHE) + long current_totalAllocs = wc_MemStats_Ptr->totalAllocs; +#endif XMEMSET(block, 0, sizeof(block)); @@ -19476,6 +19693,31 @@ static wc_test_ret_t _rng_test(WC_RNG* rng) return WC_TEST_RET_ENC_EC(ret); } +#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) + /* Test periodic reseed dynamics. */ + + ((struct DRBG_internal *)rng->drbg)->reseedCtr = WC_RESEED_INTERVAL; + + ret = wc_RNG_GenerateBlock(rng, block, sizeof(block)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (((struct DRBG_internal *)rng->drbg)->reseedCtr == WC_RESEED_INTERVAL) + return WC_TEST_RET_ENC_NC; +#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK */ + +#if defined(WOLFSSL_TRACK_MEMORY) && defined(WOLFSSL_SMALL_STACK_CACHE) + /* wc_RNG_GenerateBlock() must not allocate any memory in + * WOLFSSL_SMALL_STACK_CACHE builds, even if it had to reseed. + * LINUXKM_DRBG_GET_RANDOM_BYTES depends on this -- + * wolfssl_linuxkm_random_bytes_handlers (wc__get_random_bytes() and + * wc_crng_reseed()) can't call the heap, since the kernel heap will call + * them via get_random_u32(). + */ + if (current_totalAllocs != wc_MemStats_Ptr->totalAllocs) + return WC_TEST_RET_ENC_NC; +#endif + /* Parameter validation testing. */ ret = wc_RNG_GenerateBlock(NULL, block, sizeof(block)); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { @@ -27946,6 +28188,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t openSSL_evpMD_test(void) goto openSSL_evpMD_test_done; } + ret = wolfSSL_EVP_MD_CTX_cleanup(ctx); + if (ret != WOLFSSL_SUCCESS) { + ret = WC_TEST_RET_ENC_NC; + goto openSSL_evpMD_test_done; + } + ret = wolfSSL_EVP_DigestInit(ctx, wolfSSL_EVP_sha1()); if (ret != WOLFSSL_SUCCESS) { ret = WC_TEST_RET_ENC_NC; @@ -27973,6 +28221,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t openSSL_evpMD_test(void) goto openSSL_evpMD_test_done; } + ret = wolfSSL_EVP_MD_CTX_cleanup(ctx); + if (ret != WOLFSSL_SUCCESS) { + ret = WC_TEST_RET_ENC_NC; + goto openSSL_evpMD_test_done; + } + if (wolfSSL_EVP_DigestInit_ex(ctx, wolfSSL_EVP_sha1(), NULL) != WOLFSSL_SUCCESS) { ret = WC_TEST_RET_ENC_NC; goto openSSL_evpMD_test_done; @@ -27988,6 +28242,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t openSSL_evpMD_test(void) goto openSSL_evpMD_test_done; } + ret = wolfSSL_EVP_MD_CTX_cleanup(ctx); + if (ret != WOLFSSL_SUCCESS) { + ret = WC_TEST_RET_ENC_NC; + goto openSSL_evpMD_test_done; + } + ret = 0; /* got to success state without jumping to end with a fail */ openSSL_evpMD_test_done: From 79d1e6b295e82ba8fb5baa1e7ddaeb17d0c0b592 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 17:02:18 -0600 Subject: [PATCH 15/18] .github/workflows/trackmemory.yml: new workflow testing various configs with -DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY. --- .github/workflows/trackmemory.yml | 59 +++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/workflows/trackmemory.yml diff --git a/.github/workflows/trackmemory.yml b/.github/workflows/trackmemory.yml new file mode 100644 index 000000000..4def1759d --- /dev/null +++ b/.github/workflows/trackmemory.yml @@ -0,0 +1,59 @@ +name: WOLFSSL_TRACK_MEMORY Tests + +# START OF COMMON SECTION +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +jobs: + make_check: + strategy: + matrix: + config: [ + # Add new configs here + '--enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY"', + '--enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY"', + '--enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY"', +# Note the below smallstackcache tests are crucial coverage for the Linux kernel +# module, when targeting a kernel with the randomness patch (linuxkm/patches/) +# applied. +# +# Note, don't combine wolfEntropy with the full TLS cipher suite test -- the implicit wc_InitRng()s in each suite have an enormous CPU footprint. + '--enable-wolfEntropy --enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY -DNO_WOLFSSL_CIPHER_SUITE_TEST"', + '--enable-amdrand --enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY -DNO_WOLFSSL_CIPHER_SUITE_TEST"', + '--disable-asm --enable-wolfEntropy --enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY -DNO_WOLFSSL_CIPHER_SUITE_TEST"' + ] + name: make check + if: github.repository_owner == 'wolfssl' + runs-on: ubuntu-latest + # This should be a safe limit for the tests to run. + timeout-minutes: 6 + steps: + - uses: actions/checkout@v4 + name: Checkout wolfSSL + + - name: Test wolfSSL + run: | + ./autogen.sh + ./configure ${{ matrix.config }} + make -j 4 + make check + + - name: Print errors + if: ${{ failure() }} + run: | + for file in scripts/*.log + do + if [ -f "$file" ]; then + echo "${file}:" + cat "$file" + echo "========================================================================" + fi + done From e159c650eab72df9f1e5ca72beb778e6964e45af Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 17:03:17 -0600 Subject: [PATCH 16/18] .wolfssl_known_macro_extras: add CONFIG_CRYPTO_DRBG. --- .wolfssl_known_macro_extras | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 52270c6eb..bde418da4 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -65,6 +65,7 @@ CONFIG_CRYPTO_CBC CONFIG_CRYPTO_CTR CONFIG_CRYPTO_DH CONFIG_CRYPTO_DH_RFC7919_GROUPS +CONFIG_CRYPTO_DRBG CONFIG_CRYPTO_ECB CONFIG_CRYPTO_ECDH CONFIG_CRYPTO_ECDSA @@ -662,8 +663,8 @@ WOLFSSL_ALLOW_SERVER_SC_EXT WOLFSSL_ALLOW_TLS_SHA1 WOLFSSL_ALTERNATIVE_DOWNGRADE WOLFSSL_ALT_NAMES_NO_REV -WOLFSSL_ARM_ARCH_NEON_64BIT WOLFSSL_ARMASM_NEON_NO_TABLE_LOOKUP +WOLFSSL_ARM_ARCH_NEON_64BIT WOLFSSL_ASCON_UNROLL WOLFSSL_ASNC_CRYPT WOLFSSL_ASN_EXTRA From 33fc60101175be05514cbff10e899bb95b001ae1 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 16 Dec 2025 23:49:21 -0600 Subject: [PATCH 17/18] tweaks from PRBs results: tests/api.c: * remove inapt SSL_library_init() in test_wolfSSL_EVP_Cipher_extra(); * move TEST_X509_DECLS to follow TEST_DECL(test_wolfSSL_Init); tests/api/test_random.c: enlarge seed buffer in test_wc_RNG_TestSeed() to accommodate amdrand block size; tests/quic.c: wrap exercises in wolfSSL_Init()...wolfSSL_Cleanup(); tests/unit.c: in unit_test(), add several more fflush(stdout)s, report error from wolfSSL_Cleanup(), and fix line length; wolfcrypt/test/test.c: omit reseed test in _rng_test() if HAVE_INTEL_RDRAND or old FIPS, and use simplified random_test() if HAVE_INTEL_RDRAND; wolfssl/wolfcrypt/mem_track.h: add memList pointer in struct memoryStats, and set it in InitMemoryTracker(); wolfssl/wolfcrypt/settings.h: undefine WOLFSSL_SMALL_STACK_CACHE if WOLFSSL_SMALL_STACK is undefined; .github/workflows/trackmemory.yml: add --enable-intelrdseed scenario. --- .github/workflows/trackmemory.yml | 1 + tests/api.c | 7 +++---- tests/api/test_random.c | 2 +- tests/quic.c | 8 ++++++++ tests/unit.c | 23 +++++++++++++++++++---- wolfcrypt/test/test.c | 15 +++++++++------ wolfssl/wolfcrypt/mem_track.h | 6 ++++++ wolfssl/wolfcrypt/settings.h | 7 +++++++ 8 files changed, 54 insertions(+), 15 deletions(-) diff --git a/.github/workflows/trackmemory.yml b/.github/workflows/trackmemory.yml index 4def1759d..0c9f44cb4 100644 --- a/.github/workflows/trackmemory.yml +++ b/.github/workflows/trackmemory.yml @@ -27,6 +27,7 @@ jobs: # # Note, don't combine wolfEntropy with the full TLS cipher suite test -- the implicit wc_InitRng()s in each suite have an enormous CPU footprint. '--enable-wolfEntropy --enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY -DNO_WOLFSSL_CIPHER_SUITE_TEST"', + '--enable-intelrdseed --enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY -DNO_WOLFSSL_CIPHER_SUITE_TEST"', '--enable-amdrand --enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY -DNO_WOLFSSL_CIPHER_SUITE_TEST"', '--disable-asm --enable-wolfEntropy --enable-smallstackcache --enable-smallstack --enable-all CFLAGS="-DWC_RNG_SEED_CB -DWOLFSSL_TRACK_MEMORY -DWOLFSSL_DEBUG_MEMORY -DNO_WOLFSSL_CIPHER_SUITE_TEST"' ] diff --git a/tests/api.c b/tests/api.c index e4bb7d560..39e6f5ea3 100644 --- a/tests/api.c +++ b/tests/api.c @@ -22832,8 +22832,6 @@ static int test_wolfSSL_EVP_Cipher_extra(void) set_plain(plain, BUFFSZ * RECORDS); - SSL_library_init(); - ExpectNotNull(evp = EVP_CIPHER_CTX_new()); ExpectIntNE((ret = EVP_CipherInit(evp, type, NULL, iv, 0)), 0); @@ -41503,8 +41501,6 @@ TEST_CASE testCases[] = { TEST_MLDSA_DECLS, /* Signature API */ TEST_SIGNATURE_DECLS, - /* x509 */ - TEST_X509_DECLS, /* ASN */ TEST_ASN_DECLS, @@ -41562,6 +41558,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_Init), + /* x509 -- must appear after test_wolfSSL_Init(). */ + TEST_X509_DECLS, + TEST_DECL(test_dual_alg_support), TEST_DECL(test_dual_alg_crit_ext_support), diff --git a/tests/api/test_random.c b/tests/api/test_random.c index fa7c820c9..3b586559f 100644 --- a/tests/api/test_random.c +++ b/tests/api/test_random.c @@ -327,7 +327,7 @@ int test_wc_RNG_TestSeed(void) #if defined(HAVE_HASHDRBG) && \ (!(defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) - byte seed[16]; + byte seed[32]; byte i; #ifdef TEST_WC_RNG_TESTSEED_BAD_PARAMS diff --git a/tests/quic.c b/tests/quic.c index f3144b096..8fc5d5c43 100644 --- a/tests/quic.c +++ b/tests/quic.c @@ -1892,6 +1892,12 @@ int QuicTest(void) int ret = 0; #ifdef WOLFSSL_QUIC int verbose = 0; + + if (wolfSSL_Init() != WOLFSSL_SUCCESS) { + printf("wolfSSL_Init() failed in QuicTest()."); + return -1; + } + printf(" Begin QUIC Tests\n"); if ((ret = test_set_quic_method()) != TEST_SUCCESS) goto leave; @@ -1917,6 +1923,8 @@ leave: printf(" FAILED: some tests did not pass.\n"); } printf(" End QUIC Tests\n"); + + (void)wolfSSL_Cleanup(); #endif return ret == TEST_SUCCESS ? 0 : -1; } diff --git a/tests/unit.c b/tests/unit.c index 72c51f4ec..820388d6e 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -273,6 +273,7 @@ int unit_test(int argc, char** argv) } printf("wolfCrypt unit test completed successfully.\n\n"); + fflush(stdout); } #endif @@ -282,6 +283,7 @@ int unit_test(int argc, char** argv) { if (apiTesting) { ret = ApiTest(); + fflush(stdout); if (ret != 0) goto exit; } @@ -291,20 +293,25 @@ int unit_test(int argc, char** argv) } #ifdef WOLFSSL_W64_WRAPPER - if ((ret = w64wrapper_test()) != 0) { + ret = w64wrapper_test(); + fflush(stdout); + if (ret != 0) { fprintf(stderr, "w64wrapper test failed with %d\n", ret); goto exit; } #endif /* WOLFSSL_W64_WRAPPER */ #ifdef WOLFSSL_QUIC - if ((ret = QuicTest()) != 0) { + ret = QuicTest(); + fflush(stdout); + if (ret != 0) { fprintf(stderr, "quic test failed with %d\n", ret); goto exit; } #endif SrpTest(); + fflush(stdout); } #if !defined(NO_WOLFSSL_CIPHER_SUITE_TEST) && \ @@ -326,10 +333,18 @@ exit: #ifdef WOLFSSL_TRACK_MEMORY if (ret == 0) { - (void)wolfSSL_Cleanup(); + ret = wolfSSL_Cleanup(); /* no-op in a successful full run. */ + + if (ret == WOLFSSL_SUCCESS) + ret = 0; + else + fprintf(stderr, "wolfSSL_Cleanup() returned %d\n", ret); + if (wc_MemStats_Ptr->currentBytes > 0) { - fprintf(stderr, "WOLFSSL_TRACK_MEMORY: currentBytes after cleanup is %ld\n", wc_MemStats_Ptr->currentBytes); + fprintf(stderr, + "WOLFSSL_TRACK_MEMORY: currentBytes after cleanup is %ld\n", + wc_MemStats_Ptr->currentBytes); ret = MEMORY_E; } } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 8ae657436..f10242742 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -19693,7 +19693,9 @@ static wc_test_ret_t _rng_test(WC_RNG* rng) return WC_TEST_RET_ENC_EC(ret); } -#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) +#if defined(HAVE_HASHDRBG) && !defined(HAVE_INTEL_RDRAND) && \ + !defined(CUSTOM_RAND_GENERATE_BLOCK) && \ + !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(5,0,0)) /* Test periodic reseed dynamics. */ ((struct DRBG_internal *)rng->drbg)->reseedCtr = WC_RESEED_INTERVAL; @@ -19704,7 +19706,7 @@ static wc_test_ret_t _rng_test(WC_RNG* rng) if (((struct DRBG_internal *)rng->drbg)->reseedCtr == WC_RESEED_INTERVAL) return WC_TEST_RET_ENC_NC; -#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK */ +#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK && !HAVE_SELFTEST */ #if defined(WOLFSSL_TRACK_MEMORY) && defined(WOLFSSL_SMALL_STACK_CACHE) /* wc_RNG_GenerateBlock() must not allocate any memory in @@ -19797,7 +19799,8 @@ static wc_test_ret_t random_rng_test(void) return ret; } -#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) +#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) && \ + !defined(HAVE_INTEL_RDRAND) #if defined(WC_RNG_SEED_CB) && \ !(defined(ENTROPY_SCALE_FACTOR) || defined(SEED_BLOCK_SZ)) @@ -19940,7 +19943,7 @@ static wc_test_ret_t rng_seed_test(void) out: return ret; } -#endif /* WC_RNG_SEED_CB) && !(ENTROPY_SCALE_FACTOR || SEED_BLOCK_SZ) */ +#endif /* WC_RNG_SEED_CB && !(ENTROPY_SCALE_FACTOR || SEED_BLOCK_SZ) */ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) @@ -20060,7 +20063,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) return 0; } -#else +#else /* !HAVE_HASHDRBG || CUSTOM_RAND_GENERATE_BLOCK || HAVE_INTEL_RDRAND */ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) { @@ -20070,7 +20073,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) return random_rng_test(); } -#endif /* HAVE_HASHDRBG && !CUSTOM_RAND_GENERATE_BLOCK */ +#endif /* !HAVE_HASHDRBG || CUSTOM_RAND_GENERATE_BLOCK || HAVE_INTEL_RDRAND */ #endif /* WC_NO_RNG */ #ifndef MEM_TEST_SZ diff --git a/wolfssl/wolfcrypt/mem_track.h b/wolfssl/wolfcrypt/mem_track.h index 300c41cc0..8dcfee8b3 100644 --- a/wolfssl/wolfcrypt/mem_track.h +++ b/wolfssl/wolfcrypt/mem_track.h @@ -83,6 +83,8 @@ #define DO_MEM_LIST #endif +struct memoryList; + typedef struct memoryStats { long totalAllocs; /* number of allocations */ long totalDeallocs; /* number of deallocations */ @@ -98,6 +100,9 @@ typedef struct memoryStats { * by wolfCrypt_heap_peak_checkpoint() */ #endif +#ifdef DO_MEM_LIST + struct memoryList *memList; +#endif } memoryStats; typedef struct memHint { @@ -380,6 +385,7 @@ static WC_INLINE int InitMemoryTracker(void) #ifdef DO_MEM_LIST XMEMSET(&ourMemList, 0, sizeof(ourMemList)); + ourMemStats.memList = &ourMemList; pthread_mutex_unlock(&memLock); #endif diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 2f916b2c0..12a197615 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -4323,6 +4323,13 @@ extern void uITRON4_free(void *p) ; without staticmemory (WOLFSSL_STATIC_MEMORY) #endif +/* Undefine WOLFSSL_SMALL_STACK_CACHE if WOLFSSL_SMALL_STACK is undefined -- + * they only work together. + */ +#if defined(WOLFSSL_SMALL_STACK_CACHE) && !defined(WOLFSSL_SMALL_STACK) + #undef WOLFSSL_SMALL_STACK_CACHE +#endif + /* If malloc is disabled make sure it is also disabled in SP math */ #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_SP_NO_MALLOC) && \ (defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)) From fc7d4ffad4258a19585b4e27cb41df34c6b37e79 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 17 Dec 2025 11:07:22 -0600 Subject: [PATCH 18/18] PR#9545 20251211-DRBG-SHA2-smallstackcache-prealloc addressing peer review: clear dest if necessary in InitHandshakeHashesAndCopy(), style tweaks in random.c, explanatory comments in sha512.c. --- src/internal.c | 21 ++++++++++++++++----- wolfcrypt/src/random.c | 21 +++++++-------------- wolfcrypt/src/sha512.c | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/internal.c b/src/internal.c index 272d3ec37..da7557070 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7345,14 +7345,19 @@ int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source, { int ret; - if (source == NULL) + if ((ssl == NULL) || (source == NULL) || (destination == NULL)) return BAD_FUNC_ARG; - /* Note we can't call InitHandshakeHashes() here, because the copy methods - * overwrite the entire dest low level hash struct. With some hashes and - * settings (e.g. SHA-2 hashes with WOLFSSL_SMALL_STACK_CACHE), internal - * scratch buffers are preallocated at init and will leak if overwritten. + /* If *destination is already allocated, its constituent hashes need to be + * freed, else they would leak. To keep things simple, we reuse + * FreeHandshakeHashes(), which deallocates *destination. */ + if (*destination != NULL) { + HS_Hashes* tmp = ssl->hsHashes; + ssl->hsHashes = *destination; + FreeHandshakeHashes(ssl); + ssl->hsHashes = tmp; + } /* allocate handshake hashes */ *destination = (HS_Hashes*)XMALLOC(sizeof(HS_Hashes), ssl->heap, @@ -7361,6 +7366,12 @@ int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source, WOLFSSL_MSG("HS_Hashes Memory error"); return MEMORY_E; } + + /* Note we can't call InitHandshakeHashes() here, because the copy methods + * overwrite the entire dest low level hash struct. With some hashes and + * settings (e.g. SHA-2 hashes with WOLFSSL_SMALL_STACK_CACHE), internal + * scratch buffers are preallocated at init and will leak if overwritten. + */ XMEMSET(*destination, 0, sizeof(HS_Hashes)); /* now copy the source contents to the destination */ diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 34e7c5487..2945a88b9 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -735,9 +735,7 @@ static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 s const byte* nonce, word32 nonceSz, void* heap, int devId) { -#ifdef WOLFSSL_SMALL_STACK_CACHE int ret = DRBG_FAILURE; -#endif XMEMSET(drbg, 0, sizeof(DRBG_internal)); drbg->heap = heap; @@ -757,10 +755,9 @@ static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 s return ret; #endif - if (seed == NULL) - return 0; - else - return Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz); + if (seed != NULL) + ret = Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz); + return ret; } /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ @@ -815,11 +812,7 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, int ret = 0; #ifdef HAVE_HASHDRBG word32 seedSz = SEED_SZ + SEED_BLOCK_SZ; - #ifdef WOLFSSL_SMALL_STACK - byte* seed = NULL; - #else - byte seed[MAX_SEED_SZ]; - #endif + WC_DECLARE_VAR(seed, byte, MAX_SEED_SZ, rng->heap); int drbg_instantiated = 0; #ifdef WOLFSSL_SMALL_STACK_CACHE int drbg_scratch_instantiated = 0; @@ -981,8 +974,7 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #ifdef WOLFSSL_SMALL_STACK if (ret == 0) { - seed = (byte*)XMALLOC(MAX_SEED_SZ, rng->heap, - DYNAMIC_TYPE_SEED); + WC_ALLOC_VAR_EX(seed, byte, MAX_SEED_SZ, rng->heap, DYNAMIC_TYPE_SEED, WC_DO_NOTHING); if (seed == NULL) { ret = MEMORY_E; rng->status = DRBG_FAILED; @@ -1418,7 +1410,8 @@ static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg, } #ifdef WOLFSSL_SMALL_STACK_CACHE - (void)heap; (void)devId; + (void)heap; + (void)devId; if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz) != 0) { goto exit_rng_ht; diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index cf67478b2..2b777beb7 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -870,6 +870,10 @@ static int InitSha512_Family(wc_Sha512* sha512, void* heap, int devId, sha512->heap = heap; #ifdef WOLFSSL_SMALL_STACK_CACHE + /* This allocation combines the customary W buffer used by + * _Transform_Sha512() with additional buffer space used by + * wc_Sha512Transform(). + */ sha512->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE, sha512->heap, DYNAMIC_TYPE_DIGEST); if (sha512->W == NULL) @@ -1702,6 +1706,9 @@ int wc_Sha512Transform(wc_Sha512* sha, const unsigned char* data) #if defined(WOLFSSL_SMALL_STACK_CACHE) if (sha->W == NULL) return BAD_FUNC_ARG; + /* Skip over the initial `W' buffer at the start (used by + * _Transform_Sha512()). + */ buffer = sha->W + 16; #elif defined(WOLFSSL_SMALL_STACK) buffer = (word64*)XMALLOC(WC_SHA512_BLOCK_SIZE, sha->heap, @@ -1873,6 +1880,10 @@ static int InitSha384(wc_Sha384* sha384) #ifdef WOLFSSL_SMALL_STACK_CACHE if (sha384->W == NULL) { + /* This allocation combines the customary W buffer used by + * _Transform_Sha512() with additional buffer space used by + * wc_Sha512Transform(). + */ sha384->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE, sha384->heap, DYNAMIC_TYPE_DIGEST); if (sha384->W == NULL) @@ -2232,6 +2243,10 @@ int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst) XMEMCPY(dst, src, sizeof(wc_Sha512)); #ifdef WOLFSSL_SMALL_STACK_CACHE + /* This allocation combines the customary W buffer used by + * _Transform_Sha512() with additional buffer space used by + * wc_Sha512Transform(). + */ dst->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE, dst->heap, DYNAMIC_TYPE_DIGEST); if (dst->W == NULL) { @@ -2667,6 +2682,10 @@ int wc_Sha384Copy(wc_Sha384* src, wc_Sha384* dst) XMEMCPY(dst, src, sizeof(wc_Sha384)); #ifdef WOLFSSL_SMALL_STACK_CACHE + /* This allocation combines the customary W buffer used by + * _Transform_Sha512() with additional buffer space used by + * wc_Sha512Transform(). + */ dst->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA384_BLOCK_SIZE, dst->heap, DYNAMIC_TYPE_DIGEST); if (dst->W == NULL) {