1289 lines
43 KiB
C
1289 lines
43 KiB
C
// This file was extracted from the TCG Published
|
||
// Trusted Platform Module Library
|
||
// Part 4: Supporting Routines
|
||
// Family "2.0"
|
||
// Level 00 Revision 01.16
|
||
// October 30, 2014
|
||
|
||
#define PCR_C
|
||
#include "InternalRoutines.h"
|
||
#include "Platform.h"
|
||
//
|
||
// The initial value of PCR attributes. The value of these fields should be consistent with PC Client
|
||
// specification In this implementation, we assume the total number of implemented PCR is 24.
|
||
//
|
||
static const PCR_Attributes s_initAttributes[] =
|
||
{
|
||
// PCR 0 - 15, static RTM
|
||
{1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
|
||
{1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
|
||
{1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
|
||
{1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
|
||
{0, 0x0F, 0x1F}, // PCR 16, Debug
|
||
{0, 0x10, 0x1C}, // PCR 17, Locality 4
|
||
{0, 0x10, 0x1C}, // PCR 18, Locality 3
|
||
{0, 0x10, 0x0C}, // PCR 19, Locality 2
|
||
{0, 0x1C, 0x0E}, // PCR 20, Locality 1
|
||
{0, 0x1C, 0x04}, // PCR 21, Dynamic OS
|
||
{0, 0x1C, 0x04}, // PCR 22, Dynamic OS
|
||
{0, 0x0F, 0x1F}, // PCR 23, App specific
|
||
{0, 0x0F, 0x1F} // PCR 24, testing policy
|
||
};
|
||
//
|
||
//
|
||
// Functions
|
||
//
|
||
// PCRBelongsAuthGroup()
|
||
//
|
||
// This function indicates if a PCR belongs to a group that requires an authValue in order to modify the
|
||
// PCR. If it does, groupIndex is set to value of the group index. This feature of PCR is decided by the
|
||
// platform specification.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE: PCR belongs an auth group
|
||
// FALSE: PCR does not belong an auth group
|
||
//
|
||
BOOL
|
||
PCRBelongsAuthGroup(
|
||
TPMI_DH_PCR handle, // IN: handle of PCR
|
||
UINT32 *groupIndex // OUT: group index if PCR belongs a
|
||
// group that allows authValue. If PCR
|
||
// does not belong to an auth group,
|
||
// the value in this parameter is
|
||
// invalid
|
||
)
|
||
{
|
||
// None of the PCRs belong to a group requiring an authValue, as defined in
|
||
// Table 4 "PCR Attributes" of the "TCG PC Client Platform TPM Profile (TPT)
|
||
// Specification Level 00 Revision 00.43".
|
||
return FALSE;
|
||
}
|
||
//
|
||
//
|
||
// PCRBelongsPolicyGroup()
|
||
//
|
||
// This function indicates if a PCR belongs to a group that requires a policy authorization in order to modify
|
||
// the PCR. If it does, groupIndex is set to value of the group index. This feature of PCR is decided by the
|
||
// platform specification.
|
||
// Family "2.0" TCG Published Page 169
|
||
// Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014
|
||
// Trusted Platform Module Library Part 4: Supporting Routines
|
||
//
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE: PCR belongs a policy group
|
||
// FALSE: PCR does not belong a policy group
|
||
//
|
||
BOOL
|
||
PCRBelongsPolicyGroup(
|
||
TPMI_DH_PCR handle, // IN: handle of PCR
|
||
UINT32 *groupIndex // OUT: group index if PCR belongs a group that
|
||
// allows policy. If PCR does not belong to
|
||
// a policy group, the value in this
|
||
// parameter is invalid
|
||
)
|
||
{
|
||
// None of the PCRs belong to the policy group, as defined in Table 4
|
||
// "PCR Attributes" of the "TCG PC Client Platform TPM Profile (TPT)
|
||
// Specification Level 00 Revision 00.43".
|
||
return FALSE;
|
||
}
|
||
//
|
||
//
|
||
// PCRBelongsTCBGroup()
|
||
//
|
||
// This function indicates if a PCR belongs to the TCB group.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE: PCR belongs to TCB group
|
||
// FALSE: PCR does not belong to TCB group
|
||
//
|
||
static BOOL
|
||
PCRBelongsTCBGroup(
|
||
TPMI_DH_PCR handle // IN: handle of PCR
|
||
)
|
||
{
|
||
#if ENABLE_PCR_NO_INCREMENT == YES
|
||
// Platform specification decides if a PCR belongs to a TCB group. In this
|
||
// implementation, we assume PCR[16, 21-23] belong to TCB group as defined
|
||
// in Table 4. If the platform specification requires differently, the
|
||
// implementation should be changed accordingly
|
||
if(handle == 16 || (handle >= 21 && handle <= 23))
|
||
return TRUE;
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
//
|
||
//
|
||
// PCRPolicyIsAvailable()
|
||
//
|
||
// This function indicates if a policy is available for a PCR.
|
||
//
|
||
//
|
||
//
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE the PCR should be authorized by policy
|
||
// FALSE the PCR does not allow policy
|
||
//
|
||
BOOL
|
||
PCRPolicyIsAvailable(
|
||
TPMI_DH_PCR handle // IN: PCR handle
|
||
)
|
||
{
|
||
UINT32 groupIndex;
|
||
return PCRBelongsPolicyGroup(handle, &groupIndex);
|
||
}
|
||
//
|
||
//
|
||
// PCRGetAuthValue()
|
||
//
|
||
// This function is used to access the authValue of a PCR. If PCR does not belong to an authValue group,
|
||
// an Empty Auth will be returned.
|
||
//
|
||
void
|
||
PCRGetAuthValue(
|
||
TPMI_DH_PCR handle, // IN: PCR handle
|
||
TPM2B_AUTH *auth // OUT: authValue of PCR
|
||
)
|
||
{
|
||
UINT32 groupIndex;
|
||
if(PCRBelongsAuthGroup(handle, &groupIndex))
|
||
{
|
||
*auth = gc.pcrAuthValues.auth[groupIndex];
|
||
}
|
||
else
|
||
{
|
||
auth->t.size = 0;
|
||
}
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PCRGetAuthPolicy()
|
||
//
|
||
// This function is used to access the authorization policy of a PCR. It sets policy to the authorization policy
|
||
// and returns the hash algorithm for policy If the PCR does not allow a policy, TPM_ALG_NULL is returned.
|
||
//
|
||
TPMI_ALG_HASH
|
||
PCRGetAuthPolicy(
|
||
TPMI_DH_PCR handle, // IN: PCR handle
|
||
TPM2B_DIGEST *policy // OUT: policy of PCR
|
||
)
|
||
{
|
||
UINT32 groupIndex;
|
||
if(PCRBelongsPolicyGroup(handle, &groupIndex))
|
||
{
|
||
*policy = gp.pcrPolicies.policy[groupIndex];
|
||
return gp.pcrPolicies.hashAlg[groupIndex];
|
||
}
|
||
else
|
||
{
|
||
policy->t.size = 0;
|
||
return TPM_ALG_NULL;
|
||
}
|
||
}
|
||
//
|
||
//
|
||
// PCRSimStart()
|
||
//
|
||
// This function is used to initialize the policies when a TPM is manufactured. This function would only be
|
||
// called in a manufacturing environment or in a TPM simulator.
|
||
//
|
||
void
|
||
PCRSimStart(
|
||
void
|
||
)
|
||
{
|
||
UINT32 i;
|
||
for(i = 0; i < NUM_POLICY_PCR_GROUP; i++)
|
||
{
|
||
gp.pcrPolicies.hashAlg[i] = TPM_ALG_NULL;
|
||
gp.pcrPolicies.policy[i].t.size = 0;
|
||
}
|
||
for(i = 0; i < NUM_AUTHVALUE_PCR_GROUP; i++)
|
||
{
|
||
gc.pcrAuthValues.auth[i].t.size = 0;
|
||
}
|
||
// We need to give an initial configuration on allocated PCR before
|
||
// receiving any TPM2_PCR_Allocate command to change this configuration
|
||
// When the simulation environment starts, we allocate all the PCRs
|
||
for(gp.pcrAllocated.count = 0; gp.pcrAllocated.count < HASH_COUNT;
|
||
gp.pcrAllocated.count++)
|
||
{
|
||
gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].hash
|
||
= CryptGetHashAlgByIndex(gp.pcrAllocated.count);
|
||
gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].sizeofSelect
|
||
= PCR_SELECT_MAX;
|
||
for(i = 0; i < PCR_SELECT_MAX; i++)
|
||
gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].pcrSelect[i]
|
||
= 0xFF;
|
||
}
|
||
// Store the initial configuration to NV
|
||
NvWriteReserved(NV_PCR_POLICIES, &gp.pcrPolicies);
|
||
NvWriteReserved(NV_PCR_ALLOCATED, &gp.pcrAllocated);
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// GetSavedPcrPointer()
|
||
//
|
||
// This function returns the address of an array of state saved PCR based on the hash algorithm.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// NULL no such algorithm
|
||
// not NULL pointer to the 0th byte of the 0th PCR
|
||
//
|
||
static BYTE *
|
||
GetSavedPcrPointer (
|
||
TPM_ALG_ID alg, // IN: algorithm for bank
|
||
UINT32 pcrIndex // IN: PCR index in PCR_SAVE
|
||
)
|
||
{
|
||
switch(alg)
|
||
{
|
||
#ifdef TPM_ALG_SHA1
|
||
case TPM_ALG_SHA1:
|
||
return gc.pcrSave.sha1[pcrIndex];
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SHA256
|
||
case TPM_ALG_SHA256:
|
||
return gc.pcrSave.sha256[pcrIndex];
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SHA384
|
||
case TPM_ALG_SHA384:
|
||
return gc.pcrSave.sha384[pcrIndex];
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SHA512
|
||
case TPM_ALG_SHA512:
|
||
return gc.pcrSave.sha512[pcrIndex];
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SM3_256
|
||
case TPM_ALG_SM3_256:
|
||
return gc.pcrSave.sm3_256[pcrIndex];
|
||
break;
|
||
#endif
|
||
default:
|
||
FAIL(FATAL_ERROR_INTERNAL);
|
||
}
|
||
return NULL; // Never reached.
|
||
}
|
||
//
|
||
//
|
||
// PcrIsAllocated()
|
||
//
|
||
// This function indicates if a PCR number for the particular hash algorithm is allocated.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// FALSE PCR is not allocated
|
||
// TRUE PCR is allocated
|
||
//
|
||
BOOL
|
||
PcrIsAllocated (
|
||
UINT32 pcr, // IN: The number of the PCR
|
||
TPMI_ALG_HASH hashAlg // IN: The PCR algorithm
|
||
)
|
||
{
|
||
UINT32 i;
|
||
BOOL allocated = FALSE;
|
||
if(pcr < IMPLEMENTATION_PCR)
|
||
{
|
||
for(i = 0; i < gp.pcrAllocated.count; i++)
|
||
{
|
||
if(gp.pcrAllocated.pcrSelections[i].hash == hashAlg)
|
||
{
|
||
if(((gp.pcrAllocated.pcrSelections[i].pcrSelect[pcr/8])
|
||
& (1 << (pcr % 8))) != 0)
|
||
//
|
||
allocated = TRUE;
|
||
else
|
||
allocated = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return allocated;
|
||
}
|
||
//
|
||
//
|
||
// GetPcrPointer()
|
||
//
|
||
// This function returns the address of an array of PCR based on the hash algorithm.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// NULL no such algorithm
|
||
// not NULL pointer to the 0th byte of the 0th PCR
|
||
//
|
||
static BYTE *
|
||
GetPcrPointer (
|
||
TPM_ALG_ID alg, // IN: algorithm for bank
|
||
UINT32 pcrNumber // IN: PCR number
|
||
)
|
||
{
|
||
static BYTE *pcr = NULL;
|
||
if(!PcrIsAllocated(pcrNumber, alg))
|
||
return NULL;
|
||
switch(alg)
|
||
{
|
||
#ifdef TPM_ALG_SHA1
|
||
case TPM_ALG_SHA1:
|
||
pcr = s_pcrs[pcrNumber].sha1Pcr;
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SHA256
|
||
case TPM_ALG_SHA256:
|
||
pcr = s_pcrs[pcrNumber].sha256Pcr;
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SHA384
|
||
case TPM_ALG_SHA384:
|
||
pcr = s_pcrs[pcrNumber].sha384Pcr;
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SHA512
|
||
case TPM_ALG_SHA512:
|
||
pcr = s_pcrs[pcrNumber].sha512Pcr;
|
||
break;
|
||
#endif
|
||
#ifdef TPM_ALG_SM3_256
|
||
case TPM_ALG_SM3_256:
|
||
pcr = s_pcrs[pcrNumber].sm3_256Pcr;
|
||
break;
|
||
#endif
|
||
default:
|
||
pAssert(FALSE);
|
||
break;
|
||
}
|
||
return pcr;
|
||
//
|
||
}
|
||
//
|
||
//
|
||
// IsPcrSelected()
|
||
//
|
||
// This function indicates if an indicated PCR number is selected by the bit map in selection.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// FALSE PCR is not selected
|
||
// TRUE PCR is selected
|
||
//
|
||
static BOOL
|
||
IsPcrSelected (
|
||
UINT32 pcr, // IN: The number of the PCR
|
||
TPMS_PCR_SELECTION *selection // IN: The selection structure
|
||
)
|
||
{
|
||
BOOL selected = FALSE;
|
||
if( pcr < IMPLEMENTATION_PCR
|
||
&& ((selection->pcrSelect[pcr/8]) & (1 << (pcr % 8))) != 0)
|
||
selected = TRUE;
|
||
return selected;
|
||
}
|
||
//
|
||
//
|
||
// FilterPcr()
|
||
//
|
||
// This function modifies a PCR selection array based on the implemented PCR.
|
||
//
|
||
static void
|
||
FilterPcr(
|
||
TPMS_PCR_SELECTION *selection // IN: input PCR selection
|
||
)
|
||
{
|
||
UINT32 i;
|
||
TPMS_PCR_SELECTION *allocated = NULL;
|
||
// If size of select is less than PCR_SELECT_MAX, zero the unspecified PCR
|
||
for(i = selection->sizeofSelect; i < PCR_SELECT_MAX; i++)
|
||
selection->pcrSelect[i] = 0;
|
||
// Find the internal configuration for the bank
|
||
for(i = 0; i < gp.pcrAllocated.count; i++)
|
||
{
|
||
if(gp.pcrAllocated.pcrSelections[i].hash == selection->hash)
|
||
{
|
||
allocated = &gp.pcrAllocated.pcrSelections[i];
|
||
break;
|
||
}
|
||
}
|
||
for (i = 0; i < selection->sizeofSelect; i++)
|
||
{
|
||
if(allocated == NULL)
|
||
{
|
||
// If the required bank does not exist, clear input selection
|
||
selection->pcrSelect[i] = 0;
|
||
}
|
||
else
|
||
selection->pcrSelect[i] &= allocated->pcrSelect[i];
|
||
}
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PcrDrtm()
|
||
//
|
||
// This function does the DRTM and H-CRTM processing it is called from _TPM_Hash_End().
|
||
//
|
||
void
|
||
PcrDrtm(
|
||
const TPMI_DH_PCR pcrHandle, // IN: the index of the PCR to be
|
||
// modified
|
||
const TPMI_ALG_HASH hash, // IN: the bank identifier
|
||
const TPM2B_DIGEST *digest // IN: the digest to modify the PCR
|
||
)
|
||
{
|
||
BYTE *pcrData = GetPcrPointer(hash, pcrHandle);
|
||
if(pcrData != NULL)
|
||
{
|
||
// Rest the PCR to zeros
|
||
MemorySet(pcrData, 0, digest->t.size);
|
||
// if the TPM has not started, then set the PCR to 0...04 and then extend
|
||
if(!TPMIsStarted())
|
||
{
|
||
pcrData[digest->t.size - 1] = 4;
|
||
}
|
||
// Now, extend the value
|
||
PCRExtend(pcrHandle, hash, digest->t.size, (BYTE *)digest->t.buffer);
|
||
}
|
||
}
|
||
//
|
||
//
|
||
// PCRStartup()
|
||
//
|
||
// This function initializes the PCR subsystem at TPM2_Startup().
|
||
//
|
||
void
|
||
PCRStartup(
|
||
STARTUP_TYPE type, // IN: startup type
|
||
BYTE locality // IN: startup locality
|
||
)
|
||
{
|
||
UINT32 pcr, j;
|
||
UINT32 saveIndex = 0;
|
||
g_pcrReConfig = FALSE;
|
||
if(type != SU_RESUME)
|
||
{
|
||
// PCR generation counter is cleared at TPM_RESET and TPM_RESTART
|
||
gr.pcrCounter = 0;
|
||
}
|
||
// Initialize/Restore PCR values
|
||
for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
|
||
{
|
||
// On resume, need to know if this PCR had its state saved or not
|
||
UINT32 stateSaved =
|
||
(type == SU_RESUME && s_initAttributes[pcr].stateSave == SET) ? 1 : 0;
|
||
// If this is the H-CRTM PCR and we are not doing a resume and we
|
||
// had an H-CRTM event, then we don't change this PCR
|
||
if(pcr == HCRTM_PCR && type != SU_RESUME && g_DrtmPreStartup == TRUE)
|
||
continue;
|
||
// Iterate each hash algorithm bank
|
||
for(j = 0; j < gp.pcrAllocated.count; j++)
|
||
{
|
||
TPMI_ALG_HASH hash = gp.pcrAllocated.pcrSelections[j].hash;
|
||
BYTE *pcrData = GetPcrPointer(hash, pcr);
|
||
UINT16 pcrSize = CryptGetHashDigestSize(hash);
|
||
if(pcrData != NULL)
|
||
{
|
||
// if state was saved
|
||
if(stateSaved == 1)
|
||
{
|
||
// Restore saved PCR value
|
||
BYTE *pcrSavedData;
|
||
pcrSavedData = GetSavedPcrPointer(
|
||
gp.pcrAllocated.pcrSelections[j].hash,
|
||
saveIndex);
|
||
MemoryCopy(pcrData, pcrSavedData, pcrSize, pcrSize);
|
||
}
|
||
else
|
||
// PCR was not restored by state save
|
||
{
|
||
// If the reset locality of the PCR is 4, then
|
||
// the reset value is all one's, otherwise it is
|
||
// all zero.
|
||
if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
|
||
MemorySet(pcrData, 0xFF, pcrSize);
|
||
else
|
||
{
|
||
MemorySet(pcrData, 0, pcrSize);
|
||
if(pcr == HCRTM_PCR)
|
||
pcrData[pcrSize-1] = locality;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
saveIndex += stateSaved;
|
||
}
|
||
// Reset authValues
|
||
if(type != SU_RESUME)
|
||
{
|
||
for(j = 0; j < NUM_AUTHVALUE_PCR_GROUP; j++)
|
||
{
|
||
gc.pcrAuthValues.auth[j].t.size = 0;
|
||
}
|
||
}
|
||
}
|
||
//
|
||
//
|
||
// PCRStateSave()
|
||
//
|
||
// This function is used to save the PCR values that will be restored on TPM Resume.
|
||
//
|
||
void
|
||
PCRStateSave(
|
||
TPM_SU type // IN: startup type
|
||
)
|
||
{
|
||
UINT32 pcr, j;
|
||
UINT32 saveIndex = 0;
|
||
//
|
||
// if state save CLEAR, nothing to be done. Return here
|
||
if(type == TPM_SU_CLEAR) return;
|
||
// Copy PCR values to the structure that should be saved to NV
|
||
for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
|
||
{
|
||
UINT32 stateSaved = (s_initAttributes[pcr].stateSave == SET) ? 1 : 0;
|
||
// Iterate each hash algorithm bank
|
||
for(j = 0; j < gp.pcrAllocated.count; j++)
|
||
{
|
||
BYTE *pcrData;
|
||
UINT32 pcrSize;
|
||
pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[j].hash, pcr);
|
||
if(pcrData != NULL)
|
||
{
|
||
pcrSize
|
||
= CryptGetHashDigestSize(gp.pcrAllocated.pcrSelections[j].hash);
|
||
if(stateSaved == 1)
|
||
{
|
||
// Restore saved PCR value
|
||
BYTE *pcrSavedData;
|
||
pcrSavedData
|
||
= GetSavedPcrPointer(gp.pcrAllocated.pcrSelections[j].hash,
|
||
saveIndex);
|
||
MemoryCopy(pcrSavedData, pcrData, pcrSize, pcrSize);
|
||
}
|
||
}
|
||
}
|
||
saveIndex += stateSaved;
|
||
}
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PCRIsStateSaved()
|
||
//
|
||
// This function indicates if the selected PCR is a PCR that is state saved on TPM2_Shutdown(STATE). The
|
||
// return value is based on PCR attributes.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE PCR is state saved
|
||
// FALSE PCR is not state saved
|
||
//
|
||
BOOL
|
||
PCRIsStateSaved(
|
||
TPMI_DH_PCR handle // IN: PCR handle to be extended
|
||
)
|
||
{
|
||
UINT32 pcr = handle - PCR_FIRST;
|
||
if(s_initAttributes[pcr].stateSave == SET)
|
||
return TRUE;
|
||
else
|
||
return FALSE;
|
||
}
|
||
//
|
||
//
|
||
//
|
||
// PCRIsResetAllowed()
|
||
//
|
||
// This function indicates if a PCR may be reset by the current command locality. The return value is based
|
||
// on PCR attributes, and not the PCR allocation.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE TPM2_PCR_Reset() is allowed
|
||
// FALSE TPM2_PCR_Reset() is not allowed
|
||
//
|
||
BOOL
|
||
PCRIsResetAllowed(
|
||
TPMI_DH_PCR handle // IN: PCR handle to be extended
|
||
)
|
||
{
|
||
UINT8 commandLocality;
|
||
UINT8 localityBits = 1;
|
||
UINT32 pcr = handle - PCR_FIRST;
|
||
// Check for the locality
|
||
commandLocality = _plat__LocalityGet();
|
||
#ifdef DRTM_PCR
|
||
// For a TPM that does DRTM, Reset is not allowed at locality 4
|
||
if(commandLocality == 4)
|
||
return FALSE;
|
||
#endif
|
||
localityBits = localityBits << commandLocality;
|
||
if((localityBits & s_initAttributes[pcr].resetLocality) == 0)
|
||
return FALSE;
|
||
else
|
||
return TRUE;
|
||
}
|
||
//
|
||
//
|
||
// PCRChanged()
|
||
//
|
||
// This function checks a PCR handle to see if the attributes for the PCR are set so that any change to the
|
||
// PCR causes an increment of the pcrCounter. If it does, then the function increments the counter.
|
||
//
|
||
void
|
||
PCRChanged(
|
||
TPM_HANDLE pcrHandle // IN: the handle of the PCR that changed.
|
||
)
|
||
{
|
||
// For the reference implementation, the only change that does not cause
|
||
// increment is a change to a PCR in the TCB group.
|
||
if(!PCRBelongsTCBGroup(pcrHandle))
|
||
gr.pcrCounter++;
|
||
}
|
||
//
|
||
//
|
||
// PCRIsExtendAllowed()
|
||
//
|
||
// This function indicates a PCR may be extended at the current command locality. The return value is
|
||
// based on PCR attributes, and not the PCR allocation.
|
||
//
|
||
//
|
||
//
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE extend is allowed
|
||
// FALSE extend is not allowed
|
||
//
|
||
BOOL
|
||
PCRIsExtendAllowed(
|
||
TPMI_DH_PCR handle // IN: PCR handle to be extended
|
||
)
|
||
{
|
||
UINT8 commandLocality;
|
||
UINT8 localityBits = 1;
|
||
UINT32 pcr = handle - PCR_FIRST;
|
||
// Check for the locality
|
||
commandLocality = _plat__LocalityGet();
|
||
localityBits = localityBits << commandLocality;
|
||
if((localityBits & s_initAttributes[pcr].extendLocality) == 0)
|
||
return FALSE;
|
||
else
|
||
return TRUE;
|
||
}
|
||
//
|
||
//
|
||
// PCRExtend()
|
||
//
|
||
// This function is used to extend a PCR in a specific bank.
|
||
//
|
||
void
|
||
PCRExtend(
|
||
TPMI_DH_PCR handle, // IN: PCR handle to be extended
|
||
TPMI_ALG_HASH hash, // IN: hash algorithm of PCR
|
||
UINT32 size, // IN: size of data to be extended
|
||
BYTE *data // IN: data to be extended
|
||
)
|
||
{
|
||
UINT32 pcr = handle - PCR_FIRST;
|
||
BYTE *pcrData;
|
||
HASH_STATE hashState;
|
||
UINT16 pcrSize;
|
||
pcrData = GetPcrPointer(hash, pcr);
|
||
// Extend PCR if it is allocated
|
||
if(pcrData != NULL)
|
||
{
|
||
pcrSize = CryptGetHashDigestSize(hash);
|
||
CryptStartHash(hash, &hashState);
|
||
CryptUpdateDigest(&hashState, pcrSize, pcrData);
|
||
CryptUpdateDigest(&hashState, size, data);
|
||
CryptCompleteHash(&hashState, pcrSize, pcrData);
|
||
// If PCR does not belong to TCB group, increment PCR counter
|
||
if(!PCRBelongsTCBGroup(handle))
|
||
gr.pcrCounter++;
|
||
}
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
//
|
||
// PCRComputeCurrentDigest()
|
||
//
|
||
// This function computes the digest of the selected PCR.
|
||
// As a side-effect, selection is modified so that only the implemented PCR will have their bits still set.
|
||
//
|
||
void
|
||
PCRComputeCurrentDigest(
|
||
TPMI_ALG_HASH hashAlg, // IN: hash algorithm to compute digest
|
||
TPML_PCR_SELECTION *selection, // IN/OUT: PCR selection (filtered on
|
||
// output)
|
||
TPM2B_DIGEST *digest // OUT: digest
|
||
)
|
||
{
|
||
HASH_STATE hashState;
|
||
TPMS_PCR_SELECTION *select;
|
||
BYTE *pcrData; // will point to a digest
|
||
UINT32 pcrSize;
|
||
UINT32 pcr;
|
||
UINT32 i;
|
||
// Initialize the hash
|
||
digest->t.size = CryptStartHash(hashAlg, &hashState);
|
||
pAssert(digest->t.size > 0 && digest->t.size < UINT16_MAX);
|
||
// Iterate through the list of PCR selection structures
|
||
for(i = 0; i < selection->count; i++)
|
||
{
|
||
// Point to the current selection
|
||
select = &selection->pcrSelections[i]; // Point to the current selection
|
||
FilterPcr(select); // Clear out the bits for unimplemented PCR
|
||
// Need the size of each digest
|
||
pcrSize = CryptGetHashDigestSize(selection->pcrSelections[i].hash);
|
||
// Iterate through the selection
|
||
for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
|
||
{
|
||
if(IsPcrSelected(pcr, select)) // Is this PCR selected
|
||
{
|
||
// Get pointer to the digest data for the bank
|
||
pcrData = GetPcrPointer(selection->pcrSelections[i].hash, pcr);
|
||
pAssert(pcrData != NULL);
|
||
CryptUpdateDigest(&hashState, pcrSize, pcrData); // add to digest
|
||
}
|
||
}
|
||
}
|
||
// Complete hash stack
|
||
CryptCompleteHash2B(&hashState, &digest->b);
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PCRRead()
|
||
//
|
||
// This function is used to read a list of selected PCR. If the requested PCR number exceeds the maximum
|
||
// number that can be output, the selection is adjusted to reflect the actual output PCR.
|
||
//
|
||
void
|
||
PCRRead(
|
||
TPML_PCR_SELECTION *selection, // IN/OUT: PCR selection (filtered on
|
||
// output)
|
||
TPML_DIGEST *digest, // OUT: digest
|
||
UINT32 *pcrCounter // OUT: the current value of PCR generation
|
||
// number
|
||
)
|
||
{
|
||
TPMS_PCR_SELECTION *select;
|
||
BYTE *pcrData; // will point to a digest
|
||
UINT32 pcr;
|
||
UINT32 i;
|
||
digest->count = 0;
|
||
// Iterate through the list of PCR selection structures
|
||
for(i = 0; i < selection->count; i++)
|
||
{
|
||
// Point to the current selection
|
||
select = &selection->pcrSelections[i]; // Point to the current selection
|
||
FilterPcr(select); // Clear out the bits for unimplemented PCR
|
||
// Iterate through the selection
|
||
for (pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
|
||
{
|
||
if(IsPcrSelected(pcr, select)) // Is this PCR selected
|
||
{
|
||
// Check if number of digest exceed upper bound
|
||
if(digest->count > 7)
|
||
{
|
||
// Clear rest of the current select bitmap
|
||
while( pcr < IMPLEMENTATION_PCR
|
||
// do not round up!
|
||
&& (pcr / 8) < select->sizeofSelect)
|
||
{
|
||
// do not round up!
|
||
select->pcrSelect[pcr/8] &= (BYTE) ~(1 << (pcr % 8));
|
||
pcr++;
|
||
}
|
||
// Exit inner loop
|
||
break;;
|
||
}
|
||
// Need the size of each digest
|
||
digest->digests[digest->count].t.size =
|
||
CryptGetHashDigestSize(selection->pcrSelections[i].hash);
|
||
// Get pointer to the digest data for the bank
|
||
pcrData = GetPcrPointer(selection->pcrSelections[i].hash, pcr);
|
||
pAssert(pcrData != NULL);
|
||
// Add to the data to digest
|
||
MemoryCopy(digest->digests[digest->count].t.buffer,
|
||
pcrData,
|
||
digest->digests[digest->count].t.size,
|
||
digest->digests[digest->count].t.size);
|
||
digest->count++;
|
||
}
|
||
}
|
||
// If we exit inner loop because we have exceed the output upper bound
|
||
if(digest->count > 7 && pcr < IMPLEMENTATION_PCR)
|
||
{
|
||
// Clear rest of the selection
|
||
while(i < selection->count)
|
||
{
|
||
MemorySet(selection->pcrSelections[i].pcrSelect, 0,
|
||
selection->pcrSelections[i].sizeofSelect);
|
||
i++;
|
||
}
|
||
// exit outer loop
|
||
break;
|
||
}
|
||
}
|
||
*pcrCounter = gr.pcrCounter;
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PcrWrite()
|
||
//
|
||
// This function is used by _TPM_Hash_End() to set a PCR to the computed hash of the H-CRTM event.
|
||
//
|
||
void
|
||
PcrWrite(
|
||
TPMI_DH_PCR handle, // IN: PCR handle to be extended
|
||
TPMI_ALG_HASH hash, // IN: hash algorithm of PCR
|
||
TPM2B_DIGEST *digest // IN: the new value
|
||
)
|
||
{
|
||
UINT32 pcr = handle - PCR_FIRST;
|
||
BYTE *pcrData;
|
||
// Copy value to the PCR if it is allocated
|
||
pcrData = GetPcrPointer(hash, pcr);
|
||
if(pcrData != NULL)
|
||
{
|
||
MemoryCopy(pcrData, digest->t.buffer, digest->t.size, digest->t.size); ;
|
||
}
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PCRAllocate()
|
||
//
|
||
// This function is used to change the PCR allocation.
|
||
//
|
||
// Error Returns Meaning
|
||
//
|
||
// TPM_RC_SUCCESS allocate success
|
||
// TPM_RC_NO_RESULTS allocate failed
|
||
// TPM_RC_PCR improper allocation
|
||
//
|
||
TPM_RC
|
||
PCRAllocate(
|
||
TPML_PCR_SELECTION *allocate, // IN: required allocation
|
||
UINT32 *maxPCR, // OUT: Maximum number of PCR
|
||
UINT32 *sizeNeeded, // OUT: required space
|
||
UINT32 *sizeAvailable // OUT: available space
|
||
)
|
||
{
|
||
UINT32 i, j, k;
|
||
TPML_PCR_SELECTION newAllocate;
|
||
// Initialize the flags to indicate if HCRTM PCR and DRTM PCR are allocated.
|
||
BOOL pcrHcrtm = FALSE;
|
||
BOOL pcrDrtm = FALSE;
|
||
// Create the expected new PCR allocation based on the existing allocation
|
||
// and the new input:
|
||
// 1. if a PCR bank does not appear in the new allocation, the existing
|
||
// allocation of this PCR bank will be preserved.
|
||
// 2. if a PCR bank appears multiple times in the new allocation, only the
|
||
// last one will be in effect.
|
||
newAllocate = gp.pcrAllocated;
|
||
for(i = 0; i < allocate->count; i++)
|
||
{
|
||
for(j = 0; j < newAllocate.count; j++)
|
||
{
|
||
// If hash matches, the new allocation covers the old allocation
|
||
// for this particular bank.
|
||
// The assumption is the initial PCR allocation (from manufacture)
|
||
// has all the supported hash algorithms with an assigned bank
|
||
// (possibly empty). So there must be a match for any new bank
|
||
// allocation from the input.
|
||
if(newAllocate.pcrSelections[j].hash ==
|
||
allocate->pcrSelections[i].hash)
|
||
{
|
||
newAllocate.pcrSelections[j] = allocate->pcrSelections[i];
|
||
break;
|
||
}
|
||
}
|
||
// The j loop must exit with a match.
|
||
pAssert(j < newAllocate.count);
|
||
}
|
||
// Max PCR in a bank is MIN(implemented PCR, PCR with attributes defined)
|
||
*maxPCR = sizeof(s_initAttributes) / sizeof(PCR_Attributes);
|
||
if(*maxPCR > IMPLEMENTATION_PCR)
|
||
*maxPCR = IMPLEMENTATION_PCR;
|
||
// Compute required size for allocation
|
||
*sizeNeeded = 0;
|
||
for(i = 0; i < newAllocate.count; i++)
|
||
{
|
||
UINT32 digestSize
|
||
= CryptGetHashDigestSize(newAllocate.pcrSelections[i].hash);
|
||
#if defined(DRTM_PCR)
|
||
// Make sure that we end up with at least one DRTM PCR
|
||
# define PCR_DRTM (PCR_FIRST + DRTM_PCR) // for cosmetics
|
||
pcrDrtm = pcrDrtm || TEST_BIT(PCR_DRTM, newAllocate.pcrSelections[i]);
|
||
#else // if DRTM PCR is not required, indicate that the allocation is OK
|
||
pcrDrtm = TRUE;
|
||
#endif
|
||
#if defined(HCRTM_PCR)
|
||
// and one HCRTM PCR (since this is usually PCR 0...)
|
||
# define PCR_HCRTM (PCR_FIRST + HCRTM_PCR)
|
||
pcrHcrtm = pcrDrtm || TEST_BIT(PCR_HCRTM, newAllocate.pcrSelections[i]);
|
||
#else
|
||
pcrHcrtm = TRUE;
|
||
#endif
|
||
for(j = 0; j < newAllocate.pcrSelections[i].sizeofSelect; j++)
|
||
{
|
||
BYTE mask = 1;
|
||
for(k = 0; k < 8; k++)
|
||
{
|
||
if((newAllocate.pcrSelections[i].pcrSelect[j] & mask) != 0)
|
||
*sizeNeeded += digestSize;
|
||
mask = mask << 1;
|
||
}
|
||
}
|
||
}
|
||
if(!pcrDrtm || !pcrHcrtm)
|
||
return TPM_RC_PCR;
|
||
// In this particular implementation, we always have enough space to
|
||
// allocate PCR. Different implementation may return a sizeAvailable less
|
||
// than the sizeNeed.
|
||
*sizeAvailable = sizeof(s_pcrs);
|
||
// Save the required allocation to NV. Note that after NV is written, the
|
||
// PCR allocation in NV is no longer consistent with the RAM data
|
||
// gp.pcrAllocated. The NV version reflect the allocate after next
|
||
// TPM_RESET, while the RAM version reflects the current allocation
|
||
NvWriteReserved(NV_PCR_ALLOCATED, &newAllocate);
|
||
return TPM_RC_SUCCESS;
|
||
}
|
||
//
|
||
//
|
||
// PCRSetValue()
|
||
//
|
||
// This function is used to set the designated PCR in all banks to an initial value. The initial value is signed
|
||
// and will be sign extended into the entire PCR.
|
||
//
|
||
void
|
||
PCRSetValue(
|
||
TPM_HANDLE handle, // IN: the handle of the PCR to set
|
||
INT8 initialValue // IN: the value to set
|
||
)
|
||
{
|
||
int i;
|
||
UINT32 pcr = handle - PCR_FIRST;
|
||
TPMI_ALG_HASH hash;
|
||
UINT16 digestSize;
|
||
BYTE *pcrData;
|
||
// Iterate supported PCR bank algorithms to reset
|
||
for(i = 0; i < HASH_COUNT; i++)
|
||
{
|
||
hash = CryptGetHashAlgByIndex(i);
|
||
// Prevent runaway
|
||
if(hash == TPM_ALG_NULL)
|
||
break;
|
||
// Get a pointer to the data
|
||
pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr);
|
||
// If the PCR is allocated
|
||
if(pcrData != NULL)
|
||
{
|
||
// And the size of the digest
|
||
digestSize = CryptGetHashDigestSize(hash);
|
||
// Set the LSO to the input value
|
||
pcrData[digestSize - 1] = initialValue;
|
||
// Sign extend
|
||
if(initialValue >= 0)
|
||
MemorySet(pcrData, 0, digestSize - 1);
|
||
else
|
||
MemorySet(pcrData, -1, digestSize - 1);
|
||
}
|
||
}
|
||
}
|
||
//
|
||
//
|
||
// PCRResetDynamics
|
||
//
|
||
// This function is used to reset a dynamic PCR to 0. This function is used in DRTM sequence.
|
||
//
|
||
void
|
||
PCRResetDynamics(
|
||
void
|
||
)
|
||
{
|
||
UINT32 pcr, i;
|
||
// Initialize PCR values
|
||
for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
|
||
{
|
||
// Iterate each hash algorithm bank
|
||
for(i = 0; i < gp.pcrAllocated.count; i++)
|
||
{
|
||
BYTE *pcrData;
|
||
UINT32 pcrSize;
|
||
pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr);
|
||
if(pcrData != NULL)
|
||
{
|
||
pcrSize =
|
||
CryptGetHashDigestSize(gp.pcrAllocated.pcrSelections[i].hash);
|
||
// Reset PCR
|
||
// Any PCR can be reset by locality 4 should be reset to 0
|
||
if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
|
||
MemorySet(pcrData, 0, pcrSize);
|
||
}
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PCRCapGetAllocation()
|
||
//
|
||
// This function is used to get the current allocation of PCR banks.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// YES: if the return count is 0
|
||
// NO: if the return count is not 0
|
||
//
|
||
TPMI_YES_NO
|
||
PCRCapGetAllocation(
|
||
UINT32 count, // IN: count of return
|
||
TPML_PCR_SELECTION *pcrSelection // OUT: PCR allocation list
|
||
)
|
||
{
|
||
if(count == 0)
|
||
{
|
||
pcrSelection->count = 0;
|
||
return YES;
|
||
}
|
||
else
|
||
{
|
||
*pcrSelection = gp.pcrAllocated;
|
||
return NO;
|
||
}
|
||
}
|
||
//
|
||
//
|
||
// PCRSetSelectBit()
|
||
//
|
||
// This function sets a bit in a bitmap array.
|
||
//
|
||
static void
|
||
PCRSetSelectBit(
|
||
UINT32 pcr, // IN: PCR number
|
||
BYTE *bitmap // OUT: bit map to be set
|
||
)
|
||
{
|
||
bitmap[pcr / 8] |= (1 << (pcr % 8));
|
||
return;
|
||
}
|
||
//
|
||
//
|
||
// PCRGetProperty()
|
||
//
|
||
// This function returns the selected PCR property.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// TRUE the property type is implemented
|
||
// FALSE the property type is not implemented
|
||
//
|
||
static BOOL
|
||
PCRGetProperty(
|
||
TPM_PT_PCR property,
|
||
TPMS_TAGGED_PCR_SELECT *select
|
||
)
|
||
{
|
||
UINT32 pcr;
|
||
UINT32 groupIndex;
|
||
select->tag = property;
|
||
// Always set the bitmap to be the size of all PCR
|
||
select->sizeofSelect = (IMPLEMENTATION_PCR + 7) / 8;
|
||
// Initialize bitmap
|
||
MemorySet(select->pcrSelect, 0, select->sizeofSelect);
|
||
// Collecting properties
|
||
for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
|
||
{
|
||
switch(property)
|
||
{
|
||
case TPM_PT_PCR_SAVE:
|
||
if(s_initAttributes[pcr].stateSave == SET)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_EXTEND_L0:
|
||
if((s_initAttributes[pcr].extendLocality & 0x01) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_RESET_L0:
|
||
if((s_initAttributes[pcr].resetLocality & 0x01) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_EXTEND_L1:
|
||
if((s_initAttributes[pcr].extendLocality & 0x02) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_RESET_L1:
|
||
if((s_initAttributes[pcr].resetLocality & 0x02) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_EXTEND_L2:
|
||
if((s_initAttributes[pcr].extendLocality & 0x04) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
//
|
||
break;
|
||
case TPM_PT_PCR_RESET_L2:
|
||
if((s_initAttributes[pcr].resetLocality & 0x04) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_EXTEND_L3:
|
||
if((s_initAttributes[pcr].extendLocality & 0x08) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_RESET_L3:
|
||
if((s_initAttributes[pcr].resetLocality & 0x08) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_EXTEND_L4:
|
||
if((s_initAttributes[pcr].extendLocality & 0x10) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_RESET_L4:
|
||
if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
case TPM_PT_PCR_DRTM_RESET:
|
||
// DRTM reset PCRs are the PCR reset by locality 4
|
||
if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
#if NUM_POLICY_PCR_GROUP > 0
|
||
case TPM_PT_PCR_POLICY:
|
||
if(PCRBelongsPolicyGroup(pcr + PCR_FIRST, &groupIndex))
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
#endif
|
||
#if NUM_AUTHVALUE_PCR_GROUP > 0
|
||
case TPM_PT_PCR_AUTH:
|
||
if(PCRBelongsAuthGroup(pcr + PCR_FIRST, &groupIndex))
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
#endif
|
||
#if ENABLE_PCR_NO_INCREMENT == YES
|
||
case TPM_PT_PCR_NO_INCREMENT:
|
||
if(PCRBelongsTCBGroup(pcr + PCR_FIRST))
|
||
PCRSetSelectBit(pcr, select->pcrSelect);
|
||
break;
|
||
#endif
|
||
default:
|
||
// If property is not supported, stop scanning PCR attributes
|
||
// and return.
|
||
return FALSE;
|
||
break;
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
//
|
||
//
|
||
// PCRCapGetProperties()
|
||
//
|
||
// This function returns a list of PCR properties starting at property.
|
||
//
|
||
//
|
||
//
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// YES: if no more property is available
|
||
// NO: if there are more properties not reported
|
||
//
|
||
TPMI_YES_NO
|
||
PCRCapGetProperties(
|
||
TPM_PT_PCR property, // IN: the starting PCR property
|
||
UINT32 count, // IN: count of returned propertie
|
||
TPML_TAGGED_PCR_PROPERTY *select // OUT: PCR select
|
||
)
|
||
{
|
||
TPMI_YES_NO more = NO;
|
||
UINT32 i;
|
||
// Initialize output property list
|
||
select->count = 0;
|
||
// The maximum count of properties we may return is MAX_PCR_PROPERTIES
|
||
if(count > MAX_PCR_PROPERTIES) count = MAX_PCR_PROPERTIES;
|
||
// TPM_PT_PCR_FIRST is defined as 0 in spec. It ensures that property
|
||
// value would never be less than TPM_PT_PCR_FIRST
|
||
pAssert(TPM_PT_PCR_FIRST == 0);
|
||
// Iterate PCR properties. TPM_PT_PCR_LAST is the index of the last property
|
||
// implemented on the TPM.
|
||
for(i = property; i <= TPM_PT_PCR_LAST; i++)
|
||
{
|
||
if(select->count < count)
|
||
{
|
||
// If we have not filled up the return list, add more properties to it
|
||
if(PCRGetProperty(i, &select->pcrProperty[select->count]))
|
||
// only increment if the property is implemented
|
||
select->count++;
|
||
}
|
||
else
|
||
{
|
||
// If the return list is full but we still have properties
|
||
// available, report this and stop iterating.
|
||
more = YES;
|
||
break;
|
||
}
|
||
}
|
||
return more;
|
||
}
|
||
//
|
||
//
|
||
// PCRCapGetHandles()
|
||
//
|
||
// This function is used to get a list of handles of PCR, started from handle. If handle exceeds the maximum
|
||
// PCR handle range, an empty list will be returned and the return value will be NO.
|
||
//
|
||
// Return Value Meaning
|
||
//
|
||
// YES if there are more handles available
|
||
// NO all the available handles has been returned
|
||
//
|
||
TPMI_YES_NO
|
||
PCRCapGetHandles(
|
||
TPMI_DH_PCR handle, // IN: start handle
|
||
UINT32 count, // IN: count of returned handle
|
||
TPML_HANDLE *handleList // OUT: list of handle
|
||
)
|
||
{
|
||
TPMI_YES_NO more = NO;
|
||
UINT32 i;
|
||
pAssert(HandleGetType(handle) == TPM_HT_PCR);
|
||
// Initialize output handle list
|
||
handleList->count = 0;
|
||
// The maximum count of handles we may return is MAX_CAP_HANDLES
|
||
if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
|
||
// Iterate PCR handle range
|
||
for(i = handle & HR_HANDLE_MASK; i <= PCR_LAST; i++)
|
||
{
|
||
if(handleList->count < count)
|
||
{
|
||
// If we have not filled up the return list, add this PCR
|
||
// handle to it
|
||
handleList->handle[handleList->count] = i + PCR_FIRST;
|
||
handleList->count++;
|
||
}
|
||
else
|
||
{
|
||
// If the return list is full but we still have PCR handle
|
||
// available, report this and stop iterating
|
||
more = YES;
|
||
break;
|
||
}
|
||
}
|
||
return more;
|
||
}
|