Skip to content

Commit 8ad2d41

Browse files
committed
Skoll review fixes
1 parent e2d1c34 commit 8ad2d41

6 files changed

Lines changed: 215 additions & 43 deletions

File tree

src/fwtpm/fwtpm_command.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11129,8 +11129,12 @@ static TPM_RC FwParseAttestParams(TPM2_Packet* cmd, int cmdSize,
1112911129
* hashAlg per Part 2 Sec. 11.2.1.5. */
1113011130
if (*sigScheme == TPM_ALG_ECDAA) {
1113111131
UINT16 ecdaaCount;
11132-
TPM2_Packet_ParseU16(cmd, &ecdaaCount);
11133-
(void)ecdaaCount;
11132+
if (cmd->pos + 2 > cmdSize)
11133+
rc = TPM_RC_COMMAND_SIZE;
11134+
if (rc == 0) {
11135+
TPM2_Packet_ParseU16(cmd, &ecdaaCount);
11136+
(void)ecdaaCount;
11137+
}
1113411138
}
1113511139
}
1113611140

@@ -11441,8 +11445,12 @@ static TPM_RC FwCmd_CertifyCreation(FWTPM_CTX* ctx, TPM2_Packet* cmd,
1144111445
* hashAlg per Part 2 Sec. 11.2.1.5. */
1144211446
if (sigScheme == TPM_ALG_ECDAA) {
1144311447
UINT16 ecdaaCount;
11444-
TPM2_Packet_ParseU16(cmd, &ecdaaCount);
11445-
(void)ecdaaCount;
11448+
if (cmd->pos + 2 > cmdSize)
11449+
rc = TPM_RC_COMMAND_SIZE;
11450+
if (rc == 0) {
11451+
TPM2_Packet_ParseU16(cmd, &ecdaaCount);
11452+
(void)ecdaaCount;
11453+
}
1144611454
}
1144711455
}
1144811456

@@ -11655,13 +11663,6 @@ static TPM_RC FwCmd_NV_Certify(FWTPM_CTX* ctx, TPM2_Packet* cmd,
1165511663
&qualifyingData, &sigScheme, &sigHashAlg);
1165611664
}
1165711665

