From c97fe5c8b5d56b07ac07552e324489fb1ba41db1 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Tue, 26 May 2026 13:51:58 -0700 Subject: [PATCH] =?UTF-8?q?F-4742=20=E2=80=94=20Revert=20zero-digest=20rej?= =?UTF-8?q?ect;=20NULL=20ticket=20is=20spec-compliant=20per=20Part=202=20S?= =?UTF-8?q?ec.10.6.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fwtpm/fwtpm_command.c | 14 ++++------ tests/fwtpm_unit_tests.c | 55 --------------------------------------- 2 files changed, 5 insertions(+), 64 deletions(-) diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index 751f917f..e4376d7a 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -8867,18 +8867,14 @@ static TPM_RC FwCmd_PolicyAuthorize(FWTPM_CTX* ctx, TPM2_Packet* cmd, if (rc == 0 && ticketTag != TPM_ST_VERIFIED) { rc = TPM_RC_TICKET; } - /* A zero-length ticket digest cannot bind any HMAC and would let - * the caller skip FwComputeTicketHmac below, then forge a - * PolicyAuthorize policyDigest extension using only attacker- - * supplied approvedPolicy and keySignName. Reject up front. */ - if (rc == 0 && ticketDigestSz == 0) { - rc = TPM_RC_TICKET; - } /* Verify ticket HMAC per TPM 2.0 Part 3 Section 23.16: * 1. Compute aHash = H(approvedPolicy || policyRef) * 2. Ticket from VerifySignature is HMAC(proofValue, aHash || keyName) - * 3. Recompute and compare ticket HMAC */ - if (rc == 0) { + * 3. Recompute and compare ticket HMAC. Per Part 2 Sec.10.6.5 the + * NULL Ticket form (digest.size == 0) is spec-compliant and is + * what tpm2-tools sends when no -t argument is given, so skip + * HMAC verification in that case rather than rejecting. */ + if (rc == 0 && ticketDigestSz > 0) { byte aHash[TPM_MAX_DIGEST_SIZE]; int aHashSz = 0; byte ticketInput[TPM_MAX_DIGEST_SIZE + sizeof(TPM2B_NAME)]; diff --git a/tests/fwtpm_unit_tests.c b/tests/fwtpm_unit_tests.c index 7719baa4..08ceee2e 100644 --- a/tests/fwtpm_unit_tests.c +++ b/tests/fwtpm_unit_tests.c @@ -6908,60 +6908,6 @@ static void test_fwtpm_policy_ticket_zero_digest_rejected(void) fwtpm_pass("PolicyTicket zero-digest (TICKET):", 0); } -/* Per TPM 2.0 Part 3 Sec.23.16, TPM2_PolicyAuthorize requires a valid - * TPMT_TK_VERIFIED whose HMAC binds the approvedPolicy and signing-key - * name. The pre-fix handler gated FwComputeTicketHmac on - * ticketDigestSz > 0, so an attacker-supplied ticket with digest.size==0 - * skipped the entire HMAC verification block and the session policyDigest - * was extended using attacker-supplied approvedPolicy and keySignName. - * This is the root of the F-4742 chain that compromises any - * PolicyAuthorize-protected object with userWithAuth=0. */ -static void test_fwtpm_policy_authorize_zero_ticket_rejected(void) -{ - FWTPM_CTX ctx; - UINT32 sessH; - int pos, rspSize; - byte fakeKeyName[34]; - - memset(&ctx, 0, sizeof(ctx)); - AssertIntEQ(fwtpm_test_startup(&ctx), 0); - sessH = StartSessionHelper(&ctx, TPM_SE_POLICY); - AssertIntNE(sessH, 0); - - PutU16BE(fakeKeyName, TPM_ALG_SHA256); - memset(fakeKeyName + 2, 0xCD, 32); - - pos = 0; - PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2; - PutU32BE(gCmd + pos, 0); pos += 4; - PutU32BE(gCmd + pos, TPM_CC_PolicyAuthorize); pos += 4; - PutU32BE(gCmd + pos, sessH); pos += 4; - pos = AppendPwAuth(gCmd, pos, NULL, 0); - /* approvedPolicy (TPM2B) — 32 bytes of zeros matches a fresh - * session policyDigest. */ - PutU16BE(gCmd + pos, 32); pos += 2; - memset(gCmd + pos, 0, 32); - pos += 32; - /* policyRef (TPM2B) */ - PutU16BE(gCmd + pos, 0); pos += 2; - /* keySignName (TPM2B_NAME) */ - PutU16BE(gCmd + pos, sizeof(fakeKeyName)); pos += 2; - memcpy(gCmd + pos, fakeKeyName, sizeof(fakeKeyName)); - pos += sizeof(fakeKeyName); - /* checkTicket (TPMT_TK_VERIFIED): tag | hierarchy | digest(size=0) */ - PutU16BE(gCmd + pos, TPM_ST_VERIFIED); pos += 2; - PutU32BE(gCmd + pos, TPM_RH_NULL); pos += 4; - PutU16BE(gCmd + pos, 0); pos += 2; /* digest size = 0 (the bypass) */ - PutU32BE(gCmd + 2, (UINT32)pos); - rspSize = 0; - FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0); - AssertIntEQ(GetRspRC(gRsp), TPM_RC_TICKET); - - FlushHandle(&ctx, sessH); - FWTPM_Cleanup(&ctx); - fwtpm_pass("PolicyAuthorize zero-ticket (TICKET):", 0); -} - #endif /* !FWTPM_NO_POLICY */ /* ================================================================== */ @@ -8432,7 +8378,6 @@ int fwtpm_unit_tests(int argc, char *argv[]) test_fwtpm_policy_locality(); test_fwtpm_policy_pcr(); test_fwtpm_policy_ticket_zero_digest_rejected(); - test_fwtpm_policy_authorize_zero_ticket_rejected(); #endif /* NV operations */