F-5277 F-5122 - Store and enforce policy cpHashA command binding

pull/518/head
aidan garske 2026-06-02 13:06:36 -07:00
parent 0d95be5f65
commit 5617f43aae
2 changed files with 114 additions and 6 deletions

View File

@ -8856,6 +8856,8 @@ static TPM_RC FwCmd_PolicySecret(FWTPM_CTX* ctx, TPM2_Packet* cmd,
UINT16 nonceTpmSz, cpHashASz, policyRefSz = 0;
INT32 expiration;
byte policyRef[64];
byte nonceTpmBuf[TPM_MAX_DIGEST_SIZE];
byte cpHashBuf[TPM_MAX_DIGEST_SIZE];
byte entityName[sizeof(TPM2B_NAME)];
int entityNameSz = 0;
FWTPM_Session* sess;
@ -8868,19 +8870,25 @@ static TPM_RC FwCmd_PolicySecret(FWTPM_CTX* ctx, TPM2_Packet* cmd,
if (rc == 0) {
TPM2_Packet_ParseU16(cmd, &nonceTpmSz);
if (cmd->pos + nonceTpmSz > cmdSize) {
rc = TPM_RC_COMMAND_SIZE;
if (nonceTpmSz > (UINT16)sizeof(nonceTpmBuf) ||
cmd->pos + nonceTpmSz > cmdSize) {
rc = TPM_RC_SIZE;
}
}
if (rc == 0) {
cmd->pos += nonceTpmSz;
if (nonceTpmSz > 0) {
TPM2_Packet_ParseBytes(cmd, nonceTpmBuf, nonceTpmSz);
}
TPM2_Packet_ParseU16(cmd, &cpHashASz);
if (cmd->pos + cpHashASz > cmdSize) {
rc = TPM_RC_COMMAND_SIZE;
if (cpHashASz > (UINT16)sizeof(cpHashBuf) ||
cmd->pos + cpHashASz > cmdSize) {
rc = TPM_RC_SIZE;
}
}
if (rc == 0) {
cmd->pos += cpHashASz;
if (cpHashASz > 0) {
TPM2_Packet_ParseBytes(cmd, cpHashBuf, cpHashASz);
}
TPM2_Packet_ParseU16(cmd, &policyRefSz);
if (policyRefSz > (UINT16)sizeof(policyRef)) {
rc = TPM_RC_SIZE;
@ -8909,6 +8917,16 @@ static TPM_RC FwCmd_PolicySecret(FWTPM_CTX* ctx, TPM2_Packet* cmd,
rc = TPM_RC_AUTH_TYPE;
}
/* A supplied nonceTPM must match the session nonce (Part 3 Sec.23.4),
* preventing replay of a PolicySecret authorization to another session. */
if (rc == 0 && nonceTpmSz > 0) {
if (nonceTpmSz != sess->nonceTPM.size ||
TPM2_ConstantCompare(nonceTpmBuf, sess->nonceTPM.buffer,
nonceTpmSz) != 0) {
rc = TPM_RC_VALUE;
}
}
if (rc == 0) {
/* Auth verification for authHandle is handled by the command dispatch
* framework (FWTPM_ProcessCommand) via the authorization area, not
@ -8926,6 +8944,12 @@ static TPM_RC FwCmd_PolicySecret(FWTPM_CTX* ctx, TPM2_Packet* cmd,
}
}
/* Bind the command to cpHashA so policy enforcement can verify it */
if (rc == 0 && cpHashASz > 0) {
sess->cpHashA.size = cpHashASz;
XMEMCPY(sess->cpHashA.buffer, cpHashBuf, cpHashASz);
}
if (rc == 0) {
/* Response: timeout(TPM2B size=0) + ticket(TPMT_TK_AUTH) */
paramStart = FwRspParamsBegin(rsp, cmdTag, &paramSzPos);
@ -9431,6 +9455,12 @@ static TPM_RC FwCmd_PolicySigned(FWTPM_CTX* ctx, TPM2_Packet* cmd,
}
}
/* Bind the command to cpHashA so policy enforcement can verify it */
if (rc == 0 && cpHashASz > 0) {
sess->cpHashA.size = cpHashASz;
XMEMCPY(sess->cpHashA.buffer, cpHashBuf, cpHashASz);
}
if (rc == 0) {
/* Response: timeout(TPM2B size=0) + ticket(TPMT_TK_AUTH) */
paramStart = FwRspParamsBegin(rsp, cmdTag, &paramSzPos);
@ -15775,6 +15805,22 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
TPM_ST_NO_SESSIONS, TPM_RC_LOCALITY);
return TPM_RC_SUCCESS;
}
/* Enforce any PolicyCpHash command binding: the command's
* cpHash must equal the value the policy committed to. */
if (pSess->cpHashA.size > 0) {
byte ccpHash[TPM_MAX_DIGEST_SIZE];
int ccpHashSz = 0;
if (FwComputeCpHash(pSess->authHash, cmdCode,
cmdBuf, cmdSize, cmdHandles, cmdHandleCnt,
ctx, cpStart, ccpHash, &ccpHashSz) != 0 ||
(int)pSess->cpHashA.size != ccpHashSz ||
TPM2_ConstantCompare(pSess->cpHashA.buffer,
ccpHash, (word32)ccpHashSz) != 0) {
*rspSize = FwBuildErrorResponse(rspBuf,
TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL);
return TPM_RC_SUCCESS;
}
}
}
else if (authPolicy != NULL && authPolicy->size == 0 &&
cmdAuths[pj].cmdHmacSize == 0) {

View File

@ -7170,6 +7170,67 @@ static void test_fwtpm_policy_locality_enforced(void)
FWTPM_Cleanup(&ctx);
printf("Test fwTPM:\tPolicyLocality enforced:\tPassed\n");
}
/* PolicyCpHash binds a session to a specific command; a command whose real
* cpHash differs must be rejected even when the policyDigest matches. */
static void test_fwtpm_policy_cphash_enforced(void)
{
FWTPM_CTX ctx;
int pos, cmdSz, rspSize = 0;
UINT32 sessH;
UINT16 dSz;
byte digest[64];
byte cph[32];
UINT32 nvIdx = 0x01500062;
UINT32 nvAttrs = TPMA_NV_OWNERWRITE | TPMA_NV_OWNERREAD | TPMA_NV_NO_DA;
memset(&ctx, 0, sizeof(ctx));
AssertIntEQ(fwtpm_test_startup(&ctx), 0);
memset(cph, 0xCC, sizeof(cph));
sessH = StartSessionHelper(&ctx, TPM_SE_POLICY);
AssertIntNE(sessH, 0);
/* Bind the session to a cpHash no real command will produce */
pos = BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 0, TPM_CC_PolicyCpHash);
PutU32BE(gCmd + pos, sessH); pos += 4;
PutU16BE(gCmd + pos, (UINT16)sizeof(cph)); pos += 2;
memcpy(gCmd + pos, cph, sizeof(cph)); pos += sizeof(cph);
PutU32BE(gCmd + 2, (UINT32)pos);
FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
AssertIntEQ(SendPolicyCmd(&ctx, TPM_CC_PolicyGetDigest, sessH),
TPM_RC_SUCCESS);
dSz = GetU16BE(gRsp + TPM2_HEADER_SIZE + 4);
AssertIntEQ(dSz, 32);
memcpy(digest, gRsp + TPM2_HEADER_SIZE + 6, dSz);
pos = 0;
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
PutU32BE(gCmd + pos, 0); pos += 4;
PutU32BE(gCmd + pos, TPM_CC_SetPrimaryPolicy); pos += 4;
PutU32BE(gCmd + pos, TPM_RH_OWNER); pos += 4;
pos = AppendPwAuth(gCmd, pos, NULL, 0);
PutU16BE(gCmd + pos, dSz); pos += 2;
memcpy(gCmd + pos, digest, dSz); pos += dSz;
PutU16BE(gCmd + pos, TPM_ALG_SHA256); pos += 2;
PutU32BE(gCmd + 2, (UINT32)pos);
rspSize = 0;
FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
/* The NV_DefineSpace cpHash will not match the bound cpHashA */
cmdSz = BuildNvDefineCmd(gCmd, nvIdx, 8, nvAttrs);
PutU32BE(gCmd + 18, sessH);
rspSize = 0;
FWTPM_ProcessCommand(&ctx, gCmd, cmdSz, gRsp, &rspSize, 0);
AssertIntEQ(GetRspRC(gRsp), TPM_RC_POLICY_FAIL);
FlushHandle(&ctx, sessH);
FWTPM_Cleanup(&ctx);
printf("Test fwTPM:\tPolicyCpHash enforced:\tPassed\n");
}
#endif /* !FWTPM_NO_NV */
#endif /* !FWTPM_NO_POLICY */
@ -9255,6 +9316,7 @@ int fwtpm_unit_tests(int argc, char *argv[])
test_fwtpm_policynv_owner_read_denied();
test_fwtpm_policyauthorizenv_owner_read_denied();
test_fwtpm_policy_locality_enforced();
test_fwtpm_policy_cphash_enforced();
#endif
#endif