11658-
/* Per Part 3 Sec. 31.16.1: TPM_RH_NULL signHandle requires non-NULL
11659-
* scheme and hash algorithm, otherwise return TPM_RC_SCHEME. */
11660-
if (rc == 0 && signHandle == TPM_RH_NULL &&
11661-
(sigScheme == TPM_ALG_NULL || sigHashAlg == TPM_ALG_NULL)) {
11662-
rc = TPM_RC_SCHEME;
11663-
}
11664-
1166511666
/* size, offset */
1166611667
if (rc == 0) {
1166711668
TPM2_Packet_ParseU16(cmd, &readSize);
@@ -11739,10 +11740,13 @@ static TPM_RC FwCmd_NV_Certify(FWTPM_CTX* ctx, TPM2_Packet* cmd,
1173911740
int hashSz;
1174011741
enum wc_HashType wcDigH;
1174111742

11742-
/* Resolve hash from signing key when scheme/hash is NULL */
11743+
/* Resolve hash from signing key when scheme/hash is NULL.
11744+
* keyScheme is filled in by the by-pointer interface but
11745+
* unused here - we only need the resolved hashAlg. */
1174311746
if (hashAlg == TPM_ALG_NULL) {
1174411747
UINT16 keyScheme = TPM_ALG_NULL;
1174511748
FwResolveSignScheme(sigObj, &keyScheme, &hashAlg);
11749+
(void)keyScheme;
1174611750
}
1174711751
wcDigH = FwGetWcHashType(hashAlg);
1174811752
hashSz = TPM2_GetHashDigestSize(hashAlg);

src/tpm2_packet.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,17 @@ void TPM2_Packet_ParsePoint(TPM2_Packet* packet, TPM2B_ECC_POINT* point)
789789
TPM2_Packet_ParseEccPoint(packet, &point->point);
790790

791791
/* Resync packet position to end of declared outer size so inner
792-
* x.size / y.size disagreement can't desynchronize subsequent fields */
793-
if (packet != NULL && point->size > 0 &&
794-
pointStartPos + point->size <= packet->size) {
795-
packet->pos = pointStartPos + point->size;
792+
* x.size / y.size disagreement can't desynchronize subsequent fields.
793+
* If the declared outer size runs past the buffer, clamp to packet end
794+
* so subsequent reads return an out-of-bounds sentinel rather than
795+
* leaving the position wherever the inner parses landed. */
796+
if (packet != NULL && point->size > 0) {
797+
if (pointStartPos + point->size <= packet->size) {
798+
packet->pos = pointStartPos + point->size;
799+
}
800+
else {
801+
packet->pos = packet->size;
802+
}
796803
}
797804
}
798805

@@ -1149,10 +1156,16 @@ void TPM2_Packet_ParsePublic(TPM2_Packet* packet, TPM2B_PUBLIC* pub)
11491156

11501157
/* Resync packet position to end of declared outer size so inner
11511158
* parses can't cause field drift if declared size and actual
1152-
* inner consumption disagree */
1153-
if (packet != NULL &&
1154-
pubStartPos + pub->size <= packet->size) {
1155-
packet->pos = pubStartPos + pub->size;
1159+
* inner consumption disagree. If the declared outer size runs
1160+
* past the buffer, clamp to packet end so subsequent reads
1161+
* return an out-of-bounds sentinel. */
1162+
if (packet != NULL) {
1163+
if (pubStartPos + pub->size <= packet->size) {
1164+
packet->pos = pubStartPos + pub->size;
1165+
}
1166+
else {
1167+
packet->pos = packet->size;
1168+
}
11561169
}
11571170
}
11581171
}

src/tpm2_wrap.c

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3550,6 +3550,11 @@ int wolfTPM2_LoadEccPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
35503550
return BUFFER_E;
35513551
if (eccPubYSz > sizeof(pub.publicArea.unique.ecc.y.buffer))
35523552
return BUFFER_E;
3553+
/* TPMS_SCHEME_ECDAA requires a 'count' field this helper cannot
3554+
* supply. Callers needing ECDAA must build TPM2B_PUBLIC manually and
3555+
* use wolfTPM2_LoadPublicKey directly. */
3556+
if (scheme == TPM_ALG_ECDAA)
3557+
return BAD_FUNC_ARG;
35533558

35543559
XMEMSET(&pub, 0, sizeof(pub));
35553560
pub.publicArea.type = TPM_ALG_ECC;
@@ -5521,8 +5526,10 @@ int wolfTPM2_RsaEncrypt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
55215526
#endif
55225527
}
55235528

