Merge pull request #597 from aidangarske/tpm2-core-fixes-11899

Fix TPM2 core parsing key import and response handling
pull/603/head
David Garske 2026-09-09 13:20:57 -07:00 committed by GitHub
commit ed48b8dd23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 95 additions and 20 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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