diff --git a/src/dtls.c b/src/dtls.c index 3c2b4635af..eb5308103b 100644 --- a/src/dtls.c +++ b/src/dtls.c @@ -571,10 +571,21 @@ static void FindPskSuiteFromExt(const WOLFSSL* ssl, TLSX* extensions, byte psk_key[MAX_PSK_KEY_LEN]; word32 psk_keySz; byte foundSuite[SUITE_LEN]; + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register before the key is populated so any future path that + * fails to clear it before scope exit is caught. Baseline the + * buffer so it is defined at registration time. */ + XMEMSET(psk_key, 0, sizeof(psk_key)); + wc_MemZero_Add("FindPskSuiteFromExt psk_key", psk_key, + sizeof(psk_key)); + #endif ret = FindPskSuite(ssl, current, psk_key, &psk_keySz, suites->suites + i, &found, foundSuite); /* Clear the key just in case */ ForceZero(psk_key, sizeof(psk_key)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(psk_key, sizeof(psk_key)); + #endif if (ret == 0 && found) { pskInfo->cipherSuite0 = foundSuite[0]; pskInfo->cipherSuite = foundSuite[1]; diff --git a/src/pk.c b/src/pk.c index f4761a7418..fa6a5ae066 100644 --- a/src/pk.c +++ b/src/pk.c @@ -4933,6 +4933,13 @@ static int _DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub, if (privSz <= 0) { ret = WOLFSSL_FATAL_ERROR; } + #if defined(WOLFSSL_CHECK_MEM_ZERO) && !defined(WOLFSSL_SMALL_STACK) + /* Register as soon as the stack array holds the private key so any + * future path that fails to zeroize it before exit is caught. */ + else { + wc_MemZero_Add("_DH_compute_key priv", priv, (word32)privSz); + } + #endif } if (ret == 0) { /* Get the public key into the array. */ @@ -4996,6 +5003,9 @@ static int _DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub, { /* Zeroize sensitive data. */ ForceZero(priv, (word32)privSz); + #if defined(WOLFSSL_CHECK_MEM_ZERO) && !defined(WOLFSSL_SMALL_STACK) + wc_MemZero_Check(priv, sizeof(priv)); + #endif } } WC_FREE_VAR_EX(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); @@ -7226,6 +7236,14 @@ int wolfSSL_PEM_do_header(EncryptedInfo* cipher, unsigned char* data, long* len, if (passwordSz < 0) { ret = 0; } + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register as soon as the stack buffer holds the secret so any future + * path that fails to zeroize it before exit is caught. */ + else if (passwordSz > 0) { + wc_MemZero_Add("wolfSSL_PEM_do_header password", password, + (word32)passwordSz); + } + #endif } if (ret == 1) { @@ -7239,6 +7257,9 @@ int wolfSSL_PEM_do_header(EncryptedInfo* cipher, unsigned char* data, long* len, if (passwordSz > 0) { /* Ensure password is erased from memory. */ ForceZero(password, (word32)passwordSz); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(password, NAME_SZ); + #endif } return ret; @@ -7476,6 +7497,14 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, res = 0; } passwd = password; + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register as soon as the stack buffer holds the secret so any + * future path that fails to zeroize it before exit is caught. */ + if (passwdSz > 0) { + wc_MemZero_Add("pem_write_mem_pkcs8privatekey password", + password, (word32)passwdSz); + } + #endif } if (res == 1) { @@ -7489,6 +7518,9 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, /* Zeroize the password from memory. */ if ((password == passwd) && (passwdSz > 0)) { ForceZero(password, (word32)passwdSz); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(password, NAME_SZ); + #endif } } else if ((res == 1) && (enc == NULL)) { diff --git a/src/sniffer.c b/src/sniffer.c index a5bdf54d38..dcb1ee445a 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -7594,6 +7594,22 @@ static int parseKeyLogFile(const char* fileName, char* error) return WOLFSSL_SNIFFER_ERROR; } +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register the secret-bearing stack buffers as high as possible (right + * after the last early return that bypasses the ForceZeros, i.e. the + * fopen failure above) so any future path that fails to clear them before + * scope exit is caught. Every exit path below (the in-loop error return + * and the normal post-loop return) ForceZeros and Checks each of them, so + * exactly one Add is balanced by one Check. Baseline the not-yet-written + * buffers so they are defined at registration time (secretHex is already + * zero-initialized at declaration). */ + XMEMSET(secret, 0, sizeof(secret)); + XMEMSET(line, 0, sizeof(line)); + wc_MemZero_Add("parseKeyLogFile secret", secret, sizeof(secret)); + wc_MemZero_Add("parseKeyLogFile secretHex", secretHex, sizeof(secretHex)); + wc_MemZero_Add("parseKeyLogFile line", line, sizeof(line)); +#endif + while (fgets(line, (int)sizeof(line), file) != NULL) { /* RFC 9850 Section 1: ignore empty lines and lines whose first * character is the octothorpe ('#') comment marker. */ @@ -7658,6 +7674,11 @@ static int parseKeyLogFile(const char* fileName, char* error) ForceZero(secret, SECRET_LENGTH); ForceZero(secretHex, sizeof(secretHex)); ForceZero(line, sizeof(line)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(secret, sizeof(secret)); + wc_MemZero_Check(secretHex, sizeof(secretHex)); + wc_MemZero_Check(line, sizeof(line)); + #endif return ret; } } @@ -7666,6 +7687,11 @@ static int parseKeyLogFile(const char* fileName, char* error) ForceZero(secret, SECRET_LENGTH); ForceZero(secretHex, sizeof(secretHex)); ForceZero(line, sizeof(line)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(secret, sizeof(secret)); + wc_MemZero_Check(secretHex, sizeof(secretHex)); + wc_MemZero_Check(line, sizeof(line)); +#endif return 0; } diff --git a/src/tls13.c b/src/tls13.c index 24b15bea2d..ea7709d1e2 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1054,6 +1054,14 @@ int Tls13_Exporter(WOLFSSL* ssl, unsigned char *out, size_t outLen, return BAD_FUNC_ARG; } +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Poison and register firstExpand before it is written so that any path + * below (all of which funnel through cleanup) is covered. */ + XMEMSET(firstExpand, 0xff, sizeof(firstExpand)); + wc_MemZero_Add("Tls13_Exporter firstExpand", firstExpand, + sizeof(firstExpand)); +#endif + /* Derive-Secret(Secret, label, "") */ ret = Tls13HKDFExpandLabel(ssl, firstExpand, hashLen, ssl->arrays->exporterSecret, hashLen, @@ -1076,6 +1084,9 @@ int Tls13_Exporter(WOLFSSL* ssl, unsigned char *out, size_t outLen, * Hash(context_value); wipe both before the stack frame is reclaimed. */ ForceZero(firstExpand, sizeof(firstExpand)); ForceZero(hashOut, sizeof(hashOut)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(firstExpand, sizeof(firstExpand)); +#endif return ret; } #endif @@ -1533,6 +1544,11 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) WC_ALLOC_VAR_EX(key_dig, byte, MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_DIGEST, return MEMORY_E); +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(key_dig, 0xff, MAX_PRF_DIG); + wc_MemZero_Add("DeriveTls13Keys key_dig", key_dig, MAX_PRF_DIG); +#endif + if (side == ENCRYPT_AND_DECRYPT_SIDE) { provision = PROVISION_CLIENT_SERVER; } @@ -1665,7 +1681,8 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) WOLFSSL_SERVER_END); if (ret != 0) goto end; - i += ssl->specs.iv_size; + /* Server IV is the last key material written to key_dig, so i is not + * advanced here; the whole buffer is zeroed at end regardless. */ } /* Store keys and IVs but don't activate them. */ @@ -1717,7 +1734,9 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) #endif /* WOLFSSL_DTLS13 */ end: - ForceZero(key_dig, (word32)i); + /* Zero the whole key_dig buffer (not just the i bytes derived) so no + * key-schedule material can linger in the unused tail. */ + ForceZero(key_dig, MAX_PRF_DIG); #ifdef WOLFSSL_SMALL_STACK XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); #elif defined(WOLFSSL_CHECK_MEM_ZERO) @@ -6523,6 +6542,13 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz, (void)suite; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Poison and register binderKey up front; every exit below (including the + * error paths) funnels through the cleanup label which zeroes it. */ + XMEMSET(binderKey, 0xff, sizeof(binderKey)); + wc_MemZero_Add("DoPreSharedKeys binderKey", binderKey, sizeof(binderKey)); +#endif + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); if (ext == NULL) { WOLFSSL_MSG("No pre shared extension keys found"); @@ -6739,6 +6765,9 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz, cleanup: ForceZero(binderKey, sizeof(binderKey)); ForceZero(binder, sizeof(binder)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(binderKey, sizeof(binderKey)); +#endif WOLFSSL_LEAVE("DoPreSharedKeys", ret); return ret; diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 46a89a6ad8..9b0a59d4af 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -5886,7 +5886,13 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir) aes->ctx.cfd = -1; #endif #ifdef WOLFSSL_IMX6_CAAM_BLOB + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_AesSetKeyLocal local", local, sizeof(local)); + #endif ForceZero(local, sizeof(local)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(local, sizeof(local)); + #endif #endif return ret; #endif @@ -7483,6 +7489,9 @@ int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) byte ks[WC_AES_BLOCK_SIZE]; int ret = wc_Stm32_Aes_Ecb(aes, ks, (const byte*)aes->reg, WC_AES_BLOCK_SIZE, 1); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_AesCtrEncryptBlock ks", ks, sizeof(ks)); + #endif if (ret == 0) { xorbufout(out, in, ks, WC_AES_BLOCK_SIZE); } @@ -7493,6 +7502,9 @@ int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) ForceZero(out, WC_AES_BLOCK_SIZE); } ForceZero(ks, sizeof(ks)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(ks, sizeof(ks)); + #endif return ret; #else int ret = 0; @@ -8356,7 +8368,13 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) if (aes == NULL || key == NULL) { #ifdef WOLFSSL_IMX6_CAAM_BLOB +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_AesGcmSetKey local", local, sizeof(local)); +#endif ForceZero(local, sizeof(local)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(local, sizeof(local)); +#endif #endif return BAD_FUNC_ARG; } @@ -8508,7 +8526,13 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) #endif #ifdef WOLFSSL_IMX6_CAAM_BLOB +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_AesGcmSetKey local", local, sizeof(local)); +#endif ForceZero(local, sizeof(local)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(local, sizeof(local)); +#endif #endif return ret; } @@ -18719,6 +18743,15 @@ static WARN_UNUSED_RESULT int AesSivCipher( WC_DECLARE_VAR(aes, Aes, 1, 0); byte sivTmp[WC_AES_BLOCK_SIZE]; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Poison before the (conditional) fill so error paths that never write + * sivTmp still leave it defined; the used paths overwrite it. Register + * here (the highest point from which every exit funnels to the single + * ForceZero+Check below). */ + XMEMSET(sivTmp, 0xff, sizeof(sivTmp)); + wc_MemZero_Add("AesSivCipher sivTmp", sivTmp, sizeof(sivTmp)); +#endif + if (key == NULL || siv == NULL || out == NULL) { WOLFSSL_MSG("Bad parameter"); ret = BAD_FUNC_ARG; @@ -18798,6 +18831,9 @@ static WARN_UNUSED_RESULT int AesSivCipher( } ForceZero(sivTmp, sizeof(sivTmp)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(sivTmp, sizeof(sivTmp)); +#endif return ret; } @@ -19286,6 +19322,11 @@ static void AesGcmSivPolyvalInitSw(AesGcmSivPolyval* poly, const byte* h) /* m[8] = 1 * H = mulX_GHASH(ByteReverse(h)); successive halvings give the * power-of-two nibble entries. */ AesGcmSivByteReverse(hrev, h); +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* hrev now holds ByteReverse(H), the per-message hash key; register from + * its first write so every exit reaches the ForceZero+Check below. */ + wc_MemZero_Add("AesGcmSivPolyvalInitSw hrev", hrev, sizeof(hrev)); +#endif m[0x8][0] = AesGcmSivLoad64(hrev); m[0x8][1] = AesGcmSivLoad64(hrev + 8); AesGcmSivMulX64(&m[0x8][0], &m[0x8][1]); @@ -19308,6 +19349,9 @@ static void AesGcmSivPolyvalInitSw(AesGcmSivPolyval* poly, const byte* h) XMEMSET(poly->s, 0, sizeof(poly->s)); /* hrev held ByteReverse(H), the per-message hash key; wipe it. */ ForceZero(hrev, sizeof(hrev)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(hrev, sizeof(hrev)); +#endif } #else /* word32: GCM_WORD32 or no 64-bit type */ @@ -19413,6 +19457,11 @@ static void AesGcmSivPolyvalInitSw(AesGcmSivPolyval* poly, const byte* h) /* m[8] = 1 * H = mulX_GHASH(ByteReverse(h)); successive halvings give the * power-of-two nibble entries. */ AesGcmSivByteReverse(hrev, h); +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* hrev now holds ByteReverse(H), the per-message hash key; register from + * its first write so every exit reaches the ForceZero+Check below. */ + wc_MemZero_Add("AesGcmSivPolyvalInitSw hrev", hrev, sizeof(hrev)); +#endif m[0x8][0] = AesGcmSivLoad32(hrev); m[0x8][1] = AesGcmSivLoad32(hrev + 4); m[0x8][2] = AesGcmSivLoad32(hrev + 8); @@ -19439,6 +19488,9 @@ static void AesGcmSivPolyvalInitSw(AesGcmSivPolyval* poly, const byte* h) XMEMSET(poly->s, 0, sizeof(poly->s)); /* hrev held ByteReverse(H), the per-message hash key; wipe it. */ ForceZero(hrev, sizeof(hrev)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(hrev, sizeof(hrev)); +#endif } #endif /* POLYVAL multiply variant */ @@ -19604,6 +19656,10 @@ static void AesGcmSivPolyvalInit(AesGcmSivPolyval* poly, const byte* h) /* Prepare the hash key for the asm: byte-reversed * mulX_GHASH(ByteReverse(h)). */ AesGcmSivByteReverse(t, h); + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* t now holds the prepared hash key; register from first write. */ + wc_MemZero_Add("AesGcmSivPolyvalInit t", t, sizeof(t)); + #endif AesGcmSivMulX(t); AesGcmSivByteReverse(poly->hHw, t); XMEMSET(poly->s, 0, sizeof(poly->s)); @@ -19611,6 +19667,9 @@ static void AesGcmSivPolyvalInit(AesGcmSivPolyval* poly, const byte* h) poly->fn = fn; /* t held the prepared hash key; wipe the stack copy. */ ForceZero(t, sizeof(t)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(t, sizeof(t)); + #endif } return; } @@ -19633,6 +19692,13 @@ static void AesGcmSivPolyvalUpdate(AesGcmSivPolyval* poly, const byte* data, if (poly->fn != NULL) { word32 blocks = sz / WC_AES_BLOCK_SIZE; word32 partial = sz % WC_AES_BLOCK_SIZE; + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* block holds a padded AAD/plaintext tail; register from branch entry + * (baseline covers the partial == 0 case) so every exit of this branch + * reaches the ForceZero+Check below. */ + XMEMSET(block, 0, sizeof(block)); + wc_MemZero_Add("AesGcmSivPolyvalUpdate block", block, sizeof(block)); + #endif if (blocks > 0) { poly->fn(poly->s, poly->asmKey, data, blocks); data += blocks * WC_AES_BLOCK_SIZE; @@ -19644,8 +19710,20 @@ static void AesGcmSivPolyvalUpdate(AesGcmSivPolyval* poly, const byte* data, } /* block may have held a padded AAD/plaintext tail; wipe it. */ ForceZero(block, sizeof(block)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(block, sizeof(block)); + #endif return; } +#endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* block/rev hold byte-reversed AAD/plaintext blocks; register before the + * loops (baselines cover the sz == 0 case) so every exit reaches the + * ForceZero+Check below. */ + XMEMSET(block, 0, sizeof(block)); + XMEMSET(rev, 0, sizeof(rev)); + wc_MemZero_Add("AesGcmSivPolyvalUpdate block", block, sizeof(block)); + wc_MemZero_Add("AesGcmSivPolyvalUpdate rev", rev, sizeof(rev)); #endif while (sz >= WC_AES_BLOCK_SIZE) { AesGcmSivByteReverse(rev, data); @@ -19668,6 +19746,10 @@ static void AesGcmSivPolyvalUpdate(AesGcmSivPolyval* poly, const byte* data, /* block/rev held byte-reversed AAD/plaintext blocks; wipe them. */ ForceZero(block, sizeof(block)); ForceZero(rev, sizeof(rev)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(block, sizeof(block)); + wc_MemZero_Check(rev, sizeof(rev)); +#endif } /* Output the 16-byte POLYVAL result and wipe the key material and state. */ @@ -19694,6 +19776,12 @@ static WARN_UNUSED_RESULT int AesGcmSivDeriveKeys(Aes* kgk, const byte* nonce, * bytes of each AES output are concatenated to form the derived keys. */ XMEMCPY(block + 4, nonce, AES_GCM_SIV_NONCE_SZ); +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* out receives the derived auth/enc key bytes from each AES block. */ + XMEMSET(out, 0xff, sizeof(out)); + wc_MemZero_Add("AesGcmSivDeriveKeys out", out, sizeof(out)); +#endif + for (ctr = 0; ctr < 2; ctr++) { block[0] = (byte)ctr; block[1] = 0; block[2] = 0; block[3] = 0; @@ -19714,6 +19802,9 @@ static WARN_UNUSED_RESULT int AesGcmSivDeriveKeys(Aes* kgk, const byte* nonce, ForceZero(block, sizeof(block)); ForceZero(out, sizeof(out)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(out, sizeof(out)); +#endif return ret; } @@ -19734,6 +19825,14 @@ static WARN_UNUSED_RESULT int AesGcmSivCalcTag(Aes* enc, const byte* authKey, int i; int ret; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* s holds the POLYVAL result then the pre-encryption tag input. Register + * from the top (single exit funnels to the ForceZero+Check below); + * baseline keeps it defined for the checker. */ + XMEMSET(s, 0, sizeof(s)); + wc_MemZero_Add("AesGcmSivCalcTag s", s, sizeof(s)); +#endif + AesGcmSivPolyvalInit(&poly, authKey); AesGcmSivPolyvalUpdate(&poly, aad, aadSz); AesGcmSivPolyvalUpdate(&poly, plain, plainSz); @@ -19761,6 +19860,9 @@ static WARN_UNUSED_RESULT int AesGcmSivCalcTag(Aes* enc, const byte* authKey, ret = wc_AesEncrypt(enc, s, tag); ForceZero(s, sizeof(s)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(s, sizeof(s)); +#endif return ret; } @@ -19777,6 +19879,13 @@ static WARN_UNUSED_RESULT int AesGcmSivCtr(Aes* enc, const byte* tag, word32 c; int ret = 0; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* ks holds the AES-CTR keystream block; register from the top (single + * exit funnels to the ForceZero+Check below). */ + XMEMSET(ks, 0, sizeof(ks)); + wc_MemZero_Add("AesGcmSivCtr ks", ks, sizeof(ks)); +#endif + XMEMCPY(ctrBlock, tag, WC_AES_BLOCK_SIZE); ctrBlock[WC_AES_BLOCK_SIZE - 1] |= 0x80; @@ -19824,6 +19933,9 @@ static WARN_UNUSED_RESULT int AesGcmSivCtr(Aes* enc, const byte* tag, ForceZero(ks, sizeof(ks)); ForceZero(ctrBlock, sizeof(ctrBlock)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(ks, sizeof(ks)); +#endif return ret; } @@ -19869,6 +19981,17 @@ int wc_AesGcmSivEncrypt(const byte* key, word32 keySz, const byte* nonce, byte tagTmp[AES_GCM_SIV_TAG_SZ]; int ret; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Derived per-message MAC key, encryption key, and tag. Register from the + * top; every exit funnels to the shared ForceZero+Check block below. */ + XMEMSET(authKey, 0, sizeof(authKey)); + XMEMSET(encKey, 0, sizeof(encKey)); + XMEMSET(tagTmp, 0, sizeof(tagTmp)); + wc_MemZero_Add("wc_AesGcmSivEncrypt authKey", authKey, sizeof(authKey)); + wc_MemZero_Add("wc_AesGcmSivEncrypt encKey", encKey, sizeof(encKey)); + wc_MemZero_Add("wc_AesGcmSivEncrypt tagTmp", tagTmp, sizeof(tagTmp)); +#endif + ret = AesGcmSivCheckArgs(key, keySz, nonce, nonceSz, aad, aadSz, in, inSz, out, tag, tagSz); @@ -19913,6 +20036,11 @@ int wc_AesGcmSivEncrypt(const byte* key, word32 keySz, const byte* nonce, ForceZero(authKey, sizeof(authKey)); ForceZero(encKey, sizeof(encKey)); ForceZero(tagTmp, sizeof(tagTmp)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(authKey, sizeof(authKey)); + wc_MemZero_Check(encKey, sizeof(encKey)); + wc_MemZero_Check(tagTmp, sizeof(tagTmp)); +#endif return ret; } @@ -19934,6 +20062,18 @@ int wc_AesGcmSivDecrypt(const byte* key, word32 keySz, const byte* nonce, byte expTag[AES_GCM_SIV_TAG_SZ]; int ret; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Derived per-message MAC key, encryption key, and recomputed tag. + * Register from the top; every exit funnels to the shared ForceZero+Check + * block below. */ + XMEMSET(authKey, 0, sizeof(authKey)); + XMEMSET(encKey, 0, sizeof(encKey)); + XMEMSET(expTag, 0, sizeof(expTag)); + wc_MemZero_Add("wc_AesGcmSivDecrypt authKey", authKey, sizeof(authKey)); + wc_MemZero_Add("wc_AesGcmSivDecrypt encKey", encKey, sizeof(encKey)); + wc_MemZero_Add("wc_AesGcmSivDecrypt expTag", expTag, sizeof(expTag)); +#endif + ret = AesGcmSivCheckArgs(key, keySz, nonce, nonceSz, aad, aadSz, in, inSz, out, tag, tagSz); @@ -19980,6 +20120,11 @@ int wc_AesGcmSivDecrypt(const byte* key, word32 keySz, const byte* nonce, ForceZero(authKey, sizeof(authKey)); ForceZero(encKey, sizeof(encKey)); ForceZero(expTag, sizeof(expTag)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(authKey, sizeof(authKey)); + wc_MemZero_Check(encKey, sizeof(encKey)); + wc_MemZero_Check(expTag, sizeof(expTag)); +#endif return ret; } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index cbe149b91d..a1f9f14825 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33513,6 +33513,13 @@ static int eccToPKCS8(ecc_key* key, byte* output, word32* outLen, return MEMORY_E; #endif XMEMSET(tmpDer, 0, ECC_BUFSIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Track tmpDer from the point it is zeroed; it will hold a plaintext + * copy of the ECC private key. Registering here (rather than after it is + * populated) widens the window so any path that reaches 'exit' without a + * ForceZero is caught. Every exit below is a 'goto exit'. */ + wc_MemZero_Add("eccToPKCS8 tmpDer", tmpDer, ECC_BUFSIZE); +#endif ret = wc_BuildEccKeyDer(key, tmpDer, &sz, includePublic, 0); if (ret < 0) { @@ -33551,7 +33558,12 @@ static int eccToPKCS8(ecc_key* key, byte* output, word32* outLen, * it before releasing (or before the stack buffer goes out of scope). */ ForceZero(tmpDer, ECC_BUFSIZE); #ifndef WOLFSSL_NO_MALLOC + /* Heap build: XFREE (wolfSSL_Free) auto-runs wc_MemZero_Check over the + * freed block, so no explicit check is needed here. */ XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); +#elif defined(WOLFSSL_CHECK_MEM_ZERO) + /* Stack build: tmpDer is not freed, so verify+deregister explicitly. */ + wc_MemZero_Check(tmpDer, ECC_BUFSIZE); #endif return ret; diff --git a/wolfcrypt/src/blake2b.c b/wolfcrypt/src/blake2b.c index a0d2dad342..4456fe8c06 100644 --- a/wolfcrypt/src/blake2b.c +++ b/wolfcrypt/src/blake2b.c @@ -502,6 +502,9 @@ int wc_Blake2bHmacInit(Blake2b* b2b, const byte* key, size_t key_len) return BAD_FUNC_ARG; XMEMSET(x_key, 0, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_Blake2bHmacInit x_key", x_key, sizeof(x_key)); +#endif if (key_len > BLAKE2B_BLOCKBYTES) { ret = wc_InitBlake2b(b2b, BLAKE2B_OUTBYTES); @@ -524,6 +527,9 @@ int wc_Blake2bHmacInit(Blake2b* b2b, const byte* key, size_t key_len) ret = wc_Blake2bUpdate(b2b, x_key, BLAKE2B_BLOCKBYTES); ForceZero(x_key, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(x_key, sizeof(x_key)); +#endif return ret; } @@ -554,14 +560,25 @@ int wc_Blake2bHmacFinal(Blake2b* b2b, const byte* key, size_t key_len, return BUFFER_E; XMEMSET(x_key, 0, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_Blake2bHmacFinal x_key", x_key, sizeof(x_key)); +#endif if (key_len > BLAKE2B_BLOCKBYTES) { +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(&keyHash, 0, sizeof(keyHash)); + wc_MemZero_Add("wc_Blake2bHmacFinal keyHash", &keyHash, + sizeof(keyHash)); +#endif ret = wc_InitBlake2b(&keyHash, BLAKE2B_OUTBYTES); if (ret == 0) ret = wc_Blake2bUpdate(&keyHash, key, (word32)key_len); if (ret == 0) ret = wc_Blake2bFinal(&keyHash, x_key, 0); ForceZero(&keyHash, sizeof(keyHash)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(&keyHash, sizeof(keyHash)); +#endif } else { XMEMCPY(x_key, key, key_len); } @@ -584,6 +601,9 @@ int wc_Blake2bHmacFinal(Blake2b* b2b, const byte* key, size_t key_len, ret = wc_Blake2bFinal(b2b, out, 0); ForceZero(x_key, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(x_key, sizeof(x_key)); +#endif return ret; } diff --git a/wolfcrypt/src/blake2s.c b/wolfcrypt/src/blake2s.c index 0d2b56da6f..860268a624 100644 --- a/wolfcrypt/src/blake2s.c +++ b/wolfcrypt/src/blake2s.c @@ -499,6 +499,9 @@ int wc_Blake2sHmacInit(Blake2s* b2s, const byte* key, size_t key_len) return BAD_FUNC_ARG; XMEMSET(x_key, 0, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_Blake2sHmacInit x_key", x_key, sizeof(x_key)); +#endif if (key_len > BLAKE2S_BLOCKBYTES) { ret = wc_InitBlake2s(b2s, BLAKE2S_OUTBYTES); @@ -521,6 +524,9 @@ int wc_Blake2sHmacInit(Blake2s* b2s, const byte* key, size_t key_len) ret = wc_Blake2sUpdate(b2s, x_key, BLAKE2S_BLOCKBYTES); ForceZero(x_key, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(x_key, sizeof(x_key)); +#endif return ret; } @@ -551,14 +557,25 @@ int wc_Blake2sHmacFinal(Blake2s* b2s, const byte* key, size_t key_len, return BUFFER_E; XMEMSET(x_key, 0, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_Blake2sHmacFinal x_key", x_key, sizeof(x_key)); +#endif if (key_len > BLAKE2S_BLOCKBYTES) { +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(&keyHash, 0, sizeof(keyHash)); + wc_MemZero_Add("wc_Blake2sHmacFinal keyHash", &keyHash, + sizeof(keyHash)); +#endif ret = wc_InitBlake2s(&keyHash, BLAKE2S_OUTBYTES); if (ret == 0) ret = wc_Blake2sUpdate(&keyHash, key, (word32)key_len); if (ret == 0) ret = wc_Blake2sFinal(&keyHash, x_key, 0); ForceZero(&keyHash, sizeof(keyHash)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(&keyHash, sizeof(keyHash)); +#endif } else { XMEMCPY(x_key, key, key_len); } @@ -581,6 +598,9 @@ int wc_Blake2sHmacFinal(Blake2s* b2s, const byte* key, size_t key_len, ret = wc_Blake2sFinal(b2s, out, 0); ForceZero(x_key, sizeof(x_key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(x_key, sizeof(x_key)); +#endif return ret; } diff --git a/wolfcrypt/src/chacha.c b/wolfcrypt/src/chacha.c index bc4ec134ec..4e303049bf 100644 --- a/wolfcrypt/src/chacha.c +++ b/wolfcrypt/src/chacha.c @@ -528,11 +528,31 @@ int wc_XChacha_SetKey(ChaCha *ctx, XMEMSET(iv, 0, 4); XMEMCPY(iv + 4, nonce + 16, 8); - if ((ret = wc_Chacha_SetIV(ctx, iv, counter)) < 0) + /* k now holds the HChacha-derived subkey and iv the derived IV; register + * from here (their first-written point) so the error return below is also + * covered. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_XChacha_SetKey k", k, sizeof k); + wc_MemZero_Add("wc_XChacha_SetKey iv", iv, sizeof iv); +#endif + + if ((ret = wc_Chacha_SetIV(ctx, iv, counter)) < 0) { + /* k and iv hold derived key material - wipe before erroring out. */ + ForceZero(k, sizeof k); + ForceZero(iv, sizeof iv); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(k, sizeof k); + wc_MemZero_Check(iv, sizeof iv); + #endif return ret; + } ForceZero(k, sizeof k); ForceZero(iv, sizeof iv); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(k, sizeof k); + wc_MemZero_Check(iv, sizeof iv); +#endif return 0; } diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 5a7ebd978b..fbe8eac447 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -166,6 +166,12 @@ int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead, /* setup aead context */ XMEMSET(aead, 0, sizeof(ChaChaPoly_Aead)); XMEMSET(authKey, 0, sizeof(authKey)); + /* authKey has a zero baseline above; register here (past the arg check) + * so every exit funnels to the single ForceZero+Check below. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_ChaCha20Poly1305_Init authKey", authKey, + sizeof(authKey)); +#endif aead->isEncrypt = isEncrypt ? 1 : 0; /* Initialize the ChaCha20 context (key and iv) */ @@ -199,6 +205,9 @@ int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead, } ForceZero(authKey, sizeof(authKey)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(authKey, sizeof(authKey)); +#endif return ret; } @@ -342,6 +351,10 @@ int wc_XChaCha20Poly1305_Init( XMEMSET(authKey, 0, sizeof authKey); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("xchacha20poly1305 authKey", authKey, sizeof authKey); +#endif + /* Create the Poly1305 key */ if ((ret = wc_Chacha_Process(&aead->chacha, authKey, authKey, (word32)sizeof authKey)) < 0) @@ -367,6 +380,9 @@ int wc_XChaCha20Poly1305_Init( out: ForceZero(authKey, sizeof(authKey)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(authKey, sizeof(authKey)); +#endif return ret; } diff --git a/wolfcrypt/src/cmac.c b/wolfcrypt/src/cmac.c index cc05015d65..ff3e29feb3 100644 --- a/wolfcrypt/src/cmac.c +++ b/wolfcrypt/src/cmac.c @@ -238,18 +238,23 @@ static int _InitCmac_common(Cmac* cmac, const byte* key, word32 keySz, byte l[WC_AES_BLOCK_SIZE]; XMEMSET(l, 0, WC_AES_BLOCK_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("InitInternal l", l, WC_AES_BLOCK_SIZE); +#endif #ifndef HAVE_SELFTEST ret = wc_AesEncryptDirect(&cmac->aes, l, l); if (ret == 0) { ShiftAndXorRb(cmac->k1, l); ShiftAndXorRb(cmac->k2, cmac->k1); - ForceZero(l, WC_AES_BLOCK_SIZE); } #else wc_AesEncryptDirect(&cmac->aes, l, l); ShiftAndXorRb(cmac->k1, l); ShiftAndXorRb(cmac->k2, cmac->k1); +#endif ForceZero(l, WC_AES_BLOCK_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(l, WC_AES_BLOCK_SIZE); #endif } break; diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index 0260f07bab..f5ad930aaf 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -248,6 +248,18 @@ static int curve25519_smul_blind(byte* rp, const byte* n, const byte* p, SAVE_VECTOR_REGISTERS(return _svr_ret;); +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register the blinding scalar/value buffers up front (but below the + * SAVE_VECTOR_REGISTERS early return) so every path to the cleanup + * ForceZero is checked. XMEMSET makes them defined before first use. */ + XMEMSET(a, 0, sizeof(a)); + XMEMSET(n_a, 0, sizeof(n_a)); + XMEMSET(rz, 0, sizeof(rz)); + wc_MemZero_Add("curve25519_smul_blind a", a, sizeof(a)); + wc_MemZero_Add("curve25519_smul_blind n_a", n_a, sizeof(n_a)); + wc_MemZero_Add("curve25519_smul_blind rz", rz, sizeof(rz)); +#endif + /* Generate random z. */ for (cnt = 0; cnt < WOLFSSL_CURVE25519_BLINDING_RAND_CNT; cnt++) { ret = wc_RNG_GenerateBlock(rng, rz, sizeof(rz)); @@ -288,6 +300,11 @@ static int curve25519_smul_blind(byte* rp, const byte* n, const byte* p, ForceZero(a, sizeof(a)); ForceZero(n_a, sizeof(n_a)); ForceZero(rz, sizeof(rz)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rz, sizeof(rz)); + wc_MemZero_Check(n_a, sizeof(n_a)); + wc_MemZero_Check(a, sizeof(a)); +#endif RESTORE_VECTOR_REGISTERS(); @@ -810,6 +827,11 @@ int wc_curve25519_shared_secret_ex(curve25519_key* private_key, #endif } #endif /* FREESCALE_LTC_ECC */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Past the SAVE_VECTOR_REGISTERS early-return: o now holds the shared + * secret and every remaining path reaches the ForceZero below. */ + wc_MemZero_Add("wc_curve25519_shared_secret_ex o", &o, sizeof(o)); +#endif #ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK if (ret == 0) { int i; @@ -828,6 +850,9 @@ int wc_curve25519_shared_secret_ex(curve25519_key* private_key, } ForceZero(&o, sizeof(o)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(&o, sizeof(o)); +#endif } return ret; diff --git a/wolfcrypt/src/curve448.c b/wolfcrypt/src/curve448.c index 1247abc2a5..cce2e1beb0 100644 --- a/wolfcrypt/src/curve448.c +++ b/wolfcrypt/src/curve448.c @@ -166,6 +166,13 @@ int wc_curve448_shared_secret_ex(curve448_key* private_key, int ret = 0; int i; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register the shared-secret buffer up front (no early return bypasses the + * cleanup ForceZero) so every path is checked. XMEMSET makes it defined. */ + XMEMSET(o, 0, sizeof(o)); + wc_MemZero_Add("wc_curve448_shared_secret_ex o", o, CURVE448_PUB_KEY_SIZE); +#endif + /* sanity check */ if ((private_key == NULL) || (public_key == NULL) || (out == NULL) || (outLen == NULL) || (*outLen < CURVE448_PUB_KEY_SIZE)) { @@ -206,6 +213,9 @@ int wc_curve448_shared_secret_ex(curve448_key* private_key, } ForceZero(o, CURVE448_PUB_KEY_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(o, CURVE448_PUB_KEY_SIZE); +#endif return ret; } diff --git a/wolfcrypt/src/dsa.c b/wolfcrypt/src/dsa.c index c9caf21306..1561f2ad17 100644 --- a/wolfcrypt/src/dsa.c +++ b/wolfcrypt/src/dsa.c @@ -261,6 +261,14 @@ int wc_MakeDsaKey(WC_RNG *rng, DsaKey *dsa) } #endif +#if !(defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + /* cBuf will hold the random value that becomes the private key x. + * Register early so any future path that skips the ForceZero is caught. */ + XMEMSET(cBuf, 0, (size_t)cSz); + wc_MemZero_Add("DsaGenerateKeyPair cBuf", cBuf, (size_t)cSz); +#endif + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) if ((tmpQ = (mp_int *)XMALLOC(sizeof(*tmpQ), dsa->heap, DYNAMIC_TYPE_TMP_BUFFER)) == NULL) @@ -318,6 +326,10 @@ int wc_MakeDsaKey(WC_RNG *rng, DsaKey *dsa) } ForceZero(cBuf, (word32)cSz); +#if !(defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(cBuf, (size_t)cSz); +#endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); if (tmpQ != NULL) { @@ -850,6 +862,14 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, break; } +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + /* buffer will hold the secret nonce k and blinding value b. Register + * now (past the MP_INIT_E exit) so any later path that skips the + * ForceZero is caught. */ + XMEMSET(buffer, 0, halfSz); + wc_MemZero_Add("wc_DsaSign buffer", buffer, halfSz); +#endif + qMinus1 = kInv; /* NIST FIPS 186-4: B.2.2 @@ -1089,6 +1109,9 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, #else /* !WOLFSSL_SMALL_STACK */ if (ret != WC_NO_ERR_TRACE(MP_INIT_E)) { ForceZero(buffer, halfSz); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(buffer, halfSz); +#endif mp_forcezero(kInv); mp_forcezero(k); #ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 117adfd5ae..5c29f88c94 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -1600,10 +1600,19 @@ static int xil_mpi_import(mp_int *mpi, WC_ALLOC_VAR_EX(buf, byte, len, heap, DYNAMIC_TYPE_PRIVATE_KEY, return MEMORY_E); +#if defined(WOLFSSL_CHECK_MEM_ZERO) && !defined(WOLFSSL_SMALL_STACK) + /* Register the stack buffer before it is filled so any future exit before + * the ForceZero is checked. XMEMSET makes it defined for registration. */ + XMEMSET(buf, 0, len); + wc_MemZero_Add("xil_mpi_import buf", buf, len); +#endif buf_reverse(buf, inbuf, len); err = mp_read_unsigned_bin(mpi, buf, len); ForceZero(buf, len); +#if defined(WOLFSSL_CHECK_MEM_ZERO) && !defined(WOLFSSL_SMALL_STACK) + wc_MemZero_Check(buf, len); +#endif WC_FREE_VAR_EX(buf, heap, DYNAMIC_TYPE_PRIVATE_KEY); return err; } @@ -8334,6 +8343,12 @@ int wc_ecc_dev_make_key(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) wrapped = scratch + (3 * MAX_ECC_BYTES); #endif +#if defined(WOLFSSL_CHECK_MEM_ZERO) && !defined(WOLFSSL_SMALL_STACK) + /* Register the stack private-key buffer before keygen/export so any exit + * before the ForceZero is checked. XMEMSET makes it defined. */ + XMEMSET(d, 0, MAX_ECC_BYTES); + wc_MemZero_Add("wc_ecc_dev_make_key d", d, MAX_ECC_BYTES); +#endif ret = wc_ecc_init_ex(tmp, key->heap, INVALID_DEVID); if (ret == 0) { tmpInit = 1; @@ -8358,6 +8373,9 @@ int wc_ecc_dev_make_key(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) } ForceZero(d, MAX_ECC_BYTES); +#if defined(WOLFSSL_CHECK_MEM_ZERO) && !defined(WOLFSSL_SMALL_STACK) + wc_MemZero_Check(d, MAX_ECC_BYTES); +#endif if (tmpInit) { wc_ecc_free(tmp); } diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index 7501ab96e3..4a0bc1257d 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -566,8 +566,21 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out, } *outLen = ED25519_SIG_SIZE; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register the secret nonce/expanded-key buffers up front so that any exit + * path from here to the ForceZero below is checked for proper zeroization. + * XMEMSET gives them a defined value before the hash steps fill them. */ + XMEMSET(az, 0, sizeof(az)); + XMEMSET(nonce, 0, sizeof(nonce)); + wc_MemZero_Add("wc_ed25519_sign_msg_ex az", az, sizeof(az)); + wc_MemZero_Add("wc_ed25519_sign_msg_ex nonce", nonce, sizeof(nonce)); +#endif + #ifdef WOLFSSL_EDDSA_CHECK_PRIV_ON_SIGN XMEMCPY(orig_k, key->k, ED25519_KEY_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_ed25519_sign_msg_ex orig_k", orig_k, sizeof(orig_k)); +#endif #endif /* step 1: create nonce to use where nonce is r in @@ -681,6 +694,10 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out, ForceZero(az, sizeof(az)); ForceZero(nonce, sizeof(nonce)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(nonce, sizeof(nonce)); + wc_MemZero_Check(az, sizeof(az)); +#endif #ifdef WOLFSSL_EDDSA_CHECK_PRIV_ON_SIGN /* belongs to the software path: orig_k snapshots the key the software @@ -694,6 +711,9 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out, ret = ctMaskGT(c, 0) & SIG_VERIFY_E; } ForceZero(orig_k, sizeof(orig_k)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(orig_k, sizeof(orig_k)); +#endif #endif #endif /* WOLFSSL_SE050 */ diff --git a/wolfcrypt/src/ed448.c b/wolfcrypt/src/ed448.c index b25e3ff23f..08374ba446 100644 --- a/wolfcrypt/src/ed448.c +++ b/wolfcrypt/src/ed448.c @@ -442,6 +442,20 @@ int wc_ed448_sign_msg_ex(const byte* in, word32 inLen, byte* out, WC_DECLARE_VAR(sha, wc_Shake, 1, key ? key->heap : NULL); #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register the secret nonce/expanded-key buffers up front so that any exit + * path from here to the ForceZero below is checked for proper zeroization. + * XMEMSET gives them a defined value before the hash steps fill them. */ + XMEMSET(az, 0, sizeof(az)); + XMEMSET(nonce, 0, sizeof(nonce)); + wc_MemZero_Add("wc_ed448_sign_msg_ex az", az, sizeof(az)); + wc_MemZero_Add("wc_ed448_sign_msg_ex nonce", nonce, sizeof(nonce)); +#ifdef WOLFSSL_EDDSA_CHECK_PRIV_ON_SIGN + XMEMSET(orig_k, 0, sizeof(orig_k)); + wc_MemZero_Add("wc_ed448_sign_msg_ex orig_k", orig_k, sizeof(orig_k)); +#endif +#endif + /* sanity check on arguments */ if ((in == NULL) || (out == NULL) || (outLen == NULL) || (key == NULL) || ((context == NULL) && (contextLen != 0))) { @@ -579,10 +593,17 @@ int wc_ed448_sign_msg_ex(const byte* in, word32 inLen, byte* out, ret = ctMaskGT(c, 0) & SIG_VERIFY_E; } ForceZero(orig_k, sizeof(orig_k)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(orig_k, sizeof(orig_k)); +#endif #endif ForceZero(az, sizeof(az)); ForceZero(nonce, sizeof(nonce)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(nonce, sizeof(nonce)); + wc_MemZero_Check(az, sizeof(az)); +#endif return ret; } diff --git a/wolfcrypt/src/falcon.c b/wolfcrypt/src/falcon.c index 071b716793..14c25db845 100644 --- a/wolfcrypt/src/falcon.c +++ b/wolfcrypt/src/falcon.c @@ -28,6 +28,7 @@ #include #include #include +#include /* fpr / FFT / poly seam declarations, folded in from the former internal * wc_falcon_{fpr,fft,poly}.h so the native Falcon implementation is a single * translation unit (the AVX2/NEON FFT backends at the end of this file @@ -4246,6 +4247,11 @@ int falcon_prng_init(falcon_prng* p, WC_RNG* rng) p->err = 0; ret = wc_RNG_GenerateBlock(rng, seed, (word32)sizeof(seed)); + /* seed now holds the secret PRNG seed; register before the init/absorb + * steps so no future early-exit can leak it unzeroed. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("falcon prng seed", seed, (word32)sizeof(seed)); +#endif if (ret == 0) { ret = wc_InitShake256(&p->shake, NULL, INVALID_DEVID); if (ret == 0) { @@ -4262,6 +4268,9 @@ int falcon_prng_init(falcon_prng* p, WC_RNG* rng) } } ForceZero(seed, (word32)sizeof(seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seed, (word32)sizeof(seed)); +#endif return ret; } @@ -4552,19 +4561,28 @@ static int falcon_rng_init(falcon_rng* r, WC_RNG* rng, void* heap) if (ret != 0) { return ret; } + /* seed now holds the secret key material; register it before the init / + * absorb steps so an error path cannot leak it unzeroed. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("falcon rng seed", seed, sizeof(seed)); +#endif ret = wc_InitShake256(&r->shake, heap, INVALID_DEVID); - if (ret != 0) { - return ret; - } - ret = wc_Shake256_Absorb(&r->shake, seed, (word32)sizeof(seed)); - if (ret != 0) { - wc_Shake256_Free(&r->shake); - return ret; + if (ret == 0) { + ret = wc_Shake256_Absorb(&r->shake, seed, (word32)sizeof(seed)); + if (ret != 0) { + wc_Shake256_Free(&r->shake); + } + else { + /* Force a squeeze on the first extraction. */ + r->ptr = sizeof(r->buf); + } } - /* Force a squeeze on the first extraction. */ - r->ptr = sizeof(r->buf); - wc_ForceZero(seed, sizeof(seed)); /* seed determines the secret key */ - return 0; + /* seed determines the secret key: zeroed on every path below. */ + wc_ForceZero(seed, sizeof(seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seed, sizeof(seed)); +#endif + return ret; } static void falcon_rng_free(falcon_rng* r) @@ -8243,6 +8261,14 @@ int falcon_native_sign_msg(const byte* in, word32 inLen, byte* out, word32* outL } heap = key->heap; + /* spc may hold seed-derived sampler state; baseline-zero and register it + * before the arena/decode/sampler work so every goto-out and any future + * early-exit path is covered by the check. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(&spc, 0, sizeof(spc)); + wc_MemZero_Add("falcon sign spc", &spc, sizeof(spc)); +#endif + /* One allocation backs every sign buffer (the working set is >100KB at * Falcon-1024, so it stays on the heap in all builds). Ordered by decreasing * alignment -- fpr (expanded, tmp), then word16 (c, s2), then sword8 @@ -8360,6 +8386,9 @@ int falcon_native_sign_msg(const byte* in, word32 inLen, byte* out, word32* outL /* Always zeroize: the SHAKE sponge may hold seed-derived state even if * falcon_sampler_init failed after absorbing the seed. */ ForceZero(&spc, sizeof(spc)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(&spc, sizeof(spc)); +#endif /* One ForceZero + free covers every secret in the arena (f/g/F/G, the * expanded basis, and the sign scratch). */ if (arena != NULL) { diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index 3ed489dfaf..e5267c1cbb 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -1903,6 +1903,9 @@ int wolfSSL_GetHmacMaxSize(void) } XMEMSET(tmp, 0, WC_MAX_DIGEST_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_HKDF_Expand_ex tmp", tmp, WC_MAX_DIGEST_SIZE); +#endif while (outIdx < outSz) { word32 tmpSz = (n == 1) ? 0 : hashSz; @@ -1937,6 +1940,9 @@ int wolfSSL_GetHmacMaxSize(void) } ForceZero(tmp, WC_MAX_DIGEST_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(tmp, WC_MAX_DIGEST_SIZE); +#endif wc_HmacFree(myHmac); WC_FREE_VAR_EX(myHmac, NULL, DYNAMIC_TYPE_HMAC); @@ -1989,6 +1995,10 @@ int wolfSSL_GetHmacMaxSize(void) return ret; hashSz = (word32)ret; +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(prk, 0, WC_MAX_DIGEST_SIZE); + wc_MemZero_Add("wc_HKDF_ex prk", prk, WC_MAX_DIGEST_SIZE); +#endif ret = wc_HKDF_Extract_ex(type, salt, saltSz, inKey, inKeySz, prk, heap, devId); if (ret == 0) { @@ -1996,6 +2006,9 @@ int wolfSSL_GetHmacMaxSize(void) out, outSz, heap, devId); } ForceZero(prk, WC_MAX_DIGEST_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(prk, WC_MAX_DIGEST_SIZE); +#endif return ret; } diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index ff74e1cd93..f27de7c679 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -659,6 +659,11 @@ static int wc_HpkeExtractAndExpand( Hpke* hpke, byte* dh, word32 dh_len, WC_ALLOC_VAR_EX(eae_prk, byte, WC_MAX_DIGEST_SIZE, hpke->heap, DYNAMIC_TYPE_DIGEST, return MEMORY_E); +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(eae_prk, 0xff, WC_MAX_DIGEST_SIZE); + wc_MemZero_Add("wc_HpkeExtractAndExpand eae_prk", eae_prk, + WC_MAX_DIGEST_SIZE); +#endif /* extract */ ret = wc_HpkeLabeledExtract(hpke, hpke->kem_suite_id, @@ -675,6 +680,9 @@ static int wc_HpkeExtractAndExpand( Hpke* hpke, byte* dh, word32 dh_len, } ForceZero(eae_prk, WC_MAX_DIGEST_SIZE); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(eae_prk, WC_MAX_DIGEST_SIZE); +#endif WC_FREE_VAR_EX(eae_prk, hpke->heap, DYNAMIC_TYPE_DIGEST); return ret; @@ -712,6 +720,11 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, return MEMORY_E; } #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(secret, 0xff, WC_MAX_DIGEST_SIZE); + wc_MemZero_Add("wc_HpkeKeyScheduleBase secret", secret, + WC_MAX_DIGEST_SIZE); +#endif /* set the sequence to 0 */ context->seq = 0; @@ -767,6 +780,9 @@ static int wc_HpkeKeyScheduleBase(Hpke* hpke, HpkeBaseContext* context, ForceZero(key_schedule_context, 1 + 2 * WC_MAX_DIGEST_SIZE); ForceZero(secret, WC_MAX_DIGEST_SIZE); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(secret, WC_MAX_DIGEST_SIZE); +#endif WC_FREE_VAR_EX(key_schedule_context, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(secret, hpke->heap, DYNAMIC_TYPE_DIGEST); @@ -812,6 +828,11 @@ static int wc_HpkeEncap(Hpke* hpke, void* ephemeralKey, void* receiverKey, } #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(dh, 0xff, hpke->Ndh); + wc_MemZero_Add("wc_HpkeEncap dh", dh, hpke->Ndh); +#endif + /* generate dh */ dh_len = hpke->Ndh; @@ -874,6 +895,9 @@ static int wc_HpkeEncap(Hpke* hpke, void* ephemeralKey, void* receiverKey, ForceZero(dh, hpke->Ndh); ForceZero(kemContext, hpke->Npk * 2); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(dh, hpke->Ndh); +#endif WC_FREE_VAR_EX(dh, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(kemContext, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -899,6 +923,12 @@ static int wc_HpkeSetupBaseSender(Hpke* hpke, HpkeBaseContext* context, } #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(sharedSecret, 0xff, hpke->Nsecret); + wc_MemZero_Add("wc_HpkeSetupBaseSender sharedSecret", sharedSecret, + hpke->Nsecret); +#endif + /* encap */ ret = wc_HpkeEncap(hpke, ephemeralKey, receiverKey, sharedSecret); @@ -914,6 +944,9 @@ static int wc_HpkeSetupBaseSender(Hpke* hpke, HpkeBaseContext* context, } #endif ForceZero(sharedSecret, hpke->Nsecret); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(sharedSecret, hpke->Nsecret); +#endif WC_FREE_VAR_EX(sharedSecret, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; @@ -991,6 +1024,11 @@ int wc_HpkeSealBase(Hpke* hpke, void* ephemeralKey, void* receiverKey, WC_ALLOC_VAR_EX(context, HpkeBaseContext, 1, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(context, 0xff, sizeof(HpkeBaseContext)); + wc_MemZero_Add("wc_HpkeSealBase context", context, + sizeof(HpkeBaseContext)); +#endif PRIVATE_KEY_UNLOCK(); @@ -1007,6 +1045,9 @@ int wc_HpkeSealBase(Hpke* hpke, void* ephemeralKey, void* receiverKey, PRIVATE_KEY_LOCK(); ForceZero(context, sizeof(HpkeBaseContext)); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(context, sizeof(HpkeBaseContext)); +#endif WC_FREE_VAR_EX(context, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; @@ -1048,6 +1089,11 @@ static int wc_HpkeDecap(Hpke* hpke, void* receiverKey, const byte* pubKey, } #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(dh, 0xff, hpke->Ndh); + wc_MemZero_Add("wc_HpkeDecap dh", dh, hpke->Ndh); +#endif + /* deserialize ephemeralKey from pubKey */ ret = wc_HpkeDeserializePublicKey(hpke, &ephemeralKey, pubKey, pubKeySz); @@ -1129,6 +1175,9 @@ static int wc_HpkeDecap(Hpke* hpke, void* receiverKey, const byte* pubKey, ForceZero(dh, hpke->Ndh); ForceZero(kemContext, hpke->Npk * 2); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(dh, hpke->Ndh); +#endif WC_FREE_VAR_EX(dh, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(kemContext, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1145,6 +1194,11 @@ static int wc_HpkeSetupBaseReceiver(Hpke* hpke, HpkeBaseContext* context, WC_ALLOC_VAR_EX(sharedSecret, byte, hpke->Nsecret, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(sharedSecret, 0xff, hpke->Nsecret); + wc_MemZero_Add("wc_HpkeSetupBaseReceiver sharedSecret", sharedSecret, + hpke->Nsecret); +#endif /* decap */ ret = wc_HpkeDecap(hpke, receiverKey, pubKey, pubKeySz, sharedSecret); @@ -1161,6 +1215,9 @@ static int wc_HpkeSetupBaseReceiver(Hpke* hpke, HpkeBaseContext* context, } #endif ForceZero(sharedSecret, hpke->Nsecret); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(sharedSecret, hpke->Nsecret); +#endif WC_FREE_VAR_EX(sharedSecret, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; @@ -1238,6 +1295,11 @@ int wc_HpkeOpenBase(Hpke* hpke, void* receiverKey, const byte* pubKey, WC_ALLOC_VAR_EX(context, HpkeBaseContext, 1, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(context, 0xff, sizeof(HpkeBaseContext)); + wc_MemZero_Add("wc_HpkeOpenBase context", context, + sizeof(HpkeBaseContext)); +#endif PRIVATE_KEY_UNLOCK(); @@ -1254,6 +1316,9 @@ int wc_HpkeOpenBase(Hpke* hpke, void* receiverKey, const byte* pubKey, PRIVATE_KEY_LOCK(); ForceZero(context, sizeof(HpkeBaseContext)); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(context, sizeof(HpkeBaseContext)); +#endif WC_FREE_VAR_EX(context, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; diff --git a/wolfcrypt/src/kdf.c b/wolfcrypt/src/kdf.c index 6f6825b740..51582f485e 100644 --- a/wolfcrypt/src/kdf.c +++ b/wolfcrypt/src/kdf.c @@ -1412,12 +1412,21 @@ int wc_KDA_KDF_onestep(const byte* z, word32 zSz, const byte* fixedInfo, } if (ret == 0 && outIdx < derivedSecretSz) { + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* poison so a missed ForceZero on any path is caught by the check */ + XMEMSET(hashTempBuf, 0xff, (word32) hashOutSz); + wc_MemZero_Add("wc_KDA_KDF_onestep hashTempBuf", hashTempBuf, + (word32) hashOutSz); + #endif ret = wc_KDA_KDF_iteration(z, zSz, counter, fixedInfo, fixedInfoSz, hashType, hashTempBuf); if (ret == 0) { XMEMCPY(output + outIdx, hashTempBuf, derivedSecretSz - outIdx); } ForceZero(hashTempBuf, (word32) hashOutSz); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(hashTempBuf, (word32) hashOutSz); + #endif } if (ret != 0) { @@ -1518,6 +1527,11 @@ int wc_KDA_KDF_twostep_cmac(const byte * salt, word32 salt_len, } #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_KDA_KDF_twostep_cmac Key_kdk", Key_kdk, + sizeof(Key_kdk)); +#endif + /* step 1: cmac extract */ ret = wc_AesCmacGenerate_ex(cmac, Key_kdk, &tag_len, z, zSz, salt, salt_len, heap, devId); @@ -1549,6 +1563,9 @@ int wc_KDA_KDF_twostep_cmac(const byte * salt, word32 salt_len, /* always force zero the intermediate key derivation key. */ ForceZero(Key_kdk, sizeof(Key_kdk)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(Key_kdk, sizeof(Key_kdk)); +#endif return ret; } @@ -1653,6 +1670,9 @@ int wc_KDA_KDF_PRF_cmac(const byte* Kin, word32 KinSz, /* cmac the last little bit that wouldn't fit in a block size. */ byte rem[WC_AES_BLOCK_SIZE]; XMEMSET(rem, 0, sizeof(rem)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_KDA_KDF_PRF_cmac rem", rem, sizeof(rem)); + #endif c32toa(counter, counterBuf); #ifdef WOLFSSL_DEBUG_KDF @@ -1685,6 +1705,9 @@ int wc_KDA_KDF_PRF_cmac(const byte* Kin, word32 KinSz, } ForceZero(rem, sizeof(rem)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rem, sizeof(rem)); + #endif (void)wc_CmacFree(cmac); } diff --git a/wolfcrypt/src/pkcs12.c b/wolfcrypt/src/pkcs12.c index 2913531383..67d5511788 100644 --- a/wolfcrypt/src/pkcs12.c +++ b/wolfcrypt/src/pkcs12.c @@ -557,6 +557,19 @@ static int wc_PKCS12_create_mac(WC_PKCS12* pkcs12, byte* data, word32 dataSz, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; }); +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register both secret buffers from allocation, poisoned non-zero so a + * future path that reaches exit_mac without ForceZero is caught by the + * Check. unicodePasswd holds the (unicode-expanded) password; key holds + * the PBKDF-derived HMAC key. Every exit below is a 'goto exit_mac' + * which ForceZero+Checks both. */ + XMEMSET(unicodePasswd, 0xff, MAX_UNICODE_SZ); + wc_MemZero_Add("wc_PKCS12_create_mac unicodePasswd", unicodePasswd, + MAX_UNICODE_SZ); + XMEMSET(key, 0xff, sizeof(key)); + wc_MemZero_Add("wc_PKCS12_create_mac key", key, sizeof(key)); +#endif + /* unicode set up from asn.c */ if (pswSz >= MAX_UNICODE_SZ || (pswSz * 2 + 2) > MAX_UNICODE_SZ) { @@ -611,7 +624,15 @@ static int wc_PKCS12_create_mac(WC_PKCS12* pkcs12, byte* data, word32 dataSz, exit_mac: ForceZero(key, sizeof(key)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(key, sizeof(key)); +#endif ForceZero(unicodePasswd, MAX_UNICODE_SZ); + /* Stack build only: under WOLFSSL_SMALL_STACK unicodePasswd is heap and + * WC_FREE_VAR_EX (XFREE) auto-runs wc_MemZero_Check over the block. */ +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(unicodePasswd, MAX_UNICODE_SZ); +#endif WC_FREE_VAR_EX(unicodePasswd, pkcs12->heap, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(hmac, pkcs12->heap, DYNAMIC_TYPE_HMAC); return ret; diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 546d79535a..7699278d74 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -11820,6 +11820,11 @@ static int wc_PKCS7_KtriFakeCEK(wc_PKCS7* pkcs7, const byte* encryptedKey, return ret; } +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* seed is used as an HMAC key to derive the fallback CEK. */ + wc_MemZero_Add("wc_PKCS7_KtriFakeCEK seed", seed, sizeof(seed)); +#endif + ret = wc_HmacInit(hmac, pkcs7->heap, pkcs7->devId); if (ret == 0) { ret = wc_HmacSetKey(hmac, WC_SHA256, seed, (word32)sizeof(seed)); @@ -11832,6 +11837,9 @@ static int wc_PKCS7_KtriFakeCEK(wc_PKCS7* pkcs7, const byte* encryptedKey, wc_HmacFree(hmac); } ForceZero(seed, sizeof(seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seed, sizeof(seed)); +#endif WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC); return ret; } @@ -12205,9 +12213,18 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, * content decryption fail indistinguishably from "unwrap * succeeded but CEK is wrong". */ byte fakeKey[WC_SHA256_DIGEST_SIZE]; - int fakeRet = wc_PKCS7_KtriFakeCEK(pkcs7, encryptedKey, - (word32)encryptedKeySz, - fakeKey); + int fakeRet; + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* Register fakeKey from declaration (baseline-zeroed so it is + * defined). It will hold the fallback content-encryption key. + * Both exits below ForceZero+Check it. */ + XMEMSET(fakeKey, 0, sizeof(fakeKey)); + wc_MemZero_Add("wc_PKCS7_DecryptKtri fakeKey", fakeKey, + sizeof(fakeKey)); + #endif + fakeRet = wc_PKCS7_KtriFakeCEK(pkcs7, encryptedKey, + (word32)encryptedKeySz, + fakeKey); if (fakeRet != 0) { /* Fallback generation failed (e.g. RNG/HMAC error). @@ -12215,6 +12232,9 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, * not depend on RSA padding validity, rather than the * RSA status which would re-open the oracle. */ ForceZero(fakeKey, sizeof(fakeKey)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(fakeKey, sizeof(fakeKey)); + #endif /* In the non-OAEP path RSA is decrypted in-place via * wc_RsaPrivateDecryptInline, so encryptedKey holds * the (possibly valid) plaintext CEK. Zero it before @@ -12248,6 +12268,12 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, byte realPad[WC_SHA256_DIGEST_SIZE]; XMEMSET(realPad, 0, sizeof(realPad)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + /* realPad holds the real (padded) content-encryption + * key selected in constant time. */ + wc_MemZero_Add("wc_PKCS7_DecryptKtri realPad", realPad, + sizeof(realPad)); + #endif /* Constant-time copy: avoid data-dependent branches * that could leak whether RSA padding was valid. * When outKey is NULL (inline RSA failure), use @@ -12300,8 +12326,14 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, *decryptedKeySz = (word32)ctMaskSelInt(useFake, (int)sizeof(fakeKey), realLen); ForceZero(realPad, sizeof(realPad)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(realPad, sizeof(realPad)); + #endif } ForceZero(fakeKey, sizeof(fakeKey)); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(fakeKey, sizeof(fakeKey)); + #endif /* In the non-OAEP path RSA is decrypted in-place via * wc_RsaPrivateDecryptInline, so encryptedKey holds the * plaintext CEK after the unwrap. Zero it before free. */ diff --git a/wolfcrypt/src/puf.c b/wolfcrypt/src/puf.c index 74c5992548..aed1934bc9 100644 --- a/wolfcrypt/src/puf.c +++ b/wolfcrypt/src/puf.c @@ -504,6 +504,17 @@ int wc_PufEnroll(wc_PufCtx* ctx) XMEMSET(ctx->helperData, 0, WC_PUF_HELPER_BYTES); XMEMSET(ctx->stableBits, 0, WC_PUF_STABLE_BYTES); +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(msg, 0xff, sizeof(msg)); + XMEMSET(cw, 0xff, sizeof(cw)); + XMEMSET(rawCw, 0xff, sizeof(rawCw)); + XMEMSET(helperCw, 0xff, sizeof(helperCw)); + wc_MemZero_Add("wc_PufEnroll msg", msg, sizeof(msg)); + wc_MemZero_Add("wc_PufEnroll cw", cw, sizeof(cw)); + wc_MemZero_Add("wc_PufEnroll rawCw", rawCw, sizeof(rawCw)); + wc_MemZero_Add("wc_PufEnroll helperCw", helperCw, sizeof(helperCw)); +#endif + for (i = 0; i < WC_PUF_NUM_CODEWORDS; i++) { /* extract 64 message bits from raw SRAM */ int bitOff = i * 128; /* 128-bit stride for alignment */ @@ -536,6 +547,12 @@ int wc_PufEnroll(wc_PufCtx* ctx) ForceZero(cw, sizeof(cw)); ForceZero(rawCw, sizeof(rawCw)); ForceZero(helperCw, sizeof(helperCw)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(msg, sizeof(msg)); + wc_MemZero_Check(cw, sizeof(cw)); + wc_MemZero_Check(rawCw, sizeof(rawCw)); + wc_MemZero_Check(helperCw, sizeof(helperCw)); +#endif if (ret != 0) return PUF_ENROLL_E; @@ -563,6 +580,17 @@ int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz) XMEMSET(ctx->stableBits, 0, WC_PUF_STABLE_BYTES); +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(rawCw, 0xff, sizeof(rawCw)); + XMEMSET(helperCw, 0xff, sizeof(helperCw)); + XMEMSET(noisyCw, 0xff, sizeof(noisyCw)); + XMEMSET(msg, 0xff, sizeof(msg)); + wc_MemZero_Add("wc_PufReconstruct rawCw", rawCw, sizeof(rawCw)); + wc_MemZero_Add("wc_PufReconstruct helperCw", helperCw, sizeof(helperCw)); + wc_MemZero_Add("wc_PufReconstruct noisyCw", noisyCw, sizeof(noisyCw)); + wc_MemZero_Add("wc_PufReconstruct msg", msg, sizeof(msg)); +#endif + for (i = 0; i < WC_PUF_NUM_CODEWORDS; i++) { int bitOff = i * 128; int j; @@ -589,6 +617,12 @@ int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz) ForceZero(noisyCw, sizeof(noisyCw)); ForceZero(msg, sizeof(msg)); ForceZero(ctx->stableBits, WC_PUF_STABLE_BYTES); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rawCw, sizeof(rawCw)); + wc_MemZero_Check(helperCw, sizeof(helperCw)); + wc_MemZero_Check(noisyCw, sizeof(noisyCw)); + wc_MemZero_Check(msg, sizeof(msg)); + #endif ctx->flags &= (word32)~WC_PUF_FLAG_READY; return PUF_RECONSTRUCT_E; } @@ -604,6 +638,12 @@ int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz) ForceZero(helperCw, sizeof(helperCw)); ForceZero(noisyCw, sizeof(noisyCw)); ForceZero(msg, sizeof(msg)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rawCw, sizeof(rawCw)); + wc_MemZero_Check(helperCw, sizeof(helperCw)); + wc_MemZero_Check(noisyCw, sizeof(noisyCw)); + wc_MemZero_Check(msg, sizeof(msg)); +#endif if (ret != 0) return PUF_RECONSTRUCT_E; diff --git a/wolfcrypt/src/pwdbased.c b/wolfcrypt/src/pwdbased.c index e3a1b91e77..9b54464138 100644 --- a/wolfcrypt/src/pwdbased.c +++ b/wolfcrypt/src/pwdbased.c @@ -123,6 +123,12 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen, return err; } +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* poison so a missed ForceZero on any path is caught by the check */ + XMEMSET(digest, 0xff, sizeof(digest)); + wc_MemZero_Add("wc_PBKDF1_ex digest", digest, sizeof(digest)); +#endif + keyLeft = keyLen; ivLeft = ivLen; while (keyOutput < (keyLen + ivLen)) { @@ -181,6 +187,9 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen, WC_FREE_VAR_EX(hash, heap, DYNAMIC_TYPE_HASHCTX); ForceZero(digest, sizeof(digest)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(digest, sizeof(digest)); +#endif if (err != 0) return err; @@ -264,6 +273,12 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen, const byte* salt, } #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* poison so a missed ForceZero on any path is caught by the check */ + XMEMSET(buffer, 0xff, (word32)hLen); + wc_MemZero_Add("wc_PBKDF2_ex buffer", buffer, (word32)hLen); +#endif + ret = wc_HmacInit(hmac, heap, devId); if (ret == 0) { word32 i = 1; @@ -330,6 +345,9 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen, const byte* salt, } ForceZero(buffer, (word32)hLen); +#if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(buffer, (word32)hLen); +#endif WC_FREE_VAR_EX(buffer, heap, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(hmac, heap, DYNAMIC_TYPE_HMAC); @@ -513,6 +531,12 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen, for (i = 0; i < pLen; i++) P[i] = passwd[i % (word32)passLen]; +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_PKCS12_PBKDF_ex Ai", Ai, WC_MAX_DIGEST_SIZE); + wc_MemZero_Add("wc_PKCS12_PBKDF_ex B", B, WC_MAX_BLOCK_SIZE); + wc_MemZero_Add("wc_PKCS12_PBKDF_ex buffer", buffer, totalLen); +#endif + #ifdef WOLFSSL_SMALL_STACK if (((B1 = (mp_int *)XMALLOC(sizeof(*B1), heap, DYNAMIC_TYPE_TMP_BUFFER)) == NULL) || @@ -605,9 +629,17 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen, #else ForceZero(Ai, WC_MAX_DIGEST_SIZE); ForceZero(B, WC_MAX_BLOCK_SIZE); +#if defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(Ai, WC_MAX_DIGEST_SIZE); + wc_MemZero_Check(B, WC_MAX_BLOCK_SIZE); +#endif #endif ForceZero(buffer, totalLen); +#if defined(WOLFSSL_CHECK_MEM_ZERO) + if (!dynamic) + wc_MemZero_Check(buffer, totalLen); +#endif if (dynamic) XFREE(buffer, heap, DYNAMIC_TYPE_KEY); @@ -729,6 +761,10 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen, for (i = 0; i < pLen; i++) I[sLen + i] = passwd[i % (word32)passLen]; +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_PKCS12_PBKDF_ex buffer", buffer, totalLen); +#endif + ret = 0; while ((ret == 0) && (kLen > 0)) { /* RFC 7292 B.2 step 6a: A_i = H^r(D || I) */ @@ -782,6 +818,10 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen, ForceZero(B, WC_MAX_BLOCK_SIZE); WC_FREE_VAR_EX(B, heap, DYNAMIC_TYPE_TMP_BUFFER); ForceZero(buffer, totalLen); +#if defined(WOLFSSL_CHECK_MEM_ZERO) + if (buffer == staticBuffer) + wc_MemZero_Check(buffer, totalLen); +#endif if (buffer != staticBuffer) { XFREE(buffer, heap, DYNAMIC_TYPE_KEY); } diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index e840d95df9..a8f16bb0ae 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -494,6 +494,12 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, return DRBG_FAILURE; #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* poison so a missed ForceZero on any path is caught by the check */ + XMEMSET(digest, 0xff, WC_SHA256_DIGEST_SIZE); + wc_MemZero_Add("Hash_df digest", digest, WC_SHA256_DIGEST_SIZE); +#endif + #ifdef LITTLE_ENDIAN_ORDER bits = ByteReverseWord32(bits); #endif @@ -551,6 +557,12 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, } ForceZero(digest, WC_SHA256_DIGEST_SIZE); + /* Explicit check only where the buffer is NOT XFREEd (XFREE auto-checks): + * the stack build and the small-stack-cache build (drbg member). */ +#if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(digest, WC_SHA256_DIGEST_SIZE); +#endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); @@ -583,6 +595,9 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); #endif XMEMSET(newV, 0, DRBG_SEED_LEN); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("Hash_DRBG_Reseed newV", newV, DRBG_SEED_LEN); +#endif ret = Hash_df(drbg, newV, DRBG_SEED_LEN, drbgReseed, drbg->V, sizeof(drbg->V), seed, seedSz, @@ -598,6 +613,10 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz } ForceZero(newV, DRBG_SEED_LEN); +#if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(newV, DRBG_SEED_LEN); +#endif #ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(newV, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -723,6 +742,9 @@ static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) len = (outSz / OUTPUT_BLOCK_LEN) + ((outSz % OUTPUT_BLOCK_LEN) ? 1 : 0); XMEMCPY(data, V, DRBG_SEED_LEN); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("Hash_gen data", data, DRBG_SEED_LEN); +#endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) @@ -759,6 +781,10 @@ static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) } } ForceZero(data, DRBG_SEED_LEN); +#if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(data, DRBG_SEED_LEN); +#endif #ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); @@ -888,7 +914,16 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz, WC_SHA256_DIGEST_SIZE); } else { + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("Hash_DRBG_Generate digest", digest, + WC_SHA256_DIGEST_SIZE); + #endif ForceZero(digest, WC_SHA256_DIGEST_SIZE); + #if (!defined(WOLFSSL_SMALL_STACK) || \ + defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(digest, WC_SHA256_DIGEST_SIZE); + #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); #endif @@ -932,7 +967,16 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz, } drbg->reseedCtr++; } + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("Hash_DRBG_Generate digest", digest, + WC_SHA256_DIGEST_SIZE); + #endif ForceZero(digest, WC_SHA256_DIGEST_SIZE); + #if (!defined(WOLFSSL_SMALL_STACK) || \ + defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(digest, WC_SHA256_DIGEST_SIZE); + #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); #endif @@ -1087,6 +1131,12 @@ static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, return DRBG_FAILURE; #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* poison so a missed ForceZero on any path is caught by the check */ + XMEMSET(digest, 0xff, WC_SHA512_DIGEST_SIZE); + wc_MemZero_Add("Hash512_df digest", digest, WC_SHA512_DIGEST_SIZE); +#endif + #ifdef LITTLE_ENDIAN_ORDER bits = ByteReverseWord32(bits); #endif @@ -1144,6 +1194,12 @@ static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, } ForceZero(digest, WC_SHA512_DIGEST_SIZE); + /* Explicit check only where the buffer is NOT XFREEd (XFREE auto-checks): + * the stack build and the small-stack-cache build (drbg member). */ +#if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(digest, WC_SHA512_DIGEST_SIZE); +#endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); @@ -1177,6 +1233,9 @@ static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); #endif XMEMSET(newV, 0, DRBG_SHA512_SEED_LEN); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("Hash512_DRBG_Reseed newV", newV, DRBG_SHA512_SEED_LEN); +#endif ret = Hash512_df(drbg, newV, DRBG_SHA512_SEED_LEN, drbgReseed, drbg->V, sizeof(drbg->V), seed, seedSz, @@ -1193,6 +1252,10 @@ static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed, } ForceZero(newV, DRBG_SHA512_SEED_LEN); +#if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(newV, DRBG_SHA512_SEED_LEN); +#endif #ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(newV, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1248,6 +1311,9 @@ static int Hash512_gen(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, + ((outSz % OUTPUT_BLOCK_LEN_SHA512) ? 1 : 0); XMEMCPY(data, V, DRBG_SHA512_SEED_LEN); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("Hash512_gen data", data, DRBG_SHA512_SEED_LEN); +#endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) @@ -1283,6 +1349,10 @@ static int Hash512_gen(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, } } ForceZero(data, DRBG_SHA512_SEED_LEN); +#if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(data, DRBG_SHA512_SEED_LEN); +#endif #ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); @@ -1391,7 +1461,16 @@ static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out, } drbg->reseedCtr++; } + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("Hash512_DRBG_Generate digest", digest, + WC_SHA512_DIGEST_SIZE); + #endif ForceZero(digest, WC_SHA512_DIGEST_SIZE); + #if (!defined(WOLFSSL_SMALL_STACK) || \ + defined(WOLFSSL_SMALL_STACK_CACHE)) && \ + defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(digest, WC_SHA512_DIGEST_SIZE); + #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); #endif @@ -2019,6 +2098,10 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #else ret = wc_GenerateSeed(&rng->seed, seed, seedSz); #endif /* WC_RNG_SEED_CB */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* seed now holds entropy; register across DRBG instantiation */ + wc_MemZero_Add("_InitRng seed", seed, seedSz); +#endif if (ret != 0) { #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG_EX("Seed generation failed... %d", ret); @@ -2075,6 +2158,10 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #endif { ForceZero(seed, seedSz); + #if !defined(WOLFSSL_SMALL_STACK) && defined(WOLFSSL_CHECK_MEM_ZERO) + /* heap build's WC_FREE_VAR_EX/XFREE auto-checks; stack build needs it */ + wc_MemZero_Check(seed, seedSz); + #endif } WC_FREE_VAR_EX(seed, rng->heap, DYNAMIC_TYPE_SEED); @@ -2313,7 +2400,17 @@ static int PollAndReSeed(WC_RNG* rng) } XFREE(newSeed, rng->heap, DYNAMIC_TYPE_SEED); #else - ForceZero(newSeed, sizeof(newSeed)); + /* newSeed is a byte[] in the plain build but a byte* in the + * SMALL_STACK_CACHE build, so use the explicit buffer length (not + * sizeof) to zero the whole reseed entropy buffer in both cases. */ + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("PollAndReSeed newSeed", newSeed, + SEED_SZ + SEED_BLOCK_SZ); + #endif + ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(newSeed, SEED_SZ + SEED_BLOCK_SZ); + #endif #endif } else { @@ -3733,8 +3830,14 @@ static int wc_GenerateSeed_IntelRD(OS_Seed* os, byte* output, word32 sz) if (ret != 0) return ret; +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_GenerateSeed rndTmp", &rndTmp, sizeof(rndTmp)); +#endif XMEMCPY(output, &rndTmp, sz); ForceZero(&rndTmp, sizeof(rndTmp)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(&rndTmp, sizeof(rndTmp)); +#endif return 0; } diff --git a/wolfcrypt/src/srp.c b/wolfcrypt/src/srp.c index 6b88216f29..fcad21cfa7 100644 --- a/wolfcrypt/src/srp.c +++ b/wolfcrypt/src/srp.c @@ -450,6 +450,13 @@ int wc_SrpSetPassword(Srp* srp, const byte* password, word32 size) if (digestSz < 0) return digestSz; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* digest will hold the SRP private key x = H(salt | H(user:pass)). + * Register early so any future path that skips the ForceZero is caught. */ + XMEMSET(digest, 0, SRP_MAX_DIGEST_SIZE); + wc_MemZero_Add("wc_SrpSetPassword digest", digest, SRP_MAX_DIGEST_SIZE); +#endif + /* digest = H(username | ':' | password) */ r = SrpHashInit(&hash, srp->type, srp->heap); if (!r) r = SrpHashUpdate(&hash, srp->user, srp->userSz); @@ -469,6 +476,9 @@ int wc_SrpSetPassword(Srp* srp, const byte* password, word32 size) if (!r) r = mp_read_unsigned_bin(&srp->auth, digest, (word32)digestSz); ForceZero(digest, SRP_MAX_DIGEST_SIZE); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(digest, SRP_MAX_DIGEST_SIZE); +#endif return r; } @@ -667,6 +677,15 @@ static int wc_SrpSetKey(Srp* srp, byte* secret, word32 size) srp->keySz = 2 * (word32)digestSz; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* digest and hash will hold derived session-key K material. Register now + * (past the MEMORY_E exit) so any later path that skips the ForceZero is + * caught. digest was already zeroed above; baseline the hash struct. */ + XMEMSET(&hash, 0, sizeof(SrpHash)); + wc_MemZero_Add("wc_SrpSetKey digest", digest, sizeof(digest)); + wc_MemZero_Add("wc_SrpSetKey hash", &hash, sizeof(SrpHash)); +#endif + for (i = j = 0; j < srp->keySz; i++) { counter[0] = (byte)(i >> 24); counter[1] = (byte)(i >> 16); @@ -696,6 +715,10 @@ static int wc_SrpSetKey(Srp* srp, byte* secret, word32 size) ForceZero(digest, sizeof(digest)); ForceZero(&hash, sizeof(SrpHash)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(digest, sizeof(digest)); + wc_MemZero_Check(&hash, sizeof(SrpHash)); +#endif return r; } @@ -997,6 +1020,13 @@ int wc_SrpVerifyPeersProof(Srp* srp, byte* proof, word32 size) if (size != (word32)hashSize || size > INT_MAX) return BUFFER_E; +#ifdef WOLFSSL_CHECK_MEM_ZERO + /* digest will hold the expected peer proof derived from session key K. + * Register early so any future path that skips the ForceZero is caught. */ + XMEMSET(digest, 0, sizeof(digest)); + wc_MemZero_Add("wc_SrpVerifyPeersProof digest", digest, sizeof(digest)); +#endif + r = SrpHashFinal(srp->side == SRP_CLIENT_SIDE ? &srp->server_proof : &srp->client_proof, digest); @@ -1010,6 +1040,9 @@ int wc_SrpVerifyPeersProof(Srp* srp, byte* proof, word32 size) r = SRP_VERIFY_E; ForceZero(digest, sizeof(digest)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(digest, sizeof(digest)); +#endif return r; } diff --git a/wolfcrypt/src/wc_frodokem.c b/wolfcrypt/src/wc_frodokem.c index e6e81528e6..a8bb5c04a7 100644 --- a/wolfcrypt/src/wc_frodokem.c +++ b/wolfcrypt/src/wc_frodokem.c @@ -769,7 +769,13 @@ int wc_FrodoKemKey_MakeKey(FrodoKemKey* key, WC_RNG* rng) XFREE(rand, key->heap, DYNAMIC_TYPE_TMP_BUFFER); } #else +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("frodokem rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif #endif #else (void)key; @@ -933,7 +939,13 @@ int wc_FrodoKemKey_EncapsulateWithRandom(FrodoKemKey* key, unsigned char* ct, #ifndef WOLFSSL_SMALL_STACK ForceZero(pkh, sizeof(pkh)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("frodokem encaps seedSEk", seedSEk, sizeof(seedSEk)); +#endif ForceZero(seedSEk, sizeof(seedSEk)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedSEk, sizeof(seedSEk)); +#endif #endif /* Encode(u), V/E'' and B' live in mat (as do seedSEk and pkh under small * stack), all zeroized on free below. */ @@ -1021,7 +1033,13 @@ int wc_FrodoKemKey_Encapsulate(FrodoKemKey* key, unsigned char* ct, XFREE(rand, key->heap, DYNAMIC_TYPE_TMP_BUFFER); } #else +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("frodokem rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif #endif #else (void)key; @@ -1228,10 +1246,28 @@ int wc_FrodoKemKey_Decapsulate(FrodoKemKey* key, unsigned char* ss, } #ifndef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("frodokem decaps uSalt", uSalt, sizeof(uSalt)); +#endif ForceZero(uSalt, sizeof(uSalt)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(uSalt, sizeof(uSalt)); +#endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("frodokem decaps seedSEk", seedSEk, sizeof(seedSEk)); +#endif ForceZero(seedSEk, sizeof(seedSEk)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedSEk, sizeof(seedSEk)); +#endif /* Zeroize the secret-derived stack matrices (E'' lives in mat). */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("frodokem decaps v", v, sizeof(v)); +#endif ForceZero(v, sizeof(v)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(v, sizeof(v)); +#endif ForceZero(cEnc, sizeof(cEnc)); #endif /* Under small stack uSalt, seedSEk, cIn, v and cEnc live in mat, zeroized diff --git a/wolfcrypt/src/wc_frodokem_mat.c b/wolfcrypt/src/wc_frodokem_mat.c index b8506cc16d..7e87569add 100644 --- a/wolfcrypt/src/wc_frodokem_mat.c +++ b/wolfcrypt/src/wc_frodokem_mat.c @@ -291,7 +291,13 @@ static void frodokem_sa_accum_sme_wrap(word16* out, const word16* s, } frodokem_sa_accum_sme(out, sc, row, n); /* sc held two columns of the secret matrix S^T. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("frodokem sme sc", sc, sizeof(sc)); +#endif ForceZero(sc, sizeof(sc)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(sc, sizeof(sc)); +#endif } /* Transpose the two A rows and S into the SME interleaved layout, then run the diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index e88c032d87..908fe97555 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -3179,6 +3179,14 @@ static int wc_hss_next_subtree_inc(LmsState* state, HssPrivKey* priv_key, w64wrapper p64_hi; w64wrapper q64_hi; + /* Register tmp_priv up front (no early exit bypasses the scrub); baseline- + * zero first so the buffer is defined at registration. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(tmp_priv, 0xff, sizeof(tmp_priv)); + wc_MemZero_Add("wc_hss_next_subtree_inc tmp_priv", tmp_priv, + sizeof(tmp_priv)); +#endif + /* Get previous index. */ w64Decrement(&p64); /* Get index of previous and current parent. */ @@ -3236,6 +3244,9 @@ static int wc_hss_next_subtree_inc(LmsState* state, HssPrivKey* priv_key, } ForceZero(tmp_priv, sizeof(tmp_priv)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(tmp_priv, sizeof(tmp_priv)); +#endif return ret; } diff --git a/wolfcrypt/src/wc_mldsa.c b/wolfcrypt/src/wc_mldsa.c index addac864f2..62dd04ace8 100644 --- a/wolfcrypt/src/wc_mldsa.c +++ b/wolfcrypt/src/wc_mldsa.c @@ -167,6 +167,7 @@ #include #include #include +#include #ifdef NO_INLINE #include #else @@ -3631,7 +3632,13 @@ static int mldsa_rej_bound_poly(wc_Shake* shake256, byte* seed, sword32* s, } /* z holds the secret s1/s2 bytes. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa_rej_bound_poly z", z, sizeof(z)); +#endif ForceZero(z, sizeof(z)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(z, sizeof(z)); +#endif return ret; #else int ret; @@ -4145,7 +4152,13 @@ static int mldsa_expand_s_c(wc_Shake* shake256, byte* priv_seed, byte eta, /* seed holds a copy of the secret private seed (rho_prime) from which the * s1/s2 vectors are derived; zeroize it before return. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa gen_s seed", seed, sizeof(seed)); +#endif ForceZero(seed, sizeof(seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seed, sizeof(seed)); +#endif return ret; } @@ -8233,6 +8246,11 @@ static int mldsa_make_key(wc_MlDsaKey* key, WC_RNG* rng) /* Step 1: Generate a 32 byte random seed. */ ret = wc_RNG_GenerateBlock(rng, seed, MLDSA_SEED_SZ); + /* seed now holds the secret key seed; register before the derive step so a + * future early-exit ahead of the ForceZero cannot leak it. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_MlDsaKey_MakeKey seed", seed, sizeof(seed)); +#endif /* Step 2: Check for error. */ if (ret == 0) { /* Step 5: Make key with random seed. */ @@ -8240,6 +8258,9 @@ static int mldsa_make_key(wc_MlDsaKey* key, WC_RNG* rng) } ForceZero(seed, sizeof(seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seed, sizeof(seed)); +#endif return ret; } #endif /* !WOLFSSL_MLDSA_NO_MAKE_KEY */ @@ -8630,7 +8651,14 @@ static int mldsa_sign_with_seed_mu(wc_MlDsaKey* key, mldsa_vec_encode_gamma1(z, params->l, params->gamma1_bits, ze); } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign priv_rand_seed", priv_rand_seed, + sizeof(priv_rand_seed)); +#endif ForceZero(priv_rand_seed, sizeof(priv_rand_seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(priv_rand_seed, sizeof(priv_rand_seed)); +#endif if (y != NULL) { word32 zeroSz = allocSz; #ifndef WC_MLDSA_CACHE_MATRIX_A @@ -9194,7 +9222,14 @@ static int mldsa_sign_with_seed_mu(wc_MlDsaKey* key, while ((ret == 0) && (!valid)); } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign priv_rand_seed", priv_rand_seed, + sizeof(priv_rand_seed)); +#endif ForceZero(priv_rand_seed, sizeof(priv_rand_seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(priv_rand_seed, sizeof(priv_rand_seed)); +#endif if (y != NULL) { ForceZero(y, allocSz); } @@ -9251,7 +9286,13 @@ static int mldsa_sign_ctx_msg_with_seed(wc_MlDsaKey* key, ret = mldsa_sign_with_seed_mu(key, seedMu, sig, sigLen); } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign seedMu", seedMu, sizeof(seedMu)); +#endif ForceZero(seedMu, sizeof(seedMu)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedMu, sizeof(seedMu)); +#endif return ret; } @@ -9301,7 +9342,13 @@ static int mldsa_sign_msg_with_seed(wc_MlDsaKey* key, const byte* seed, ret = mldsa_sign_with_seed_mu(key, seedMu, sig, sigLen); } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign seedMu", seedMu, sizeof(seedMu)); +#endif ForceZero(seedMu, sizeof(seedMu)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedMu, sizeof(seedMu)); +#endif return ret; } #endif /* WOLFSSL_MLDSA_NO_CTX */ @@ -9367,7 +9414,13 @@ static int mldsa_sign_ctx_msg(wc_MlDsaKey* key, WC_RNG* rng, ret = mldsa_sign_with_seed_mu(key, seedMu, sig, sigLen); } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign seedMu", seedMu, sizeof(seedMu)); +#endif ForceZero(seedMu, sizeof(seedMu)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedMu, sizeof(seedMu)); +#endif return ret; } @@ -9430,7 +9483,13 @@ static int mldsa_sign_msg(wc_MlDsaKey* key, WC_RNG* rng, ret = mldsa_sign_with_seed_mu(key, seedMu, sig, sigLen); } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign seedMu", seedMu, sizeof(seedMu)); +#endif ForceZero(seedMu, sizeof(seedMu)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedMu, sizeof(seedMu)); +#endif return ret; } #endif /* WOLFSSL_MLDSA_NO_CTX */ @@ -9505,7 +9564,13 @@ static int mldsa_sign_ctx_hash_with_seed(wc_MlDsaKey* key, ret = mldsa_sign_with_seed_mu(key, seedMu, sig, sigLen); } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign seedMu", seedMu, sizeof(seedMu)); +#endif ForceZero(seedMu, sizeof(seedMu)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedMu, sizeof(seedMu)); +#endif return ret; } @@ -9548,6 +9613,10 @@ static int mldsa_sign_ctx_hash(wc_MlDsaKey* key, WC_RNG* rng, if (ret == 0) { /* Step 7: Generate random seed. */ ret = wc_RNG_GenerateBlock(rng, seed, MLDSA_RND_SZ); + /* seed now holds the secret signing randomness; register before use. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign_ctx_hash seed", seed, sizeof(seed)); +#endif } if (ret == 0) { @@ -9556,6 +9625,9 @@ static int mldsa_sign_ctx_hash(wc_MlDsaKey* key, WC_RNG* rng, } ForceZero(seed, sizeof(seed)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seed, sizeof(seed)); +#endif return ret; } @@ -10602,7 +10674,13 @@ int wc_MlDsaKey_SignMuWithSeed(wc_MlDsaKey* key, byte* sig, word32 *sigLen, XMEMCPY(seedMu, seed, MLDSA_RND_SZ); XMEMCPY(seedMu + MLDSA_RND_SZ, mu, MLDSA_MU_SZ); ret = mldsa_sign_with_seed_mu(key, seedMu, sig, sigLen); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mldsa sign_mu seedMu", seedMu, sizeof(seedMu)); +#endif ForceZero(seedMu, sizeof(seedMu)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(seedMu, sizeof(seedMu)); +#endif } return ret; diff --git a/wolfcrypt/src/wc_mlkem.c b/wolfcrypt/src/wc_mlkem.c index eb96e9526b..e6bf7d9d07 100644 --- a/wolfcrypt/src/wc_mlkem.c +++ b/wolfcrypt/src/wc_mlkem.c @@ -687,6 +687,11 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) */ ret = wc_RNG_GenerateBlock(rng, rand, WC_ML_KEM_SYM_SZ * 2); /* Step 3: ret is not zero when d == NULL or z == NULL. */ + /* rand now holds the secret seeds d||z; register before key gen / + * PCT so any future early-exit before the ForceZero is caught. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem makekey rand", (void*)rand, (word32)sizeof(rand)); +#endif } if (ret == 0) { /* Make a key pair from the random. @@ -724,8 +729,16 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) ret = ML_KEM_PCT_E; } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem pct ss1", pct_ss1, sizeof(pct_ss1)); + wc_MemZero_Add("mlkem pct ss2", pct_ss2, sizeof(pct_ss2)); +#endif ForceZero(pct_ss1, sizeof(pct_ss1)); ForceZero(pct_ss2, sizeof(pct_ss2)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(pct_ss1, sizeof(pct_ss1)); + wc_MemZero_Check(pct_ss2, sizeof(pct_ss2)); +#endif if (WC_VAR_OK(pct_ct)) ForceZero(pct_ct, WC_ML_KEM_MAX_CIPHER_TEXT_SIZE); @@ -742,6 +755,9 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) /* Ensure seeds are zeroized. */ ForceZero((void*)rand, (word32)sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check((void*)rand, (word32)sizeof(rand)); +#endif /* Step 4: return ret != 0 on falsum or internal key generation failure. */ return ret; @@ -968,9 +984,21 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand, } /* Zeroize the secret seed material in rho||sigma (sigma) before return. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem keygen buf", buf, sizeof(buf)); +#endif ForceZero(buf, sizeof(buf)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(buf, sizeof(buf)); +#endif #ifdef WC_MLKEM_FAULT_HARDEN +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem keygen sigma", sigma, sizeof(sigma)); +#endif ForceZero(sigma, sizeof(sigma)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(sigma, sizeof(sigma)); +#endif #endif #ifndef WOLFSSL_NO_MALLOC @@ -984,7 +1012,13 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand, } #else /* e is a stack buffer holding the secret noise vector; zeroize it. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem keygen e", e, (size_t)(k * MLKEM_N) * sizeof(sword16)); +#endif ForceZero(e, (size_t)(k * MLKEM_N) * sizeof(sword16)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(e, (size_t)(k * MLKEM_N) * sizeof(sword16)); +#endif #endif /* Note: PCT is performed in wc_MlKemKey_MakeKey() which calls this @@ -1323,7 +1357,13 @@ static int mlkemkey_encapsulate(MlKemKey* key, const byte* m, byte* r, byte* c) } #else /* y is a stack buffer holding secret noise/message material; zeroize it. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem encrypt y", y, sizeof(y)); +#endif ForceZero(y, sizeof(y)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(y, sizeof(y)); +#endif #endif return ret; @@ -1446,6 +1486,11 @@ int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* ct, unsigned char* ss, * Step 1: m is 32 random bytes */ ret = wc_RNG_GenerateBlock(rng, m, sizeof(m)); + /* m now holds the encapsulation randomness (the shared secret is + * derived from it); register before the encapsulate call. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem encapsulate m", m, sizeof(m)); +#endif /* Step 2: ret is not zero when m == NULL. */ } if (ret == 0) { @@ -1458,6 +1503,9 @@ int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* ct, unsigned char* ss, /* Zeroize the random message seed before return - it is the encapsulation * randomness from which the shared secret is derived (FIPS 203 Alg 17). */ ForceZero(m, sizeof(m)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(m, sizeof(m)); +#endif /* Step 3: return ret != 0 on falsum or internal key generation failure. */ return ret; @@ -1646,9 +1694,21 @@ int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, unsigned char* ct, #ifdef WOLFSSL_MLKEM_KYBER /* msg holds the secret message H(rand) used for Kyber encapsulation; * zeroize it before return (the ML-KEM path uses the caller's rand). */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem encapsulate msg", msg, sizeof(msg)); +#endif ForceZero(msg, sizeof(msg)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(msg, sizeof(msg)); +#endif +#endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem encapsulate kr", kr, sizeof(kr)); #endif ForceZero(kr, sizeof(kr)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(kr, sizeof(kr)); +#endif return ret; } @@ -1810,7 +1870,13 @@ static MLKEM_NOINLINE int mlkemkey_decapsulate(MlKemKey* key, byte* m, } #else /* u is a stack buffer holding the secret decrypted polynomial; zeroize. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem decrypt u", u, sizeof(u)); +#endif ForceZero(u, sizeof(u)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(u, sizeof(u)); +#endif #endif return ret; @@ -2026,8 +2092,16 @@ int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss, ForceZero(cmp, sizeof(cmp)); #endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem decapsulate msg", msg, sizeof(msg)); + wc_MemZero_Add("mlkem decapsulate kr", kr, sizeof(kr)); +#endif ForceZero(msg, sizeof(msg)); ForceZero(kr, sizeof(kr)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(msg, sizeof(msg)); + wc_MemZero_Check(kr, sizeof(kr)); +#endif return ret; } diff --git a/wolfcrypt/src/wc_mlkem_poly.c b/wolfcrypt/src/wc_mlkem_poly.c index 2ab7299cfe..ec61e67b6e 100644 --- a/wolfcrypt/src/wc_mlkem_poly.c +++ b/wolfcrypt/src/wc_mlkem_poly.c @@ -83,6 +83,7 @@ #include #include #include +#include #ifdef WOLFSSL_HAVE_MLKEM @@ -3107,7 +3108,13 @@ static int mlkem_prf(wc_Shake* shake256, byte* out, unsigned int outLen, } /* state holds secret PRF output. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif return 0; #else int ret; @@ -3160,7 +3167,13 @@ int mlkem_kdf(const byte* seed, int seedLen, byte* out, int outLen) XMEMCPY(out, state, outLen); /* state holds secret KDF output. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif return 0; } #endif @@ -3188,7 +3201,13 @@ int mlkem_kdf(const byte* seed, int seedLen, byte* out, int outLen) XMEMCPY(out, state, outLen); /* state holds secret KDF output. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif return 0; } #endif @@ -4050,7 +4069,13 @@ static int mlkem_get_noise_eta1_c(MLKEM_PRF_T* prf, sword16* p, mlkem_cbd_eta3(p, rand); } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif } else #endif @@ -4064,7 +4089,13 @@ static int mlkem_get_noise_eta1_c(MLKEM_PRF_T* prf, sword16* p, mlkem_cbd_eta2(p, rand); } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif } return ret; @@ -4098,7 +4129,13 @@ static int mlkem_get_noise_eta2_c(MLKEM_PRF_T* prf, sword16* p, } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif return ret; } @@ -4137,7 +4174,13 @@ static void mlkem_get_noise_x4_eta2_avx2(byte* rand, byte* seed, byte o) rand + 3 * ETA2_RAND_SIZE); /* state is secret-seeded; caller zeroizes rand. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif } #endif @@ -4192,7 +4235,13 @@ static int mlkem_get_noise_eta2_avx2(MLKEM_PRF_T* prf, sword16* p, mlkem_cbd_eta2_avx2(p, (byte*)state); /* state holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif return 0; } #endif @@ -4235,7 +4284,13 @@ static void mlkem_get_noise_x4_eta3_avx2(byte* rand, byte* seed) rand + i + 3 * PRF_RAND_SZ); /* state is secret-seeded; caller zeroizes rand. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif } /* Get the noise/error by calculating random bytes and sampling to a binomial @@ -4310,7 +4365,13 @@ static int mlkem_get_noise_k3_avx2(sword16* vec1, sword16* vec2, sword16* poly, } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif return 0; } #endif @@ -4350,7 +4411,13 @@ static int mlkem_get_noise_k4_avx2(MLKEM_PRF_T* prf, sword16* vec1, } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif return ret; } #endif @@ -4424,7 +4491,13 @@ static void mlkem_get_noise_x3_eta3_aarch64(byte* rand, byte* seed, byte o) ETA3_RAND_SIZE - SHA3_256_BYTES); /* state is secret-seeded; caller zeroizes rand. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif } /* Get the noise/error by calculating random bytes. @@ -4455,7 +4528,13 @@ static void mlkem_get_noise_eta3_aarch64(byte* rand, byte* seed, byte o) XMEMCPY(rand + SHA3_256_BYTES, state, ETA3_RAND_SIZE - SHA3_256_BYTES); /* state is secret-seeded; caller zeroizes rand. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly state", state, sizeof(state)); +#endif ForceZero(state, sizeof(state)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(state, sizeof(state)); +#endif } /* Get the noise/error by calculating random bytes and sampling to a binomial @@ -4489,7 +4568,13 @@ static int mlkem_get_noise_k2_aarch64(sword16* vec1, sword16* vec2, } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif return ret; } #endif @@ -4551,7 +4636,13 @@ static int mlkem_get_noise_k3_aarch64(sword16* vec1, sword16* vec2, } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif return 0; } #endif @@ -4588,7 +4679,13 @@ static int mlkem_get_noise_k4_aarch64(sword16* vec1, sword16* vec2, } /* rand holds secret noise. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("mlkem_poly rand", rand, sizeof(rand)); +#endif ForceZero(rand, sizeof(rand)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(rand, sizeof(rand)); +#endif return ret; } #endif diff --git a/wolfcrypt/src/wc_she.c b/wolfcrypt/src/wc_she.c index 712e760a9b..c4e7060736 100644 --- a/wolfcrypt/src/wc_she.c +++ b/wolfcrypt/src/wc_she.c @@ -561,6 +561,18 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, return ret; } + /* Register the key-material buffers now: past this point every path reaches + * the scrub below. Baseline-zero first so they are defined at registration. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(k1, 0xff, sizeof(k1)); + XMEMSET(k2, 0xff, sizeof(k2)); + XMEMSET(kdfInput, 0xff, sizeof(kdfInput)); + wc_MemZero_Add("wc_SHE_GenerateM1M2M3 kdfInput", kdfInput, + sizeof(kdfInput)); + wc_MemZero_Add("wc_SHE_GenerateM1M2M3 k1", k1, sizeof(k1)); + wc_MemZero_Add("wc_SHE_GenerateM1M2M3 k2", k2, sizeof(k2)); +#endif + /* ---- Derive K1 = AES-MP(AuthKey || CENC) ---- */ XMEMCPY(kdfInput, authKey, WC_SHE_KEY_SZ); XMEMCPY(kdfInput + WC_SHE_KEY_SZ, encC, WC_SHE_KEY_SZ); @@ -613,6 +625,11 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, ForceZero(k1, sizeof(k1)); ForceZero(k2, sizeof(k2)); ForceZero(kdfInput, sizeof(kdfInput)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(k1, sizeof(k1)); + wc_MemZero_Check(k2, sizeof(k2)); + wc_MemZero_Check(kdfInput, sizeof(kdfInput)); +#endif wc_AesFree(aes); WC_FREE_VAR(aes, she->heap); @@ -716,6 +733,18 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, return ret; } + /* Register the key-material buffers now: past this point every path reaches + * the scrub below. Baseline-zero first so they are defined at registration. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + XMEMSET(k3, 0xff, sizeof(k3)); + XMEMSET(k4, 0xff, sizeof(k4)); + XMEMSET(kdfInput, 0xff, sizeof(kdfInput)); + wc_MemZero_Add("wc_SHE_GenerateM4M5 kdfInput", kdfInput, + sizeof(kdfInput)); + wc_MemZero_Add("wc_SHE_GenerateM4M5 k3", k3, sizeof(k3)); + wc_MemZero_Add("wc_SHE_GenerateM4M5 k4", k4, sizeof(k4)); +#endif + /* ---- Derive K3 = AES-MP(NewKey || CENC) ---- */ XMEMCPY(kdfInput, newKey, WC_SHE_KEY_SZ); XMEMCPY(kdfInput + WC_SHE_KEY_SZ, encC, WC_SHE_KEY_SZ); @@ -760,6 +789,11 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, ForceZero(k3, sizeof(k3)); ForceZero(k4, sizeof(k4)); ForceZero(kdfInput, sizeof(kdfInput)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(k3, sizeof(k3)); + wc_MemZero_Check(k4, sizeof(k4)); + wc_MemZero_Check(kdfInput, sizeof(kdfInput)); +#endif wc_AesFree(aes); WC_FREE_VAR(aes, she->heap); diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index c70310ff22..789c09c2ff 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef NO_INLINE #include #else @@ -1006,7 +1007,13 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, } /* digest holds the secret PRF output (WOTS+/FORS key). */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("slhdsa prf digest", digest, sizeof(digest)); +#endif ForceZero(digest, sizeof(digest)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(digest, sizeof(digest)); +#endif return ret; } #endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ @@ -3349,7 +3356,13 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, /* On error sk still holds a secret WOTS+ leaf; on success it is overwritten * with a public chain value. */ if (ret != 0) { +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("slhdsa wots sk", sk, n); +#endif ForceZero(sk, n); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(sk, n); +#endif } #endif @@ -3875,7 +3888,13 @@ static int slhdsakey_wots_sign(SlhDsaKey* key, const byte* m, } /* sk held the secret WOTS+ leaf. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("slhdsa wots sk", sk, n); +#endif ForceZero(sk, n); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(sk, n); +#endif } return ret; @@ -7518,6 +7537,11 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz, if (ret == 0) { /* Generate n bytes of random. */ ret = wc_RNG_GenerateBlock(rng, addRnd, key->params->n); + /* addRnd now holds the secret signing randomness; register before the + * sign call so a future early-exit before the ForceZero is caught. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("slhdsa sign addRnd", addRnd, sizeof(addRnd)); +#endif } if (ret == 0) { /* Pure sign. */ @@ -7526,6 +7550,9 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz, } ForceZero(addRnd, sizeof(addRnd)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(addRnd, sizeof(addRnd)); +#endif return ret; } @@ -8441,6 +8468,11 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, if (ret == 0) { /* Generate n bytes of random. */ ret = wc_RNG_GenerateBlock(rng, addRnd, key->params->n); + /* addRnd now holds the secret signing randomness; register before the + * sign call so a future early-exit before the ForceZero is caught. */ +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("slhdsa sign_hash addRnd", addRnd, sizeof(addRnd)); +#endif } if (ret == 0) { /* HashSLH-DSA sign with caller-supplied digest. */ @@ -8449,6 +8481,9 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, } ForceZero(addRnd, sizeof(addRnd)); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(addRnd, sizeof(addRnd)); +#endif return ret; }