5524-
/* Plaintext copy lingers in the rsaEncIn stack frame after return -
5525-
* scrub it on every exit path. */
5529+
/* Plaintext copy lingers in rsaEncIn after the XMEMCPY above. Scrub
5530+
* before returning so the stack frame doesn't leak it. The early
5531+
* BUFFER_E returns above happen before the XMEMCPY so they don't
5532+
* need this path. */
55265533
TPM2_ForceZero(&rsaEncIn, sizeof(rsaEncIn));
55275534
return rc;
55285535
}
@@ -5725,9 +5732,14 @@ int wolfTPM2_UnloadHandle(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle)
57255732
/* nv is the populated handle and auth */
57265733
/* auth and authSz are optional NV authentication */
57275734
/* authPolicy and authPolicySz are optional policy digest */
5728-
int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
5735+
/* nameAlg is the index name hash algorithm; must match the hash that
5736+
* produced authPolicy when one is supplied, otherwise the policy can
5737+
* never be satisfied. Pass TPM_ALG_NULL to use WOLFTPM2_WRAP_DIGEST
5738+
* (default) or auto-infer from authPolicySz for SHA-only policies. */
5739+
int wolfTPM2_NVCreateAuthPolicy_ex(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
57295740
WOLFTPM2_NV* nv, word32 nvIndex, word32 nvAttributes, word32 maxSize,
5730-
const byte* auth, int authSz, const byte* authPolicy, int authPolicySz)
5741+
const byte* auth, int authSz, const byte* authPolicy, int authPolicySz,
5742+
TPMI_ALG_HASH nameAlg)
57315743
{
57325744
int rc, rctmp;
57335745
NV_DefineSpace_In in;
@@ -5758,11 +5770,21 @@ int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
57585770
XMEMCPY(in.auth.buffer, auth, in.auth.size);
57595771
}
57605772
in.publicInfo.nvPublic.nvIndex = nvIndex;
5761-
/* When a policy digest is supplied, nameAlg must match the hash that
5762-
* produced it - otherwise the policy can never be satisfied. Infer
5763-
* nameAlg from authPolicySz when possible, defaulting to
5764-
* WOLFTPM2_WRAP_DIGEST for the no-policy case. */
5765-
if (authPolicy != NULL && authPolicySz > 0) {
5773+
if (nameAlg != TPM_ALG_NULL) {
5774+
/* Caller supplied an explicit nameAlg; use it as-is and only
5775+
* sanity-check against the policy digest size. */
5776+
if (authPolicy != NULL && authPolicySz > 0) {
5777+
int expectSz = TPM2_GetHashDigestSize(nameAlg);
5778+
if (expectSz <= 0 || expectSz != authPolicySz)
5779+
return BAD_FUNC_ARG;
5780+
}
5781+
in.publicInfo.nvPublic.nameAlg = nameAlg;
5782+
}
5783+
else if (authPolicy != NULL && authPolicySz > 0) {
5784+
/* No explicit nameAlg supplied. Infer from policy digest size for
5785+
* SHA-only policies. Note: digest size is a weak discriminator -
5786+
* SM3-256 / SHA3-256 also produce 32 bytes; callers needing those
5787+
* must pass nameAlg explicitly. */
57665788
switch (authPolicySz) {
57675789
#ifndef NO_SHA
57685790
case TPM_SHA_DIGEST_SIZE:
@@ -5830,6 +5852,15 @@ int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
58305852
return rc;
58315853
}
58325854

5855+
int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
5856+
WOLFTPM2_NV* nv, word32 nvIndex, word32 nvAttributes, word32 maxSize,
5857+
const byte* auth, int authSz, const byte* authPolicy, int authPolicySz)
5858+
{
5859+
return wolfTPM2_NVCreateAuthPolicy_ex(dev, parent, nv, nvIndex,
5860+
nvAttributes, maxSize, auth, authSz, authPolicy, authPolicySz,
5861+
TPM_ALG_NULL);
5862+
}
5863+
58335864
int wolfTPM2_NVCreateAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
58345865
WOLFTPM2_NV* nv, word32 nvIndex, word32 nvAttributes, word32 maxSize,
58355866
const byte* auth, int authSz)

tests/fwtpm_unit_tests.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,13 +1578,15 @@ static void test_fwtpm_nv_counter(void)
15781578
}
15791579

