From 319d689108ca357705c05c04f67509d147320377 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:05:35 -0700 Subject: [PATCH 01/45] F-9172 - Use XSTRNCMP to parse the -digest option in pcr policy --- examples/pcr/policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pcr/policy.c b/examples/pcr/policy.c index b7c0730e5..47570f78e 100644 --- a/examples/pcr/policy.c +++ b/examples/pcr/policy.c @@ -94,7 +94,7 @@ int TPM2_PCR_Policy_Test(void* userCtx, int argc, char *argv[]) else if (XSTRCMP(argv[argc-1], "-xor") == 0) { paramEncAlg = TPM_ALG_XOR; } - else if (XMEMCMP(argv[argc-1], "-digest=", XSTRLEN("-digest=")) == 0) { + else if (XSTRNCMP(argv[argc-1], "-digest=", XSTRLEN("-digest=")) == 0) { const char *digestStr, *end; digestStr = argv[argc-1] + XSTRLEN("-digest="); end = XSTRSTR(digestStr, " "); From 91326022d027ede63ef5f6ade56f1c159b01c701 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:06:02 -0700 Subject: [PATCH 02/45] F-9173 - Return an error status from pcr policy argument validation --- examples/pcr/policy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/pcr/policy.c b/examples/pcr/policy.c index 47570f78e..eabd0f835 100644 --- a/examples/pcr/policy.c +++ b/examples/pcr/policy.c @@ -108,13 +108,13 @@ int TPM2_PCR_Policy_Test(void* userCtx, int argc, char *argv[]) digestLen > sizeof(digest)*2) { printf("Invalid digest! Must be 16 or 32 bytes of hex like 01020304050607080910111213141516\n"); usage(); - return 0; + return BAD_FUNC_ARG; } hexRet = hexToByte(digestStr, digest, digestLen); if (hexRet < 0) { printf("Invalid hex digest string\n"); usage(); - return 0; + return BAD_FUNC_ARG; } digestLen = (word32)hexRet; } @@ -124,7 +124,7 @@ int TPM2_PCR_Policy_Test(void* userCtx, int argc, char *argv[]) if (pcrIndex < (int)PCR_FIRST || pcrIndex > (int)PCR_LAST) { printf("PCR index is out of range (0-23)\n"); usage(); - return 0; + return BAD_FUNC_ARG; } } else { From 7792efb8ec732b145ddfa0631e8dbe3b84a076f3 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:06:20 -0700 Subject: [PATCH 03/45] F-9174 - Unload the TPM hash sequence object on failure paths --- examples/wrap/hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/wrap/hash.c b/examples/wrap/hash.c index 83116629b..82356df0f 100644 --- a/examples/wrap/hash.c +++ b/examples/wrap/hash.c @@ -146,6 +146,7 @@ int TPM2_Hash_Example(void* userCtx, int argc, char* argv[]) exit: + wolfTPM2_UnloadHandle(&dev, &hash.handle); wolfTPM2_Cleanup(&dev); return rc; From 995b0879bc907b0eb1121ef7b155c86d83682e50 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:06:46 -0700 Subject: [PATCH 04/45] F-9175 - Return the flush result for an explicit handle --- examples/management/flush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/management/flush.c b/examples/management/flush.c index 1a55d0874..751b599da 100644 --- a/examples/management/flush.c +++ b/examples/management/flush.c @@ -101,7 +101,7 @@ int TPM2_Flush_Tool(void* userCtx, int argc, char *argv[]) else { flushCtx.flushHandle = handle; printf("Freeing %X object\n", handle); - TPM2_FlushContext(&flushCtx); + rc = TPM2_FlushContext(&flushCtx); } wolfTPM2_Cleanup(&dev); From c4252427301a658a9a0c0723917bb00e0982700b Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:07:18 -0700 Subject: [PATCH 05/45] F-9180 - Mask to the format-one field when checking hash bench errors --- examples/bench/bench.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/bench/bench.c b/examples/bench/bench.c index e705548d1..37e96b8f8 100644 --- a/examples/bench/bench.c +++ b/examples/bench/bench.c @@ -516,19 +516,19 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[]) /* SHA1 */ rc = bench_sym_hash(&dev, "SHA1", TPM_ALG_SHA1, message.buffer, sizeof(message.buffer), cipher.buffer, TPM_SHA_DIGEST_SIZE, maxDuration); - if (rc != 0 && (rc & TPM_RC_HASH) != TPM_RC_HASH) goto exit; + if (rc != 0 && (rc & RC_MAX_FMT1) != TPM_RC_HASH) goto exit; /* SHA256 */ rc = bench_sym_hash(&dev, "SHA256", TPM_ALG_SHA256, message.buffer, sizeof(message.buffer), cipher.buffer, TPM_SHA256_DIGEST_SIZE, maxDuration); - if (rc != 0 && (rc & TPM_RC_HASH) != TPM_RC_HASH) goto exit; + if (rc != 0 && (rc & RC_MAX_FMT1) != TPM_RC_HASH) goto exit; /* SHA384 */ rc = bench_sym_hash(&dev, "SHA384", TPM_ALG_SHA384, message.buffer, sizeof(message.buffer), cipher.buffer, TPM_SHA384_DIGEST_SIZE, maxDuration); - if (rc != 0 && (rc & TPM_RC_HASH) != TPM_RC_HASH) goto exit; + if (rc != 0 && (rc & RC_MAX_FMT1) != TPM_RC_HASH) goto exit; /* SHA512 */ rc = bench_sym_hash(&dev, "SHA512", TPM_ALG_SHA512, message.buffer, sizeof(message.buffer), cipher.buffer, TPM_SHA512_DIGEST_SIZE, maxDuration); - if (rc != 0 && (rc & TPM_RC_HASH) != TPM_RC_HASH) goto exit; + if (rc != 0 && (rc & RC_MAX_FMT1) != TPM_RC_HASH) goto exit; /* Create RSA key for encrypt/decrypt */ From b58bee59526898e781662b129738cc0fd25826eb Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:10:02 -0700 Subject: [PATCH 06/45] F-9182 - Free PKCS7 state on error paths in the sign verify examples --- examples/pkcs7/pkcs7.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/examples/pkcs7/pkcs7.c b/examples/pkcs7/pkcs7.c index 721c8beab..f54bde479 100644 --- a/examples/pkcs7/pkcs7.c +++ b/examples/pkcs7/pkcs7.c @@ -109,6 +109,7 @@ static int PKCS7_SignVerifyEx(WOLFTPM2_DEV* dev, int tpmDevId, { int rc; wc_PKCS7 pkcs7; + int pkcs7Init = 0; wc_HashAlg hash; byte hashBuf[TPM_MAX_DIGEST_SIZE]; word32 hashSz; @@ -155,6 +156,7 @@ static int PKCS7_SignVerifyEx(WOLFTPM2_DEV* dev, int tpmDevId, /* Generate and verify PKCS#7 files containing data using TPM key */ rc = wc_PKCS7_Init(&pkcs7, NULL, tpmDevId); if (rc != 0) goto exit; + pkcs7Init = 1; rc = wc_PKCS7_InitWithCert(&pkcs7, derCert, derCertSz); if (rc != 0) goto exit; @@ -177,6 +179,7 @@ static int PKCS7_SignVerifyEx(WOLFTPM2_DEV* dev, int tpmDevId, if (rc != 0) goto exit; wc_PKCS7_Free(&pkcs7); + pkcs7Init = 0; printf("PKCS7 Header %d\n", outputHeadSz); TPM2_PrintBin(outputHead, outputHeadSz); @@ -232,6 +235,7 @@ static int PKCS7_SignVerifyEx(WOLFTPM2_DEV* dev, int tpmDevId, /* Test verify with TPM */ rc = wc_PKCS7_Init(&pkcs7, NULL, tpmDevId); if (rc != 0) goto exit; + pkcs7Init = 1; rc = wc_PKCS7_InitWithCert(&pkcs7, NULL, 0); if (rc != 0) goto exit; @@ -241,12 +245,14 @@ static int PKCS7_SignVerifyEx(WOLFTPM2_DEV* dev, int tpmDevId, if (rc != 0) goto exit; wc_PKCS7_Free(&pkcs7); + pkcs7Init = 0; printf("PKCS7 Container Verified (using TPM)\n"); /* Test verify with software */ rc = wc_PKCS7_Init(&pkcs7, NULL, INVALID_DEVID); if (rc != 0) goto exit; + pkcs7Init = 1; rc = wc_PKCS7_InitWithCert(&pkcs7, NULL, 0); if (rc != 0) goto exit; pkcs7.contentSz = dataChunkSz; @@ -254,10 +260,14 @@ static int PKCS7_SignVerifyEx(WOLFTPM2_DEV* dev, int tpmDevId, outputHead, outputHeadSz, outputFoot, outputFootSz); if (rc != 0) goto exit; wc_PKCS7_Free(&pkcs7); + pkcs7Init = 0; printf("PKCS7 Container Verified (using software)\n"); exit: + if (pkcs7Init) { + wc_PKCS7_Free(&pkcs7); + } return rc; } #endif /* ENABLE_PKCS7EX_EXAMPLE */ @@ -268,6 +278,7 @@ static int PKCS7_SignVerify(WOLFTPM2_DEV* dev, int tpmDevId, { int rc; wc_PKCS7 pkcs7; + int pkcs7Init = 0; byte data[] = "My encoded DER cert."; byte output[MAX_PKCS7_SIZE]; int outputSz; @@ -280,6 +291,7 @@ static int PKCS7_SignVerify(WOLFTPM2_DEV* dev, int tpmDevId, /* Generate and verify PKCS#7 files containing data using TPM key */ rc = wc_PKCS7_Init(&pkcs7, NULL, tpmDevId); if (rc != 0) goto exit; + pkcs7Init = 1; rc = wc_PKCS7_InitWithCert(&pkcs7, derCert, derCertSz); if (rc != 0) goto exit; @@ -296,6 +308,7 @@ static int PKCS7_SignVerify(WOLFTPM2_DEV* dev, int tpmDevId, rc = wc_PKCS7_EncodeSignedData(&pkcs7, output, sizeof(output)); if (rc <= 0) goto exit; wc_PKCS7_Free(&pkcs7); + pkcs7Init = 0; outputSz = rc; printf("PKCS7 Signed Container %d\n", outputSz); @@ -321,26 +334,33 @@ static int PKCS7_SignVerify(WOLFTPM2_DEV* dev, int tpmDevId, /* Test verify with TPM */ rc = wc_PKCS7_Init(&pkcs7, NULL, tpmDevId); if (rc != 0) goto exit; + pkcs7Init = 1; rc = wc_PKCS7_InitWithCert(&pkcs7, NULL, 0); if (rc != 0) goto exit; rc = wc_PKCS7_VerifySignedData(&pkcs7, output, outputSz); if (rc != 0) goto exit; wc_PKCS7_Free(&pkcs7); + pkcs7Init = 0; printf("PKCS7 Container Verified (using TPM)\n"); /* Test verify with software */ rc = wc_PKCS7_Init(&pkcs7, NULL, INVALID_DEVID); if (rc != 0) goto exit; + pkcs7Init = 1; rc = wc_PKCS7_InitWithCert(&pkcs7, NULL, 0); if (rc != 0) goto exit; rc = wc_PKCS7_VerifySignedData(&pkcs7, output, outputSz); if (rc != 0) goto exit; wc_PKCS7_Free(&pkcs7); + pkcs7Init = 0; printf("PKCS7 Container Verified (using software)\n"); exit: + if (pkcs7Init) { + wc_PKCS7_Free(&pkcs7); + } return rc; } From e3cbe8ee1d7d13b290a0edb4db1ecf582de0bd5d Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:12:25 -0700 Subject: [PATCH 07/45] F-11903 - Reject a negative get random length argument --- examples/wrap/getrandom.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/wrap/getrandom.c b/examples/wrap/getrandom.c index 135205929..b6e04610f 100644 --- a/examples/wrap/getrandom.c +++ b/examples/wrap/getrandom.c @@ -58,6 +58,7 @@ int TPM2_GetRandom_Example(void* userCtx, int argc, char* argv[]) byte buf[GETRANDOM_MAX_BYTES]; word32 len = GETRANDOM_DEFAULT_BYTES; word32 i; + int lenArg; if (argc > 1) { if (XSTRCMP(argv[1], "-?") == 0 || @@ -66,7 +67,12 @@ int TPM2_GetRandom_Example(void* userCtx, int argc, char* argv[]) usage(); return 0; } - len = (word32)XATOI(argv[1]); + lenArg = XATOI(argv[1]); + if (lenArg < 0) { + printf("Invalid length %d\n", lenArg); + return BAD_FUNC_ARG; + } + len = (word32)lenArg; if (len == 0) { len = GETRANDOM_DEFAULT_BYTES; } From 94963636ac647784af5c73760f240726656afd14 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:12:25 -0700 Subject: [PATCH 08/45] F-11901 - Fail make credential when the AK name cannot be read --- examples/attestation/make_credential.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/examples/attestation/make_credential.c b/examples/attestation/make_credential.c index 7e52969ea..512c1a4c4 100644 --- a/examples/attestation/make_credential.c +++ b/examples/attestation/make_credential.c @@ -143,9 +143,18 @@ int TPM2_MakeCredential_Example(void* userCtx, int argc, char *argv[]) fp = XFOPEN("ak.name", "rb"); if (fp != XBADFILE) { size_t nameReadSz = XFREAD((BYTE*)&name, 1, sizeof(name), fp); - printf("Read AK Name digest %s\n", - nameReadSz == sizeof(name) ? "success" : "failed"); XFCLOSE(fp); + if (nameReadSz != sizeof(name)) { + printf("Read AK Name digest failed\n"); + rc = BUFFER_E; + goto exit; + } + printf("Read AK Name digest success\n"); + } + else { + printf("Failed to open ak.name\n"); + rc = BAD_FUNC_ARG; + goto exit; } #endif From 7d4d39780d4fd2eb93071ebf86f9abddeeb9fe84 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:12:25 -0700 Subject: [PATCH 09/45] F-13461 - Return success from the capabilities example handle listing --- examples/wrap/caps.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/wrap/caps.c b/examples/wrap/caps.c index 450014c98..25b4c4308 100644 --- a/examples/wrap/caps.c +++ b/examples/wrap/caps.c @@ -129,6 +129,7 @@ int TPM2_Wrapper_CapsArgs(void* userCtx, int argc, char *argv[]) rc = wolfTPM2_GetHandles(PERSISTENT_FIRST, NULL); if (rc >= 0) { printf("Found %d persistent handles\n", rc); + rc = TPM_RC_SUCCESS; } /* Print the available PCR's */ From 27d1bf5f9f320ef2a48aaf7468e997d8c40a15b6 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:12:59 -0700 Subject: [PATCH 10/45] F-10763 - Return an error on a GPIO config vendor mismatch --- examples/gpio/gpio_config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/gpio/gpio_config.c b/examples/gpio/gpio_config.c index 1e7f8ab1c..182f4bf57 100644 --- a/examples/gpio/gpio_config.c +++ b/examples/gpio/gpio_config.c @@ -176,6 +176,7 @@ int TPM2_GPIO_Config_Example(void* userCtx, int argc, char *argv[]) #ifdef WOLFTPM_ST33 if (caps.mfg != TPM_MFG_STM) { printf("TPM vendor mismatch. GPIO support requires an ST33 TPM 2.0 module\n"); + rc = BAD_FUNC_ARG; goto exit; } @@ -263,6 +264,7 @@ int TPM2_GPIO_Config_Example(void* userCtx, int argc, char *argv[]) if (caps.mfg != TPM_MFG_NUVOTON) { printf("TPM vendor mismatch. GPIO support requires Nuvoton NPCT7xx TPM 2.0 module\n"); + rc = BAD_FUNC_ARG; goto exit; } From 3adb0f5e4a8159d244e6d45c6a6017d147463e22 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:13:54 -0700 Subject: [PATCH 11/45] F-13457 - Return an error for incomplete firmware update arguments --- examples/firmware/ifx_fw_update.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/firmware/ifx_fw_update.c b/examples/firmware/ifx_fw_update.c index 33b5d4fb3..b696b7899 100644 --- a/examples/firmware/ifx_fw_update.c +++ b/examples/firmware/ifx_fw_update.c @@ -253,6 +253,7 @@ int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[]) if (manifest_file == NULL || firmware_file == NULL) { if (argc > 1) { printf("Manifest file or firmware file arguments missing!\n"); + rc = BAD_FUNC_ARG; } goto exit; } From 0d3f2f756a1f051981c67763c7c72b0a40ee318a Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:13:54 -0700 Subject: [PATCH 12/45] F-13463 - Clear ECC r and s on all policy signing paths --- examples/pcr/policy_sign.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/pcr/policy_sign.c b/examples/pcr/policy_sign.c index 86c6c9c69..ab8a9081a 100644 --- a/examples/pcr/policy_sign.c +++ b/examples/pcr/policy_sign.c @@ -196,17 +196,17 @@ static int PolicySign(TPM_ALG_ID alg, const char* keyFile, const char* password, rc = mp_init_multi(&r, &s, NULL, NULL, NULL, NULL); if (rc == 0) { rc = wc_ecc_sign_hash_ex(hash, hashSz, &rng, &key.ecc, &r, &s); - } - if (rc == 0) { - word32 keySz = key.ecc.dp->size; - *sigSz = keySz * 2; - /* Pre-zero in case mp export fails and leaves the buffer - * partially written. Fixed-width export of r and s - * removes the data-dependent wire offset that previously - * leaked the leading-zero count. */ - XMEMSET(sig, 0, *sigSz); - mp_to_unsigned_bin_len(&r, &sig[0], keySz); - mp_to_unsigned_bin_len(&s, &sig[keySz], keySz); + if (rc == 0) { + word32 keySz = key.ecc.dp->size; + *sigSz = keySz * 2; + /* Pre-zero in case mp export fails and leaves the buffer + * partially written. Fixed-width export of r and s + * removes the data-dependent wire offset that previously + * leaked the leading-zero count. */ + XMEMSET(sig, 0, *sigSz); + mp_to_unsigned_bin_len(&r, &sig[0], keySz); + mp_to_unsigned_bin_len(&s, &sig[keySz], keySz); + } mp_clear(&r); mp_clear(&s); } From 03446a71691a5043da9595d748529d485ae66b8c Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:13:54 -0700 Subject: [PATCH 13/45] F-12753 - Wipe the hex render buffer in the Espressif debug helper --- hal/tpm_io_espressif.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/tpm_io_espressif.c b/hal/tpm_io_espressif.c index d54c1b438..a68374631 100644 --- a/hal/tpm_io_espressif.c +++ b/hal/tpm_io_espressif.c @@ -187,6 +187,7 @@ static esp_err_t show_binary(byte* theVar, size_t dataSz) { hex_buffer[maxSz * 2] = '\0'; ESP_LOGI("TAG", "%s", hex_buffer); ESP_LOGI(TAG, "*********************************************************"); + TPM2_ForceZero(hex_buffer, sizeof(hex_buffer)); return ESP_OK; } #endif From 4b76ba64a086f2b30d486ebadda423171ee9831c Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:14:43 -0700 Subject: [PATCH 14/45] F-13532 - Bound the advanced IO SPI size to the frame buffer --- hal/tpm_io.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/hal/tpm_io.c b/hal/tpm_io.c index 9ed1cfe27..9c4e4452c 100644 --- a/hal/tpm_io.c +++ b/hal/tpm_io.c @@ -183,27 +183,32 @@ int TPM2_IoCb(TPM2_CTX* ctx, INT32 isRead, UINT32 addr, (void)userCtx; #endif #else - /* Build TPM header */ - txBuf[1] = (addr>>16) & 0xFF; - txBuf[2] = (addr>>8) & 0xFF; - txBuf[3] = (addr) & 0xFF; - if (isRead) { - txBuf[0] = TPM_TIS_READ | ((size & 0xFF) - 1); - XMEMSET(&txBuf[TPM_TIS_HEADER_SZ], 0, - sizeof(txBuf) - TPM_TIS_HEADER_SZ); + if (buf == NULL || size == 0 || size > MAX_SPI_FRAMESIZE) { + ret = BAD_FUNC_ARG; } else { - txBuf[0] = TPM_TIS_WRITE | ((size & 0xFF) - 1); - XMEMCPY(&txBuf[TPM_TIS_HEADER_SZ], buf, size); - XMEMSET(&txBuf[TPM_TIS_HEADER_SZ + size], 0, - sizeof(txBuf) - TPM_TIS_HEADER_SZ - size); - } - XMEMSET(rxBuf, 0, sizeof(rxBuf)); - - ret = TPM2_IoCb_SPI(ctx, txBuf, rxBuf, size + TPM_TIS_HEADER_SZ, userCtx); - - if (isRead) { - XMEMCPY(buf, &rxBuf[TPM_TIS_HEADER_SZ], size); + /* Build TPM header */ + txBuf[1] = (addr>>16) & 0xFF; + txBuf[2] = (addr>>8) & 0xFF; + txBuf[3] = (addr) & 0xFF; + if (isRead) { + txBuf[0] = TPM_TIS_READ | ((size & 0xFF) - 1); + XMEMSET(&txBuf[TPM_TIS_HEADER_SZ], 0, + sizeof(txBuf) - TPM_TIS_HEADER_SZ); + } + else { + txBuf[0] = TPM_TIS_WRITE | ((size & 0xFF) - 1); + XMEMCPY(&txBuf[TPM_TIS_HEADER_SZ], buf, size); + XMEMSET(&txBuf[TPM_TIS_HEADER_SZ + size], 0, + sizeof(txBuf) - TPM_TIS_HEADER_SZ - size); + } + XMEMSET(rxBuf, 0, sizeof(rxBuf)); + + ret = TPM2_IoCb_SPI(ctx, txBuf, rxBuf, size + TPM_TIS_HEADER_SZ, userCtx); + + if (isRead) { + XMEMCPY(buf, &rxBuf[TPM_TIS_HEADER_SZ], size); + } } #endif From cedcd8e5926cc4e227b3dfcf5051289d710a1bd2 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:16:28 -0700 Subject: [PATCH 15/45] F-11908 - Reject truncated Nations GET_STATUS payloads --- src/spdm/spdm_nations.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/spdm/spdm_nations.c b/src/spdm/spdm_nations.c index 33108fbc9..37d722442 100644 --- a/src/spdm/spdm_nations.c +++ b/src/spdm/spdm_nations.c @@ -75,6 +75,9 @@ int wolfSPDM_Nations_GetStatus(WOLFSPDM_CTX* ctx, status->pskProvisioned ? "YES" : "NO", rsp.payload[3]); } + else { + return WOLFSPDM_E_FRAMING; + } return WOLFSPDM_SUCCESS; } From 1be467d96b960d1a595e676d042abb2d9314b84d Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:16:28 -0700 Subject: [PATCH 16/45] F-11909 - Reject an empty Nuvoton GET_STATUS response --- src/spdm/spdm_nuvoton.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/spdm/spdm_nuvoton.c b/src/spdm/spdm_nuvoton.c index 6ef017702..400046db6 100644 --- a/src/spdm/spdm_nuvoton.c +++ b/src/spdm/spdm_nuvoton.c @@ -82,6 +82,9 @@ int wolfSPDM_Nuvoton_GetStatus( wolfSPDM_DebugPrint(ctx, "GET_STS_: SPDMOnly=%s (minimal response)\n", status->spdmOnlyLocked ? "LOCKED" : "unlocked"); } + else { + return WOLFSPDM_E_FRAMING; + } return WOLFSPDM_SUCCESS; } From 38850cee43e69ea43c54fa4ba0baebead10919f9 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:16:28 -0700 Subject: [PATCH 17/45] F-11891 - Correct the SPDM disconnect key wipe comment --- src/spdm/spdm_context.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spdm/spdm_context.c b/src/spdm/spdm_context.c index cc6b17f9d..5d2a569eb 100644 --- a/src/spdm/spdm_context.c +++ b/src/spdm/spdm_context.c @@ -369,7 +369,8 @@ int wolfSPDM_Disconnect(WOLFSPDM_CTX* ctx) } } - /* Reset state and zero ALL key material */ + /* Reset session state and wipe session-scoped keys; configured identity + * keys remain for a later connection */ ctx->state = WOLFSPDM_STATE_INIT; ctx->sessionId = 0; ctx->reqSeqNum = 0; From e86c7573d0cf9d63dbcdcc534ff9c557f08cbdbb Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:16:55 -0700 Subject: [PATCH 18/45] F-9179 - Reject a NULL vendor payload with a nonzero size --- src/spdm/spdm_tcg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/spdm/spdm_tcg.c b/src/spdm/spdm_tcg.c index e80184bb1..10ea96ca9 100644 --- a/src/spdm/spdm_tcg.c +++ b/src/spdm/spdm_tcg.c @@ -204,6 +204,9 @@ int wolfSPDM_BuildVendorDefined( if (vdCode == NULL || outBuf == NULL) { return WOLFSPDM_E_INVALID_ARG; } + if (payload == NULL && payloadSz != 0) { + return WOLFSPDM_E_INVALID_ARG; + } /* SPDM VENDOR_DEFINED_REQUEST format: * SPDMVersion(1) + reqRspCode(1) + param1(1) + param2(1) + From 43f34846a55dac12ff62707596f789e6f15adf18 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:17:08 -0700 Subject: [PATCH 19/45] F-10762 - Reject an oversized vendor payload that wraps the length field --- src/spdm/spdm_tcg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/spdm/spdm_tcg.c b/src/spdm/spdm_tcg.c index 10ea96ca9..936df65a9 100644 --- a/src/spdm/spdm_tcg.c +++ b/src/spdm/spdm_tcg.c @@ -208,6 +208,11 @@ int wolfSPDM_BuildVendorDefined( return WOLFSPDM_E_INVALID_ARG; } + /* Reject a payload that would overflow the 16-bit request-length field */ + if (payloadSz > (word32)(0xFFFF - WOLFSPDM_VDCODE_LEN)) { + return WOLFSPDM_E_INVALID_ARG; + } + /* SPDM VENDOR_DEFINED_REQUEST format: * SPDMVersion(1) + reqRspCode(1) + param1(1) + param2(1) + * standardId(2/LE) + vendorIdLen(1) + reqLength(2/LE) + From c8ce45ebdfc24beae41e5b317ccf70e7861cd2bc Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:18:30 -0700 Subject: [PATCH 20/45] F-10760 - Size the key exchange buffer check to the encoded request --- src/spdm/spdm_msg.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/spdm/spdm_msg.c b/src/spdm/spdm_msg.c index e627a5661..9cd50007c 100644 --- a/src/spdm/spdm_msg.c +++ b/src/spdm/spdm_msg.c @@ -64,7 +64,15 @@ int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) word32 pubKeyYSz = sizeof(pubKeyY); int rc; - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 180); + /* Require exactly the encoded request size: 40-byte fixed header, two ECC + * coordinates, and the config-specific OpaqueData block */ +#ifdef WOLFSPDM_NUVOTON + SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 14); +#elif defined(WOLFSPDM_NATIONS) + SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 2); +#else + SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 22); +#endif rc = wolfSPDM_GenerateEphemeralKey(ctx); if (rc == WOLFSPDM_SUCCESS) From 19b33fb29f74d683688323268f2c0849104dd87c Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:19:03 -0700 Subject: [PATCH 21/45] F-9176 - Provision the responder PSK only after the inner set succeeds --- src/spdm/spdm_responder.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/spdm/spdm_responder.c b/src/spdm/spdm_responder.c index 371122885..e58e3db2b 100644 --- a/src/spdm/spdm_responder.c +++ b/src/spdm/spdm_responder.c @@ -152,12 +152,19 @@ int wolfSPDM_RespSetPSK(WOLFSPDM_RESP_CTX* ctx, (void)hintSz; return WOLFSPDM_E_NOT_AVAILABLE; #else + int rc; if (ctx == NULL || !ctx->flags.initialized) { return WOLFSPDM_E_INVALID_ARG; } if (psk == NULL || pskSz == 0 || pskSz > sizeof(ctx->pskStore)) { return WOLFSPDM_E_INVALID_ARG; } + /* Commit the inner context first so a rejected PSK leaves no partially + * provisioned responder state */ + rc = wolfSPDM_SetPSK(&ctx->ctx, psk, pskSz, hint, hintSz); + if (rc != WOLFSPDM_SUCCESS) { + return rc; + } XMEMCPY(ctx->pskStore, psk, pskSz); ctx->pskStoreSz = pskSz; if (hint != NULL && hintSz > 0 && hintSz <= sizeof(ctx->pskHintStore)) { @@ -168,7 +175,7 @@ int wolfSPDM_RespSetPSK(WOLFSPDM_RESP_CTX* ctx, ctx->pskHintStoreSz = 0; } ctx->flags.pskProvisioned = 1; - return wolfSPDM_SetPSK(&ctx->ctx, psk, pskSz, hint, hintSz); + return WOLFSPDM_SUCCESS; #endif } From 550277ef13c3d6a6cc6612d6365dd3b8c785ee76 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:19:23 -0700 Subject: [PATCH 22/45] F-9177 - Reset the responder only after the end session ack is encrypted --- src/spdm/spdm_responder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spdm/spdm_responder.c b/src/spdm/spdm_responder.c index e58e3db2b..b6e205592 100644 --- a/src/spdm/spdm_responder.c +++ b/src/spdm/spdm_responder.c @@ -1159,7 +1159,7 @@ static int RespDispatchSecured(WOLFSPDM_RESP_CTX* rctx, rc = wolfSPDM_DeriveAppDataKeys(ctx); } - if (sessionEnded) { + if (sessionEnded && rc == WOLFSPDM_SUCCESS) { wolfSPDM_RespReset(rctx); } return rc; From 3ac5feb984143c44ac5b60f8c90a5ac48a73e404 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:19:58 -0700 Subject: [PATCH 23/45] F-13467 - Validate declared PSK exchange field lengths against the request --- src/spdm/spdm_responder.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/spdm/spdm_responder.c b/src/spdm/spdm_responder.c index b6e205592..05aff93c6 100644 --- a/src/spdm/spdm_responder.c +++ b/src/spdm/spdm_responder.c @@ -491,9 +491,10 @@ static int RespBuildPskExchangeRsp(WOLFSPDM_RESP_CTX* rctx, reqHintLen = SPDM_Get16LE(&in[6]); reqContextLen = SPDM_Get16LE(&in[8]); reqOpaqueLen = SPDM_Get16LE(&in[10]); - (void)reqHintLen; - (void)reqContextLen; - (void)reqOpaqueLen; + /* Every declared variable-length field must fit within the request */ + if ((word32)12 + reqHintLen + reqContextLen + reqOpaqueLen > inSz) { + return WOLFSPDM_E_FRAMING; + } ctx->rspSessionId = 0xFFFE; ctx->sessionId = (word32)ctx->reqSessionId | From 60fd8ae1d2a469e5d592cbac11b0574026db6297 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:22:08 -0700 Subject: [PATCH 24/45] F-9185 - Fail MCTP encryption once the sequence number exceeds 16 bits --- src/spdm/spdm_secured.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/spdm/spdm_secured.c b/src/spdm/spdm_secured.c index 6544c13b8..761d5b455 100644 --- a/src/spdm/spdm_secured.c +++ b/src/spdm/spdm_secured.c @@ -120,6 +120,12 @@ int wolfSPDM_EncryptInternal(WOLFSPDM_CTX* ctx, word16 appDataLen = (word16)(1 + plainSz); word16 encDataLen = (word16)(2 + appDataLen); + /* MCTP carries a 16-bit sequence number; fail rather than let the wire + * value and the 64-bit IV counter diverge past 0xFFFF */ + if (ctx->reqSeqNum > 0xFFFF) { + return WOLFSPDM_E_BAD_STATE; + } + plainBufSz = encDataLen; recordLen = (word16)(encDataLen + WOLFSPDM_AEAD_TAG_SIZE); hdrSz = 8; /* 4 + 2 + 2 */ From ef6e19e25b72a1599797627ecb9259cf3543dd96 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:22:28 -0700 Subject: [PATCH 25/45] F-11934 - Advance the SPDM receive sequence only after authentication --- src/spdm/spdm_secured.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/spdm/spdm_secured.c b/src/spdm/spdm_secured.c index 761d5b455..acc5a6e36 100644 --- a/src/spdm/spdm_secured.c +++ b/src/spdm/spdm_secured.c @@ -278,10 +278,6 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, wolfSPDM_BuildIV(iv, ctx->rspDataIv, (word64)rspSeqNum); } - /* response consumed and seq validated; advance to stay in lockstep with - * the peer even if AEAD/parse below fails */ - ctx->rspSeqNum++; - /* ----- AES-GCM decrypt (shared for both transports) ----- */ ret = WOLFSPDM_E_CRYPTO_FAIL; @@ -340,6 +336,9 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, } if (ret == WOLFSPDM_SUCCESS) { + /* Advance the receive counter only after authentication and payload + * validation succeed, so a forged record cannot desync the sequence */ + ctx->rspSeqNum++; wolfSPDM_DebugPrint(ctx, "Decrypted %u bytes -> %u bytes\n", encSz, *plainSz); } From 55135d1cd2c5e63cc5983d5d8bcb3e22c8b40dbe Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:24:40 -0700 Subject: [PATCH 26/45] F-13452 - Free the wrap HMAC only after it is initialized --- src/fwtpm/fwtpm_crypto.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/fwtpm/fwtpm_crypto.c b/src/fwtpm/fwtpm_crypto.c index 5ffea3422..006df98cc 100644 --- a/src/fwtpm/fwtpm_crypto.c +++ b/src/fwtpm/fwtpm_crypto.c @@ -2259,6 +2259,7 @@ int FwWrapPrivate(FWTPM_Object* parent, WC_RNG* rng, FWTPM_DECLARE_VAR(hmac, Hmac); int sensSz = 0; int aesInit = 0; + int hmacInit = 0; int pos = 0; FWTPM_ALLOC_BUF(sensBuf, FWTPM_MAX_PRIVKEY_DER + 128); @@ -2304,6 +2305,9 @@ int FwWrapPrivate(FWTPM_Object* parent, WC_RNG* rng, /* HMAC integrity over IV and encrypted data */ if (rc == 0) { rc = wc_HmacInit(hmac, NULL, INVALID_DEVID); + if (rc == 0) { + hmacInit = 1; + } } if (rc == 0) { rc = wc_HmacSetKey(hmac, WC_SHA256, macKey, sizeof(macKey)); @@ -2317,7 +2321,9 @@ int FwWrapPrivate(FWTPM_Object* parent, WC_RNG* rng, if (rc == 0) { rc = wc_HmacFinal(hmac, hmacDigest); } - wc_HmacFree(hmac); + if (hmacInit) { + wc_HmacFree(hmac); + } /* Pack into TPM2B_PRIVATE */ if (rc == 0) { From ae3581982e7d1583f1ac3ccccb1161d95609f19a Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:24:51 -0700 Subject: [PATCH 27/45] F-13453 - Preserve an allocation failure before generating the context IV --- src/fwtpm/fwtpm_crypto.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fwtpm/fwtpm_crypto.c b/src/fwtpm/fwtpm_crypto.c index 006df98cc..b19459d6c 100644 --- a/src/fwtpm/fwtpm_crypto.c +++ b/src/fwtpm/fwtpm_crypto.c @@ -2523,7 +2523,9 @@ int FwWrapContextBlob(FWTPM_CTX* ctx, UINT64 seq, byte ctxType, FWTPM_ALLOC_VAR(hmac, Hmac); /* Generate random IV */ - rc = wc_RNG_GenerateBlock(&ctx->rng, iv, AES_BLOCK_SIZE); + if (rc == 0) { + rc = wc_RNG_GenerateBlock(&ctx->rng, iv, AES_BLOCK_SIZE); + } /* AES-CFB encrypt */ if (rc == 0) { From b12c95e64a9972abff90cf636671773690dff39d Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:25:53 -0700 Subject: [PATCH 28/45] F-11929 - Zeroize the append-only NV replay buffer before freeing --- src/fwtpm/fwtpm_nv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fwtpm/fwtpm_nv.c b/src/fwtpm/fwtpm_nv.c index fe1059c5e..df17ea8ab 100644 --- a/src/fwtpm/fwtpm_nv.c +++ b/src/fwtpm/fwtpm_nv.c @@ -1759,6 +1759,7 @@ static int FwNvInitAppendOnly(FWTPM_CTX* ctx, byte** valueBufP, rc = TPM_RC_MEMORY; break; } + TPM2_ForceZero(valueBuf, valueBufSz); XFREE(valueBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); valueBuf = newBuf; valueBufSz = len; From f53b7ecf655e7822482008bdc5fb458545f3cba9 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:26:13 -0700 Subject: [PATCH 29/45] F-10824 - Zeroize the NV journal load buffer before freeing --- src/fwtpm/fwtpm_nv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fwtpm/fwtpm_nv.c b/src/fwtpm/fwtpm_nv.c index df17ea8ab..e91e36e33 100644 --- a/src/fwtpm/fwtpm_nv.c +++ b/src/fwtpm/fwtpm_nv.c @@ -1934,6 +1934,7 @@ int FWTPM_NV_Init(FWTPM_CTX* ctx) rc = TPM_RC_MEMORY; break; } + TPM2_ForceZero(valueBuf, valueBufSz); XFREE(valueBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); valueBuf = newBuf; valueBufSz = len; @@ -1971,6 +1972,7 @@ int FWTPM_NV_Init(FWTPM_CTX* ctx) rc = FwNvGenFreshState(ctx); } + TPM2_ForceZero(valueBuf, valueBufSz); XFREE(valueBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return rc; } From b8615b3504d2f6a3d87a74f06b84ee46baa81fe6 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:27:12 -0700 Subject: [PATCH 30/45] F-11930 - Zeroize the NV save marshal buffer before grow frees --- src/fwtpm/fwtpm_nv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fwtpm/fwtpm_nv.c b/src/fwtpm/fwtpm_nv.c index e91e36e33..9d7428472 100644 --- a/src/fwtpm/fwtpm_nv.c +++ b/src/fwtpm/fwtpm_nv.c @@ -2100,6 +2100,7 @@ int FWTPM_NV_Save(FWTPM_CTX* ctx) rc = TPM_RC_MEMORY; } else { + TPM2_ForceZero(buf, bufSz); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); buf = newBuf; bufSz = needed; @@ -2217,6 +2218,7 @@ int FWTPM_NV_Save(FWTPM_CTX* ctx) rc = TPM_RC_MEMORY; break; } + TPM2_ForceZero(buf, bufSz); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); buf = newBuf; bufSz = needed; @@ -2245,6 +2247,7 @@ int FWTPM_NV_Save(FWTPM_CTX* ctx) rc = TPM_RC_MEMORY; break; } + TPM2_ForceZero(buf, bufSz); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); buf = newBuf; bufSz = needed; @@ -2272,6 +2275,7 @@ int FWTPM_NV_Save(FWTPM_CTX* ctx) rc = TPM_RC_MEMORY; break; } + TPM2_ForceZero(buf, bufSz); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); buf = newBuf; bufSz = needed; From 36a549d773c093fa24e3061b384c1957fa24f071 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:27:54 -0700 Subject: [PATCH 31/45] F-11931 - Zeroize the PCR authorization buffer before freeing --- src/fwtpm/fwtpm_nv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fwtpm/fwtpm_nv.c b/src/fwtpm/fwtpm_nv.c index 9d7428472..f0a6a390d 100644 --- a/src/fwtpm/fwtpm_nv.c +++ b/src/fwtpm/fwtpm_nv.c @@ -2433,6 +2433,7 @@ int FWTPM_NV_SavePcrAuth(FWTPM_CTX* ctx) rc = FwNvAppendEntry(ctx, FWTPM_NV_TAG_PCR_AUTH, buf, (UINT16)pos); + TPM2_ForceZero(buf, bufSz); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return rc; } From efa68e4acf150bd89fdf80e62fa7a26c47c86ebe Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:28:13 -0700 Subject: [PATCH 32/45] F-11932 - Zeroize the hierarchy authorization stack buffer --- src/fwtpm/fwtpm_nv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fwtpm/fwtpm_nv.c b/src/fwtpm/fwtpm_nv.c index f0a6a390d..9c4ecc612 100644 --- a/src/fwtpm/fwtpm_nv.c +++ b/src/fwtpm/fwtpm_nv.c @@ -2378,6 +2378,7 @@ int FWTPM_NV_SaveAuth(FWTPM_CTX* ctx, UINT32 hierarchy) if (rc == 0) { rc = FwNvAppendEntry(ctx, tag, buf, (UINT16)pos); } + TPM2_ForceZero(buf, sizeof(buf)); return rc; } From 7f02facf8985069cb503508250e96bb41db06a80 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:29:28 -0700 Subject: [PATCH 33/45] F-12707 - Clean up wolfCrypt only when its init succeeded --- src/fwtpm/fwtpm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fwtpm/fwtpm.c b/src/fwtpm/fwtpm.c index 1d6c2b0be..12d653720 100644 --- a/src/fwtpm/fwtpm.c +++ b/src/fwtpm/fwtpm.c @@ -40,6 +40,7 @@ int FWTPM_Init(FWTPM_CTX* ctx) { int rc; int rngInit = 0; + int wcInit = 0; FWTPM_NV_HAL savedNvHal; struct FWTPM_CLOCK_HAL_S savedClockHal; #ifndef FWTPM_NO_PP @@ -96,6 +97,7 @@ int FWTPM_Init(FWTPM_CTX* ctx) /* Initialize wolfCrypt RNG */ rc = wolfCrypt_Init(); if (rc == 0) { + wcInit = 1; rc = wc_InitRng(&ctx->rng); if (rc == 0) { rngInit = 1; @@ -141,7 +143,9 @@ int FWTPM_Init(FWTPM_CTX* ctx) if (rngInit) { wc_FreeRng(&ctx->rng); } - wolfCrypt_Cleanup(); + if (wcInit) { + wolfCrypt_Cleanup(); + } } return rc; From facc55c239d783a57338a52151fed7eec9441082 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:29:52 -0700 Subject: [PATCH 34/45] F-9193 - Assert the TIS FIFO can hold the maximum command response --- src/fwtpm/fwtpm_tis.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fwtpm/fwtpm_tis.c b/src/fwtpm/fwtpm_tis.c index b78d38ea5..0169081db 100644 --- a/src/fwtpm/fwtpm_tis.c +++ b/src/fwtpm/fwtpm_tis.c @@ -51,6 +51,11 @@ * VID = "WF" (0x4657), DID = "TP" (0x5054) */ #define FWTPM_TIS_DID_VID_VAL 0x50544657UL +/* The TIS response FIFO must hold a full dispatched response; a mismatched + * FWTPM_TIS_FIFO_SIZE override must fail the build, not overflow at runtime */ +typedef char fwtpm_tis_fifo_fits_max_cmd[ + (FWTPM_TIS_FIFO_SIZE >= FWTPM_MAX_COMMAND_SIZE) ? 1 : -1]; + /* --- Static helpers --- */ /* Extract register offset from a full TIS address. From 651a35f2a51fe84cd66a87feace70107ddedaf5e Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:31:54 -0700 Subject: [PATCH 35/45] F-12755 - Zeroize the session start nonce structures on all exits --- src/tpm2_wrap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 53f8e2976..2a9476400 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -2904,6 +2904,8 @@ int wolfTPM2_StartSession_ex(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session, #ifdef DEBUG_WOLFTPM printf("TPM2_GetNonce failed %d: %s\n", rc, wolfTPM2_GetRCString(rc)); #endif + TPM2_ForceZero(&authSesIn, sizeof(authSesIn)); + TPM2_ForceZero(&authSesOut, sizeof(authSesOut)); return rc; } @@ -2913,6 +2915,8 @@ int wolfTPM2_StartSession_ex(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session, rc = TPM2_GetNonceNoLock(session->salt.buffer, session->salt.size); if (rc != 0) { TPM2_ForceZero(&session->salt, sizeof(session->salt)); + TPM2_ForceZero(&authSesIn, sizeof(authSesIn)); + TPM2_ForceZero(&authSesOut, sizeof(authSesOut)); return rc; } @@ -2925,6 +2929,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; } } From ed95d45f642fe151461fbfc0f98a26d8dfc7458e Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:34:25 -0700 Subject: [PATCH 36/45] F-11916 - Use a constant-time compare for the primary key cache lookup --- src/fwtpm/fwtpm_command.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index fa201d3e9..9bc90a8dd 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -3565,8 +3565,8 @@ static TPM_RC FwCmd_CreatePrimary(FWTPM_CTX* ctx, TPM2_Packet* cmd, for (cacheIdx = 0; cacheIdx < FWTPM_MAX_PRIMARY_CACHE; cacheIdx++) { if (ctx->primaryCache[cacheIdx].used && ctx->primaryCache[cacheIdx].hierarchy == primaryHandle && - XMEMCMP(ctx->primaryCache[cacheIdx].templateHash, templateHash, - WC_SHA256_DIGEST_SIZE) == 0) { + TPM2_ConstantCompare(ctx->primaryCache[cacheIdx].templateHash, + templateHash, WC_SHA256_DIGEST_SIZE) == 0) { cached = &ctx->primaryCache[cacheIdx]; break; } From 022fe8409df6af956269714c1276317fa09c5aa3 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:34:41 -0700 Subject: [PATCH 37/45] F-13531 - Guard the object name marshalling on a successful allocation --- src/fwtpm/fwtpm_command.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index 9bc90a8dd..410c50bfb 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -6457,18 +6457,21 @@ static TPM_RC FwCmd_Create(FWTPM_CTX* ctx, TPM2_Packet* cmd, /* Compute object name from public area for creation ticket */ nameDigSz = TPM2_GetHashDigestSize(inPublic->publicArea.nameAlg); FWTPM_ALLOC_BUF(pubBuf2, FWTPM_MAX_PUB_BUF); - tmpPkt2.buf = pubBuf2; - tmpPkt2.pos = 0; - tmpPkt2.size = (int)FWTPM_MAX_PUB_BUF; - TPM2_Packet_AppendPublicArea(&tmpPkt2, &inPublic->publicArea); - FwStoreU16BE(objName, inPublic->publicArea.nameAlg); - if (nameDigSz > 0) { - int hashRc = wc_Hash(FwGetWcHashType(inPublic->publicArea.nameAlg), - pubBuf2, tmpPkt2.pos, objName + 2, nameDigSz); - if (hashRc == 0) - objNameSz = 2 + nameDigSz; - } - FWTPM_FREE_BUF(pubBuf2); + if (rc == 0) { + tmpPkt2.buf = pubBuf2; + tmpPkt2.pos = 0; + tmpPkt2.size = (int)FWTPM_MAX_PUB_BUF; + TPM2_Packet_AppendPublicArea(&tmpPkt2, &inPublic->publicArea); + FwStoreU16BE(objName, inPublic->publicArea.nameAlg); + if (nameDigSz > 0) { + int hashRc = wc_Hash( + FwGetWcHashType(inPublic->publicArea.nameAlg), + pubBuf2, tmpPkt2.pos, objName + 2, nameDigSz); + if (hashRc == 0) + objNameSz = 2 + nameDigSz; + } + FWTPM_FREE_BUF(pubBuf2); + } /* Creation ticket hierarchy = parent's hierarchy per Part 2 * Sec.10.6.5 Table 112. */ From d679f5bec5b329d229dc61fc4cb9f1af4590cb7e Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:35:17 -0700 Subject: [PATCH 38/45] F-13530 - Guard the encrypted salt zeroization against a NULL buffer --- src/fwtpm/fwtpm_command.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index 410c50bfb..feb1c86d5 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -10596,7 +10596,13 @@ static TPM_RC FwCmd_StartAuthSession(FWTPM_CTX* ctx, TPM2_Packet* cmd, FwFreeSession(sess); } TPM2_ForceZero(salt, sizeof(salt)); +#ifdef WOLFTPM_SMALL_STACK + if (encSalt != NULL) { + TPM2_ForceZero(encSalt, FWTPM_MAX_PUB_BUF); + } +#else TPM2_ForceZero(encSalt, FWTPM_MAX_PUB_BUF); +#endif FWTPM_FREE_BUF(encSalt); return rc; } From e15f515b662ee9db1483118903b5a654ec80f7f9 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:35:36 -0700 Subject: [PATCH 39/45] F-13529 - Guard the EncryptDecrypt input buffer against a NULL allocation --- src/fwtpm/fwtpm_command.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index feb1c86d5..082e8ccc2 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -14422,7 +14422,13 @@ static TPM_RC FwEncryptDecryptCore(FWTPM_CTX* ctx, TPM2_Packet* cmd, FWTPM_ALLOC_VAR(aes, Aes); XMEMSET(ivBuf, 0, sizeof(ivBuf)); +#ifdef WOLFTPM_SMALL_STACK + if (inData != NULL) { + XMEMSET(inData, 0, FWTPM_MAX_COMMAND_SIZE / 2); + } +#else XMEMSET(inData, 0, FWTPM_MAX_COMMAND_SIZE / 2); +#endif if (cmdSize < TPM2_HEADER_SIZE + 4) { rc = TPM_RC_COMMAND_SIZE; @@ -14668,7 +14674,13 @@ static TPM_RC FwEncryptDecryptCore(FWTPM_CTX* ctx, TPM2_Packet* cmd, FwRspParamsEnd(rsp, cmdTag, paramSzPos, paramStart); } +#ifdef WOLFTPM_SMALL_STACK + if (inData != NULL) { + TPM2_ForceZero(inData, FWTPM_MAX_COMMAND_SIZE / 2); + } +#else TPM2_ForceZero(inData, FWTPM_MAX_COMMAND_SIZE / 2); +#endif FWTPM_FREE_BUF(inData); FWTPM_FREE_VAR(aes); return rc; From 7ce7a6791958a819bbb51e59f5655b3da1270529 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:36:44 -0700 Subject: [PATCH 40/45] F-12713 - Reject malformed PCR_Read selection counts and sizes --- src/fwtpm/fwtpm_command.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index 082e8ccc2..f69fd94c8 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -2401,6 +2401,14 @@ static TPM_RC FwCmd_PCR_Read(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, printf("fwTPM: PCR_Read(selCount=%d)\n", pcrSelCount); #endif + /* Reject more banks than the implementation supports rather than + * echoing a count that exceeds the emitted selections */ + if (pcrSelCount > HASH_COUNT) { + rc = TPM_RC_SIZE; + } + } + + if (rc == 0) { /* pcrUpdateCounter */ TPM2_Packet_AppendU32(rsp, ctx->pcrUpdateCounter); @@ -2408,9 +2416,6 @@ static TPM_RC FwCmd_PCR_Read(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, TPM2_Packet_AppendU32(rsp, pcrSelCount); numSel = pcrSelCount; - if (numSel > HASH_COUNT) { - numSel = HASH_COUNT; - } for (s = 0; s < numSel && rc == 0; s++) { int j; @@ -2422,7 +2427,8 @@ static TPM_RC FwCmd_PCR_Read(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, TPM2_Packet_ParseU16(cmd, &selections[s].hashAlg); TPM2_Packet_ParseU8(cmd, &selections[s].sizeOfSelect); if (selections[s].sizeOfSelect > PCR_SELECT_MAX) { - selections[s].sizeOfSelect = PCR_SELECT_MAX; + rc = TPM_RC_SIZE; + break; } for (j = 0; j < selections[s].sizeOfSelect; j++) { if (cmd->pos >= cmdSize) { From 6ecdd4ba8ba64be71a4887a5fc200d6d79934e0c Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:38:03 -0700 Subject: [PATCH 41/45] F-13498 - Run policy assertion compares without short-circuiting on size --- src/fwtpm/fwtpm_command.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index f69fd94c8..f7c535510 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -18986,18 +18986,29 @@ static TPM_RC FwCheckPolicyAssertions(FWTPM_CTX* ctx, TPM_RC rc = TPM_RC_SUCCESS; byte digest[TPM_MAX_DIGEST_SIZE]; int digestSz = 0; + int sizeMismatch; + word32 cmpSz; if (sess->commandCode != 0 && sess->commandCode != cmdCode) { rc = TPM_RC_POLICY_CC; } if (rc == 0 && sess->nameHash.size > 0) { if (FwComputeNameHash(ctx, sess->authHash, handles, handleCnt, - digest, &digestSz) != 0 || - (int)sess->nameHash.size != digestSz || - TPM2_ConstantCompare(sess->nameHash.buffer, digest, - (word32)digestSz) != 0) { + digest, &digestSz) != 0) { rc = TPM_RC_POLICY_FAIL; } + else { + /* Always run the compare so a size mismatch cannot short-circuit + * the constant-time path */ + sizeMismatch = ((int)sess->nameHash.size != digestSz); + cmpSz = (sess->nameHash.size < (word32)digestSz) ? + sess->nameHash.size : (word32)digestSz; + if (sizeMismatch | + (TPM2_ConstantCompare(sess->nameHash.buffer, digest, + cmpSz) != 0)) { + rc = TPM_RC_POLICY_FAIL; + } + } } /* PolicyTemplate binds only the creation template (Part 3 Sec.23.19); * it does not restrict the command, that is PolicyCommandCode's role. */ @@ -19005,12 +19016,19 @@ static TPM_RC FwCheckPolicyAssertions(FWTPM_CTX* ctx, (cmdCode == TPM_CC_Create || cmdCode == TPM_CC_CreatePrimary || cmdCode == TPM_CC_CreateLoaded)) { if (FwComputeTemplateHash(sess->authHash, cmdBuf, cmdSize, cpStart, - digest, &digestSz) != 0 || - (int)sess->templateHash.size != digestSz || - TPM2_ConstantCompare(sess->templateHash.buffer, digest, - (word32)digestSz) != 0) { + digest, &digestSz) != 0) { rc = TPM_RC_POLICY_FAIL; } + else { + sizeMismatch = ((int)sess->templateHash.size != digestSz); + cmpSz = (sess->templateHash.size < (word32)digestSz) ? + sess->templateHash.size : (word32)digestSz; + if (sizeMismatch | + (TPM2_ConstantCompare(sess->templateHash.buffer, digest, + cmpSz) != 0)) { + rc = TPM_RC_POLICY_FAIL; + } + } } if (rc == 0 && sess->checkNvWritten) { #ifndef FWTPM_NO_NV From c06f2c2cb8293e386e9e5ebc37a75fc8ff73de8f Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:38:30 -0700 Subject: [PATCH 42/45] F-13499 - Run the PolicyTemplate compare without short-circuiting on size --- src/fwtpm/fwtpm_command.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index f7c535510..74d6555bd 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -12408,11 +12408,17 @@ static TPM_RC FwCmd_PolicyTemplate(FWTPM_CTX* ctx, TPM2_Packet* cmd, if (sess->cpHashA.size > 0 || sess->nameHash.size > 0) { rc = TPM_RC_CPHASH; } - else if (sess->templateHash.size > 0 && - (sess->templateHash.size != templateHashSz || - TPM2_ConstantCompare(sess->templateHash.buffer, templateHash, - templateHashSz) != 0)) { - rc = TPM_RC_VALUE; + else if (sess->templateHash.size > 0) { + /* Always run the compare so a size mismatch cannot short-circuit + * the constant-time path */ + int sizeMismatch = (sess->templateHash.size != templateHashSz); + word32 cmpSz = (sess->templateHash.size < templateHashSz) ? + sess->templateHash.size : templateHashSz; + if (sizeMismatch | + (TPM2_ConstantCompare(sess->templateHash.buffer, templateHash, + cmpSz) != 0)) { + rc = TPM_RC_VALUE; + } } } if (rc == 0) { From c33c5036e2ffaceedb01d3ff3f59aecde8cdc475 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:41:18 -0700 Subject: [PATCH 43/45] F-11933 - Skip the authorization area in no-auth-handle session commands --- src/fwtpm/fwtpm_command.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index 74d6555bd..985197421 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -10377,17 +10377,22 @@ static TPM_RC FwCmd_StartAuthSession(FWTPM_CTX* ctx, TPM2_Packet* cmd, FWTPM_ALLOC_BUF(encSalt, FWTPM_MAX_PUB_BUF); - (void)cmdTag; - (void)cmdSize; - /* Parse: tpmKey(U32), bind(U32) */ TPM2_Packet_ParseU32(cmd, &tpmKey); TPM2_Packet_ParseU32(cmd, &bind); + /* A session-tagged command with no auth handles still carries an auth + * area between the handles and parameters; skip it before parsing */ + if (cmdTag == TPM_ST_SESSIONS) { + rc = FwSkipAuthArea(cmd, cmdSize); + } + /* Parse: nonceCaller (TPM2B) */ - TPM2_Packet_ParseU16(cmd, &nonceCallerSize); - if (nonceCallerSize > sizeof(nonceCaller)) { - rc = TPM_RC_SIZE; + if (rc == 0) { + TPM2_Packet_ParseU16(cmd, &nonceCallerSize); + if (nonceCallerSize > sizeof(nonceCaller)) { + rc = TPM_RC_SIZE; + } } if (rc == 0 && nonceCallerSize > 0) { TPM2_Packet_ParseBytes(cmd, nonceCaller, nonceCallerSize); @@ -15619,7 +15624,11 @@ static TPM_RC FwCmd_MakeCredential(FWTPM_CTX* ctx, TPM2_Packet* cmd, } } - /* MakeCredential has no auth area */ + /* A session-tagged command with no auth handles still carries an auth + * area between the handle and parameters; skip it before parsing */ + if (rc == 0 && cmdTag == TPM_ST_SESSIONS) { + rc = FwSkipAuthArea(cmd, cmdSize); + } /* credential (TPM2B_DIGEST) */ if (rc == 0) { From 58d0fa65fb710a5634d5d857a3898e757e1e5e2e Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 11:43:52 -0700 Subject: [PATCH 44/45] F-9194 - Zeroize the command auth cache on every process command exit --- src/fwtpm/fwtpm_command.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index 985197421..d70b05cf0 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -19241,6 +19241,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, if (authAreaSz > (UINT32)(cmdSize - cmdPkt.pos)) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_AUTHSIZE); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } cpStart = cmdPkt.pos + (int)authAreaSz; @@ -19384,6 +19385,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, if (rc != TPM_RC_SUCCESS) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, rc); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } @@ -19392,6 +19394,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, if (entry->authHandleCnt > 0 && cmdAuthCnt < (int)entry->authHandleCnt) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_AUTH_MISSING); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } @@ -19402,6 +19405,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, cmdAuths[pj].sess->sessionType == TPM_SE_TRIAL) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_AUTH_TYPE); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19429,6 +19433,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, pSess->pcrUpdateCounter != ctx->pcrUpdateCounter) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_PCR_CHANGED); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } @@ -19492,6 +19497,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } /* Enforce any PolicyLocality constraint bound to the session */ @@ -19500,6 +19506,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, !((1u << ctx->activeLocality) & pSess->requiredLocality))) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_LOCALITY); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } #ifndef FWTPM_NO_PP @@ -19509,6 +19516,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, !FwPhysicalPresenceAsserted(ctx)) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_PP); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } #endif /* !FWTPM_NO_PP */ @@ -19525,6 +19533,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, ccpHash, (word32)ccpHashSz) != 0) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19543,6 +19552,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } else if (authPolicy == NULL) { @@ -19555,6 +19565,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } @@ -19569,6 +19580,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, rc); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19595,6 +19607,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, NULL) & FW_AUTH_USES_LOCKOUT) != 0) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19632,6 +19645,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, hasDaAuth) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19680,6 +19694,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #ifdef FWTPM_DA_USED_RETRY *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_RETRY); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; #endif } @@ -19700,6 +19715,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_AUTH_TYPE); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } @@ -19744,6 +19760,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_AUTH_TYPE); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } if (adminSess != NULL && adminSess->sessionType == TPM_SE_POLICY && @@ -19754,6 +19771,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_POLICY_CC); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19780,6 +19798,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_AUTH_UNAVAILABLE); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19816,12 +19835,14 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, if (FwDaRegisterFailure(ctx, daHandle)) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, authRc); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -19849,6 +19870,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, ctx, cpStart, cpHash, &cpHashSz) != 0) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_FAILURE); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } @@ -19880,12 +19902,14 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, if (FwDaRegisterFailure(ctx, daHandle)) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, authRc); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } TPM2_ForceZero(cpHash, sizeof(cpHash)); @@ -19928,12 +19952,14 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, if (FwDaRegisterFailure(ctx, daHandle)) { *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, authRc); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } @@ -19958,6 +19984,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, #endif *rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, TPM_RC_FAILURE); + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } } @@ -20211,10 +20238,12 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, FwFlushAllObjects(ctx); nvRc = FWTPM_NV_Save(ctx); if (nvRc != TPM_RC_SUCCESS) { + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return nvRc; } } + TPM2_ForceZero(cmdAuths, sizeof(cmdAuths)); return TPM_RC_SUCCESS; } From 1d8ea0cfd2df6188701f6fd8c0aba9ad3bc1b743 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 14:05:48 -0700 Subject: [PATCH 45/45] Advance SPDM receive sequence after auth and harden size checks --- hal/tpm_io.c | 3 ++- src/spdm/spdm_msg.c | 24 +++++++++++++++--------- src/spdm/spdm_secured.c | 10 +++++++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/hal/tpm_io.c b/hal/tpm_io.c index 9c4e4452c..4ab945d62 100644 --- a/hal/tpm_io.c +++ b/hal/tpm_io.c @@ -183,7 +183,8 @@ int TPM2_IoCb(TPM2_CTX* ctx, INT32 isRead, UINT32 addr, (void)userCtx; #endif #else - if (buf == NULL || size == 0 || size > MAX_SPI_FRAMESIZE) { + if (buf == NULL || size == 0 || + size > (UINT16)(sizeof(txBuf) - TPM_TIS_HEADER_SZ)) { ret = BAD_FUNC_ARG; } else { diff --git a/src/spdm/spdm_msg.c b/src/spdm/spdm_msg.c index 9cd50007c..388ec4032 100644 --- a/src/spdm/spdm_msg.c +++ b/src/spdm/spdm_msg.c @@ -55,6 +55,18 @@ static int wolfSPDM_BuildSimpleMsg(WOLFSPDM_CTX* ctx, byte msgCode, return WOLFSPDM_SUCCESS; } +/* KEY_EXCHANGE request size: 8-byte header, 32-byte RandomData, and two ECC + * coordinates, plus a config-specific OpaqueData block. Keep + * WOLFSPDM_KEYEX_OPAQUE_SZ in sync with the OpaqueData written below. */ +#define WOLFSPDM_KEYEX_FIXED_SZ (40 + 2 * WOLFSPDM_ECC_KEY_SIZE) +#ifdef WOLFSPDM_NUVOTON + #define WOLFSPDM_KEYEX_OPAQUE_SZ 14 +#elif defined(WOLFSPDM_NATIONS) + #define WOLFSPDM_KEYEX_OPAQUE_SZ 2 +#else + #define WOLFSPDM_KEYEX_OPAQUE_SZ 22 +#endif + int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) { word32 offset = 0; @@ -64,15 +76,9 @@ int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) word32 pubKeyYSz = sizeof(pubKeyY); int rc; - /* Require exactly the encoded request size: 40-byte fixed header, two ECC - * coordinates, and the config-specific OpaqueData block */ -#ifdef WOLFSPDM_NUVOTON - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 14); -#elif defined(WOLFSPDM_NATIONS) - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 2); -#else - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 22); -#endif + /* Require exactly the encoded request size */ + SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, + WOLFSPDM_KEYEX_FIXED_SZ + WOLFSPDM_KEYEX_OPAQUE_SZ); rc = wolfSPDM_GenerateEphemeralKey(ctx); if (rc == WOLFSPDM_SUCCESS) diff --git a/src/spdm/spdm_secured.c b/src/spdm/spdm_secured.c index acc5a6e36..705a757d4 100644 --- a/src/spdm/spdm_secured.c +++ b/src/spdm/spdm_secured.c @@ -294,6 +294,13 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, wolfSPDM_DebugPrint(ctx, "AES-GCM decrypt failed: %d\n", rc); ret = WOLFSPDM_E_DECRYPT_FAIL; } + else { + /* Record is authenticated (tag verified) so the peer has advanced; + * advance now. A forged record fails the tag and never reaches + * here, and a later payload parse error stays fatal without + * desyncing the sequence. */ + ctx->rspSeqNum++; + } } if (aesInit) { wc_AesFree(&aes); @@ -336,9 +343,6 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, } if (ret == WOLFSPDM_SUCCESS) { - /* Advance the receive counter only after authentication and payload - * validation succeed, so a forged record cannot desync the sequence */ - ctx->rspSeqNum++; wolfSPDM_DebugPrint(ctx, "Decrypted %u bytes -> %u bytes\n", encSz, *plainSz); }