From 48e812ef3ffa0308d41e12a93e5d98136a84aae1 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:03:09 -0700 Subject: [PATCH 01/33] F-12758 - Zeroize RNG structure in EccMakePubBlinded --- src/tpm2_wrap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 96999072..8bb283d0 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -5178,6 +5178,7 @@ static int wolfTPM2_EccMakePubBlinded(ecc_key* key, ecc_point* point) wc_FreeRng(&rng); } + TPM2_ForceZero(&rng, sizeof(rng)); return rc; #else (void)key; From 6dc639ddac04a6ed4d137dc5edde6261d44beae1 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:03:38 -0700 Subject: [PATCH 02/33] F-11924 - Zeroize ECC key and RNG structures after encrypt-secret cleanup --- src/tpm2_wrap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 8bb283d0..7f069bb1 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -2505,6 +2505,9 @@ static int wolfTPM2_EncryptSecret_ECC(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpm wc_ecc_free(&eccKeyPub); wc_ecc_free(&eccKeyPriv); wc_FreeRng(&rng); + TPM2_ForceZero(&eccKeyPub, sizeof(eccKeyPub)); + TPM2_ForceZero(&eccKeyPriv, sizeof(eccKeyPriv)); + TPM2_ForceZero(&rng, sizeof(rng)); TPM2_ForceZero(&secretPoint, sizeof(secretPoint)); if (rc >= 0) { From 34d4bd528d424d79cdcc55105abad7977a8b46d5 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:04:41 -0700 Subject: [PATCH 03/33] F-12756 - Zeroize SPDM requester key and RNG structures after cleanup --- src/tpm2_wrap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 7f069bb1..ee8374d5 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -1620,6 +1620,8 @@ int wolfTPM2_SpdmConnectNuvoton(WOLFTPM2_DEV* dev, pubKeyY, &ySz); wc_ecc_free(&hostKey); wc_FreeRng(&rng); + TPM2_ForceZero(&hostKey, sizeof(hostKey)); + TPM2_ForceZero(&rng, sizeof(rng)); if (rc != 0) { wc_ForceZero(privKey, sizeof(privKey)); return rc; @@ -1806,6 +1808,8 @@ int wolfTPM2_SpdmConnectNations(WOLFTPM2_DEV* dev, pubKeyY, &ySz); wc_ecc_free(&hostKey); wc_FreeRng(&rng); + TPM2_ForceZero(&hostKey, sizeof(hostKey)); + TPM2_ForceZero(&rng, sizeof(rng)); if (rc != 0) { wc_ForceZero(privKey, sizeof(privKey)); return rc; From 2aabc020f0d9e660ac13fa528e2bab65b2b9ac0e Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:05:55 -0700 Subject: [PATCH 04/33] F-12757 - Zeroize private-key decoder contexts after release --- src/tpm2_wrap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index ee8374d5..8ef00785 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -4419,6 +4419,7 @@ int wolfTPM2_DecodeRsaDer(const byte* der, word32 derSz, } } wc_FreeRsaKey(key); + TPM2_ForceZero(key, sizeof(RsaKey)); } TPM2_ForceZero(d, sizeof(d)); @@ -4544,6 +4545,7 @@ int wolfTPM2_DecodeEccDer(const byte* der, word32 derSz, TPM2B_PUBLIC* pub, } wc_ecc_free(key); + TPM2_ForceZero(key, sizeof(ecc_key)); } TPM2_ForceZero(d, sizeof(d)); @@ -4887,8 +4889,10 @@ int wolfTPM2_RsaPrivateKeyImportDer(WOLFTPM2_DEV* dev, qSz, scheme, hashAlg); } - if (initRc == 0) + if (initRc == 0) { wc_FreeRsaKey(key); + TPM2_ForceZero(key, sizeof(RsaKey)); + } TPM2_ForceZero(d, sizeof(d)); TPM2_ForceZero(p, sizeof(p)); From 31a5a009ed8ec15386ef2507da45a7eac925aee8 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:06:59 -0700 Subject: [PATCH 05/33] F-12755 - Zeroize session start nonce structures after use --- src/tpm2_wrap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 8ef00785..2cbf1ba9 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -2916,6 +2916,8 @@ int wolfTPM2_StartSession_ex(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session, wolfTPM2_GetRCString(rc)); #endif TPM2_ForceZero(&session->salt, sizeof(session->salt)); + TPM2_ForceZero(&authSesIn, sizeof(authSesIn)); + TPM2_ForceZero(&authSesOut, sizeof(authSesOut)); return rc; } @@ -3021,6 +3023,8 @@ int wolfTPM2_StartSession_ex(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session, } TPM2_ForceZero(keyIn, sizeof(keyIn)); + TPM2_ForceZero(&authSesIn, sizeof(authSesIn)); + TPM2_ForceZero(&authSesOut, sizeof(authSesOut)); return rc; } From fe58cd303fa30acea9d53317ac385fd075d650f0 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:08:33 -0700 Subject: [PATCH 06/33] F-9225 - Scrub partial random output when GetRandom fails --- src/tpm2_wrap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 2cbf1ba9..762bfffd 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -8040,6 +8040,10 @@ int wolfTPM2_GetRandom(WOLFTPM2_DEV* dev, byte* buf, word32 len) TPM2_ForceZero(&out, sizeof(out)); } TPM2_ForceZero(&out, sizeof(out)); + if (rc != TPM_RC_SUCCESS) { + /* Scrub any partial random material already written to the caller */ + TPM2_ForceZero(buf, len); + } return rc; } From 883b2f3dd58b0c1ff89347d362abd4e5fda0ec0f Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:08:33 -0700 Subject: [PATCH 07/33] F-9226 - Clear prior HMAC usage auth before storing a shorter value --- src/tpm2_wrap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 762bfffd..cda53149 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -8725,7 +8725,9 @@ int wolfTPM2_HmacStart(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac, } if (usageAuth != NULL) { - /* Capture usage auth */ + /* Capture usage auth, clearing any longer prior value first */ + TPM2_ForceZero(hmac->hash.handle.auth.buffer, + sizeof(hmac->hash.handle.auth.buffer)); hmac->hash.handle.auth.size = usageAuthSz; XMEMCPY(hmac->hash.handle.auth.buffer, usageAuth, usageAuthSz); } From 4ea966cf502aa942328daf40340378d6811dbc4a Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:10:03 -0700 Subject: [PATCH 08/33] F-9227 - Clear the previous private blob tail when copying a shorter one --- src/tpm2_wrap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index cda53149..28165ac7 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -10221,6 +10221,8 @@ static void wolfTPM2_CopyPub(TPM2B_PUBLIC* out, const TPM2B_PUBLIC* in) static void wolfTPM2_CopyPriv(TPM2B_PRIVATE* out, const TPM2B_PRIVATE* in) { if (out != NULL && in != NULL) { + /* Clear any longer prior blob so its tail does not remain resident */ + TPM2_ForceZero(out->buffer, sizeof(out->buffer)); out->size = in->size; if (out->size > (UINT16)sizeof(out->buffer)) out->size = (UINT16)sizeof(out->buffer); From 7bf779831a3d613fc98a0bde4a2f385a476ee238 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:10:03 -0700 Subject: [PATCH 09/33] F-9228 - Wipe key blob when trailing-data validation fails --- src/tpm2_wrap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 28165ac7..1bc147a8 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -902,6 +902,7 @@ int wolfTPM2_SetKeyBlobFromBuffer(WOLFTPM2_KEYBLOB* key, byte *buffer, printf("Extra data left in buffer (%d!=%d)\n", bufferSz, (word32)done_reading); #endif + TPM2_ForceZero(key, sizeof(*key)); return BUFFER_E; } From 21bfefb346492fa41e1a5bf389c497bae5488292 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:10:30 -0700 Subject: [PATCH 10/33] F-13538 - Clear plaintext salt or seed after failed RSA secret encryption --- src/tpm2_wrap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 1bc147a8..0ae5ae5f 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -2609,6 +2609,12 @@ static int wolfTPM2_EncryptSecret_RSA(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpm rc = (rc == secret->size) ? 0 /* success */ : BUFFER_E /* fail */; } + if (rc != 0) { + /* Do not leave the plaintext salt or seed in the caller buffer */ + TPM2_ForceZero(data->buffer, sizeof(data->buffer)); + data->size = 0; + } + return rc; } #endif /* !WOLFTPM2_NO_WOLFCRYPT && !NO_RSA && !WC_NO_RNG */ From e7b4210bf2915be1f78dbf33fe105f2f89825bd1 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:15:24 -0700 Subject: [PATCH 11/33] F-13464 - Reject a NULL second HMAC buffer with a nonzero length --- src/tpm2_crypto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tpm2_crypto.c b/src/tpm2_crypto.c index 2b3ec226..2f975f51 100644 --- a/src/tpm2_crypto.c +++ b/src/tpm2_crypto.c @@ -420,7 +420,8 @@ int TPM2_HmacCompute( int dSz; if (digest == NULL || (key == NULL && keySz > 0) || - (data == NULL && dataSz > 0)) { + (data == NULL && dataSz > 0) || + (data2 == NULL && data2Sz > 0)) { return BAD_FUNC_ARG; } From 101af8eac1c6e6dfb71fcf3cdf792f379c583f90 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:15:24 -0700 Subject: [PATCH 12/33] F-12734 - Bound RsaPadPss scratch write to the block length --- src/tpm2_cryptocb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2_cryptocb.c b/src/tpm2_cryptocb.c index 0fc7ecb4..774d66c6 100644 --- a/src/tpm2_cryptocb.c +++ b/src/tpm2_cryptocb.c @@ -1110,6 +1110,10 @@ static int RsaPadPss(const byte* input, word32 inputLen, byte* pkcsBlock, if ((int)pkcsBlockLen - hLen < saltLen + 2) { return PSS_SALTLEN_E; } + /* Ensure M' (padding || hLen || saltLen) fits the scratch buffer */ + if ((int)pkcsBlockLen < RSA_PSS_PAD_SZ + hLen + saltLen) { + return PSS_SALTLEN_E; + } ret = wc_HashInit_ex(&hashCtx, hType, NULL, INVALID_DEVID); if (ret != 0) { From f6662b50c6a7ef026433b26b68cbed3f47726048 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:15:24 -0700 Subject: [PATCH 13/33] F-9181 - Distinguish TPM integrity errors from invalid ECDSA signatures --- src/tpm2_cryptocb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tpm2_cryptocb.c b/src/tpm2_cryptocb.c index 774d66c6..5fd167c4 100644 --- a/src/tpm2_cryptocb.c +++ b/src/tpm2_cryptocb.c @@ -382,7 +382,7 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) sigRS, keySz*2, info->pk.eccverify.hash, info->pk.eccverify.hashlen); if (info->pk.eccverify.res) { - if ((rc & TPM_RC_SIGNATURE) == TPM_RC_SIGNATURE) { + if ((rc & RC_MAX_FMT1) == TPM_RC_SIGNATURE) { /* mark invalid signature */ *info->pk.eccverify.res = 0; rc = 0; From 876be62682741f997e93379c7662b5f4a221b220 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:28:27 -0700 Subject: [PATCH 14/33] F-9223 - Scrub session auth and cpHash on command-process error paths --- src/tpm2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tpm2.c b/src/tpm2.c index e3d1ec67..c43b8647 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -235,6 +235,7 @@ static int TPM2_CommandProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Command parameter encryption failed\n"); #endif + TPM2_ForceZero(&authCmd, sizeof(authCmd)); return rc; } } @@ -249,6 +250,7 @@ static int TPM2_CommandProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Error getting names for cpHash!\n"); #endif + TPM2_ForceZero(&authCmd, sizeof(authCmd)); return BAD_FUNC_ARG; } @@ -259,6 +261,8 @@ static int TPM2_CommandProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Error calculating cpHash!\n"); #endif + TPM2_ForceZero(&hash, sizeof(hash)); + TPM2_ForceZero(&authCmd, sizeof(authCmd)); return rc; } /* Calculate HMAC for policy, hmac or salted sessions */ @@ -270,6 +274,8 @@ static int TPM2_CommandProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Error calculating command HMAC!\n"); #endif + TPM2_ForceZero(&hash, sizeof(hash)); + TPM2_ForceZero(&authCmd, sizeof(authCmd)); return rc; } #endif /* !WOLFTPM2_NO_WOLFCRYPT && !NO_HMAC */ From 6a29422a4a8bf26466ca03cc1cde85e2327f5149 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:29:22 -0700 Subject: [PATCH 15/33] F-9224 - Scrub partial nonce bytes when a later RNG chunk fails --- src/tpm2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2.c b/src/tpm2.c index c43b8647..1627c4a6 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -6828,6 +6828,10 @@ int TPM2_GetNonceNoLock(byte* nonceBuf, int nonceSz) } /* response buffer held freshly generated random; wipe before return */ TPM2_ForceZero(buffer, sizeof(buffer)); + if (rc != TPM_RC_SUCCESS && randSz > 0) { + /* wipe partial nonce bytes already written from earlier chunks */ + TPM2_ForceZero(nonceBuf, (word32)randSz); + } #endif return rc; From d7d86acdb526a1eae036bddbbb05c3c2dec57601 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:29:22 -0700 Subject: [PATCH 16/33] F-13497 - Verify response HMAC in constant time on size mismatch --- src/tpm2.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/tpm2.c b/src/tpm2.c index 1627c4a6..92ede7be 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -394,14 +394,21 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, XMEMSET(&hash, 0, sizeof(hash)); XMEMSET(&hmac, 0, sizeof(hmac)); - if (expectedHmacSz == 0 || authRsp.hmac.size != expectedHmacSz) { + if (expectedHmacSz == 0) { #ifdef DEBUG_WOLFTPM - printf("Response HMAC size mismatch! expected=%u got=%u\n", - expectedHmacSz, authRsp.hmac.size); + printf("Response HMAC size invalid! expected=%u\n", + expectedHmacSz); #endif TPM2_ForceZero(&authRsp, sizeof(authRsp)); return TPM_RC_HMAC; } + sizeMismatch = (authRsp.hmac.size != expectedHmacSz); + #ifdef DEBUG_WOLFTPM + if (sizeMismatch) { + printf("Response HMAC size mismatch! expected=%u got=%u\n", + expectedHmacSz, authRsp.hmac.size); + } + #endif /* calculate "rpHash" hash for command code and parameters */ rc = TPM2_CalcRpHash(session->authHash, cmdCode, param, paramSz, @@ -429,11 +436,11 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, return rc; } - /* Verify HMAC using constant-time comparison. Wire-format - * size is validated above; this is a branch-free tail check - * (hmac.size and authRsp.hmac.size are both algorithm-derived - * and equal to expectedHmacSz at this point). */ - sizeMismatch = (hmac.size != authRsp.hmac.size); + /* Verify HMAC using constant-time comparison. A wire-size + * mismatch captured above is combined here rather than + * rejected early, so this always reads expectedHmacSz + * bytes regardless of the attacker-supplied wire size. */ + sizeMismatch |= (hmac.size != authRsp.hmac.size); diff = TPM2_ConstantCompare(hmac.buffer, authRsp.hmac.buffer, expectedHmacSz); if (sizeMismatch | diff) { From 23ebb85f73bebca3043f4db1c7dc0c92068514e3 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:30:17 -0700 Subject: [PATCH 17/33] F-10761 - Clear sensitive output when the outer TPM2B size is zero --- src/tpm2_packet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index 5dee7e98..308d72ce 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -946,6 +946,7 @@ void TPM2_Packet_ParseSensitive(TPM2_Packet* packet, TPM2B_SENSITIVE* sensitive) TPM2_Packet_ParseU16(packet, &sensitive->size); if (sensitive->size == 0) { + XMEMSET(&sensitive->sensitiveArea, 0, sizeof(sensitive->sensitiveArea)); return; } /* Clamp outer size to remaining packet bytes so inner parses are bounded */ From 26e7873427cd1ef2b22d63bbdc98f14bbb48a404 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:30:17 -0700 Subject: [PATCH 18/33] F-12714 - Flag packet overflow on truncated outer ECC point length --- src/tpm2_packet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index 308d72ce..1f07a248 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -871,6 +871,7 @@ void TPM2_Packet_ParsePoint(TPM2_Packet* packet, TPM2B_ECC_POINT* point) } else { packet->pos = packet->size; + packet->overflow = 1; } } } From 89c20bf6614b78f37cf921d580c1621788e76974 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:30:17 -0700 Subject: [PATCH 19/33] F-11914 - Reject nonzero SWTPM protocol acknowledgement --- src/tpm2_swtpm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tpm2_swtpm.c b/src/tpm2_swtpm.c index 34c1c64b..bfa2ddee 100644 --- a/src/tpm2_swtpm.c +++ b/src/tpm2_swtpm.c @@ -611,11 +611,12 @@ int TPM2_SWTPM_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) if (rc == TPM_RC_SUCCESS) { rc = SwTpmReceive(ctx, &tss_word, sizeof(uint32_t)); tss_word = TPM2_Packet_SwapU32(tss_word); - #ifdef WOLFTPM_DEBUG - if (tss_word != 0) { + if (rc == TPM_RC_SUCCESS && tss_word != 0) { + #ifdef WOLFTPM_DEBUG printf("SWTPM ack %d\n", tss_word); + #endif + rc = TPM_RC_FAILURE; } - #endif } From b77afa5a594e8dc099df27e7c13dc3e24d55b052 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:30:17 -0700 Subject: [PATCH 20/33] F-11913 - Propagate positive TIS burst-count errors --- src/tpm2_tis.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tpm2_tis.c b/src/tpm2_tis.c index 2e72aca1..c0cf4fa8 100644 --- a/src/tpm2_tis.c +++ b/src/tpm2_tis.c @@ -527,7 +527,7 @@ int TPM2_TIS_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) pos = 0; while (pos < packet->pos) { rc = TPM2_TIS_GetBurstCount(ctx, &burstCount); - if (rc < 0) + if (rc != TPM_RC_SUCCESS) goto exit; xferSz = packet->pos - pos; @@ -590,7 +590,7 @@ int TPM2_TIS_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) } rc = TPM2_TIS_GetBurstCount(ctx, &burstCount); - if (rc < 0) + if (rc != TPM_RC_SUCCESS) goto exit; xferSz = rspSz - pos; From 33f6f954d3ead7d77d867c80df46c6746f45ee42 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:31:04 -0700 Subject: [PATCH 21/33] F-13460 - Copy CreateAndLoadKey output only after success --- src/tpm2_wrap.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 0ae5ae5f..de3bd9ce 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -3372,14 +3372,19 @@ int wolfTPM2_CreateAndLoadKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, if (dev == NULL || key == NULL) return BAD_FUNC_ARG; + XMEMSET(key, 0, sizeof(WOLFTPM2_KEY)); + XMEMSET(&keyBlob, 0, sizeof(keyBlob)); + rc = wolfTPM2_CreateKey(dev, &keyBlob, parent, publicTemplate, auth, authSz); if (rc == TPM_RC_SUCCESS) { rc = wolfTPM2_LoadKey(dev, &keyBlob, parent); } - /* return loaded key */ - XMEMCPY(key, &keyBlob, sizeof(WOLFTPM2_KEY)); + if (rc == TPM_RC_SUCCESS) { + /* return loaded key */ + XMEMCPY(key, &keyBlob, sizeof(WOLFTPM2_KEY)); + } TPM2_ForceZero(&keyBlob, sizeof(keyBlob)); return rc; From 44e976c9aa5a6e62672f68b8241707ca7c88f268 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:31:04 -0700 Subject: [PATCH 22/33] F-11900 - Reject unsupported key types in SignHashScheme --- src/tpm2_wrap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index de3bd9ce..34e21bb4 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -5531,6 +5531,11 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, return BAD_FUNC_ARG; } + if (key->pub.publicArea.type != TPM_ALG_ECC && + key->pub.publicArea.type != TPM_ALG_RSA) { + return BAD_FUNC_ARG; + } + if (key->pub.publicArea.type == TPM_ALG_ECC) { /* get curve size */ curveSize = wolfTPM2_GetCurveSize( From 69a22797ffc2e2c0ab377c671fe82f81f0563b9b Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:31:04 -0700 Subject: [PATCH 23/33] F-13466 - Reject unsupported key types in ImportPrivateKeyBuffer --- src/tpm2_wrap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 34e21bb4..ac8e7953 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -4758,6 +4758,10 @@ int wolfTPM2_ImportPrivateKeyBuffer(WOLFTPM2_DEV* dev, return BAD_FUNC_ARG; } + if (keyType != TPM_ALG_RSA && keyType != TPM_ALG_ECC) { + return BAD_FUNC_ARG; + } + pub = &keyBlob->pub; XMEMSET(pub, 0, sizeof(*pub)); XMEMSET(&sens, 0, sizeof(sens)); From e080e326eaab3f374c94d2b08ea9cf956176d65e Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:31:05 -0700 Subject: [PATCH 24/33] F-9178 - Reject unsupported key types in ImportPublicKeyBuffer --- src/tpm2_wrap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index ac8e7953..5e220721 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -4692,6 +4692,10 @@ int wolfTPM2_ImportPublicKeyBuffer(WOLFTPM2_DEV* dev, int keyType, return BAD_FUNC_ARG; } + if (keyType != TPM_ALG_RSA && keyType != TPM_ALG_ECC) { + return BAD_FUNC_ARG; + } + if (encodingType == ENCODING_TYPE_PEM) { #ifdef WOLFTPM2_PEM_DECODE /* der size is base 64 decode length */ From 41df4302f5ff4c53cde0f29d303f23e0c0170fe5 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:31:05 -0700 Subject: [PATCH 25/33] F-11923 - Zeroize sequence-start command structures --- src/tpm2_wrap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 5e220721..4865f1d8 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -5880,6 +5880,8 @@ int wolfTPM2_SignSequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, *sequenceHandle = signSeqStartOut.sequenceHandle; } + TPM2_ForceZero(&signSeqStartIn, sizeof(signSeqStartIn)); + return rc; } @@ -6070,6 +6072,8 @@ int wolfTPM2_VerifySequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, *sequenceHandle = verifySeqStartOut.sequenceHandle; } + TPM2_ForceZero(&verifySeqStartIn, sizeof(verifySeqStartIn)); + return rc; } From 7345dd085d6d541ce91aeb93072944a038c4a433 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:32:25 -0700 Subject: [PATCH 26/33] F-11895 - Make TPM2_ForceZero a no-op for a NULL pointer --- src/tpm2_util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tpm2_util.c b/src/tpm2_util.c index 88560eb2..686d862d 100644 --- a/src/tpm2_util.c +++ b/src/tpm2_util.c @@ -140,6 +140,9 @@ int TPM2_ConstantCompare(const byte* a, const byte* b, word32 len) void TPM2_ForceZero(void* mem, word32 len) { volatile byte* z = (volatile byte*)mem; + if (mem == NULL) { + return; + } while (len--) { *z++ = 0; } From b8d98fa6c16420a7f1cd9d57ae075d4dd605049d Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:32:25 -0700 Subject: [PATCH 27/33] F-10778 - Document that FWTPM_Clock_SetHAL rejects a NULL callback --- wolftpm/fwtpm/fwtpm.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wolftpm/fwtpm/fwtpm.h b/wolftpm/fwtpm/fwtpm.h index d25cb1af..cca588fe 100644 --- a/wolftpm/fwtpm/fwtpm.h +++ b/wolftpm/fwtpm/fwtpm.h @@ -979,11 +979,11 @@ WOLFTPM_API const char* FWTPM_GetVersionString(void); FWTPM_Clock_GetMs returns ctx->clockOffset only. \return 0 on success - \return BAD_FUNC_ARG if ctx is NULL + \return BAD_FUNC_ARG if ctx or get_ms is NULL \param ctx pointer to an initialized FWTPM_CTX - \param get_ms callback returning milliseconds-since-boot; may be NULL - to clear a previously registered HAL + \param get_ms callback returning milliseconds-since-boot; must be + non-NULL, or the call returns BAD_FUNC_ARG \param halCtx opaque context passed back to get_ms \sa FWTPM_Clock_GetMs From 16fe89b6f6393425a3133ab4da093613536b36d6 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:34:40 -0700 Subject: [PATCH 28/33] F-12752 - Wipe TPM SPDM I/O staging buffers before return --- src/tpm2_spdm.c | 76 ++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/src/tpm2_spdm.c b/src/tpm2_spdm.c index f3c7a44c..a1c19e7b 100644 --- a/src/tpm2_spdm.c +++ b/src/tpm2_spdm.c @@ -111,30 +111,31 @@ static int wolfTPM2_SPDM_TisIoCb( /* Ensure we have TPM locality */ rc = TPM2_TIS_RequestLocality(tpmCtx, TPM_TIMEOUT_TRIES); - if (rc != TPM_RC_SUCCESS) { - return rc; + if (rc == TPM_RC_SUCCESS) { + /* Send through TIS FIFO and receive response */ + rc = TPM2_TIS_SendCommand(tpmCtx, &packet); } - /* Send through TIS FIFO and receive response */ - rc = TPM2_TIS_SendCommand(tpmCtx, &packet); - if (rc != TPM_RC_SUCCESS) { - return rc; + if (rc == TPM_RC_SUCCESS) { + /* Extract response size from header bytes [2..5] (big-endian). + * Both TPM headers and TCG SPDM binding headers store the total + * message size at this offset in the same format. */ + XMEMCPY(&rspSz, &ioBuf[2], sizeof(UINT32)); + rspSz = TPM2_Packet_SwapU32(rspSz); + + if (wolfTPM2_SPDM_ValidateRspSz(rspSz, *rxSz, sizeof(ioBuf)) != 0) { + rc = -1; + } } - /* Extract response size from header bytes [2..5] (big-endian). - * Both TPM headers and TCG SPDM binding headers store the total - * message size at this offset in the same format. */ - XMEMCPY(&rspSz, &ioBuf[2], sizeof(UINT32)); - rspSz = TPM2_Packet_SwapU32(rspSz); - - if (wolfTPM2_SPDM_ValidateRspSz(rspSz, *rxSz, sizeof(ioBuf)) != 0) { - return -1; + if (rc == TPM_RC_SUCCESS) { + XMEMCPY(rxBuf, ioBuf, rspSz); + *rxSz = rspSz; } - XMEMCPY(rxBuf, ioBuf, rspSz); - *rxSz = rspSz; + TPM2_ForceZero(ioBuf, sizeof(ioBuf)); - return 0; + return rc; } #endif /* WOLFTPM_SPDM_TIS_IO */ @@ -166,28 +167,33 @@ static int wolfTPM2_SPDM_SwtpmIoCb( packet.size = (int)sizeof(ioBuf); rc = TPM2_SWTPM_SendCommand(tpmCtx, &packet); - if (rc != TPM_RC_SUCCESS) { - return rc; + + if (rc == TPM_RC_SUCCESS) { + /* TPM2_SWTPM_SendCommand validated the received length against + * TPM2_HEADER_SIZE, so the size field below is present. */ + + /* TCG SPDM Binding header and TPM2 header both carry total size at + * bytes [2..5] big-endian. */ + XMEMCPY(&rspSz, &ioBuf[2], sizeof(word32)); + rspSz = TPM2_Packet_SwapU32(rspSz); + + if (rspSz < TPM2_HEADER_SIZE) { + rc = -1; + } + else if (wolfTPM2_SPDM_ValidateRspSz(rspSz, *rxSz, + sizeof(ioBuf)) != 0) { + rc = -1; + } } - /* TPM2_SWTPM_SendCommand validated the received length against - * TPM2_HEADER_SIZE, so the size field below is present. */ - - /* TCG SPDM Binding header and TPM2 header both carry total size at - * bytes [2..5] big-endian. */ - XMEMCPY(&rspSz, &ioBuf[2], sizeof(word32)); - rspSz = TPM2_Packet_SwapU32(rspSz); - - if (rspSz < TPM2_HEADER_SIZE) { - return -1; - } - if (wolfTPM2_SPDM_ValidateRspSz(rspSz, *rxSz, sizeof(ioBuf)) != 0) { - return -1; + if (rc == TPM_RC_SUCCESS) { + XMEMCPY(rxBuf, ioBuf, rspSz); + *rxSz = rspSz; } - XMEMCPY(rxBuf, ioBuf, rspSz); - *rxSz = rspSz; - return 0; + TPM2_ForceZero(ioBuf, sizeof(ioBuf)); + + return rc; } #endif /* WOLFTPM_SPDM_SWTPM_IO */ From 5e20f44d00abf6efed77f08eb76c1a23d7cc4f65 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:47:07 -0700 Subject: [PATCH 29/33] F-10810 - Accept exact-fit buffers in TPM2_AppendPublic --- src/tpm2.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tpm2.c b/src/tpm2.c index 92ede7be..bdbac1d2 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -7598,19 +7598,21 @@ int TPM2_AppendPublic(byte* buf, word32 size, int* sizeUsed, TPM2B_PUBLIC* pub) if (buf == NULL || pub == NULL || sizeUsed == NULL) return BAD_FUNC_ARG; - if (size < sizeof(TPM2B_PUBLIC)) { + /* Prepare temporary buffer. The append helpers bounds-check against + * packet.size and set packet.overflow, so an exact-fit buffer is + * accepted and only an actually-too-small buffer is rejected. */ + packet.buf = buf; + packet.pos = 0; + packet.size = (int)size; + packet.overflow = 0; + + TPM2_Packet_AppendPublic(&packet, pub); + if (packet.overflow) { #ifdef DEBUG_WOLFTPM printf("Insufficient buffer size for TPM2B_PUBLIC operations\n"); #endif return TPM_RC_FAILURE; } - - /* Prepare temporary buffer */ - packet.buf = buf; - packet.pos = 0; - packet.size = (int)size; - - TPM2_Packet_AppendPublic(&packet, pub); *sizeUsed = packet.pos; return TPM_RC_SUCCESS; From 3f1baaee9fddd7ad3d2c6ade2a3848c52b034521 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:48:07 -0700 Subject: [PATCH 30/33] F-10811 - Retire one-shot sessions after a verified response --- src/tpm2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tpm2.c b/src/tpm2.c index bdbac1d2..e8825345 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -480,6 +480,15 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, return rc; } } + + /* Retire a one-shot session: when the TPM clears + * continueSession the session is consumed, so clear the local + * slot to prevent reuse of a stale handle. */ + if ((authRsp.sessionAttributes & TPMA_SESSION_continueSession) + == 0) { + TPM2_ForceZero(session, sizeof(TPM2_AUTH_SESSION)); + session->sessionHandle = TPM_RS_PW; + } } TPM2_ForceZero(&authRsp, sizeof(authRsp)); From 3d31a932bff0ad4ac6514ecf948b9705e61708ce Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:50:09 -0700 Subject: [PATCH 31/33] F-10816 - Size PCR selection storage and marshalling for PCR_SELECT_MAX --- src/tpm2_packet.c | 8 ++++---- wolftpm/tpm2.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index 1f07a248..4e768090 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -573,8 +573,8 @@ void TPM2_Packet_AppendPCR(TPM2_Packet* packet, TPML_PCR_SELECTION* pcr) TPM2_Packet_AppendU32(packet, count); for (i=0; i<(int)count; i++) { UINT8 selectSz = pcr->pcrSelections[i].sizeofSelect; - if (selectSz > PCR_SELECT_MIN) - selectSz = PCR_SELECT_MIN; + if (selectSz > PCR_SELECT_MAX) + selectSz = PCR_SELECT_MAX; TPM2_Packet_AppendU16(packet, pcr->pcrSelections[i].hash); TPM2_Packet_AppendU8(packet, selectSz); TPM2_Packet_AppendBytes(packet, @@ -621,8 +621,8 @@ void TPM2_Packet_ParsePCR(TPM2_Packet* packet, TPML_PCR_SELECTION* pcr) if (i < (int)pcr->count) { pcr->pcrSelections[i].hash = hash; pcr->pcrSelections[i].sizeofSelect = wireSizeofSelect; - if (pcr->pcrSelections[i].sizeofSelect > PCR_SELECT_MIN) - pcr->pcrSelections[i].sizeofSelect = PCR_SELECT_MIN; + if (pcr->pcrSelections[i].sizeofSelect > PCR_SELECT_MAX) + pcr->pcrSelections[i].sizeofSelect = PCR_SELECT_MAX; TPM2_Packet_ParseBytes(packet, pcr->pcrSelections[i].pcrSelect, pcr->pcrSelections[i].sizeofSelect); diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index 84a11b88..057c95fd 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -1158,7 +1158,7 @@ typedef struct TPMS_PCR_SELECT { typedef struct TPMS_PCR_SELECTION { TPMI_ALG_HASH hash; BYTE sizeofSelect; - BYTE pcrSelect[PCR_SELECT_MIN]; + BYTE pcrSelect[PCR_SELECT_MAX]; } TPMS_PCR_SELECTION; From 13055855403afd78e884a910fb3011c9cd6a66ff Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:52:32 -0700 Subject: [PATCH 32/33] F-10837 - Reject truncated public area when computing an object Name --- src/tpm2_wrap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 4865f1d8..33c06a93 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -3543,6 +3543,11 @@ int wolfTPM2_ComputeName(const TPM2B_PUBLIC* pub, TPM2B_NAME* out) packet.buf = data.buffer; packet.size = sizeof(data.buffer); TPM2_Packet_AppendPublicArea(&packet, (TPMT_PUBLIC*)&pub->publicArea); + if (packet.overflow) { + /* A truncated public area would produce a wrong Name and corrupt + * authorization binding, so reject rather than hash a partial area */ + return BUFFER_E; + } data.size = packet.pos; hashSz = TPM2_GetHashDigestSize(nameAlg); From c9e49e03ddadbefc2b1bf47ae0419fb47fb6a0a2 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 8 Sep 2026 12:53:14 -0700 Subject: [PATCH 33/33] F-12754 - Zeroize hash context and buffer in TPM2_HashNvPublic --- src/tpm2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tpm2.c b/src/tpm2.c index e8825345..a0c5c95a 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -7538,6 +7538,7 @@ int TPM2_HashNvPublic(TPMS_NV_PUBLIC* nvPublic, byte* buffer, UINT16* size) #ifndef WOLFTPM2_NO_WOLFCRYPT int rc; int hashSize, nameAlgSize; + int hashInitialized = 0; UINT16 nameAlgValue; wc_HashAlg hash; enum wc_HashType hashType; @@ -7573,6 +7574,7 @@ int TPM2_HashNvPublic(TPMS_NV_PUBLIC* nvPublic, byte* buffer, UINT16* size) rc = wc_HashInit(&hash, hashType); if (rc == 0) { + hashInitialized = 1; rc = wc_HashUpdate(&hash, hashType, packet.buf, packet.pos); } if (rc == 0) { @@ -7589,7 +7591,11 @@ int TPM2_HashNvPublic(TPMS_NV_PUBLIC* nvPublic, byte* buffer, UINT16* size) rc = TPM_RC_SUCCESS; } - wc_HashFree(&hash, hashType); + if (hashInitialized) { + wc_HashFree(&hash, hashType); + } + TPM2_ForceZero(&hash, sizeof(hash)); + TPM2_ForceZero(appending, sizeof(appending)); return rc; #else