15801580
#ifndef FWTPM_NO_ATTESTATION
1581+
#ifdef HAVE_ECC
15811582
/* TPMT_SIG_SCHEME parser must consume the extra UINT16 count field for
15821583
* TPMS_SCHEME_ECDAA per Part 2 Sec. 11.2.1.5. Sending a Quote with
15831584
* inScheme.scheme = TPM_ALG_ECDAA followed by hashAlg + count + a single
15841585
* PCR selection (count=1) verifies that subsequent PCRselect parsing
15851586
* is not desynchronized. With the bug, pcrSelectionsCount reads as 0
15861587
* because the count field is interpreted as the high 16 bits of the
1587-
* PCR-selection count. */
1588+
* PCR-selection count. ECC-only because the RSA sign path rejects
1589+
* TPM_ALG_ECDAA with TPM_RC_SCHEME. */
15881590
static void test_fwtpm_quote_ecdaa_scheme(void)
15891591
{
15901592
FWTPM_CTX ctx;
@@ -1598,11 +1600,7 @@ static void test_fwtpm_quote_ecdaa_scheme(void)
15981600
memset(&ctx, 0, sizeof(ctx));
15991601
AssertIntEQ(fwtpm_test_startup(&ctx), 0);
16001602

1601-
#ifdef HAVE_ECC
16021603
keyH = CreatePrimaryHelper(&ctx, TPM_ALG_ECC);
1603-
#else
1604-
keyH = CreatePrimaryHelper(&ctx, TPM_ALG_RSA);
1605-
#endif
16061604
AssertIntNE(keyH, 0);
16071605

16081606
/* Build TPM2_Quote with ECDAA inScheme. */
@@ -1650,6 +1648,7 @@ static void test_fwtpm_quote_ecdaa_scheme(void)
16501648
FWTPM_Cleanup(&ctx);
16511649
printf("Test fwTPM:\tQuote(ECDAA scheme):\t\tPassed\n");
16521650
}
1651+
#endif /* HAVE_ECC */
16531652

16541653
#ifdef HAVE_ECC
16551654
/* TPM2_CertifyCreation inScheme parser must consume the extra UINT16
@@ -2540,8 +2539,8 @@ int fwtpm_unit_tests(int argc, char *argv[])
25402539
test_fwtpm_nv_counter();
25412540
#ifndef FWTPM_NO_ATTESTATION
25422541
test_fwtpm_nv_certify_digest_mode();
2543-
test_fwtpm_quote_ecdaa_scheme();
25442542
#ifdef HAVE_ECC
2543+
test_fwtpm_quote_ecdaa_scheme();
25452544
test_fwtpm_sign_ecdaa_scheme();
25462545
test_fwtpm_certify_creation_ecdaa_scheme();
25472546
#endif

tests/unit_tests.c

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ static void test_wolfTPM2_SetAuthHandle_PolicyAuthOffset(void)
592592
static void test_wolfTPM2_StartSession_SaltedEncryptAttrs(void)
593593
{
594594
#if !defined(WOLFTPM2_NO_WOLFCRYPT)
595+
int rc;
595596
WOLFTPM2_DEV dev;
596597
WOLFTPM2_KEY tpmKey;
597598
WOLFTPM2_SESSION session;
@@ -601,17 +602,26 @@ static void test_wolfTPM2_StartSession_SaltedEncryptAttrs(void)
601602
XMEMSET(&tpmKey, 0, sizeof(tpmKey));
602603
XMEMSET(&session, 0, sizeof(session));
603604

605+
/* Initialize so TPM2_GetNonceNoLock and dependent code paths have a
606+
* valid context. Skip if no TPM is reachable. */
607+
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
608+
if (rc != 0) {
609+
printf("Test TPM Wrapper:\tStartSession salted enc attrs:\tSkipped\n");
610+
return;
611+
}
612+
604613
/* tpmKey with a non-NULL handle, no auth */
605614
tpmKey.handle.hndl = 0x80000000;
606615

607-
/* Best effort - if no TPM is present the call returns early after the
608-
* SetAuth path, which is what we want to inspect. */
616+
/* The call will fail later (no real key with that handle) but the
617+
* SetAuth path that sets sessionAttributes runs first. */
609618
(void)wolfTPM2_StartSession(&dev, &session, &tpmKey, NULL,
610619
TPM_SE_HMAC, TPM_ALG_CFB);
611620

612621
AssertIntEQ((int)(dev.session[0].sessionAttributes & expected),
613622
(int)expected);
614623

