// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 3: Commands
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014
#include "InternalRoutines.h"
#include "PolicyNV_fp.h"
#include "Policy_spt_fp.h"
#include "NV_spt_fp.h" // Include NV support routine for read access check
//
//
// Error Returns Meaning
//
// TPM_RC_AUTH_TYPE NV index authorization type is not correct
// TPM_RC_NV_LOCKED NV index read locked
// TPM_RC_NV_UNINITIALIZED the NV index has not been initialized
// TPM_RC_POLICY the comparison to the NV contents failed
// TPM_RC_SIZE the size of nvIndex data starting at offset is less than the size of
// operandB
//
TPM_RC
TPM2_PolicyNV(
PolicyNV_In *in // IN: input parameter list
)
{
TPM_RC result;
SESSION *session;
NV_INDEX nvIndex;
BYTE nvBuffer[sizeof(in->operandB.t.buffer)];
TPM2B_NAME nvName;
TPM_CC commandCode = TPM_CC_PolicyNV;
HASH_STATE hashState;
TPM2B_DIGEST argHash;
// Input Validation
// Get NV index information
NvGetIndexInfo(in->nvIndex, &nvIndex);
// Get pointer to the session structure
session = SessionGet(in->policySession);
//If this is a trial policy, skip all validations and the operation
if(session->attributes.isTrialPolicy == CLEAR)
{
// NV Read access check. NV index should be allowed for read. A
// TPM_RC_AUTH_TYPE or TPM_RC_NV_LOCKED error may be return at this
// point
result = NvReadAccessChecks(in->authHandle, in->nvIndex);
if(result != TPM_RC_SUCCESS) return result;
// Valid NV data size should not be smaller than input operandB size
if((nvIndex.publicArea.dataSize - in->offset) < in->operandB.t.size)
return TPM_RC_SIZE + RC_PolicyNV_operandB;
// Arithmetic Comparison
// Get NV data. The size of NV data equals the input operand B size
NvGetIndexData(in->nvIndex, &nvIndex, in->offset,
in->operandB.t.size, nvBuffer);
switch(in->operation)
{
case TPM_EO_EQ:
// compare A = B
if(CryptCompare(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) != 0)
return TPM_RC_POLICY;
break;
case TPM_EO_NEQ:
// compare A != B
if(CryptCompare(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) == 0)
return TPM_RC_POLICY;
break;
case TPM_EO_SIGNED_GT:
// compare A > B signed
if(CryptCompareSigned(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) <= 0)
return TPM_RC_POLICY;
break;
case TPM_EO_UNSIGNED_GT:
// compare A > B unsigned
if(CryptCompare(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) <= 0)
return TPM_RC_POLICY;
break;
case TPM_EO_SIGNED_LT:
// compare A < B signed
if(CryptCompareSigned(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) >= 0)
return TPM_RC_POLICY;
break;
case TPM_EO_UNSIGNED_LT:
// compare A < B unsigned
if(CryptCompare(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) >= 0)
return TPM_RC_POLICY;
break;
case TPM_EO_SIGNED_GE:
// compare A >= B signed
if(CryptCompareSigned(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) < 0)
return TPM_RC_POLICY;
break;
case TPM_EO_UNSIGNED_GE:
// compare A >= B unsigned
if(CryptCompare(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) < 0)
return TPM_RC_POLICY;
break;
case TPM_EO_SIGNED_LE:
// compare A <= B signed
if(CryptCompareSigned(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) > 0)
return TPM_RC_POLICY;
break;
case TPM_EO_UNSIGNED_LE:
// compare A <= B unsigned
if(CryptCompare(in->operandB.t.size, nvBuffer,
in->operandB.t.size, in->operandB.t.buffer) > 0)
return TPM_RC_POLICY;
break;
case TPM_EO_BITSET:
// All bits SET in B are SET in A. ((A&B)=B)
{
UINT32 i;
for (i = 0; i < in->operandB.t.size; i++)
if((nvBuffer[i] & in->operandB.t.buffer[i])
!= in->operandB.t.buffer[i])
return TPM_RC_POLICY;
}
break;
case TPM_EO_BITCLEAR:
// All bits SET in B are CLEAR in A. ((A&B)=0)
{
UINT32 i;
for (i = 0; i < in->operandB.t.size; i++)
if((nvBuffer[i] & in->operandB.t.buffer[i]) != 0)
return TPM_RC_POLICY;
}
break;
default:
pAssert(FALSE);
break;
}
}
// Internal Data Update
// Start argument hash
argHash.t.size = CryptStartHash(session->authHashAlg, &hashState);
// add operandB
CryptUpdateDigest2B(&hashState, &in->operandB.b);
// add offset
CryptUpdateDigestInt(&hashState, sizeof(UINT16), &in->offset);
// add operation
CryptUpdateDigestInt(&hashState, sizeof(TPM_EO), &in->operation);
// complete argument digest
CryptCompleteHash2B(&hashState, &argHash.b);
// Update policyDigest
// Start digest
CryptStartHash(session->authHashAlg, &hashState);
// add old digest
CryptUpdateDigest2B(&hashState, &session->u2.policyDigest.b);
// add commandCode
CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode);
// add argument digest
CryptUpdateDigest2B(&hashState, &argHash.b);
// Adding nvName
nvName.t.size = EntityGetName(in->nvIndex, &nvName.t.name);
CryptUpdateDigest2B(&hashState, &nvName.b);
// complete the digest
CryptCompleteHash2B(&hashState, &session->u2.policyDigest.b);
return TPM_RC_SUCCESS;
}