aboutsummaryrefslogtreecommitdiff
path: root/PCR.c
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2015-05-20 10:32:25 -0700
committerVadim Bendebury <vbendeb@chromium.org>2015-05-20 22:32:05 -0700
commit5679752bf24c21135884e987c4077e2f71848971 (patch)
tree3e680dd91a7af84c45ea1170ee88225bd4ad32c8 /PCR.c
downloadtpm2-5679752bf24c21135884e987c4077e2f71848971.tar.gz
Initial commit to seed TPM2.0 source code directory
LICENSE file text copied from TCG library specification. README describes the procedure used to extract source code from parts 3 and 4 of the specification. The python scripts and part{34}.txt files will be removed in the following commits. Change-Id: Ie281e6e988481831f33483053455e8aff8f3f75f Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Diffstat (limited to 'PCR.c')
-rw-r--r--PCR.c1305
1 files changed, 1305 insertions, 0 deletions
diff --git a/PCR.c b/PCR.c
new file mode 100644
index 0000000..84aac03
--- /dev/null
+++ b/PCR.c
@@ -0,0 +1,1305 @@
+// 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, 0x14, 0x0E}, // PCR 20, Locality 1
+ {0, 0x14, 0x04}, // PCR 21, Dynamic OS
+ {0, 0x14, 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
+)
+{
+#if NUM_AUTHVALUE_PCR_GROUP > 0
+ // Platform specification determines to which auth group a PCR belongs (if
+ // any). In this implementation, we assume there is only
+ // one auth group which contains PCR[20-22]. If the platform specification
+ // requires differently, the implementation should be changed accordingly
+ if(handle >= 20 && handle <= 22)
+ {
+ *groupIndex = 0;
+ return TRUE;
+ }
+#endif
+ 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
+ )
+{
+#if NUM_POLICY_PCR_GROUP > 0
+ // Platform specification decides if a PCR belongs to a policy group and
+ // belongs to which group. In this implementation, we assume there is only
+ // one policy group which contains PCR20-22. If the platform specification
+ // requires differently, the implementation should be changed accordingly
+ if(handle >= 20 && handle <= 22)
+ {
+ *groupIndex = 0;
+ return TRUE;
+ }
+#endif
+ 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[20-22] belong to TCB group. If the platform
+ // specification requires differently, the implementation should be
+ // changed accordingly
+ if(handle >= 20 && handle <= 22)
+ 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; // Can't be 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;
+}