Merge pull request #551 from aidangarske/fenrir-fixes-6839-6850

Harden crypto callback, ASN.1 parsing, param-enc and marshalling; add negative tests
pull/552/head
Eric Blankenhorn 2026-07-13 16:48:00 -05:00 committed by GitHub
commit 7d02b58e4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 537 additions and 9 deletions

View File

@ -2592,6 +2592,7 @@ TPM_RC FwDecryptSeed(FWTPM_CTX* ctx,
encSeedBuf, encSeedSz, &sharedK);
}
if (rc == 0) {
/* K is 32-byte ML-KEM secret per FIPS 203 (Part 1 47.4 errata) */
int kdfRc = TPM2_KDFa_ex(nameAlg,
sharedK.buffer, sharedK.size, kdfLabel,
encSeedBuf, (UINT32)encSeedSz,
@ -2845,6 +2846,7 @@ TPM_RC FwEncryptSeed(FWTPM_CTX* ctx,
rc = TPM_RC_SIZE;
}
if (rc == 0) {
/* K is 32-byte ML-KEM secret per FIPS 203 (Part 1 47.4 errata) */
int kdfRc = TPM2_KDFa_ex(nameAlg,
sharedK.buffer, sharedK.size, kdfLabel,
ciphertext->buffer, (UINT32)ciphertext->size,

View File

@ -352,6 +352,7 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
byte sigRS[MAX_ECC_BYTES*2];
byte *r = sigRS, *s = &sigRS[MAX_ECC_BYTES];
word32 rLen = MAX_ECC_BYTES, sLen = MAX_ECC_BYTES;
word32 keySz = 0;
XMEMSET(&eccPub, 0, sizeof(eccPub));
XMEMSET(sigRS, 0, sizeof(sigRS));
@ -359,13 +360,20 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
/* Decode ECDSA Header */
rc = wc_ecc_sig_to_rs(info->pk.eccverify.sig,
info->pk.eccverify.siglen, r, &rLen, s, &sLen);
if (rc == 0) {
/* R/S larger than key size underflows the pad offset */
keySz = wc_ecc_size(info->pk.eccverify.key);
if (keySz == 0 || keySz > MAX_ECC_BYTES ||
rLen > keySz || sLen > keySz) {
rc = exit_rc;
}
}
if (rc == 0) {
/* load public key into TPM */
rc = wolfTPM2_EccKey_WolfToTpm(tlsCtx->dev,
info->pk.eccverify.key, &eccPub);
if (rc == 0) {
/* combine R and S at key size (zero pad leading) */
word32 keySz = wc_ecc_size(info->pk.eccverify.key);
XMEMMOVE(&sigRS[keySz-rLen], r, rLen);
XMEMSET(&sigRS[0], 0, keySz-rLen);
XMEMMOVE(&sigRS[keySz + (keySz-sLen)], s, sLen);

View File

@ -740,8 +740,12 @@ void TPM2_Packet_ParseAsymScheme(TPM2_Packet* packet, TPMT_ASYM_SCHEME* scheme)
void TPM2_Packet_AppendEccPoint(TPM2_Packet* packet, TPMS_ECC_POINT* point)
{
if (point->x.size > sizeof(point->x.buffer))
point->x.size = sizeof(point->x.buffer);
TPM2_Packet_AppendU16(packet, point->x.size);
TPM2_Packet_AppendBytes(packet, point->x.buffer, point->x.size);
if (point->y.size > sizeof(point->y.buffer))
point->y.size = sizeof(point->y.buffer);
TPM2_Packet_AppendU16(packet, point->y.size);
TPM2_Packet_AppendBytes(packet, point->y.buffer, point->y.size);
}
@ -1157,6 +1161,8 @@ void TPM2_Packet_AppendPublicArea(TPM2_Packet* packet, TPMT_PUBLIC* publicArea)
TPM2_Packet_AppendU16(packet, publicArea->type);
TPM2_Packet_AppendU16(packet, publicArea->nameAlg);
TPM2_Packet_AppendU32(packet, publicArea->objectAttributes);
if (publicArea->authPolicy.size > sizeof(publicArea->authPolicy.buffer))
publicArea->authPolicy.size = sizeof(publicArea->authPolicy.buffer);
TPM2_Packet_AppendU16(packet, publicArea->authPolicy.size);
TPM2_Packet_AppendBytes(packet, publicArea->authPolicy.buffer,
publicArea->authPolicy.size);
@ -1166,16 +1172,28 @@ void TPM2_Packet_AppendPublicArea(TPM2_Packet* packet, TPMT_PUBLIC* publicArea)
switch (publicArea->type) {
case TPM_ALG_KEYEDHASH:
if (publicArea->unique.keyedHash.size >
sizeof(publicArea->unique.keyedHash.buffer))
publicArea->unique.keyedHash.size =
sizeof(publicArea->unique.keyedHash.buffer);
TPM2_Packet_AppendU16(packet, publicArea->unique.keyedHash.size);
TPM2_Packet_AppendBytes(packet, publicArea->unique.keyedHash.buffer,
publicArea->unique.keyedHash.size);
break;
case TPM_ALG_SYMCIPHER:
if (publicArea->unique.sym.size >
sizeof(publicArea->unique.sym.buffer))
publicArea->unique.sym.size =
sizeof(publicArea->unique.sym.buffer);
TPM2_Packet_AppendU16(packet, publicArea->unique.sym.size);
TPM2_Packet_AppendBytes(packet, publicArea->unique.sym.buffer,
publicArea->unique.sym.size);
break;
case TPM_ALG_RSA:
if (publicArea->unique.rsa.size >
sizeof(publicArea->unique.rsa.buffer))
publicArea->unique.rsa.size =
sizeof(publicArea->unique.rsa.buffer);
TPM2_Packet_AppendU16(packet, publicArea->unique.rsa.size);
TPM2_Packet_AppendBytes(packet, publicArea->unique.rsa.buffer,
publicArea->unique.rsa.size);
@ -1186,6 +1204,10 @@ void TPM2_Packet_AppendPublicArea(TPM2_Packet* packet, TPMT_PUBLIC* publicArea)
#ifdef WOLFTPM_MLDSA
case TPM_ALG_MLDSA:
case TPM_ALG_HASH_MLDSA:
if (publicArea->unique.mldsa.size >
sizeof(publicArea->unique.mldsa.buffer))
publicArea->unique.mldsa.size =
sizeof(publicArea->unique.mldsa.buffer);
TPM2_Packet_AppendU16(packet, publicArea->unique.mldsa.size);
TPM2_Packet_AppendBytes(packet, publicArea->unique.mldsa.buffer,
publicArea->unique.mldsa.size);
@ -1193,6 +1215,10 @@ void TPM2_Packet_AppendPublicArea(TPM2_Packet* packet, TPMT_PUBLIC* publicArea)
#endif /* WOLFTPM_MLDSA */
#ifdef WOLFTPM_MLKEM
case TPM_ALG_MLKEM:
if (publicArea->unique.mlkem.size >
sizeof(publicArea->unique.mlkem.buffer))
publicArea->unique.mlkem.size =
sizeof(publicArea->unique.mlkem.buffer);
TPM2_Packet_AppendU16(packet, publicArea->unique.mlkem.size);
TPM2_Packet_AppendBytes(packet, publicArea->unique.mlkem.buffer,
publicArea->unique.mlkem.size);

View File

@ -57,13 +57,6 @@
/* --- Param Enc/Dec Functions -- */
/******************************************************************************/
/* Maximum XOR mask size. RSA-2048 inSensitive parameter blobs on Create can
* exceed MAX_DIGEST_BUFFER (1024), so leave headroom to ~1250 bytes. Keep
* stack usage bounded by switching to heap under WOLFTPM_SMALL_STACK. */
#ifndef TPM2_XOR_MASK_MAX
#define TPM2_XOR_MASK_MAX 1280
#endif
/* XOR parameter encryption/decryption (shared by client and fwTPM).
* XOR is symmetric so encrypt and decrypt are the same operation.
* nonceA/nonceB order determines direction (caller/TPM or TPM/caller). */
@ -389,6 +382,7 @@ int TPM2_CalcCpHash(TPMI_ALG_HASH authHash, TPM_CC cmdCode,
rc = wc_HashFinal(&hash_ctx, hashType, hash->buffer);
wc_HashFree(&hash_ctx, hashType);
TPM2_ForceZero(&hash_ctx, sizeof(hash_ctx));
}
#ifdef WOLFTPM_DEBUG_VERBOSE
@ -435,6 +429,7 @@ int TPM2_CalcRpHash(TPMI_ALG_HASH authHash,
rc = wc_HashFinal(&hash_ctx, hashType, hash->buffer);
wc_HashFree(&hash_ctx, hashType);
TPM2_ForceZero(&hash_ctx, sizeof(hash_ctx));
}
#ifdef WOLFTPM_DEBUG_VERBOSE

View File

@ -1987,6 +1987,41 @@ static void test_TPM2_ParamEnc_XOR_Vector(void)
#endif
}
static void test_TPM2_ParamEnc_XOR_MaskBoundary(void)
{
#ifndef WOLFTPM2_NO_WOLFCRYPT
int rc;
TPMI_ALG_HASH authHash = TPM_ALG_SHA256;
TPM2B_AUTH sessKey;
TPM2B_NONCE nonceCaller, nonceTPM;
byte data[TPM2_XOR_MASK_MAX + 1];
sessKey.size = TPM_SHA256_DIGEST_SIZE;
XMEMSET(sessKey.buffer, 0xCC, sessKey.size);
nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
XMEMSET(nonceCaller.buffer, 0x11, nonceCaller.size);
nonceTPM.size = TPM_SHA256_DIGEST_SIZE;
XMEMSET(nonceTPM.buffer, 0x22, nonceTPM.size);
XMEMSET(data, 0, sizeof(data));
/* exactly at capacity must succeed */
rc = TPM2_ParamEnc_XOR(authHash, sessKey.buffer, sessKey.size,
nonceCaller.buffer, nonceCaller.size,
nonceTPM.buffer, nonceTPM.size,
data, TPM2_XOR_MASK_MAX);
AssertIntEQ(TPM_RC_SUCCESS, rc);
/* one byte past capacity must be rejected */
rc = TPM2_ParamEnc_XOR(authHash, sessKey.buffer, sessKey.size,
nonceCaller.buffer, nonceCaller.size,
nonceTPM.buffer, nonceTPM.size,
data, TPM2_XOR_MASK_MAX + 1);
AssertIntEQ(BUFFER_E, rc);
printf("Test TPM Wrapper: %-40s Passed\n", "ParamEnc_XOR mask boundary:");
#endif
}
static void test_TPM2_ParamEnc_AESCFB_Vector(void)
{
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFSSL_AES_CFB)
@ -2034,6 +2069,35 @@ static void test_TPM2_ParamEnc_AESCFB_Vector(void)
#endif
}
static void test_TPM2_ParamEnc_AESCFB_KeyBoundary(void)
{
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFSSL_AES_CFB)
int rc;
TPMI_ALG_HASH authHash = TPM_ALG_SHA256;
TPM2B_AUTH sessKey;
TPM2B_NONCE nonceCaller, nonceTPM;
byte data[32];
sessKey.size = TPM_SHA256_DIGEST_SIZE;
XMEMSET(sessKey.buffer, 0xDD, sessKey.size);
nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
XMEMSET(nonceCaller.buffer, 0x33, nonceCaller.size);
nonceTPM.size = TPM_SHA256_DIGEST_SIZE;
XMEMSET(nonceTPM.buffer, 0x44, nonceTPM.size);
XMEMSET(data, 0, sizeof(data));
/* keyBits above 256 (symKeySz > 32) must be rejected, not overflow symKey */
rc = TPM2_ParamEnc_AESCFB(authHash, 512,
sessKey.buffer, sessKey.size,
nonceCaller.buffer, nonceCaller.size,
nonceTPM.buffer, nonceTPM.size,
data, sizeof(data), 1);
AssertIntEQ(BUFFER_E, rc);
printf("Test TPM Wrapper: %-40s Passed\n", "ParamEnc_AESCFB key boundary:");
#endif
}
/* Known-answer test cross-checking TPM2_ParamEnc_AESCFB against an
* independent KDFa + AES-CFB reference built from wolfCrypt primitives.
* The pure round-trip test above cannot detect mutations that affect
@ -3179,6 +3243,82 @@ static void test_TPM2_ResponseProcess_ParamSizeOverflow(void)
printf("Test TPM Wrapper:\tResponseProcess paramSize overflow:\tPassed\n");
}
static void test_TPM2_ResponseProcess_HmacVerify(void)
{
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_HMAC)
TPM2_CTX ctx;
TPM2_AUTH_SESSION session[1];
TPM2_Packet packet;
CmdInfo_t info;
TPM2B_DIGEST rpHash;
TPM2B_AUTH expHmac;
TPM2B_NONCE nonceTPM;
byte buf[128];
int rc, i;
TPM_CC cmdCode = 0x17F;
UINT16 hmacSz = 32, nonceSz = 32;
UINT32 paramSz = 4;
UINT32 pos, hmacOff, respSz;
byte attr = 0x01;
XMEMSET(&ctx, 0, sizeof(ctx));
XMEMSET(session, 0, sizeof(session));
XMEMSET(&info, 0, sizeof(info));
XMEMSET(buf, 0, sizeof(buf));
/* HMAC session with a known auth value and nonces */
session[0].sessionHandle = HMAC_SESSION_FIRST;
session[0].authHash = TPM_ALG_SHA256;
session[0].auth.size = 4;
XMEMSET(session[0].auth.buffer, 0xA5, 4);
session[0].nonceCaller.size = 32;
XMEMSET(session[0].nonceCaller.buffer, 0x5C, 32);
session[0].nonceTPM.size = 32;
XMEMSET(session[0].nonceTPM.buffer, 0xC5, 32);
ctx.session = session;
info.authCnt = 1;
/* header + paramSize(U32) + params + auth area (nonce, attr, hmac) */
pos = TPM2_HEADER_SIZE;
buf[pos++] = 0; buf[pos++] = 0; buf[pos++] = 0; buf[pos++] = (byte)paramSz;
buf[pos++] = 0xDE; buf[pos++] = 0xAD; buf[pos++] = 0xBE; buf[pos++] = 0xEF;
buf[pos++] = (byte)(nonceSz >> 8); buf[pos++] = (byte)(nonceSz & 0xFF);
for (i = 0; i < nonceSz; i++)
buf[pos++] = 0x99; /* response nonceTPM */
buf[pos++] = attr; /* sessionAttributes */
buf[pos++] = (byte)(hmacSz >> 8); buf[pos++] = (byte)(hmacSz & 0xFF);
hmacOff = pos;
pos += hmacSz;
respSz = pos;
/* expected HMAC uses the response nonce as nonceTPM */
nonceTPM.size = nonceSz;
XMEMSET(nonceTPM.buffer, 0x99, nonceSz);
rc = TPM2_CalcRpHash(TPM_ALG_SHA256, cmdCode, &buf[TPM2_HEADER_SIZE + 4],
paramSz, &rpHash);
AssertIntEQ(rc, TPM_RC_SUCCESS);
XMEMSET(&expHmac, 0, sizeof(expHmac));
rc = TPM2_CalcHmac(TPM_ALG_SHA256, &session[0].auth, &rpHash,
&nonceTPM, &session[0].nonceCaller, attr, &expHmac);
AssertIntEQ(rc, TPM_RC_SUCCESS);
XMEMCPY(&buf[hmacOff], expHmac.buffer, hmacSz);
/* untampered response HMAC must verify and update nonceTPM */
packet.buf = buf; packet.pos = 0; packet.size = (int)respSz;
rc = TPM2_ResponseProcess(&ctx, &packet, &info, cmdCode, respSz);
AssertIntEQ(rc, TPM_RC_SUCCESS);
AssertIntEQ(session[0].nonceTPM.buffer[0], 0x99);
/* flipping one HMAC byte must be detected */
buf[hmacOff] ^= 0xFF;
packet.buf = buf; packet.pos = 0; packet.size = (int)respSz;
rc = TPM2_ResponseProcess(&ctx, &packet, &info, cmdCode, respSz);
AssertIntEQ(rc, TPM_RC_HMAC);
printf("Test TPM Wrapper:\tResponseProcess HMAC verify:\tPassed\n");
#endif
}
/* wolfTPM2_NVCreateAuthPolicy must derive nameAlg from authPolicySz so
* the policy digest hash matches the index's nameAlg. Bug-mode hardcoded
* SHA-256 nameAlg, which made SHA-384/SHA-512 policies unsatisfiable.
@ -3626,6 +3766,111 @@ static void test_TPM2_Signature_EcSchnorrSm2Serialize(void)
"Signature ECSCHNORR/SM2 serialize:");
}
static void test_TPM2_Public_RsaEcc_Roundtrip(void)
{
#if !defined(WOLFTPM2_NO_WOLFCRYPT)
int rc, sz;
byte buf[sizeof(TPM2B_PUBLIC)];
TPM2B_PUBLIC pubIn, pubOut;
const byte uniqueBytes[8] = {
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22
};
/* RSA with AES-128-CFB symmetric wrapper (exercises the AES mode field)
* and an RSASSA-SHA256 scheme */
XMEMSET(&pubIn, 0, sizeof(pubIn));
pubIn.publicArea.type = TPM_ALG_RSA;
pubIn.publicArea.nameAlg = TPM_ALG_SHA256;
pubIn.publicArea.objectAttributes = TPMA_OBJECT_sign;
pubIn.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
pubIn.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
pubIn.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
pubIn.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_RSASSA;
pubIn.publicArea.parameters.rsaDetail.scheme.details.rsassa.hashAlg =
TPM_ALG_SHA256;
pubIn.publicArea.parameters.rsaDetail.keyBits = 2048;
pubIn.publicArea.parameters.rsaDetail.exponent = 0x10001;
pubIn.publicArea.unique.rsa.size = sizeof(uniqueBytes);
XMEMCPY(pubIn.publicArea.unique.rsa.buffer, uniqueBytes,
sizeof(uniqueBytes));
XMEMSET(buf, 0, sizeof(buf));
sz = 0;
rc = TPM2_AppendPublic(buf, (word32)sizeof(buf), &sz, &pubIn);
AssertIntEQ(rc, TPM_RC_SUCCESS);
AssertIntGT(sz, 0);
XMEMSET(&pubOut, 0, sizeof(pubOut));
rc = TPM2_ParsePublic(&pubOut, buf, (word32)sz, &sz);
AssertIntEQ(rc, TPM_RC_SUCCESS);
AssertIntEQ(pubOut.publicArea.type, TPM_ALG_RSA);
AssertIntEQ(pubOut.publicArea.nameAlg, TPM_ALG_SHA256);
AssertIntEQ(pubOut.publicArea.parameters.rsaDetail.symmetric.algorithm,
TPM_ALG_AES);
AssertIntEQ(pubOut.publicArea.parameters.rsaDetail.symmetric.keyBits.aes,
128);
AssertIntEQ(pubOut.publicArea.parameters.rsaDetail.symmetric.mode.aes,
TPM_ALG_CFB);
AssertIntEQ(pubOut.publicArea.parameters.rsaDetail.scheme.scheme,
TPM_ALG_RSASSA);
AssertIntEQ(
pubOut.publicArea.parameters.rsaDetail.scheme.details.rsassa.hashAlg,
TPM_ALG_SHA256);
AssertIntEQ(pubOut.publicArea.parameters.rsaDetail.keyBits, 2048);
AssertIntEQ((int)pubOut.publicArea.parameters.rsaDetail.exponent, 0x10001);
AssertIntEQ(pubOut.publicArea.unique.rsa.size, sizeof(uniqueBytes));
AssertIntEQ(XMEMCMP(pubOut.publicArea.unique.rsa.buffer, uniqueBytes,
sizeof(uniqueBytes)), 0);
/* ECC P-256 with ECDSA-SHA256 scheme and NULL symmetric/kdf */
XMEMSET(&pubIn, 0, sizeof(pubIn));
pubIn.publicArea.type = TPM_ALG_ECC;
pubIn.publicArea.nameAlg = TPM_ALG_SHA256;
pubIn.publicArea.objectAttributes = TPMA_OBJECT_sign;
pubIn.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
pubIn.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_ECDSA;
pubIn.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg =
TPM_ALG_SHA256;
pubIn.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
pubIn.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
pubIn.publicArea.unique.ecc.x.size = sizeof(uniqueBytes);
XMEMCPY(pubIn.publicArea.unique.ecc.x.buffer, uniqueBytes,
sizeof(uniqueBytes));
pubIn.publicArea.unique.ecc.y.size = sizeof(uniqueBytes);
XMEMCPY(pubIn.publicArea.unique.ecc.y.buffer, uniqueBytes,
sizeof(uniqueBytes));
XMEMSET(buf, 0, sizeof(buf));
sz = 0;
rc = TPM2_AppendPublic(buf, (word32)sizeof(buf), &sz, &pubIn);
AssertIntEQ(rc, TPM_RC_SUCCESS);
XMEMSET(&pubOut, 0, sizeof(pubOut));
rc = TPM2_ParsePublic(&pubOut, buf, (word32)sz, &sz);
AssertIntEQ(rc, TPM_RC_SUCCESS);
AssertIntEQ(pubOut.publicArea.type, TPM_ALG_ECC);
AssertIntEQ(pubOut.publicArea.parameters.eccDetail.symmetric.algorithm,
TPM_ALG_NULL);
AssertIntEQ(pubOut.publicArea.parameters.eccDetail.scheme.scheme,
TPM_ALG_ECDSA);
AssertIntEQ(
pubOut.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg,
TPM_ALG_SHA256);
AssertIntEQ(pubOut.publicArea.parameters.eccDetail.curveID,
TPM_ECC_NIST_P256);
AssertIntEQ(pubOut.publicArea.parameters.eccDetail.kdf.scheme,
TPM_ALG_NULL);
AssertIntEQ(pubOut.publicArea.unique.ecc.x.size, sizeof(uniqueBytes));
AssertIntEQ(XMEMCMP(pubOut.publicArea.unique.ecc.x.buffer, uniqueBytes,
sizeof(uniqueBytes)), 0);
AssertIntEQ(pubOut.publicArea.unique.ecc.y.size, sizeof(uniqueBytes));
AssertIntEQ(XMEMCMP(pubOut.publicArea.unique.ecc.y.buffer, uniqueBytes,
sizeof(uniqueBytes)), 0);
printf("Test TPM Wrapper: %-40s Passed\n", "Public RSA/ECC roundtrip:");
#endif
}
#ifdef WOLFTPM_PQC
/* Round-trip the v1.85 PQC arms of TPMT_SIGNATURE through the packet
* marshaler. Pure ML-DSA (Table 217 mldsa arm) is bare TPM2B + bytes
@ -4105,6 +4350,100 @@ static void test_TPM2_AppendSensitive_Clamp(void)
printf("Test TPM2: %-40s Passed\n", "AppendSensitive clamp:");
}
static void test_TPM2_AppendPublic_Clamp(void)
{
TPM2_Packet packet;
byte buf[sizeof(TPM2B_PUBLIC)];
TPM2B_PUBLIC pub;
word16 policyCap, rsaCap, eccCap, khCap, symCap;
#ifdef WOLFTPM_MLDSA
word16 mldsaCap;
#endif
#ifdef WOLFTPM_MLKEM
word16 mlkemCap;
#endif
policyCap = (word16)sizeof(pub.publicArea.authPolicy.buffer);
rsaCap = (word16)sizeof(pub.publicArea.unique.rsa.buffer);
eccCap = (word16)sizeof(pub.publicArea.unique.ecc.x.buffer);
khCap = (word16)sizeof(pub.publicArea.unique.keyedHash.buffer);
symCap = (word16)sizeof(pub.publicArea.unique.sym.buffer);
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_RSA;
pub.publicArea.nameAlg = TPM_ALG_SHA256;
pub.publicArea.authPolicy.size = policyCap + 100;
pub.publicArea.unique.rsa.size = rsaCap + 100;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendPublic(&packet, &pub);
AssertIntEQ(pub.publicArea.authPolicy.size, policyCap);
AssertIntEQ(pub.publicArea.unique.rsa.size, rsaCap);
/* ECC point x/y sizes must clamp on append too */
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_ECC;
pub.publicArea.nameAlg = TPM_ALG_SHA256;
pub.publicArea.unique.ecc.x.size = eccCap + 100;
pub.publicArea.unique.ecc.y.size = eccCap + 100;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendPublic(&packet, &pub);
AssertIntEQ(pub.publicArea.unique.ecc.x.size, eccCap);
AssertIntEQ(pub.publicArea.unique.ecc.y.size, eccCap);
/* keyedHash unique size must clamp */
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_KEYEDHASH;
pub.publicArea.nameAlg = TPM_ALG_SHA256;
pub.publicArea.unique.keyedHash.size = khCap + 100;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendPublic(&packet, &pub);
AssertIntEQ(pub.publicArea.unique.keyedHash.size, khCap);
/* symcipher unique size must clamp */
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_SYMCIPHER;
pub.publicArea.nameAlg = TPM_ALG_SHA256;
pub.publicArea.unique.sym.size = symCap + 100;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendPublic(&packet, &pub);
AssertIntEQ(pub.publicArea.unique.sym.size, symCap);
#ifdef WOLFTPM_MLDSA
mldsaCap = (word16)sizeof(pub.publicArea.unique.mldsa.buffer);
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_MLDSA;
pub.publicArea.nameAlg = TPM_ALG_SHA256;
pub.publicArea.unique.mldsa.size = mldsaCap + 100;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendPublic(&packet, &pub);
AssertIntEQ(pub.publicArea.unique.mldsa.size, mldsaCap);
#endif
#ifdef WOLFTPM_MLKEM
mlkemCap = (word16)sizeof(pub.publicArea.unique.mlkem.buffer);
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_MLKEM;
pub.publicArea.nameAlg = TPM_ALG_SHA256;
pub.publicArea.unique.mlkem.size = mlkemCap + 100;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendPublic(&packet, &pub);
AssertIntEQ(pub.publicArea.unique.mlkem.size, mlkemCap);
#endif
printf("Test TPM2: %-40s Passed\n", "AppendPublic clamp:");
}
/* Roundtrip a maximum-size inner payload (size == buffer capacity) so the
* parse-side ParseU16Buf clamp branch is exercised with valid data. */
static void test_TPM2_Sensitive_MaxRoundtrip(void)
@ -4260,6 +4599,149 @@ static void test_wolfTPM2_CSR(void)
#endif
}
static void test_wolfTPM2_CryptoDevCb_EccVerifyOversizedRS(void)
{
#if !defined(WOLFTPM2_NO_WRAPPER) && defined(WOLFTPM_CRYPTOCB) && \
!defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
defined(HAVE_ECC_VERIFY) && !defined(WC_NO_RNG) && (MAX_ECC_BYTES > 32)
int rc;
int i;
int c, rLen, sLen;
int verifyRes = 0;
WOLFTPM2_DEV dev;
TpmCryptoDevCtx tpmCtx;
wc_CryptoInfo info;
ecc_key key;
byte digest[32];
byte sig[128];
word32 sigSz;
XMEMSET(digest, 0x33, sizeof(digest));
XMEMSET(&tpmCtx, 0, sizeof(tpmCtx));
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
AssertIntEQ(rc, 0);
tpmCtx.dev = &dev;
rc = wc_ecc_init(&key);
AssertIntEQ(rc, 0);
rc = wc_ecc_make_key_ex(wolfTPM2_GetRng(&dev), 32, &key, ECC_SECP256R1);
AssertIntEQ(rc, 0);
/* c==0 drives the oversized-R guard, c==1 the oversized-S guard; both
* exceed the P-256 key size and must fall back before the TPM key load */
for (c = 0; c < 2; c++) {
rLen = (c == 0) ? 40 : 32;
sLen = (c == 0) ? 32 : 40;
sigSz = 0;
sig[sigSz++] = 0x30;
sig[sigSz++] = (byte)(2 + rLen + 2 + sLen);
sig[sigSz++] = 0x02;
sig[sigSz++] = (byte)rLen;
for (i = 0; i < rLen; i++)
sig[sigSz++] = 0x11;
sig[sigSz++] = 0x02;
sig[sigSz++] = (byte)sLen;
for (i = 0; i < sLen; i++)
sig[sigSz++] = 0x22;
XMEMSET(&info, 0, sizeof(info));
info.algo_type = WC_ALGO_TYPE_PK;
info.pk.type = WC_PK_TYPE_ECDSA_VERIFY;
info.pk.eccverify.sig = sig;
info.pk.eccverify.siglen = sigSz;
info.pk.eccverify.hash = digest;
info.pk.eccverify.hashlen = (word32)sizeof(digest);
info.pk.eccverify.res = &verifyRes;
info.pk.eccverify.key = &key;
rc = wolfTPM2_CryptoDevCb(INVALID_DEVID, &info, &tpmCtx);
AssertIntEQ(rc, CRYPTOCB_UNAVAILABLE);
}
wc_ecc_free(&key);
wolfTPM2_Cleanup(&dev);
printf("Test TPM Wrapper: %-40s Passed\n", "CryptoDevCb ECC oversized R/S:");
#endif
}
static void test_TPM2_ASN_DecodeX509Cert_Errors(void)
{
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_ASN)
int rc;
DecodedX509 x509;
byte garbage[16];
byte trunc[4];
XMEMSET(&x509, 0, sizeof(x509));
XMEMSET(garbage, 0xFF, sizeof(garbage));
/* NULL arguments must be rejected, not dereferenced */
rc = TPM2_ASN_DecodeX509Cert(NULL, 0, &x509);
AssertIntNE(rc, 0);
rc = TPM2_ASN_DecodeX509Cert(garbage, (int)sizeof(garbage), NULL);
AssertIntNE(rc, 0);
/* malformed input must not report success */
rc = TPM2_ASN_DecodeX509Cert(garbage, (int)sizeof(garbage), &x509);
AssertIntNE(rc, 0);
/* outer SEQUENCE whose length runs past the buffer (TPM_RC_INSUFFICIENT) */
trunc[0] = 0x30; trunc[1] = 0x20; trunc[2] = 0x00; trunc[3] = 0x00;
rc = TPM2_ASN_DecodeX509Cert(trunc, (int)sizeof(trunc), &x509);
AssertIntNE(rc, 0);
printf("Test TPM Wrapper: %-40s Passed\n", "ASN DecodeX509Cert errors:");
#endif
}
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_ASN)
#include <examples/endorsement/trusted_certs_der.h>
#endif
static void test_TPM2_ASN_DecodeX509Cert_Valid(void)
{
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_ASN)
int rc;
DecodedX509 x509;
/* a well-formed DER certificate must decode and populate the fields */
XMEMSET(&x509, 0, sizeof(x509));
rc = TPM2_ASN_DecodeX509Cert((uint8_t*)kSTSAFEIntCa20,
(int)sizeof(kSTSAFEIntCa20), &x509);
AssertIntEQ(rc, TPM_RC_SUCCESS);
AssertIntGT(x509.certSz, 0);
AssertNotNull(x509.publicKey);
AssertIntGT(x509.pubKeySz, 0);
AssertNotNull(x509.signature);
AssertIntGT(x509.sigSz, 0);
printf("Test TPM Wrapper: %-40s Passed\n", "ASN DecodeX509Cert valid:");
#endif
}
static void test_TPM2_ASN_DecodeTag_Errors(void)
{
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_ASN)
int rc, idx, tagLen;
byte buf[4];
buf[0] = 0x30; buf[1] = 0x02; buf[2] = 0x00; buf[3] = 0x00;
idx = 0;
rc = TPM2_ASN_DecodeTag(buf, (int)sizeof(buf), &idx, &tagLen, 0x30);
AssertIntEQ(rc, 0);
/* wrong expected tag must be reported, not accepted as success */
idx = 0;
rc = TPM2_ASN_DecodeTag(buf, (int)sizeof(buf), &idx, &tagLen, 0x02);
AssertIntNE(rc, 0);
printf("Test TPM Wrapper: %-40s Passed\n", "ASN DecodeTag tag mismatch:");
#endif
}
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
!defined(WOLFTPM2_NO_ASN)
#define FLAGS_USE_WOLFCRYPT (1 << 0)
@ -6368,7 +6850,9 @@ int unit_tests(int argc, char *argv[])
test_TPM2_ResponseHmacVerification();
test_TPM2_CalcHmac();
test_TPM2_ParamEnc_XOR_Vector();
test_TPM2_ParamEnc_XOR_MaskBoundary();
test_TPM2_ParamEnc_AESCFB_Vector();
test_TPM2_ParamEnc_AESCFB_KeyBoundary();
test_TPM2_ParamEnc_AESCFB_KAT();
test_TPM2_ParamDec_XOR_Roundtrip();
test_TPM2_ParamDec_AESCFB_Roundtrip();
@ -6395,6 +6879,7 @@ int unit_tests(int argc, char *argv[])
test_TPM2_Packet_RetryRestore();
#endif
test_TPM2_ResponseProcess_ParamSizeOverflow();
test_TPM2_ResponseProcess_HmacVerify();
test_wolfTPM2_NVCreateAuthPolicy_NameAlg();
test_wolfTPM2_GetKeyTemplate_KeyedHash_Scheme();
#if defined(WOLFTPM_MFG_IDENTITY) && \
@ -6407,6 +6892,7 @@ int unit_tests(int argc, char *argv[])
test_wolfTPM2_LoadEccPublicKey_Ex();
test_TPM2_KeyedHashScheme_XorSerialize();
test_TPM2_Signature_EcSchnorrSm2Serialize();
test_TPM2_Public_RsaEcc_Roundtrip();
#ifdef WOLFTPM_PQC
test_TPM2_Signature_PQC_Serialize();
test_TPM2_Public_PQC_Roundtrip();
@ -6415,12 +6901,17 @@ int unit_tests(int argc, char *argv[])
test_TPM2_TIS_ValidateRspSz();
test_TPM2_ParsePublic_EmptyClears();
test_TPM2_AppendSensitive_Clamp();
test_TPM2_AppendPublic_Clamp();
test_TPM2_Sensitive_MaxRoundtrip();
test_KeySealTemplate();
test_SealAndKeyedHash_Boundaries();
test_GetAlgId();
test_wolfTPM2_ReadPublicKey();
test_wolfTPM2_CSR();
test_wolfTPM2_CryptoDevCb_EccVerifyOversizedRS();
test_TPM2_ASN_DecodeX509Cert_Errors();
test_TPM2_ASN_DecodeX509Cert_Valid();
test_TPM2_ASN_DecodeTag_Errors();
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFTPM2_PEM_DECODE) && \
!defined(NO_RSA)
test_wolfTPM_ImportPublicKey();

View File

@ -30,6 +30,12 @@
extern "C" {
#endif
/* Maximum XOR mask size. RSA-2048 inSensitive parameter blobs on Create can
* exceed MAX_DIGEST_BUFFER (1024), so leave headroom to ~1250 bytes. */
#ifndef TPM2_XOR_MASK_MAX
#define TPM2_XOR_MASK_MAX 1280
#endif
/* XOR parameter encryption/decryption (raw pointer interface).
* XOR is symmetric so encrypt and decrypt are the same operation. */
WOLFTPM_TEST_API int TPM2_ParamEnc_XOR(
@ -54,7 +60,7 @@ WOLFTPM_TEST_API int TPM2_CalcHmac(TPMI_ALG_HASH authHash, TPM2B_AUTH* auth,
const TPM2B_DIGEST* hash, const TPM2B_NONCE* nonceNew,
const TPM2B_NONCE* nonceOld, TPMA_SESSION sessionAttributes,
TPM2B_AUTH* hmac);
WOLFTPM_LOCAL int TPM2_CalcRpHash(TPMI_ALG_HASH authHash,
WOLFTPM_TEST_API int TPM2_CalcRpHash(TPMI_ALG_HASH authHash,
TPM_CC cmdCode, BYTE* param, UINT32 paramSz, TPM2B_DIGEST* hash);
WOLFTPM_LOCAL int TPM2_CalcCpHash(TPMI_ALG_HASH authHash, TPM_CC cmdCode,
TPM2B_NAME* name1, TPM2B_NAME* name2, TPM2B_NAME* name3,