diff --git a/src/tpm2.c b/src/tpm2.c index e3d1ec67..cbce0a32 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -1921,6 +1921,10 @@ TPM_RC TPM2_Unseal(Unseal_In* in, Unseal_Out* out) (UINT16)sizeof(out->outData.buffer)); } + /* Wipe the shared buffer so the unsealed plaintext does not linger in + * the caller-owned context on any post-send path */ + TPM2_ForceZero(ctx->cmdBuf, sizeof(ctx->cmdBuf)); + TPM2_ReleaseLock(ctx); } return rc; diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index 5dee7e98..29577077 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -1723,7 +1723,7 @@ TPM_RC TPM2_Packet_Parse(TPM_RC rc, TPM2_Packet* packet) * malicious or MITM responder could inflate respSz and cause * downstream parsers (bounded only by packet->size) to read * past the physical allocation. */ - if (respSz > (UINT32)packet->size) { + if (respSz < TPM2_HEADER_SIZE || respSz > (UINT32)packet->size) { return TPM_RC_SIZE; } packet->size = respSz; diff --git a/src/tpm2_tis.c b/src/tpm2_tis.c index 2e72aca1..ce75e130 100644 --- a/src/tpm2_tis.c +++ b/src/tpm2_tis.c @@ -484,7 +484,8 @@ int TPM2_TIS_GetBurstCount(TPM2_CTX* ctx, word16* burstCount) int TPM2_TIS_ValidateRspSz(int rspSz, int packetSize) { int rc = TPM_RC_SUCCESS; - if (rspSz < 0 || rspSz >= MAX_RESPONSE_SIZE || rspSz > packetSize) { + if (rspSz < TPM2_HEADER_SIZE || rspSz > MAX_RESPONSE_SIZE || + rspSz > packetSize) { rc = TPM_RC_FAILURE; } return rc; diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 96999072..19a746fe 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -549,6 +549,7 @@ WOLFTPM2_DEV* wolfTPM2_New(void) sizeof(WOLFTPM2_DEV), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dev != NULL) { if (wolfTPM2_Init(dev, TPM2_IoCb, NULL) != TPM_RC_SUCCESS) { + TPM2_ForceZero(dev, sizeof(WOLFTPM2_DEV)); XFREE(dev, NULL, DYNAMIC_TYPE_TMP_BUFFER); dev = NULL; } @@ -1576,7 +1577,8 @@ int wolfTPM2_SpdmConnectNuvoton(WOLFTPM2_DEV* dev, return rc; } } -#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \ + defined(ECC_TIMING_RESISTANT) else { /* Auto-generate ephemeral P-384 key pair for mutual authentication */ ecc_key hostKey; @@ -1664,6 +1666,11 @@ int wolfTPM2_SpdmConnectNuvoton(WOLFTPM2_DEV* dev, tpmtPub, (word32)(p - tpmtPub)); if (rc != 0) return rc; } +#elif !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) + else { + /* Requester key auto-generation requires timing-resistant ECC */ + return NOT_COMPILED_IN; + } #endif /* !WOLFTPM2_NO_WOLFCRYPT && HAVE_ECC */ /* Perform the Nuvoton SPDM handshake */ @@ -1762,7 +1769,8 @@ int wolfTPM2_SpdmConnectNations(WOLFTPM2_DEV* dev, return rc; } } -#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \ + defined(ECC_TIMING_RESISTANT) else { /* Auto-generate ephemeral P-384 key pair for mutual authentication. * Nations: GIVE_PUB is not supported, but MUT_AUTH is still required. @@ -1838,6 +1846,11 @@ int wolfTPM2_SpdmConnectNations(WOLFTPM2_DEV* dev, tpmtPub, (word32)(p - tpmtPub)); if (rc != 0) return rc; } +#elif !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) + else { + /* Requester key auto-generation requires timing-resistant ECC */ + return NOT_COMPILED_IN; + } #endif /* !WOLFTPM2_NO_WOLFCRYPT && HAVE_ECC */ /* Perform the TCG SPDM handshake */ @@ -3624,19 +3637,28 @@ static int SensitiveToPrivate(TPM2B_SENSITIVE* sens, TPM2B_PRIVATE* priv, if (parentKey != NULL) { symKey.size = parentKey->handle.symmetric.keyBits.sym; } - else { + else if (sym != NULL) { symKey.size = sym->keyBits.sym; } - /* convert from bit to byte and round up */ - symKey.size = (symKey.size + 7) / 8; - /* check for invalid value */ - if (symKey.size > sizeof(symKey.buffer)) { - rc = BUFFER_E; + else { + rc = BAD_FUNC_ARG; + } + if (rc == 0) { + /* convert from bit to byte and round up */ + symKey.size = (symKey.size + 7) / 8; + /* check for invalid value */ + if (symKey.size > sizeof(symKey.buffer)) { + rc = BUFFER_E; + } } #endif - if (innerWrap) { - /* TODO: Inner wrap support */ + if (innerWrap && !outerWrap) { + /* A symmetric definition without an outer wrap seed would emit the + * sensitive unprotected (inner-wrap-only is not implemented); reject + * rather than return success with plaintext. When an outer wrap is + * present it applies this symmetric encryption. */ + rc = NOT_COMPILED_IN; } if (rc == 0 && outerWrap) { @@ -4846,7 +4868,7 @@ int wolfTPM2_RsaPrivateKeyImportDer(WOLFTPM2_DEV* dev, int initRc = -1; RsaKey key[1]; word32 idx = 0; - word32 e; + word32 e = 0; byte n[RSA_MAX_SIZE / 8]; byte d[RSA_MAX_SIZE / 8]; byte p[RSA_MAX_SIZE / 8]; @@ -4865,8 +4887,13 @@ int wolfTPM2_RsaPrivateKeyImportDer(WOLFTPM2_DEV* dev, if (rc == 0) rc = initRc = wc_InitRsaKey(key, NULL); - if (rc == 0) + if (rc == 0) { + #ifdef HAVE_PKCS8 + /* Skip a PKCS#8 wrapper if present (BEGIN PRIVATE KEY) */ + (void)wc_GetPkcs8TraditionalOffset((byte*)input, &idx, inSz); + #endif rc = wc_RsaPrivateKeyDecode(input, &idx, key, inSz); + } if (rc == 0) { PRIVATE_KEY_UNLOCK(); @@ -4896,10 +4923,38 @@ int wolfTPM2_RsaPrivateKeyImportPem(WOLFTPM2_DEV* dev, const char* input, word32 inSz, char* pass, TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg) { - (void)scheme; - (void)hashAlg; - return wolfTPM2_ImportPrivateKeyBuffer(dev, parentKey, TPM_ALG_RSA, keyBlob, - ENCODING_TYPE_PEM, input, inSz, pass, 0, NULL, 0); + int rc; + byte* derBuf; + word32 derSz; + word32 derBufSz; + + if (dev == NULL || parentKey == NULL || keyBlob == NULL || + input == NULL || inSz == 0) { + return BAD_FUNC_ARG; + } + + /* der size is base 64 decode length */ + if (inSz > (0xFFFFFFFFU / 3)) + return BAD_FUNC_ARG; + derSz = inSz * 3 / 4 + 1; + derBufSz = derSz; + derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) + return MEMORY_E; + + /* Convert PEM to DER, then import through the DER path so the requested + * RSA scheme and hash are applied. The DER importer skips any PKCS#8 + * wrapper wc_KeyPemToDer leaves in place. */ + rc = wc_KeyPemToDer((byte*)input, inSz, derBuf, derBufSz, pass); + if (rc >= 0) { + derSz = (word32)rc; + rc = wolfTPM2_RsaPrivateKeyImportDer(dev, parentKey, keyBlob, + derBuf, derSz, scheme, hashAlg); + } + + TPM2_ForceZero(derBuf, derBufSz); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return rc; } #endif /* WOLFTPM2_PEM_DECODE */ diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 2eee812a..449c7977 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -6110,6 +6110,10 @@ static void test_TPM2_TIS_ValidateRspSz(void) AssertIntEQ(TPM2_TIS_ValidateRspSz(packetSize + 1, packetSize), TPM_RC_FAILURE); AssertIntEQ(TPM2_TIS_ValidateRspSz(MAX_RESPONSE_SIZE, MAX_RESPONSE_SIZE), + TPM_RC_SUCCESS); + AssertIntEQ(TPM2_TIS_ValidateRspSz(MAX_RESPONSE_SIZE + 1, + MAX_RESPONSE_SIZE), TPM_RC_FAILURE); + AssertIntEQ(TPM2_TIS_ValidateRspSz(TPM2_HEADER_SIZE - 1, packetSize), TPM_RC_FAILURE); AssertIntEQ(TPM2_TIS_ValidateRspSz(-1, packetSize), TPM_RC_FAILURE); diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index 84a11b88..b339a7cd 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -412,6 +412,11 @@ typedef enum { TPM_RC_BINDING = RC_FMT1 + 0x025, TPM_RC_CURVE = RC_FMT1 + 0x026, TPM_RC_ECC_POINT = RC_FMT1 + 0x027, +#ifdef WOLFTPM_V185 + /* Part 2 v1.85 Sec.6.6.3 Table 17 firmware/SVN-limited codes */ + TPM_RC_FW_LIMITED = RC_FMT1 + 0x028, + TPM_RC_SVN_LIMITED = RC_FMT1 + 0x029, +#endif /* TCG Part 2 Sec.6.6.3 Table 17 -- present since v1.16, not v1.85 */ TPM_RC_PARMS = RC_FMT1 + 0x02A, #ifdef WOLFTPM_PQC @@ -419,6 +424,11 @@ typedef enum { TPM_RC_EXT_MU = RC_FMT1 + 0x02B, TPM_RC_ONE_SHOT_SIGNATURE = RC_FMT1 + 0x02C, TPM_RC_SIGN_CONTEXT_KEY = RC_FMT1 + 0x02D, +#endif +#ifdef WOLFTPM_V185 + /* Part 2 v1.85 Sec.6.6.3 Table 17 channel protocol codes */ + TPM_RC_CHANNEL = RC_FMT1 + 0x030, + TPM_RC_CHANNEL_KEY = RC_FMT1 + 0x031, #endif RC_MAX_FMT1 = RC_FMT1 + 0x03F, @@ -873,11 +883,12 @@ enum TPMA_OBJECT_mask { TPMA_OBJECT_restricted = 0x00010000, TPMA_OBJECT_decrypt = 0x00020000, TPMA_OBJECT_sign = 0x00040000, +#ifndef WOLFTPM_V185 /* Deprecated alias. Earlier versions of this header labeled bit 9 * as derivedDataOrigin, which does not appear in the TCG spec. - * Retained at the same bit value (now svnLimited per Part 2 v1.85) - * for source compatibility with downstream code. */ + * In v1.85 builds bit 9 is exposed only as svnLimited. */ TPMA_OBJECT_derivedDataOrigin = 0x00000200, +#endif #ifdef WOLFTPM_V185 /* Part 2 v1.85 Sec.8.3.2 Table 36 bits 8 and 9: firmwareLimited / * svnLimited mark keys whose lifetime is bound to the firmware