From 85b96e00d59a57a4b200c49c1a5a979dc678d1b9 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Mon, 20 Jul 2026 09:50:23 -0700 Subject: [PATCH 1/5] F-7011 - Route fwTPM PolicyPassword auth through fixed-length FwCtAuthCompare --- src/fwtpm/fwtpm_command.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index dfb07ede..1ce45eda 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -16735,17 +16735,13 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx, /* PolicyPassword with no sessionKey (unsalted/unbound): * HMAC field contains plaintext authValue per spec Section 19.6.13. - * Always run TPM2_ConstantCompare so timing doesn't leak auth - * length match. */ + * Use fixed-length FwCtAuthCompare so the compare trip count can't + * leak the auth value length (matches the TPM_RS_PW path). */ if (hSess->sessionType == TPM_SE_POLICY && hSess->isPasswordPolicy && hSess->sessionKey.size == 0) { - sizeMismatch = ((int)cmdAuths[hj].cmdHmacSize != authValSz); - cmpSz = (cmdAuths[hj].cmdHmacSize < (UINT16)authValSz) ? - cmdAuths[hj].cmdHmacSize : (word32)authValSz; - hmacDiff = TPM2_ConstantCompare(cmdAuths[hj].cmdHmac, - authVal, cmpSz); - if (sizeMismatch | hmacDiff) { + if (FwCtAuthCompare(cmdAuths[hj].cmdHmac, + (int)cmdAuths[hj].cmdHmacSize, authVal, authValSz)) { #ifdef DEBUG_WOLFTPM printf("fwTPM: PolicyPassword auth failed for handle " "0x%x (CC=0x%x)\n", entityH, cmdCode); From 5d826bf825fb5498e3f6c83377471e5f8ebde53f Mon Sep 17 00:00:00 2001 From: aidan garske Date: Mon, 20 Jul 2026 09:50:23 -0700 Subject: [PATCH 2/5] F-7020 - Zeroize local primary-key auth copy in wolfTPM2_CreatePrimaryKey --- src/tpm2_wrap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 9e349dd3..d6e17961 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -2833,6 +2833,8 @@ int wolfTPM2_CreatePrimaryKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, XMEMCPY(&key->handle, &pKey.handle, sizeof(WOLFTPM2_HANDLE)); XMEMCPY(&key->pub, &pKey.pub, sizeof(TPM2B_PUBLIC)); } + /* scrub the duplicated primary-key auth from the local copy */ + TPM2_ForceZero(&pKey, sizeof(pKey)); return rc; } From 493e3359c79cf06be455de23fa0f6aaa71e6f662 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Mon, 20 Jul 2026 09:50:45 -0700 Subject: [PATCH 3/5] F-7014 - Bound decrypt-parameter size in TPM2_ResponseProcess against OOB write --- src/tpm2.c | 17 +++++++++++- tests/unit_tests.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/tpm2.c b/src/tpm2.c index 734a97ec..52845bc0 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -314,20 +314,35 @@ int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet, param = &packet->buf[packet->pos]; /* Mark parameter data */ authPos = packet->pos + paramSz; - /* Mark "first" decryption parameter */ + /* Mark "first" decryption parameter. Reject a parameter area too small to + * hold the size prefix before parsing it, so a truncated response returns + * TPM_RC_SIZE without reading past the declared parameter area. */ if (info->flags & CMD_FLAG_DEC2) { UINT16 tempSz; + if (paramSz < sizeof(UINT16)) + return TPM_RC_SIZE; TPM2_Packet_ParseU16(packet, &tempSz); decParam = param + sizeof(UINT16); decParamSz = tempSz; } else if (info->flags & CMD_FLAG_DEC4) { UINT32 tempSz; + if (paramSz < sizeof(UINT32)) + return TPM_RC_SIZE; TPM2_Packet_ParseU32(packet, &tempSz); decParam = param + sizeof(UINT32); decParamSz = tempSz; } + /* Bound the decrypt region to the parameter area so a malicious or faulty + * TPM cannot drive an out-of-bounds parameter decryption write */ + if (decParam != NULL) { + UINT32 decOffset = (UINT32)(decParam - param); + if (decParamSz > paramSz - decOffset) { + return TPM_RC_SIZE; + } + } + #ifdef WOLFTPM_DEBUG_VERBOSE printf("ResponseProcess: Handles (Out %d), RespSz %d, ParamSz %d, DecSz %d, AuthSz %d\n", info->outHandleCnt, (int)respSz, (int)paramSz, (int)decParamSz, (int)(respSz - authPos)); diff --git a/tests/unit_tests.c b/tests/unit_tests.c index ca40237d..7c9b1f9a 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -3243,6 +3243,74 @@ static void test_TPM2_ResponseProcess_ParamSizeOverflow(void) printf("Test TPM Wrapper:\tResponseProcess paramSize overflow:\tPassed\n"); } +static void test_TPM2_ResponseProcess_DecParamSizeOverflow(void) +{ + TPM2_CTX ctx; + TPM2_AUTH_SESSION session[1]; + TPM2_Packet packet; + CmdInfo_t info; + byte buf[128]; + int rc; + + XMEMSET(&ctx, 0, sizeof(ctx)); + XMEMSET(session, 0, sizeof(session)); + XMEMSET(&info, 0, sizeof(info)); + ctx.session = session; + packet.buf = buf; + + /* DEC2: first-parameter size larger than the parameter area must be + * rejected before any decrypt (paramSz=4, decParamSz=0xFFFF) */ + XMEMSET(buf, 0, sizeof(buf)); + buf[TPM2_HEADER_SIZE + 3] = 0x04; + buf[TPM2_HEADER_SIZE + 4] = 0xFF; + buf[TPM2_HEADER_SIZE + 5] = 0xFF; + info.authCnt = 0; + info.flags = CMD_FLAG_DEC2; + packet.pos = 0; + packet.size = (int)sizeof(buf); + rc = TPM2_ResponseProcess(&ctx, &packet, &info, (TPM_CC)0, + (UINT32)sizeof(buf)); + AssertIntEQ(rc, TPM_RC_SIZE); + + /* DEC2: paramSz smaller than the size prefix (underflow guard, paramSz=1) */ + XMEMSET(buf, 0, sizeof(buf)); + buf[TPM2_HEADER_SIZE + 3] = 0x01; + info.flags = CMD_FLAG_DEC2; + packet.pos = 0; + packet.size = (int)sizeof(buf); + rc = TPM2_ResponseProcess(&ctx, &packet, &info, (TPM_CC)0, + (UINT32)sizeof(buf)); + AssertIntEQ(rc, TPM_RC_SIZE); + + /* DEC2: exact-fit first-parameter (decParamSz == paramSz - 2) is accepted */ + XMEMSET(buf, 0, sizeof(buf)); + buf[TPM2_HEADER_SIZE + 3] = 0x04; + buf[TPM2_HEADER_SIZE + 5] = 0x02; + info.flags = CMD_FLAG_DEC2; + packet.pos = 0; + packet.size = (int)sizeof(buf); + rc = TPM2_ResponseProcess(&ctx, &packet, &info, (TPM_CC)0, + (UINT32)sizeof(buf)); + AssertIntEQ(rc, TPM_RC_SUCCESS); + + /* DEC4: 32-bit first-parameter size overflow is likewise rejected + * (paramSz=8, decParamSz=0xFFFFFFFF) */ + XMEMSET(buf, 0, sizeof(buf)); + buf[TPM2_HEADER_SIZE + 3] = 0x08; + buf[TPM2_HEADER_SIZE + 4] = 0xFF; + buf[TPM2_HEADER_SIZE + 5] = 0xFF; + buf[TPM2_HEADER_SIZE + 6] = 0xFF; + buf[TPM2_HEADER_SIZE + 7] = 0xFF; + info.flags = CMD_FLAG_DEC4; + packet.pos = 0; + packet.size = (int)sizeof(buf); + rc = TPM2_ResponseProcess(&ctx, &packet, &info, (TPM_CC)0, + (UINT32)sizeof(buf)); + AssertIntEQ(rc, TPM_RC_SIZE); + + printf("Test TPM Wrapper:\tResponseProcess decParamSize overflow:\tPassed\n"); +} + static void test_TPM2_ResponseProcess_HmacVerify(void) { #if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_HMAC) @@ -6879,6 +6947,7 @@ int unit_tests(int argc, char *argv[]) test_TPM2_Packet_RetryRestore(); #endif test_TPM2_ResponseProcess_ParamSizeOverflow(); + test_TPM2_ResponseProcess_DecParamSizeOverflow(); test_TPM2_ResponseProcess_HmacVerify(); test_wolfTPM2_NVCreateAuthPolicy_NameAlg(); test_wolfTPM2_GetKeyTemplate_KeyedHash_Scheme(); From 09c8af0d4c9e88a535091f20d862a25538c28de7 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Mon, 20 Jul 2026 09:50:59 -0700 Subject: [PATCH 4/5] F-7017 - Cover import private-key TPM2B size guards at their boundary --- tests/unit_tests.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 7c9b1f9a..74820da9 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -5937,10 +5937,17 @@ static void test_wolfTPM2_ImportEccPrivateKeySeed_ErrorPaths(void) byte seed[1] = {0x42}; TPMA_OBJECT attrs = (TPMA_OBJECT_sign | TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA); + TPM2B_SENSITIVE sens; + byte big[MAX_ECC_KEY_BYTES]; + word32 capX, capY, capP; XMEMSET(eccPubX, 0x01, sizeof(eccPubX)); XMEMSET(eccPubY, 0x02, sizeof(eccPubY)); XMEMSET(eccPriv, 0x03, sizeof(eccPriv)); + XMEMSET(big, 0x05, sizeof(big)); + capX = (word32)sizeof(keyBlob.pub.publicArea.unique.ecc.x.buffer); + capY = (word32)sizeof(keyBlob.pub.publicArea.unique.ecc.y.buffer); + capP = (word32)sizeof(sens.sensitiveArea.sensitive.ecc.buffer); rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); AssertIntEQ(rc, 0); @@ -5953,12 +5960,78 @@ static void test_wolfTPM2_ImportEccPrivateKeySeed_ErrorPaths(void) eccPriv, sizeof(eccPriv), attrs, seed, sizeof(seed)); AssertIntEQ(rc, BAD_FUNC_ARG); + /* Each component one byte over its TPM2B capacity must return BUFFER_E */ + rc = wolfTPM2_ImportEccPrivateKeySeed(&dev, &parentKey, &keyBlob, + TPM_ECC_NIST_P256, big, capX + 1, big, capY, big, capP, + attrs, seed, sizeof(seed)); + AssertIntEQ(rc, BUFFER_E); + rc = wolfTPM2_ImportEccPrivateKeySeed(&dev, &parentKey, &keyBlob, + TPM_ECC_NIST_P256, big, capX, big, capY + 1, big, capP, + attrs, seed, sizeof(seed)); + AssertIntEQ(rc, BUFFER_E); + rc = wolfTPM2_ImportEccPrivateKeySeed(&dev, &parentKey, &keyBlob, + TPM_ECC_NIST_P256, big, capX, big, capY, big, capP + 1, + attrs, seed, sizeof(seed)); + AssertIntEQ(rc, BUFFER_E); + + /* Exact-fit components must clear the bounds check (fail later at the + * seed size check, not BUFFER_E) - pins '>' against '>=' and deletion */ + rc = wolfTPM2_ImportEccPrivateKeySeed(&dev, &parentKey, &keyBlob, + TPM_ECC_NIST_P256, big, capX, big, capY, big, capP, + attrs, seed, sizeof(seed)); + AssertIntNE(rc, BUFFER_E); + wolfTPM2_Cleanup(&dev); printf("Test TPM Wrapper:\tImportEccSeed error paths:\tPassed\n"); } #endif /* HAVE_ECC */ +#ifndef NO_RSA +static void test_wolfTPM2_ImportRsaPrivateKeySeed_ErrorPaths(void) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY parentKey; + WOLFTPM2_KEYBLOB keyBlob; + TPM2B_SENSITIVE sens; + byte big[MAX_RSA_KEY_BYTES]; + byte seed[1] = {0x42}; + word32 capPub, capPriv; + TPMA_OBJECT attrs = (TPMA_OBJECT_sign | TPMA_OBJECT_userWithAuth | + TPMA_OBJECT_noDA); + + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + AssertIntEQ(rc, 0); + XMEMSET(&parentKey, 0, sizeof(parentKey)); + XMEMSET(&keyBlob, 0, sizeof(keyBlob)); + XMEMSET(big, 0x05, sizeof(big)); + capPub = (word32)sizeof(keyBlob.pub.publicArea.unique.rsa.buffer); + capPriv = (word32)sizeof(sens.sensitiveArea.sensitive.rsa.buffer); + + /* Public/private modulus one byte over capacity must return BUFFER_E */ + rc = wolfTPM2_ImportRsaPrivateKeySeed(&dev, &parentKey, &keyBlob, + big, capPub + 1, 0x10001, big, capPriv, + TPM_ALG_NULL, WOLFTPM2_WRAP_DIGEST, attrs, seed, sizeof(seed)); + AssertIntEQ(rc, BUFFER_E); + rc = wolfTPM2_ImportRsaPrivateKeySeed(&dev, &parentKey, &keyBlob, + big, capPub, 0x10001, big, capPriv + 1, + TPM_ALG_NULL, WOLFTPM2_WRAP_DIGEST, attrs, seed, sizeof(seed)); + AssertIntEQ(rc, BUFFER_E); + + /* Exact-fit components clear the bounds check (fail later at the seed + * size check, not BUFFER_E) - pins '>' against '>=' and deletion */ + rc = wolfTPM2_ImportRsaPrivateKeySeed(&dev, &parentKey, &keyBlob, + big, capPub, 0x10001, big, capPriv, + TPM_ALG_NULL, WOLFTPM2_WRAP_DIGEST, attrs, seed, sizeof(seed)); + AssertIntNE(rc, BUFFER_E); + + wolfTPM2_Cleanup(&dev); + + printf("Test TPM Wrapper:\tImportRsaSeed error paths:\tPassed\n"); +} +#endif /* !NO_RSA */ + static void test_wolfTPM2_NVStoreKey_BoundaryChecks(void) { int rc; @@ -6996,6 +7069,9 @@ int unit_tests(int argc, char *argv[]) #ifdef HAVE_ECC test_wolfTPM2_ImportEccPrivateKeySeed_ErrorPaths(); #endif + #ifndef NO_RSA + test_wolfTPM2_ImportRsaPrivateKeySeed_ErrorPaths(); + #endif test_wolfTPM2_NVStoreKey_BoundaryChecks(); test_wolfTPM2_NVDeleteKey_BoundaryChecks(); test_wolfTPM2_UnloadHandle_PersistentGuard(); From 79f497becdfe20ac6dc9c27df9bc49f606c20199 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Mon, 20 Jul 2026 09:50:59 -0700 Subject: [PATCH 5/5] F-7018 - Cover RSASSA/RSAPSS/HMAC signature and KEYEDHASH/SYMCIPHER public marshalling roundtrips (F-7019) --- tests/unit_tests.c | 166 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 74820da9..7f06ed9c 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -3834,6 +3834,93 @@ static void test_TPM2_Signature_EcSchnorrSm2Serialize(void) "Signature ECSCHNORR/SM2 serialize:"); } +static void test_TPM2_Signature_RsaHmacSerialize(void) +{ + TPM2_Packet packet; + byte buf[256]; + TPMT_SIGNATURE sigIn, sigOut; + const byte rsaSig[16] = { + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF + }; + byte hmacDigest[TPM_MAX_DIGEST_SIZE]; + int digestSz; + int i; + + /* RSASSA: sigAlg(2) + hash(2) + sigSz(2) + sig(16) = 22 bytes */ + XMEMSET(&sigIn, 0, sizeof(sigIn)); + sigIn.sigAlg = TPM_ALG_RSASSA; + sigIn.signature.rsassa.hash = TPM_ALG_SHA256; + sigIn.signature.rsassa.sig.size = sizeof(rsaSig); + XMEMCPY(sigIn.signature.rsassa.sig.buffer, rsaSig, sizeof(rsaSig)); + + XMEMSET(buf, 0, sizeof(buf)); + XMEMSET(&packet, 0, sizeof(packet)); + packet.buf = buf; + packet.size = sizeof(buf); + + TPM2_Packet_AppendSignature(&packet, &sigIn); + AssertIntEQ(packet.pos, 22); + + packet.pos = 0; + XMEMSET(&sigOut, 0, sizeof(sigOut)); + TPM2_Packet_ParseSignature(&packet, &sigOut); + AssertIntEQ(sigOut.sigAlg, TPM_ALG_RSASSA); + AssertIntEQ(sigOut.signature.rsassa.hash, TPM_ALG_SHA256); + AssertIntEQ(sigOut.signature.rsassa.sig.size, sizeof(rsaSig)); + AssertIntEQ(XMEMCMP(sigOut.signature.rsassa.sig.buffer, rsaSig, + sizeof(rsaSig)), 0); + + /* RSAPSS: identical wire format */ + sigIn.sigAlg = TPM_ALG_RSAPSS; + + XMEMSET(buf, 0, sizeof(buf)); + XMEMSET(&packet, 0, sizeof(packet)); + packet.buf = buf; + packet.size = sizeof(buf); + + TPM2_Packet_AppendSignature(&packet, &sigIn); + AssertIntEQ(packet.pos, 22); + + packet.pos = 0; + XMEMSET(&sigOut, 0, sizeof(sigOut)); + TPM2_Packet_ParseSignature(&packet, &sigOut); + AssertIntEQ(sigOut.sigAlg, TPM_ALG_RSAPSS); + AssertIntEQ(sigOut.signature.rsapss.sig.size, sizeof(rsaSig)); + AssertIntEQ(XMEMCMP(sigOut.signature.rsapss.sig.buffer, rsaSig, + sizeof(rsaSig)), 0); + + /* HMAC: sigAlg(2) + hashAlg(2) + digest(digestSz), no length prefix - + * on-wire length derives solely from TPM2_GetHashDigestSize(hashAlg) */ + digestSz = TPM2_GetHashDigestSize(TPM_ALG_SHA256); + for (i = 0; i < digestSz; i++) { + hmacDigest[i] = (byte)(0x40 + i); + } + XMEMSET(&sigIn, 0, sizeof(sigIn)); + sigIn.sigAlg = TPM_ALG_HMAC; + sigIn.signature.hmac.hashAlg = TPM_ALG_SHA256; + XMEMCPY(sigIn.signature.hmac.digest.H, hmacDigest, digestSz); + + XMEMSET(buf, 0, sizeof(buf)); + XMEMSET(&packet, 0, sizeof(packet)); + packet.buf = buf; + packet.size = sizeof(buf); + + TPM2_Packet_AppendSignature(&packet, &sigIn); + AssertIntEQ(packet.pos, 4 + digestSz); + + packet.pos = 0; + XMEMSET(&sigOut, 0, sizeof(sigOut)); + TPM2_Packet_ParseSignature(&packet, &sigOut); + AssertIntEQ(sigOut.sigAlg, TPM_ALG_HMAC); + AssertIntEQ(sigOut.signature.hmac.hashAlg, TPM_ALG_SHA256); + AssertIntEQ(XMEMCMP(sigOut.signature.hmac.digest.H, hmacDigest, + digestSz), 0); + + printf("Test TPM Wrapper: %-40s Passed\n", + "Signature RSASSA/RSAPSS/HMAC serialize:"); +} + static void test_TPM2_Public_RsaEcc_Roundtrip(void) { #if !defined(WOLFTPM2_NO_WOLFCRYPT) @@ -3939,6 +4026,83 @@ static void test_TPM2_Public_RsaEcc_Roundtrip(void) #endif } +static void test_TPM2_Public_KeyedHashSym_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 + }; + + /* KEYEDHASH (the seal/unseal object type) with an HMAC-SHA256 scheme */ + XMEMSET(&pubIn, 0, sizeof(pubIn)); + pubIn.publicArea.type = TPM_ALG_KEYEDHASH; + pubIn.publicArea.nameAlg = TPM_ALG_SHA256; + pubIn.publicArea.objectAttributes = TPMA_OBJECT_sign; + pubIn.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_HMAC; + pubIn.publicArea.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = + TPM_ALG_SHA256; + pubIn.publicArea.unique.keyedHash.size = sizeof(uniqueBytes); + XMEMCPY(pubIn.publicArea.unique.keyedHash.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_KEYEDHASH); + AssertIntEQ(pubOut.publicArea.nameAlg, TPM_ALG_SHA256); + AssertIntEQ(pubOut.publicArea.parameters.keyedHashDetail.scheme.scheme, + TPM_ALG_HMAC); + AssertIntEQ(pubOut.publicArea.parameters.keyedHashDetail.scheme.details.hmac + .hashAlg, TPM_ALG_SHA256); + AssertIntEQ(pubOut.publicArea.unique.keyedHash.size, sizeof(uniqueBytes)); + AssertIntEQ(XMEMCMP(pubOut.publicArea.unique.keyedHash.buffer, uniqueBytes, + sizeof(uniqueBytes)), 0); + + /* SYMCIPHER with an AES-128-CFB key definition */ + XMEMSET(&pubIn, 0, sizeof(pubIn)); + pubIn.publicArea.type = TPM_ALG_SYMCIPHER; + pubIn.publicArea.nameAlg = TPM_ALG_SHA256; + pubIn.publicArea.objectAttributes = + (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt); + pubIn.publicArea.parameters.symDetail.sym.algorithm = TPM_ALG_AES; + pubIn.publicArea.parameters.symDetail.sym.keyBits.aes = 128; + pubIn.publicArea.parameters.symDetail.sym.mode.aes = TPM_ALG_CFB; + pubIn.publicArea.unique.sym.size = sizeof(uniqueBytes); + XMEMCPY(pubIn.publicArea.unique.sym.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_SYMCIPHER); + AssertIntEQ(pubOut.publicArea.parameters.symDetail.sym.algorithm, + TPM_ALG_AES); + AssertIntEQ(pubOut.publicArea.parameters.symDetail.sym.keyBits.aes, 128); + AssertIntEQ(pubOut.publicArea.parameters.symDetail.sym.mode.aes, + TPM_ALG_CFB); + AssertIntEQ(pubOut.publicArea.unique.sym.size, sizeof(uniqueBytes)); + AssertIntEQ(XMEMCMP(pubOut.publicArea.unique.sym.buffer, uniqueBytes, + sizeof(uniqueBytes)), 0); + + printf("Test TPM Wrapper: %-40s Passed\n", + "Public KEYEDHASH/SYMCIPHER 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 — @@ -7034,7 +7198,9 @@ int unit_tests(int argc, char *argv[]) test_wolfTPM2_LoadEccPublicKey_Ex(); test_TPM2_KeyedHashScheme_XorSerialize(); test_TPM2_Signature_EcSchnorrSm2Serialize(); + test_TPM2_Signature_RsaHmacSerialize(); test_TPM2_Public_RsaEcc_Roundtrip(); + test_TPM2_Public_KeyedHashSym_Roundtrip(); #ifdef WOLFTPM_PQC test_TPM2_Signature_PQC_Serialize(); test_TPM2_Public_PQC_Roundtrip();