624+
wolfTPM2_Cleanup(&dev);
615625
printf("Test TPM Wrapper:\tStartSession salted enc attrs:\tPassed\n");
616626
#endif
617627
}
@@ -1902,11 +1912,11 @@ static void test_TPM2_ECC_Parameters_EcdaaResponseParse(void)
19021912
printf("Test TPM Wrapper:\tEcdaaResponseParse:\t\tPassed\n");
19031913
}
19041914

1905-
/* TPM2_Packet_ParseSignature must explicitly recognize TPM_ALG_NULL as a
1906-
* zero-payload signature so subsequent fields stay aligned. The previous
1907-
* default-fallthrough lumped TPM_ALG_NULL together with unknown algorithms,
1908-
* making the property "Parse(Append(NULL signature)) consumes exactly the
1909-
* sigAlg bytes" depend on undocumented behavior. */
1915+
/* TPM2_Packet_AppendSignature / ParseSignature must explicitly recognize
1916+
* TPM_ALG_NULL as a zero-payload signature so subsequent fields stay
1917+
* aligned. The previous default-fallthrough lumped TPM_ALG_NULL together
1918+
* with unknown algorithms, making the property "Parse(Append(NULL))
1919+
* consumes exactly the sigAlg bytes" depend on undocumented behavior. */
19101920
static void test_TPM2_ParseSignature_NullAlg(void)
19111921
{
19121922
TPM2_Packet packet;
@@ -1936,6 +1946,29 @@ static void test_TPM2_ParseSignature_NullAlg(void)
19361946
sentinel = (UINT16)((buf[packet.pos] << 8) | buf[packet.pos + 1]);
19371947
AssertIntEQ(sentinel, 0xDEAD);
19381948

1949+
/* Round-trip: Append a TPM_ALG_NULL signature into a fresh packet and
1950+
* verify only the 2-byte sigAlg was written. A future regression that
1951+
* drops the explicit case (defaulting to silent fallthrough) would
1952+
* still pass for Parse but the Append side is also locked in here. */
1953+
XMEMSET(buf, 0, sizeof(buf));
1954+
XMEMSET(&packet, 0, sizeof(packet));
1955+
XMEMSET(&sig, 0, sizeof(sig));
1956+
sig.sigAlg = TPM_ALG_NULL;
1957+
packet.buf = buf;
1958+
packet.size = sizeof(buf);
1959+
packet.pos = 0;
1960+
TPM2_Packet_AppendSignature(&packet, &sig);
1961+
AssertIntEQ(packet.pos, 2);
1962+
AssertIntEQ(buf[0], (byte)((TPM_ALG_NULL >> 8) & 0xFF));
1963+
AssertIntEQ(buf[1], (byte)(TPM_ALG_NULL & 0xFF));
1964+
1965+
/* Re-parse confirms the round-trip. */
1966+
XMEMSET(&sig, 0, sizeof(sig));
1967+
packet.pos = 0;
1968+
TPM2_Packet_ParseSignature(&packet, &sig);
1969+
AssertIntEQ(sig.sigAlg, TPM_ALG_NULL);
1970+
AssertIntEQ(packet.pos, 2);
1971+
19391972
printf("Test TPM Wrapper:\tParseSignature NULL alg:\tPassed\n");
19401973
}
19411974

@@ -2224,6 +2257,44 @@ static void test_wolfTPM2_GetKeyTemplate_KeyedHash_Scheme(void)
22242257
#endif
22252258
}
22262259

