diff --git a/examples/boot/secret_seal.c b/examples/boot/secret_seal.c index 94266847a..93d3e3d4d 100644 --- a/examples/boot/secret_seal.c +++ b/examples/boot/secret_seal.c @@ -152,8 +152,8 @@ int TPM2_Boot_SecretSeal_Example(void* userCtx, int argc, char *argv[]) const char* secretStr = argv[argc-1] + XSTRLEN("-secrethex="); word32 secretStrSz = (word32)XSTRLEN(secretStr); int secretHexSz; - if (secretStrSz > (word32)(sizeof(secret)*2-1)) - secretStrSz = (word32)(sizeof(secret)*2-1); + if (secretStrSz > (word32)((sizeof(secret)-1)*2)) + secretStrSz = (word32)((sizeof(secret)-1)*2); secretHexSz = hexToByte(secretStr, secret, secretStrSz); if (secretHexSz < 0) { printf("Invalid secret hex string\n"); diff --git a/examples/endorsement/get_ek_certs.c b/examples/endorsement/get_ek_certs.c index c442e5c85..0a2cca076 100644 --- a/examples/endorsement/get_ek_certs.c +++ b/examples/endorsement/get_ek_certs.c @@ -505,10 +505,10 @@ int TPM2_EndorsementCert_Example(void* userCtx, int argc, char *argv[]) #ifndef WOLFCRYPT_ONLY if (rc == 0) { /* Validate EK certificate against trusted certificates */ - rc = wolfSSL_CertManagerVerifyBuffer(cm, certBuf, certSz, + int vfyRc = wolfSSL_CertManagerVerifyBuffer(cm, certBuf, certSz, WOLFSSL_FILETYPE_ASN1); printf("EK Certificate is %s\n", - (rc == WOLFSSL_SUCCESS) ? "VALID" : "INVALID"); + (vfyRc == WOLFSSL_SUCCESS) ? "VALID" : "INVALID"); } #endif diff --git a/examples/gpio/gpio_config.c b/examples/gpio/gpio_config.c index 20d791669..d68bcd761 100644 --- a/examples/gpio/gpio_config.c +++ b/examples/gpio/gpio_config.c @@ -404,13 +404,13 @@ int TPM2_GPIO_Config_Example(void* userCtx, int argc, char *argv[]) /* Initial NV attributes */ parent.hndl = TPM_RH_PLATFORM; rc = wolfTPM2_GetNvAttributesTemplate(parent.hndl, &nvAttributes); - /* Add NV attributes required by Nuvoton specification */ - nvAttributes |= (TPMA_NV_PLATFORMCREATE | TPMA_NV_POLICY_DELETE); - nvAttributes |= (TPMA_NV_TPM_NT & (TPM_NT_ORDINARY << 4)); if (rc != TPM_RC_SUCCESS) { printf("Setting NV attributes failed\n"); goto exit; } + /* Add NV attributes required by Nuvoton specification */ + nvAttributes |= (TPMA_NV_PLATFORMCREATE | TPMA_NV_POLICY_DELETE); + nvAttributes |= (TPMA_NV_TPM_NT & (TPM_NT_ORDINARY << 4)); #ifdef DEBUG_WOLFTPM printf("nvAttributes = 0x%8.8X\n", nvAttributes); #endif diff --git a/examples/nvram/extend.c b/examples/nvram/extend.c index 1601bdd0e..31fba14fd 100644 --- a/examples/nvram/extend.c +++ b/examples/nvram/extend.c @@ -161,7 +161,11 @@ int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) /* Policy A: TPM2_PolicyCommandCode -> TPM_CC_NV_Read */ /* 47ce3032d8bad1f3089cb0c09088de43501491d460402b90cd1b7fc0b68ca92f */ policy[0] = &policyDigest[policyDigestSz]; - BuildPolicyCommandCode(hashAlg, policy[0], &nvSize, TPM_CC_NV_Read); + rc = BuildPolicyCommandCode(hashAlg, policy[0], &nvSize, TPM_CC_NV_Read); + if (rc != TPM_RC_SUCCESS) { + printf("Building PolicyA failed!\n"); + goto exit; + } printf("PolicyA: %d\n", nvSize); TPM2_PrintBin(policy[0], nvSize); policyDigestSz += nvSize; @@ -169,7 +173,11 @@ int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) /* Policy B: TPM2_PolicyCommandCode -> TPM_CC_NV_Extend */ /* b6a2e7142ee56fd978047488483daa5b42b8dc4cc7ddcceddfb91793cf1ff1b7 */ policy[1] = &policyDigest[policyDigestSz]; - BuildPolicyCommandCode(hashAlg, policy[1], &nvSize, TPM_CC_NV_Extend); + rc = BuildPolicyCommandCode(hashAlg, policy[1], &nvSize, TPM_CC_NV_Extend); + if (rc != TPM_RC_SUCCESS) { + printf("Building PolicyB failed!\n"); + goto exit; + } printf("PolicyB: %d\n", nvSize); TPM2_PrintBin(policy[1], nvSize); policyDigestSz += nvSize; @@ -177,7 +185,11 @@ int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) /* Policy C: TPM2_PolicyCommandCode -> TPM_CC_PolicyNV */ /* 203e4bd5d0448c9615cc13fa18e8d39222441cc40204d99a77262068dbd55a43 */ policy[2] = &policyDigest[policyDigestSz]; - BuildPolicyCommandCode(hashAlg, policy[2], &nvSize, TPM_CC_PolicyNV); + rc = BuildPolicyCommandCode(hashAlg, policy[2], &nvSize, TPM_CC_PolicyNV); + if (rc != TPM_RC_SUCCESS) { + printf("Building PolicyC failed!\n"); + goto exit; + } printf("PolicyC: %d\n", nvSize); TPM2_PrintBin(policy[2], nvSize); policyDigestSz += nvSize; diff --git a/examples/pcr/policy_sign.c b/examples/pcr/policy_sign.c index 066ee9238..86c6c9c69 100644 --- a/examples/pcr/policy_sign.c +++ b/examples/pcr/policy_sign.c @@ -292,15 +292,17 @@ int TPM2_PCR_PolicySign_Example(void* userCtx, int argc, char *argv[]) else if (XSTRNCMP(argv[argc-1], "-pcrdigest=", XSTRLEN("-pcrdigest=")) == 0) { const char* hashHexStr = argv[argc-1] + XSTRLEN("-pcrdigest="); int hashHexStrLen = (int)XSTRLEN(hashHexStr); - if (hashHexStrLen > (int)sizeof(pcrDigest)*2+1) - pcrDigestSz = -1; + int hexRet; + if (hashHexStrLen > (int)sizeof(pcrDigest)*2) + hexRet = -1; else - pcrDigestSz = hexToByte(hashHexStr, pcrDigest, hashHexStrLen); - if (pcrDigestSz <= 0) { + hexRet = hexToByte(hashHexStr, pcrDigest, hashHexStrLen); + if (hexRet <= 0) { fprintf(stderr, "Invalid PCR hash length\n"); usage(); return -1; } + pcrDigestSz = (word32)hexRet; } else if (XSTRNCMP(argv[argc-1], "-password=", XSTRLEN("-password=")) == 0) { diff --git a/hal/tpm_io_espressif.c b/hal/tpm_io_espressif.c index 27a370c45..5599770b7 100644 --- a/hal/tpm_io_espressif.c +++ b/hal/tpm_io_espressif.c @@ -367,6 +367,8 @@ static esp_err_t esp_tpm_register_write(uint32_t reg, } } + TPM2_ForceZero(buf, sizeof(buf)); + return result; } diff --git a/hal/tpm_io_infineon.c b/hal/tpm_io_infineon.c index 8d3eb88c4..3ba116b6d 100644 --- a/hal/tpm_io_infineon.c +++ b/hal/tpm_io_infineon.c @@ -130,6 +130,7 @@ else { printf("CyHAL I2C Write failure %d\n", (int)result); } + TPM2_ForceZero(buf, sizeof(buf)); return ret; } diff --git a/hal/tpm_io_linux.c b/hal/tpm_io_linux.c index 6f969577e..5f798058e 100644 --- a/hal/tpm_io_linux.c +++ b/hal/tpm_io_linux.c @@ -185,6 +185,8 @@ break; } while (--timeout > 0); + TPM2_ForceZero(buf, sizeof(buf)); + return (rc == -1) ? TPM_RC_FAILURE : TPM_RC_SUCCESS; } diff --git a/hal/tpm_io_microchip.c b/hal/tpm_io_microchip.c index 2c42a8fa5..9a7299c74 100644 --- a/hal/tpm_io_microchip.c +++ b/hal/tpm_io_microchip.c @@ -67,6 +67,29 @@ static uintptr_t dummy_context; + /* Staging buffers stay at file scope: a busy-timeout bail-out returns + * while the bit-bang engine is still clocking data in or out of them, so + * they must outlive the call that queued the transfer. Reads stage here + * too, so a timeout cannot leave the engine writing into the caller's + * (often stack-local) buffer. */ + static byte i2cRegBuf[1]; + static byte i2cXferBuf[MAX_SPI_FRAMESIZE+1]; + static byte i2cRdBuf[MAX_SPI_FRAMESIZE]; + /* Set when a busy timeout leaves plaintext in a staging buffer that could + * not be scrubbed; cleared by the next call that finds the engine idle. */ + static int i2cXferDirty = 0; + + /* Scrub staging left dirty by a previous busy timeout. Only safe once the + * engine is idle, so callers must check I2C_BB_IsBusy() first. */ + static void i2c_scrub_stale(void) + { + if (i2cXferDirty) { + TPM2_ForceZero(i2cXferBuf, sizeof(i2cXferBuf)); + TPM2_ForceZero(i2cRdBuf, sizeof(i2cRdBuf)); + i2cXferDirty = 0; + } + } + static void dummy_callback(uintptr_t context) { (void) context; @@ -101,12 +124,13 @@ bool queued = false; int timeout = TPM_I2C_TRIES; int busy_retry = TPM_I2C_TRIES; - byte buf[1]; + byte* buf = i2cRegBuf; if (I2C_BB_IsBusy()) { printf("error: i2c_read: already busy\n"); return -1; } + i2c_scrub_stale(); /* TIS layer should never provide a buffer larger than this, but double check for good coding practice */ @@ -119,7 +143,7 @@ do { /* Queue the write with I2C_BB. */ - queued = I2C_BB_Write(TPM2_I2C_ADDR, buf, sizeof(buf)); + queued = I2C_BB_Write(TPM2_I2C_ADDR, buf, sizeof(i2cRegBuf)); if (!queued) { printf("error: i2c_read: I2C_BB_Write failed\n"); @@ -159,7 +183,7 @@ do { /* Queue the read with I2C_BB. */ - queued = I2C_BB_Read(TPM2_I2C_ADDR, data, len); + queued = I2C_BB_Read(TPM2_I2C_ADDR, i2cRdBuf, len); if (!queued) { printf("error: i2c_read: I2C_BB_Read failed\n"); @@ -172,6 +196,14 @@ microchip_wait(250); } + if (I2C_BB_IsBusy()) { + /* Engine still owns i2cRdBuf; it cannot be scrubbed here, so + * flag it for the next call that finds the engine idle */ + i2cXferDirty = 1; + printf("error: i2c_read: busy wait timed out\n"); + return -1; + } + status = I2C_BB_ErrorGet(); if (status == I2CBB_ERROR_NAK) { microchip_wait(250); @@ -179,6 +211,7 @@ } while (status == I2CBB_ERROR_NAK && --timeout > 0); if (status == I2CBB_ERROR_NONE) { + XMEMCPY(data, i2cRdBuf, len); ret = TPM_RC_SUCCESS; } else { @@ -186,6 +219,7 @@ status, TPM_I2C_TRIES - timeout); } + TPM2_ForceZero(i2cRdBuf, sizeof(i2cRdBuf)); return ret; } @@ -196,7 +230,7 @@ bool queued = false; int timeout = TPM_I2C_TRIES; int busy_retry = TPM_I2C_TRIES; - byte buf[MAX_SPI_FRAMESIZE+1]; + byte* buf = i2cXferBuf; /* TIS layer should never provide a buffer larger than this, but double check for good coding practice */ @@ -209,8 +243,11 @@ printf("error: i2c_write: already busy\n"); return -1; } + i2c_scrub_stale(); - /* Build packet with TPM register and data */ + /* Build packet with TPM register and data. The engine is idle here, + * so clear any residue a previous busy-timeout bail-out left */ + TPM2_ForceZero(buf, sizeof(i2cXferBuf)); buf[0] = (reg & 0xFF); /* convert to simple 8-bit address for I2C */ XMEMCPY(buf + 1, data, len); @@ -220,6 +257,7 @@ if (!queued) { printf("error: i2c_write: I2C_BB_Write failed: %d\n", status); + TPM2_ForceZero(buf, sizeof(i2cXferBuf)); return -1; } @@ -229,6 +267,15 @@ microchip_wait(250); } + if (I2C_BB_IsBusy()) { + /* Engine is still clocking out i2cXferBuf, so it cannot be + * scrubbed here; flag it for the next call that finds the + * engine idle */ + i2cXferDirty = 1; + printf("error: i2c_write: busy wait timed out\n"); + return -1; + } + status = I2C_BB_ErrorGet(); if (status == I2CBB_ERROR_NAK) { @@ -242,6 +289,7 @@ else { printf("I2C Write failure %d\n", status); } + TPM2_ForceZero(buf, sizeof(i2cXferBuf)); return ret; } @@ -279,7 +327,7 @@ /* TPM Chip Select Pin (default PC5) */ #ifndef TPM_SPI_PIN -#define SYS_PORT_PIN_PC5 +#define TPM_SPI_PIN SYS_PORT_PIN_PC5 #endif int TPM2_IoCb_Microchip_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, diff --git a/hal/tpm_io_st.c b/hal/tpm_io_st.c index ac9d02550..70eaefca4 100644 --- a/hal/tpm_io_st.c +++ b/hal/tpm_io_st.c @@ -127,6 +127,7 @@ else { printf("I2C Write failure %d\n", status); } + TPM2_ForceZero(buf, sizeof(buf)); return ret; } diff --git a/hal/tpm_io_zephyr.c b/hal/tpm_io_zephyr.c index d07d78131..804a42382 100644 --- a/hal/tpm_io_zephyr.c +++ b/hal/tpm_io_zephyr.c @@ -154,6 +154,7 @@ int TPM2_IoCb_Zephyr_I2C(TPM2_CTX* ctx, int isRead, word32 addr, printf("Failed to write to TPM at register 0x%02X! Error: %d\n", addr, ret); } + TPM2_ForceZero(tempBuf, size + 1); XFREE(tempBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index 049b060c2..157fe6267 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -541,6 +541,32 @@ static int FwCtAuthCompare(const byte* password, int pwSz, return ((int)diff != 0) ? 1 : 0; } +#ifndef FWTPM_NO_POLICY +/* Constant-time lexicographic comparison of two equal-length big-endian + * byte strings, for the TPM_EO_* relational policy assertions. + * Runs a fixed number of iterations with mask accumulation so the timing + * does not reveal the index of the first differing byte. + * Returns -1 if a < b, 1 if a > b, 0 if equal. */ +static int FwCtRelCompare(const byte* a, const byte* b, int len) +{ + volatile byte gt = 0; + volatile byte eq = 1; + int ci; + + /* Borrow-bit form, not a sign-of-difference shift: the latter is + * canonicalized back into icmp/select, which becomes a real branch on + * cores without conditional execution (ARMv6-M, ARMv8-M Baseline). + * Most significant byte first, so the first difference decides. */ + for (ci = 0; ci < len; ci++) { + gt = (byte)(gt | ((((UINT32)((int)b[ci] - (int)a[ci])) >> 8) & eq)); + eq = (byte)(eq & + (((((UINT32)((int)b[ci] ^ (int)a[ci]))) - 1u) >> 8)); + } + + return ((int)gt + (int)gt + (int)eq) - 1; +} +#endif /* !FWTPM_NO_POLICY */ + /* Compute cpHash = H(commandCode || name1 || ... || cpBuffer) * Per TPM 2.0 Part 1 Section 18.7 */ static int FwComputeCpHash(TPMI_ALG_HASH hashAlg, TPM_CC cmdCode, @@ -10267,28 +10293,20 @@ static TPM_RC FwCmd_PolicyNV(FWTPM_CTX* ctx, TPM2_Packet* cmd, /* Compare operandB with NV data at offset */ byte* nvData = nv->data + offset; int pass = 0; + volatile byte bitDiff = 0; - /* Byte-by-byte comparison for relational operators */ - cmpResult = 0; - for (i = 0; i < (int)operandBSz; i++) { - if (nvData[i] < operandB[i]) { - cmpResult = -1; - break; - } - else if (nvData[i] > operandB[i]) { - cmpResult = 1; - break; - } - } + /* Constant-time comparison for relational operators */ + cmpResult = FwCtRelCompare(nvData, operandB, (int)operandBSz); - /* For signed comparisons, check sign bits (big-endian MSB) */ + /* Signed comparison flips the result when the sign bits differ. + * Selected with masks so the secret MSB is not branched on. */ signedCmpResult = cmpResult; if (operandBSz > 0) { - int nvSign = (nvData[0] & 0x80) ? 1 : 0; - int opSign = (operandB[0] & 0x80) ? 1 : 0; - if (nvSign != opSign) { - signedCmpResult = nvSign ? -1 : 1; - } + int diffSign = (int)(((UINT32)(nvData[0] ^ operandB[0])) >> 7) & 1; + int nvNeg = (int)(((UINT32)nvData[0]) >> 7) & 1; + int signRes = 1 - (2 * nvNeg); /* nv negative => -1, else 1 */ + signedCmpResult = (signRes & -diffSign) | + (cmpResult & ~(-diffSign)); } switch (operation) { @@ -10323,22 +10341,16 @@ static TPM_RC FwCmd_PolicyNV(FWTPM_CTX* ctx, TPM2_Packet* cmd, pass = (cmpResult <= 0); break; case TPM_EO_BITSET: - pass = 1; for (i = 0; i < (int)operandBSz; i++) { - if ((nvData[i] & operandB[i]) != operandB[i]) { - pass = 0; - break; - } + bitDiff |= (byte)((nvData[i] & operandB[i]) ^ operandB[i]); } + pass = ((int)bitDiff == 0); break; case TPM_EO_BITCLEAR: - pass = 1; for (i = 0; i < (int)operandBSz; i++) { - if ((nvData[i] & operandB[i]) != 0) { - pass = 0; - break; - } + bitDiff |= (byte)(nvData[i] & operandB[i]); } + pass = ((int)bitDiff == 0); break; default: rc = TPM_RC_VALUE; @@ -10880,27 +10892,20 @@ static TPM_RC FwCmd_PolicyCounterTimer(FWTPM_CTX* ctx, TPM2_Packet* cmd, int pass = 0; int cmpResult = 0; int signedCmpResult = 0; + volatile byte bitDiff = 0; int i; - for (i = 0; i < (int)operandBSz; i++) { - if (data[i] < operandB[i]) { - cmpResult = -1; - break; - } - else if (data[i] > operandB[i]) { - cmpResult = 1; - break; - } - } + cmpResult = FwCtRelCompare(data, operandB, (int)operandBSz); - /* For signed comparisons, check sign bits (big-endian MSB) */ + /* Signed comparison flips the result when the sign bits differ. + * Selected with masks so the compared MSB is not branched on. */ signedCmpResult = cmpResult; if (operandBSz > 0) { - int nvSign = (data[0] & 0x80) ? 1 : 0; - int opSign = (operandB[0] & 0x80) ? 1 : 0; - if (nvSign != opSign) { - signedCmpResult = nvSign ? -1 : 1; - } + int diffSign = (int)(((UINT32)(data[0] ^ operandB[0])) >> 7) & 1; + int nvNeg = (int)(((UINT32)data[0]) >> 7) & 1; + int signRes = 1 - (2 * nvNeg); + signedCmpResult = (signRes & -diffSign) | + (cmpResult & ~(-diffSign)); } switch (operation) { @@ -10915,20 +10920,16 @@ static TPM_RC FwCmd_PolicyCounterTimer(FWTPM_CTX* ctx, TPM2_Packet* cmd, case TPM_EO_SIGNED_LE: pass = (signedCmpResult <= 0); break; case TPM_EO_UNSIGNED_LE: pass = (cmpResult <= 0); break; case TPM_EO_BITSET: - pass = 1; for (i = 0; i < (int)operandBSz; i++) { - if ((data[i] & operandB[i]) != operandB[i]) { - pass = 0; break; - } + bitDiff |= (byte)((data[i] & operandB[i]) ^ operandB[i]); } + pass = ((int)bitDiff == 0); break; case TPM_EO_BITCLEAR: - pass = 1; for (i = 0; i < (int)operandBSz; i++) { - if ((data[i] & operandB[i]) != 0) { - pass = 0; break; - } + bitDiff |= (byte)(data[i] & operandB[i]); } + pass = ((int)bitDiff == 0); break; default: rc = TPM_RC_VALUE; diff --git a/src/fwtpm/fwtpm_tis.c b/src/fwtpm/fwtpm_tis.c index 8d26fe2c8..0edfe401f 100644 --- a/src/fwtpm/fwtpm_tis.c +++ b/src/fwtpm/fwtpm_tis.c @@ -314,6 +314,11 @@ static void TisHandleRegAccess(FWTPM_CTX* ctx, FWTPM_TIS_REGS* regs) /* Snapshot read state to locals for TOCTOU safety */ UINT32 rpos = regs->fifo_read_pos; UINT32 rlen = regs->rsp_len; + /* Client-writable shared memory: clamp to FIFO capacity the + * same way the command side clamps localCmdLen */ + if (rlen > (UINT32)sizeof(regs->rsp_buf)) { + rlen = (UINT32)sizeof(regs->rsp_buf); + } /* Zero full reg_data first: client may copy more bytes than * we write here (it uses its originally-requested size, not * our clamped len), so any stale shared-memory bytes would diff --git a/src/spdm/spdm_secured.c b/src/spdm/spdm_secured.c index 36b8af8af..6544c13b8 100644 --- a/src/spdm/spdm_secured.c +++ b/src/spdm/spdm_secured.c @@ -299,7 +299,11 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, /* ----- Parse decrypted payload ----- */ - if (rc == 0) { + if (rc == 0 && cipherLen < 2) { + /* authenticated record too short to hold the application length */ + ret = WOLFSPDM_E_BUFFER_SMALL; + } + else if (rc == 0) { appDataLen = SPDM_Get16LE(decrypted); #ifdef WOLFTPM_SPDM_TCG if (ctx->mode == WOLFSPDM_MODE_NUVOTON || diff --git a/src/spdm/spdm_transcript.c b/src/spdm/spdm_transcript.c index b0215b7e1..05bbd2b2c 100644 --- a/src/spdm/spdm_transcript.c +++ b/src/spdm/spdm_transcript.c @@ -53,7 +53,8 @@ int wolfSPDM_TranscriptAdd(WOLFSPDM_CTX* ctx, const byte* data, word32 len) return WOLFSPDM_E_INVALID_ARG; } - if (ctx->transcriptLen + len > WOLFSPDM_MAX_TRANSCRIPT) { + if (ctx->transcriptLen > WOLFSPDM_MAX_TRANSCRIPT || + len > WOLFSPDM_MAX_TRANSCRIPT - ctx->transcriptLen) { return WOLFSPDM_E_BUFFER_SMALL; } diff --git a/src/tpm2.c b/src/tpm2.c index 6c4c8cee5..5b233dbd8 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -378,11 +378,15 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, int sizeMismatch; int diff; + XMEMSET(&hash, 0, sizeof(hash)); + XMEMSET(&hmac, 0, sizeof(hmac)); + if (expectedHmacSz == 0 || authRsp.hmac.size != expectedHmacSz) { #ifdef DEBUG_WOLFTPM printf("Response HMAC size mismatch! expected=%u got=%u\n", expectedHmacSz, authRsp.hmac.size); #endif + TPM2_ForceZero(&authRsp, sizeof(authRsp)); return TPM_RC_HMAC; } @@ -393,6 +397,8 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Error calculating rpHash!\n"); #endif + TPM2_ForceZero(&hash, sizeof(hash)); + TPM2_ForceZero(&authRsp, sizeof(authRsp)); return rc; } @@ -404,6 +410,9 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Error calculating response HMAC!\n"); #endif + TPM2_ForceZero(&hmac, sizeof(hmac)); + TPM2_ForceZero(&hash, sizeof(hash)); + TPM2_ForceZero(&authRsp, sizeof(authRsp)); return rc; } @@ -418,8 +427,14 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Response HMAC verification failed!\n"); #endif + TPM2_ForceZero(&hmac, sizeof(hmac)); + TPM2_ForceZero(&hash, sizeof(hash)); + TPM2_ForceZero(&authRsp, sizeof(authRsp)); return TPM_RC_HMAC; } + + TPM2_ForceZero(&hmac, sizeof(hmac)); + TPM2_ForceZero(&hash, sizeof(hash)); } /* Save off last known HMAC */ @@ -441,10 +456,13 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, #ifdef DEBUG_WOLFTPM printf("Response parameter decryption failed\n"); #endif + TPM2_ForceZero(&authRsp, sizeof(authRsp)); return rc; } } } + + TPM2_ForceZero(&authRsp, sizeof(authRsp)); } return rc; diff --git a/src/tpm2_cryptocb.c b/src/tpm2_cryptocb.c index 0a6500e67..d8cc83804 100644 --- a/src/tpm2_cryptocb.c +++ b/src/tpm2_cryptocb.c @@ -620,6 +620,8 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) hashCtx->handle = 0; /* clear hash handle */ if ((hashFlags & WC_HASH_FLAG_ISCOPY) == 0) { if (hashCtx->cacheBuf) { + TPM2_ForceZero(hashCtx->cacheBuf, + hashCtx->cacheBufSz); XFREE(hashCtx->cacheBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); hashCtx->cacheBuf = NULL; } @@ -832,6 +834,7 @@ static int wolfTPM2_HashUpdateCache(WOLFTPM2_HASHCTX* hashCtx, return MEMORY_E; } XMEMCPY(hashCtx->cacheBuf, oldIn, hashCtx->cacheSz); + TPM2_ForceZero(oldIn, oldBufSz); XFREE(oldIn, NULL, DYNAMIC_TYPE_TMP_BUFFER); } diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index b28ffa86f..c4ffe4669 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -571,6 +571,7 @@ void TPM2_Packet_ParsePCR(TPM2_Packet* packet, TPML_PCR_SELECTION* pcr) int i; UINT32 wireCount; UINT32 loopCount; + UINT32 parsedCount; UINT16 hash; UINT8 wireSizeofSelect; TPM2_Packet_ParseU32(packet, &wireCount); @@ -594,7 +595,12 @@ void TPM2_Packet_ParsePCR(TPM2_Packet* packet, TPML_PCR_SELECTION* pcr) else { loopCount = 0; } + /* remaining/3 assumes a zero-length select, so it over-estimates how + * many entries the wire actually carries; count what is really parsed */ + parsedCount = 0; for (i = 0; i < (int)loopCount; i++) { + if (packet == NULL || packet->pos + 3 > packet->size) + break; TPM2_Packet_ParseU16(packet, &hash); TPM2_Packet_ParseU8(packet, &wireSizeofSelect); if (i < (int)pcr->count) { @@ -615,7 +621,10 @@ void TPM2_Packet_ParsePCR(TPM2_Packet* packet, TPML_PCR_SELECTION* pcr) /* Skip entire entry for overflow iterations */ TPM2_Packet_ParseBytes(packet, NULL, wireSizeofSelect); } + parsedCount++; } + if (pcr->count > parsedCount) + pcr->count = parsedCount; /* Skip remaining wire entries beyond the capped loop so packet->pos * stays synchronized with the wire format for subsequent parsing. * Break when the packet is exhausted to avoid spinning on an diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index d50044bbe..9200d9c0a 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -5547,6 +5547,8 @@ int wolfTPM2_SignSequenceUpdate(WOLFTPM2_DEV* dev, rc = TPM2_SequenceUpdate(&seqUpdateIn); + TPM2_ForceZero(&seqUpdateIn, sizeof(seqUpdateIn)); + return rc; } @@ -5652,6 +5654,8 @@ int wolfTPM2_SignSequenceComplete(WOLFTPM2_DEV* dev, } } + TPM2_ForceZero(&signSeqCompleteIn, sizeof(signSeqCompleteIn)); + return rc; } #endif /* WOLFTPM_MLDSA_SIGN */ @@ -5720,6 +5724,8 @@ int wolfTPM2_VerifySequenceUpdate(WOLFTPM2_DEV* dev, rc = TPM2_SequenceUpdate(&seqUpdateIn); + TPM2_ForceZero(&seqUpdateIn, sizeof(seqUpdateIn)); + return rc; } @@ -9843,6 +9849,7 @@ static int CSR_Parse_DN(CertName* name, const char* subject) for (i = 0; i < (int)(sizeof(tags) / sizeof(DNTags)); i++) { const char *begin, *end; + char* dst; word32 len = 0; /* find start tag */ begin = XSTRSTR(subject, tags[i].tag); @@ -9859,7 +9866,13 @@ static int CSR_Parse_DN(CertName* name, const char* subject) if (len > CTC_NAME_SIZE-1) { len = CTC_NAME_SIZE-1; /* leave room for null term */ } - XMEMCPY((byte*)name + tags[i].certNameOff, begin, len); + /* Clear only the component being written: SetSubject may be + * called more than once to build a DN, so components absent from + * this subject must survive */ + dst = (char*)name + tags[i].certNameOff; + XMEMSET(dst, 0, CTC_NAME_SIZE); + XMEMCPY(dst, begin, len); + dst[len] = '\0'; } } return rc; @@ -10760,6 +10773,7 @@ int wolfTPM2_PCRGetDigest(WOLFTPM2_DEV* dev, TPM_ALG_ID pcrAlg, rc = wc_HashFinal(&hash_ctx, hashType, pcrDigest); } wc_HashFree(&hash_ctx, hashType); + TPM2_ForceZero(&hash_ctx, sizeof(hash_ctx)); #ifdef DEBUG_WOLFTPM if (rc != 0) { @@ -10826,6 +10840,7 @@ int wolfTPM2_PolicyHash(TPM_ALG_ID hashAlg, rc = wc_HashFinal(&hash_ctx, hashType, digest); } wc_HashFree(&hash_ctx, hashType); + TPM2_ForceZero(&hash_ctx, sizeof(hash_ctx)); #ifdef DEBUG_WOLFTPM if (rc != 0) { @@ -10867,7 +10882,8 @@ int wolfTPM2_PolicyPCRMake(TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz, TPM2_Packet_AppendPCR(&packet, &pcr); /* Copy the pcrDigest to the end of buffer */ - if (pcrDigestSz + packet.pos > sizeof(buf)) { + if (packet.pos < 0 || (word32)packet.pos > (word32)sizeof(buf) || + pcrDigestSz > (word32)sizeof(buf) - (word32)packet.pos) { return BUFFER_E; } XMEMCPY(buf + packet.pos, pcrDigest, pcrDigestSz); @@ -11108,6 +11124,14 @@ static int tpm2_ifx_firmware_start(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, int rc; WOLFTPM2_SESSION tpmSession; + if (dev == NULL || manifest_hash == NULL || manifest_hash_sz == 0 || + manifest_hash_sz > TPM_SHA512_DIGEST_SIZE) { + return BAD_FUNC_ARG; + } + if (manifest_hash_sz != (uint32_t)TPM2_GetHashDigestSize(hashAlg)) { + return BAD_FUNC_ARG; + } + XMEMSET(&tpmSession, 0, sizeof(tpmSession)); rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL,