F-13524 - Verify the PolicyPCR digest against live PCR values

pull/593/head
Aidan Garske 2026-09-07 12:14:43 -07:00
parent 9bb9e2f8f7
commit 11917addc0
2 changed files with 82 additions and 7 deletions

View File

@ -10667,6 +10667,7 @@ static TPM_RC FwCmd_PolicyPCR(FWTPM_CTX* ctx, TPM2_Packet* cmd,
UINT32 sessHandle;
UINT16 pcrDigestSize;
byte pcrDigest[TPM_MAX_DIGEST_SIZE];
byte liveDigest[TPM_MAX_DIGEST_SIZE];
TPML_PCR_SELECTION pcrs;
FWTPM_Session* sess = NULL;
int digestSz = 0;
@ -10733,8 +10734,10 @@ static TPM_RC FwCmd_PolicyPCR(FWTPM_CTX* ctx, TPM2_Packet* cmd,
}
}
/* If pcrDigest.size == 0, compute it from current PCR values */
if (rc == 0 && pcrDigestSize == 0) {
/* Compute the digest of the selected PCRs when none was supplied, and
* always for a real policy session so a supplied digest is verified
* against the live PCR values rather than trusted (Part 3 Sec.23.7). */
if (rc == 0 && (pcrDigestSize == 0 || sess->sessionType == TPM_SE_POLICY)) {
/* Hash together all selected PCR values */
wcHash = FwGetWcHashType(sess->authHash);
if (wc_HashInit_ex(hashCtx, wcHash, NULL, INVALID_DEVID) != 0) {
@ -10750,17 +10753,29 @@ static TPM_RC FwCmd_PolicyPCR(FWTPM_CTX* ctx, TPM2_Packet* cmd,
pcrs.pcrSelections[i].hash);
if (bankIdx < 0 || pcrDSz == 0)
continue;
for (j = 0; j < IMPLEMENTATION_PCR; j++) {
for (j = 0; j < IMPLEMENTATION_PCR && rc == 0; j++) {
if (j / 8 < pcrs.pcrSelections[i].sizeofSelect &&
(pcrs.pcrSelections[i].pcrSelect[j / 8] &
(1 << (j % 8)))) {
wc_HashUpdate(hashCtx, wcHash,
ctx->pcrDigest[j][bankIdx], pcrDSz);
if (wc_HashUpdate(hashCtx, wcHash,
ctx->pcrDigest[j][bankIdx], pcrDSz) != 0) {
rc = TPM_RC_FAILURE;
}
}
}
}
pcrDigestSize = digestSz;
wc_HashFinal(hashCtx, wcHash, pcrDigest);
if (rc == 0 && wc_HashFinal(hashCtx, wcHash, liveDigest) != 0) {
rc = TPM_RC_FAILURE;
}
if (rc == 0 && pcrDigestSize != 0 &&
(pcrDigestSize != digestSz ||
TPM2_ConstantCompare(pcrDigest, liveDigest, digestSz) != 0)) {
rc = TPM_RC_VALUE;
}
if (rc == 0) {
pcrDigestSize = (UINT16)digestSz;
XMEMCPY(pcrDigest, liveDigest, digestSz);
}
}
if (hashInit) {
wc_HashFree(hashCtx, wcHash);

View File

@ -9587,6 +9587,65 @@ static void test_fwtpm_policy_cphash_enforced(void)
}
#endif /* !FWTPM_NO_NV */
/* PolicyPCR selecting PCR 0 in the SHA-256 bank with an optional caller digest */
static TPM_RC SendPolicyPcrCmd(FWTPM_CTX* ctx, UINT32 sessH,
const byte* digest, UINT16 digestSz)
{
int pos = 0, rspSize = 0;
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
PutU32BE(gCmd + pos, 0); pos += 4;
PutU32BE(gCmd + pos, TPM_CC_PolicyPCR); pos += 4;
PutU32BE(gCmd + pos, sessH); pos += 4;
pos = AppendPwAuth(gCmd, pos, NULL, 0);
PutU16BE(gCmd + pos, digestSz); pos += 2;
if (digestSz > 0) {
memcpy(gCmd + pos, digest, digestSz); pos += digestSz;
}
PutU32BE(gCmd + pos, 1); pos += 4; /* count */
PutU16BE(gCmd + pos, TPM_ALG_SHA256); pos += 2; /* hash */
gCmd[pos++] = 3; /* sizeofSelect */
gCmd[pos++] = 0x01; gCmd[pos++] = 0x00; gCmd[pos++] = 0x00; /* PCR 0 */
PutU32BE(gCmd + 2, (UINT32)pos);
FWTPM_ProcessCommand(ctx, gCmd, pos, gRsp, &rspSize, 0);
return GetRspRC(gRsp);
}
/* A real policy session must verify a caller-supplied pcrDigest against the
* live PCR values; only a trial session may take it on faith. */
static void test_fwtpm_policy_pcr_digest_verified(void)
{
FWTPM_CTX ctx;
UINT32 sessH;
byte pcr0[32];
byte expect[32];
byte wrong[32];
memset(&ctx, 0, sizeof(ctx));
AssertIntEQ(fwtpm_test_startup(&ctx), 0);
memset(pcr0, 0, sizeof(pcr0)); /* PCR 0 reset by Startup */
AssertIntEQ(wc_Hash(WC_HASH_TYPE_SHA256, pcr0, sizeof(pcr0),
expect, sizeof(expect)), 0);
memset(wrong, 0xAB, sizeof(wrong));
sessH = StartSessionHelper(&ctx, TPM_SE_POLICY);
AssertIntNE(sessH, 0);
AssertIntEQ(SendPolicyPcrCmd(&ctx, sessH, wrong, sizeof(wrong)),
TPM_RC_VALUE);
AssertIntEQ(SendPolicyPcrCmd(&ctx, sessH, expect, 16), TPM_RC_VALUE);
AssertIntEQ(SendPolicyPcrCmd(&ctx, sessH, expect, sizeof(expect)),
TPM_RC_SUCCESS);
FlushHandle(&ctx, sessH);
sessH = StartSessionHelper(&ctx, TPM_SE_TRIAL);
AssertIntNE(sessH, 0);
AssertIntEQ(SendPolicyPcrCmd(&ctx, sessH, wrong, sizeof(wrong)),
TPM_RC_SUCCESS);
FlushHandle(&ctx, sessH);
FWTPM_Cleanup(&ctx);
fwtpm_pass("PolicyPCR digest verified:", 0);
}
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
static void test_fwtpm_admin_authorization_requires_policy(void)
{
@ -14543,6 +14602,7 @@ int fwtpm_unit_tests(int argc, char *argv[])
test_fwtpm_policy_command_code();
test_fwtpm_policy_locality();
test_fwtpm_policy_pcr();
test_fwtpm_policy_pcr_digest_verified();
test_fwtpm_policy_ticket_zero_digest_rejected();
test_fwtpm_policyauthorize_null_ticket_rejected();
#ifndef FWTPM_NO_NV