2260+
/* wolfTPM2_VerifyHashTicket must apply the same RSA-strict / ECDSA-permissive
2261+
* digest size policy as wolfTPM2_SignHashScheme. The bounds check fires
2262+
* before any TPM call so this test does not require a working TPM. */
2263+
static void test_wolfTPM2_VerifyHashTicket_DigestSize(void)
2264+
{
2265+
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_RSA)
2266+
int rc;
2267+
WOLFTPM2_DEV dev;
2268+
WOLFTPM2_KEY key;
2269+
byte digest[TPM_MAX_DIGEST_SIZE];
2270+
byte sig[MAX_RSA_KEY_BYTES];
2271+
2272+
XMEMSET(&dev, 0, sizeof(dev));
2273+
XMEMSET(&key, 0, sizeof(key));
2274+
XMEMSET(digest, 0xCC, sizeof(digest));
2275+
XMEMSET(sig, 0, sizeof(sig));
2276+
key.handle.hndl = 0x80000000;
2277+
key.pub.publicArea.type = TPM_ALG_RSA;
2278+
2279+
/* SHA-256 digest (32) + hashAlg=SHA512 -> RSA mismatch -> BUFFER_E */
2280+
rc = wolfTPM2_VerifyHashTicket(&dev, &key, sig, 256, digest, 32,
2281+
TPM_ALG_RSASSA, TPM_ALG_SHA512, NULL);
2282+
AssertIntEQ(rc, BUFFER_E);
2283+
2284+
/* Oversized digest (64) + hashAlg=SHA256 -> BUFFER_E */
2285+
rc = wolfTPM2_VerifyHashTicket(&dev, &key, sig, 256, digest, 64,
2286+
TPM_ALG_RSASSA, TPM_ALG_SHA256, NULL);
2287+
AssertIntEQ(rc, BUFFER_E);
2288+
2289+
/* Negative digestSz -> BUFFER_E */
2290+
rc = wolfTPM2_VerifyHashTicket(&dev, &key, sig, 256, digest, -1,
2291+
TPM_ALG_RSASSA, TPM_ALG_SHA256, NULL);
2292+
AssertIntEQ(rc, BUFFER_E);
2293+
2294+
printf("Test TPM Wrapper:\tVerifyHashTicket size:\t\tPassed\n");
2295+
#endif
2296+
}
2297+
22272298
/* wolfTPM2_NVCreateAuthPolicy must derive nameAlg from authPolicySz so
22282299
* the policy digest hash matches the index's nameAlg. Bug-mode hardcoded
22292300
* SHA-256 nameAlg, which made SHA-384/SHA-512 policies unsatisfiable.
@@ -2354,6 +2425,12 @@ static void test_TPM2_BrainpoolCurveMapping(void)
23542425
AssertIntEQ(TPM2_GetTpmCurve(ECC_SECP256R1), TPM_ECC_NIST_P256);
23552426
AssertIntEQ(TPM2_GetWolfCurve(TPM_ECC_NIST_P256), ECC_SECP256R1);
23562427

2428+
/* TPM2_GetCurveSize must report the correct byte size for the new
2429+
* Brainpool curve IDs (32 / 48 / 64). */
2430+
AssertIntEQ(TPM2_GetCurveSize(TPM_ECC_BP_P256_R1), 32);
2431+
AssertIntEQ(TPM2_GetCurveSize(TPM_ECC_BP_P384_R1), 48);
2432+
AssertIntEQ(TPM2_GetCurveSize(TPM_ECC_BP_P512_R1), 64);
2433+
23572434
printf("Test TPM Wrapper:\tBrainpool curve mapping:\tPassed\n");
23582435
#endif
23592436
}
@@ -3752,6 +3829,7 @@ int unit_tests(int argc, char *argv[])
37523829
test_TPM2_BrainpoolCurveMapping();
37533830
test_wolfTPM2_RsaEncryptDecrypt_OversizedBufferE();
37543831
test_wolfTPM2_SignHashScheme_DigestSize();
3832+
test_wolfTPM2_VerifyHashTicket_DigestSize();
37553833
test_wolfTPM2_NVCreateAuthPolicy_NameAlg();
37563834
test_wolfTPM2_GetKeyTemplate_KeyedHash_Scheme();
37573835
test_wolfTPM2_LoadEccPublicKey_Ex();

0 commit comments

Comments
 (0)