1// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 4: Supporting Routines
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
8#define PCR_C
9#include "InternalRoutines.h"
10#include "Platform.h"
11//
12//      The initial value of PCR attributes. The value of these fields should be consistent with PC Client
13//      specification In this implementation, we assume the total number of implemented PCR is 24.
14//
15static const PCR_Attributes s_initAttributes[] =
16{
17    // PCR    0 - 15, static RTM
18    {1, 0,    0x1F}, {1, 0, 0x1F},     {1,   0,    0x1F},   {1,   0,   0x1F},
19    {1, 0,    0x1F}, {1, 0, 0x1F},     {1,   0,    0x1F},   {1,   0,   0x1F},
20    {1, 0,    0x1F}, {1, 0, 0x1F},     {1,   0,    0x1F},   {1,   0,   0x1F},
21    {1, 0,    0x1F}, {1, 0, 0x1F},     {1,   0,    0x1F},   {1,   0,   0x1F},
22    {0,   0x0F,   0x1F},         //   PCR    16,   Debug
23    {0,   0x10,   0x1C},         //   PCR    17,   Locality 4
24    {0,   0x10,   0x1C},         //   PCR    18,   Locality 3
25    {0,   0x10,   0x0C},         //   PCR    19,   Locality 2
26    {0,   0x1C,   0x0E},         //   PCR    20,   Locality 1
27    {0,   0x1C,   0x04},         //   PCR    21,   Dynamic OS
28    {0,   0x1C,   0x04},         //   PCR    22,   Dynamic OS
29    {0,   0x0F,   0x1F},         //   PCR    23,   App specific
30    {0,   0x0F,   0x1F}          //   PCR    24,   testing policy
31};
32//
33//
34//           Functions
35//
36//          PCRBelongsAuthGroup()
37//
38//     This function indicates if a PCR belongs to a group that requires an authValue in order to modify the
39//     PCR. If it does, groupIndex is set to value of the group index. This feature of PCR is decided by the
40//     platform specification.
41//
42//     Return Value                    Meaning
43//
44//     TRUE:                           PCR belongs an auth group
45//     FALSE:                          PCR does not belong an auth group
46//
47BOOL
48PCRBelongsAuthGroup(
49    TPMI_DH_PCR          handle,              // IN: handle of PCR
50    UINT32              *groupIndex           // OUT: group index if PCR belongs a
51                                              //      group that allows authValue. If PCR
52                                              //      does not belong to an auth group,
53                                              //      the value in this parameter is
54                                              //      invalid
55)
56{
57  // None of the PCRs belong to a group requiring an authValue, as defined in
58  // Table 4 "PCR Attributes" of the "TCG PC Client Platform TPM Profile (TPT)
59  // Specification Level 00 Revision 00.43".
60  return FALSE;
61}
62//
63//
64//          PCRBelongsPolicyGroup()
65//
66//     This function indicates if a PCR belongs to a group that requires a policy authorization in order to modify
67//     the PCR. If it does, groupIndex is set to value of the group index. This feature of PCR is decided by the
68//     platform specification.
69//     Family "2.0"                                   TCG Published                                          Page 169
70//     Level 00 Revision 01.16                Copyright © TCG 2006-2014                             October 30, 2014
71//     Trusted Platform Module Library                                          Part 4: Supporting Routines
72//
73//
74//     Return Value                      Meaning
75//
76//     TRUE:                             PCR belongs a policy group
77//     FALSE:                            PCR does not belong a policy group
78//
79BOOL
80PCRBelongsPolicyGroup(
81    TPMI_DH_PCR           handle,            // IN: handle of PCR
82    UINT32               *groupIndex         // OUT: group index if PCR belongs a group that
83                                             //     allows policy. If PCR does not belong to
84                                             //     a policy group, the value in this
85                                             //     parameter is invalid
86   )
87{
88  // None of the PCRs belong to the policy group, as defined in Table 4
89  // "PCR Attributes" of the "TCG PC Client Platform TPM Profile (TPT)
90  // Specification Level 00 Revision 00.43".
91  return FALSE;
92}
93//
94//
95//           PCRBelongsTCBGroup()
96//
97//     This function indicates if a PCR belongs to the TCB group.
98//
99//     Return Value                      Meaning
100//
101//     TRUE:                             PCR belongs to TCB group
102//     FALSE:                            PCR does not belong to TCB group
103//
104static BOOL
105PCRBelongsTCBGroup(
106    TPMI_DH_PCR           handle             // IN: handle of PCR
107    )
108{
109#if ENABLE_PCR_NO_INCREMENT == YES
110  // Platform specification decides if a PCR belongs to a TCB group. In this
111  // implementation, we assume PCR[16, 21-23] belong to TCB group as defined
112  // in Table 4. If the platform specification requires differently, the
113  // implementation should be changed accordingly
114  if(handle == 16 || (handle >= 21 && handle <= 23))
115    return TRUE;
116#endif
117   return FALSE;
118}
119//
120//
121//           PCRPolicyIsAvailable()
122//
123//     This function indicates if a policy is available for a PCR.
124//
125//
126//
127//
128//      Return Value                     Meaning
129//
130//      TRUE                             the PCR should be authorized by policy
131//      FALSE                            the PCR does not allow policy
132//
133BOOL
134PCRPolicyIsAvailable(
135    TPMI_DH_PCR          handle             // IN: PCR handle
136    )
137{
138    UINT32              groupIndex;
139    return PCRBelongsPolicyGroup(handle, &groupIndex);
140}
141//
142//
143//           PCRGetAuthValue()
144//
145//      This function is used to access the authValue of a PCR. If PCR does not belong to an authValue group,
146//      an Empty Auth will be returned.
147//
148void
149PCRGetAuthValue(
150    TPMI_DH_PCR          handle,            // IN: PCR handle
151    TPM2B_AUTH          *auth               // OUT: authValue of PCR
152    )
153{
154    UINT32         groupIndex;
155    if(PCRBelongsAuthGroup(handle, &groupIndex))
156    {
157        *auth = gc.pcrAuthValues.auth[groupIndex];
158    }
159    else
160    {
161        auth->t.size = 0;
162    }
163    return;
164}
165//
166//
167//           PCRGetAuthPolicy()
168//
169//      This function is used to access the authorization policy of a PCR. It sets policy to the authorization policy
170//      and returns the hash algorithm for policy If the PCR does not allow a policy, TPM_ALG_NULL is returned.
171//
172TPMI_ALG_HASH
173PCRGetAuthPolicy(
174    TPMI_DH_PCR          handle,            // IN: PCR handle
175    TPM2B_DIGEST        *policy             // OUT: policy of PCR
176    )
177{
178    UINT32               groupIndex;
179    if(PCRBelongsPolicyGroup(handle, &groupIndex))
180    {
181        *policy = gp.pcrPolicies.policy[groupIndex];
182        return gp.pcrPolicies.hashAlg[groupIndex];
183    }
184    else
185    {
186        policy->t.size = 0;
187          return TPM_ALG_NULL;
188   }
189}
190//
191//
192//            PCRSimStart()
193//
194//      This function is used to initialize the policies when a TPM is manufactured. This function would only be
195//      called in a manufacturing environment or in a TPM simulator.
196//
197void
198PCRSimStart(
199   void
200   )
201{
202   UINT32 i;
203   for(i = 0; i < NUM_POLICY_PCR_GROUP; i++)
204   {
205       gp.pcrPolicies.hashAlg[i] = TPM_ALG_NULL;
206       gp.pcrPolicies.policy[i].t.size = 0;
207   }
208   for(i = 0; i < NUM_AUTHVALUE_PCR_GROUP; i++)
209   {
210       gc.pcrAuthValues.auth[i].t.size = 0;
211   }
212   // We need to give an initial configuration on allocated PCR before
213   // receiving any TPM2_PCR_Allocate command to change this configuration
214   // When the simulation environment starts, we allocate all the PCRs
215   for(gp.pcrAllocated.count = 0; gp.pcrAllocated.count < HASH_COUNT;
216           gp.pcrAllocated.count++)
217   {
218       gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].hash
219           = CryptGetHashAlgByIndex(gp.pcrAllocated.count);
220          gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].sizeofSelect
221              = PCR_SELECT_MAX;
222          for(i = 0; i < PCR_SELECT_MAX; i++)
223              gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].pcrSelect[i]
224                  = 0xFF;
225   }
226   // Store the initial configuration to NV
227   NvWriteReserved(NV_PCR_POLICIES, &gp.pcrPolicies);
228   NvWriteReserved(NV_PCR_ALLOCATED, &gp.pcrAllocated);
229   return;
230}
231//
232//
233//            GetSavedPcrPointer()
234//
235//      This function returns the address of an array of state saved PCR based on the hash algorithm.
236//
237//      Return Value                      Meaning
238//
239//      NULL                              no such algorithm
240//      not NULL                          pointer to the 0th byte of the 0th PCR
241//
242static BYTE *
243GetSavedPcrPointer (
244   TPM_ALG_ID           alg,                 // IN: algorithm for bank
245   UINT32               pcrIndex             // IN: PCR index in PCR_SAVE
246    )
247{
248   switch(alg)
249   {
250#ifdef TPM_ALG_SHA1
251   case TPM_ALG_SHA1:
252       return gc.pcrSave.sha1[pcrIndex];
253       break;
254#endif
255#ifdef TPM_ALG_SHA256
256   case TPM_ALG_SHA256:
257       return gc.pcrSave.sha256[pcrIndex];
258       break;
259#endif
260#ifdef TPM_ALG_SHA384
261   case TPM_ALG_SHA384:
262       return gc.pcrSave.sha384[pcrIndex];
263       break;
264#endif
265#ifdef TPM_ALG_SHA512
266   case TPM_ALG_SHA512:
267       return gc.pcrSave.sha512[pcrIndex];
268       break;
269#endif
270#ifdef TPM_ALG_SM3_256
271   case TPM_ALG_SM3_256:
272       return gc.pcrSave.sm3_256[pcrIndex];
273       break;
274#endif
275   default:
276       FAIL(FATAL_ERROR_INTERNAL);
277   }
278   return NULL; // Never reached.
279}
280//
281//
282//           PcrIsAllocated()
283//
284//      This function indicates if a PCR number for the particular hash algorithm is allocated.
285//
286//      Return Value                     Meaning
287//
288//      FALSE                            PCR is not allocated
289//      TRUE                             PCR is allocated
290//
291BOOL
292PcrIsAllocated (
293    UINT32               pcr,               // IN: The number of the PCR
294    TPMI_ALG_HASH        hashAlg            // IN: The PCR algorithm
295    )
296{
297    UINT32                    i;
298    BOOL                      allocated = FALSE;
299    if(pcr < IMPLEMENTATION_PCR)
300    {
301         for(i = 0; i < gp.pcrAllocated.count; i++)
302         {
303             if(gp.pcrAllocated.pcrSelections[i].hash == hashAlg)
304             {
305                 if(((gp.pcrAllocated.pcrSelections[i].pcrSelect[pcr/8])
306                         & (1 << (pcr % 8))) != 0)
307//
308                        allocated = TRUE;
309                    else
310                        allocated = FALSE;
311                    break;
312                }
313          }
314   }
315   return allocated;
316}
317//
318//
319//             GetPcrPointer()
320//
321//      This function returns the address of an array of PCR based on the hash algorithm.
322//
323//      Return Value                      Meaning
324//
325//      NULL                              no such algorithm
326//      not NULL                          pointer to the 0th byte of the 0th PCR
327//
328static BYTE *
329GetPcrPointer (
330   TPM_ALG_ID            alg,                // IN: algorithm for bank
331   UINT32                pcrNumber           // IN: PCR number
332   )
333{
334   static BYTE          *pcr = NULL;
335   if(!PcrIsAllocated(pcrNumber, alg))
336       return NULL;
337   switch(alg)
338   {
339#ifdef TPM_ALG_SHA1
340   case TPM_ALG_SHA1:
341       pcr = s_pcrs[pcrNumber].sha1Pcr;
342       break;
343#endif
344#ifdef TPM_ALG_SHA256
345   case TPM_ALG_SHA256:
346       pcr = s_pcrs[pcrNumber].sha256Pcr;
347       break;
348#endif
349#ifdef TPM_ALG_SHA384
350   case TPM_ALG_SHA384:
351       pcr = s_pcrs[pcrNumber].sha384Pcr;
352       break;
353#endif
354#ifdef TPM_ALG_SHA512
355   case TPM_ALG_SHA512:
356       pcr = s_pcrs[pcrNumber].sha512Pcr;
357       break;
358#endif
359#ifdef TPM_ALG_SM3_256
360   case TPM_ALG_SM3_256:
361       pcr = s_pcrs[pcrNumber].sm3_256Pcr;
362       break;
363#endif
364   default:
365       pAssert(FALSE);
366       break;
367   }
368   return pcr;
369//
370}
371//
372//
373//          IsPcrSelected()
374//
375//      This function indicates if an indicated PCR number is selected by the bit map in selection.
376//
377//      Return Value                     Meaning
378//
379//      FALSE                            PCR is not selected
380//      TRUE                             PCR is selected
381//
382static BOOL
383IsPcrSelected (
384   UINT32                     pcr,                // IN: The number of the PCR
385   TPMS_PCR_SELECTION        *selection           // IN: The selection structure
386   )
387{
388   BOOL                 selected = FALSE;
389   if(   pcr < IMPLEMENTATION_PCR
390      && ((selection->pcrSelect[pcr/8]) & (1 << (pcr % 8))) != 0)
391       selected = TRUE;
392   return selected;
393}
394//
395//
396//          FilterPcr()
397//
398//      This function modifies a PCR selection array based on the implemented PCR.
399//
400static void
401FilterPcr(
402   TPMS_PCR_SELECTION        *selection           // IN: input PCR selection
403   )
404{
405   UINT32     i;
406   TPMS_PCR_SELECTION            *allocated = NULL;
407   // If size of select is less than PCR_SELECT_MAX, zero the unspecified PCR
408   for(i = selection->sizeofSelect; i < PCR_SELECT_MAX; i++)
409       selection->pcrSelect[i] = 0;
410   // Find the internal configuration for the bank
411   for(i = 0; i < gp.pcrAllocated.count; i++)
412   {
413       if(gp.pcrAllocated.pcrSelections[i].hash == selection->hash)
414       {
415           allocated = &gp.pcrAllocated.pcrSelections[i];
416           break;
417       }
418   }
419   for (i = 0; i < selection->sizeofSelect; i++)
420   {
421       if(allocated == NULL)
422       {
423            // If the required bank does not exist, clear input selection
424            selection->pcrSelect[i] = 0;
425       }
426       else
427            selection->pcrSelect[i] &= allocated->pcrSelect[i];
428   }
429   return;
430}
431//
432//
433//           PcrDrtm()
434//
435//      This function does the DRTM and H-CRTM processing it is called from _TPM_Hash_End().
436//
437void
438PcrDrtm(
439   const TPMI_DH_PCR              pcrHandle,       // IN: the index of the PCR to be
440                                                   //     modified
441   const TPMI_ALG_HASH            hash,            // IN: the bank identifier
442   const TPM2B_DIGEST            *digest           // IN: the digest to modify the PCR
443   )
444{
445   BYTE           *pcrData = GetPcrPointer(hash, pcrHandle);
446   if(pcrData != NULL)
447   {
448       // Rest the PCR to zeros
449       MemorySet(pcrData, 0, digest->t.size);
450          // if the TPM has not started, then set the PCR to 0...04 and then extend
451          if(!TPMIsStarted())
452          {
453              pcrData[digest->t.size - 1] = 4;
454          }
455          // Now, extend the value
456          PCRExtend(pcrHandle, hash, digest->t.size, (BYTE *)digest->t.buffer);
457   }
458}
459//
460//
461//           PCRStartup()
462//
463//      This function initializes the PCR subsystem at TPM2_Startup().
464//
465void
466PCRStartup(
467   STARTUP_TYPE         type,              // IN: startup type
468   BYTE                 locality           // IN: startup locality
469   )
470{
471   UINT32                  pcr, j;
472   UINT32                  saveIndex = 0;
473   g_pcrReConfig = FALSE;
474   if(type != SU_RESUME)
475   {
476       // PCR generation counter is cleared at TPM_RESET and TPM_RESTART
477       gr.pcrCounter = 0;
478   }
479   // Initialize/Restore PCR values
480   for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
481   {
482       // On resume, need to know if this PCR had its state saved or not
483       UINT32      stateSaved =
484           (type == SU_RESUME && s_initAttributes[pcr].stateSave == SET) ? 1 : 0;
485          // If this is the H-CRTM PCR and we are not doing a resume and we
486          // had an H-CRTM event, then we don't change this PCR
487          if(pcr == HCRTM_PCR && type != SU_RESUME && g_DrtmPreStartup == TRUE)
488              continue;
489          // Iterate each hash algorithm bank
490          for(j = 0; j < gp.pcrAllocated.count; j++)
491          {
492              TPMI_ALG_HASH    hash = gp.pcrAllocated.pcrSelections[j].hash;
493              BYTE            *pcrData = GetPcrPointer(hash, pcr);
494              UINT16           pcrSize = CryptGetHashDigestSize(hash);
495              if(pcrData != NULL)
496              {
497                  // if state was saved
498                  if(stateSaved == 1)
499                  {
500                      // Restore saved PCR value
501                      BYTE     *pcrSavedData;
502                      pcrSavedData = GetSavedPcrPointer(
503                                          gp.pcrAllocated.pcrSelections[j].hash,
504                                          saveIndex);
505                      MemoryCopy(pcrData, pcrSavedData, pcrSize, pcrSize);
506                  }
507                  else
508                      // PCR was not restored by state save
509                  {
510                      // If the reset locality of the PCR is 4, then
511                      // the reset value is all one's, otherwise it is
512                      // all zero.
513                      if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
514                           MemorySet(pcrData, 0xFF, pcrSize);
515                      else
516                      {
517                           MemorySet(pcrData, 0, pcrSize);
518                           if(pcr == HCRTM_PCR)
519                               pcrData[pcrSize-1] = locality;
520                      }
521                  }
522              }
523          }
524          saveIndex += stateSaved;
525   }
526   // Reset authValues
527   if(type != SU_RESUME)
528   {
529       for(j = 0; j < NUM_AUTHVALUE_PCR_GROUP; j++)
530       {
531           gc.pcrAuthValues.auth[j].t.size = 0;
532       }
533   }
534}
535//
536//
537//           PCRStateSave()
538//
539//      This function is used to save the PCR values that will be restored on TPM Resume.
540//
541void
542PCRStateSave(
543   TPM_SU                 type             // IN: startup type
544   )
545{
546   UINT32                 pcr, j;
547   UINT32                 saveIndex = 0;
548//
549   // if state save CLEAR, nothing to be done.            Return here
550   if(type == TPM_SU_CLEAR) return;
551   // Copy PCR values to the structure that should be saved to NV
552   for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
553   {
554       UINT32 stateSaved = (s_initAttributes[pcr].stateSave == SET) ? 1 : 0;
555          // Iterate each hash algorithm bank
556          for(j = 0; j < gp.pcrAllocated.count; j++)
557          {
558              BYTE    *pcrData;
559              UINT32 pcrSize;
560              pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[j].hash, pcr);
561              if(pcrData != NULL)
562              {
563                  pcrSize
564                      = CryptGetHashDigestSize(gp.pcrAllocated.pcrSelections[j].hash);
565                  if(stateSaved == 1)
566                  {
567                      // Restore saved PCR value
568                      BYTE     *pcrSavedData;
569                      pcrSavedData
570                           = GetSavedPcrPointer(gp.pcrAllocated.pcrSelections[j].hash,
571                                                saveIndex);
572                      MemoryCopy(pcrSavedData, pcrData, pcrSize, pcrSize);
573                  }
574              }
575          }
576          saveIndex += stateSaved;
577   }
578   return;
579}
580//
581//
582//           PCRIsStateSaved()
583//
584//      This function indicates if the selected PCR is a PCR that is state saved on TPM2_Shutdown(STATE). The
585//      return value is based on PCR attributes.
586//
587//      Return Value                      Meaning
588//
589//      TRUE                              PCR is state saved
590//      FALSE                             PCR is not state saved
591//
592BOOL
593PCRIsStateSaved(
594   TPMI_DH_PCR         handle                // IN: PCR handle to be extended
595   )
596{
597   UINT32                  pcr = handle - PCR_FIRST;
598   if(s_initAttributes[pcr].stateSave == SET)
599       return TRUE;
600   else
601       return FALSE;
602}
603//
604//
605//
606//          PCRIsResetAllowed()
607//
608//      This function indicates if a PCR may be reset by the current command locality. The return value is based
609//      on PCR attributes, and not the PCR allocation.
610//
611//      Return Value                    Meaning
612//
613//      TRUE                            TPM2_PCR_Reset() is allowed
614//      FALSE                           TPM2_PCR_Reset() is not allowed
615//
616BOOL
617PCRIsResetAllowed(
618   TPMI_DH_PCR          handle            // IN: PCR handle to be extended
619   )
620{
621   UINT8                     commandLocality;
622   UINT8                     localityBits = 1;
623   UINT32                    pcr = handle - PCR_FIRST;
624   // Check for the locality
625   commandLocality = _plat__LocalityGet();
626#ifdef DRTM_PCR
627   // For a TPM that does DRTM, Reset is not allowed at locality 4
628   if(commandLocality == 4)
629       return FALSE;
630#endif
631   localityBits = localityBits << commandLocality;
632   if((localityBits & s_initAttributes[pcr].resetLocality) == 0)
633       return FALSE;
634   else
635       return TRUE;
636}
637//
638//
639//          PCRChanged()
640//
641//      This function checks a PCR handle to see if the attributes for the PCR are set so that any change to the
642//      PCR causes an increment of the pcrCounter. If it does, then the function increments the counter.
643//
644void
645PCRChanged(
646   TPM_HANDLE           pcrHandle         // IN: the handle of the PCR that changed.
647   )
648{
649   // For the reference implementation, the only change that does not cause
650   // increment is a change to a PCR in the TCB group.
651   if(!PCRBelongsTCBGroup(pcrHandle))
652       gr.pcrCounter++;
653}
654//
655//
656//          PCRIsExtendAllowed()
657//
658//      This function indicates a PCR may be extended at the current command locality. The return value is
659//      based on PCR attributes, and not the PCR allocation.
660//
661//
662//
663//
664//      Return Value                      Meaning
665//
666//      TRUE                              extend is allowed
667//      FALSE                             extend is not allowed
668//
669BOOL
670PCRIsExtendAllowed(
671   TPMI_DH_PCR          handle               // IN: PCR handle to be extended
672   )
673{
674   UINT8                    commandLocality;
675   UINT8                    localityBits = 1;
676   UINT32                   pcr = handle - PCR_FIRST;
677   // Check for the locality
678   commandLocality = _plat__LocalityGet();
679   localityBits = localityBits << commandLocality;
680   if((localityBits & s_initAttributes[pcr].extendLocality) == 0)
681       return FALSE;
682   else
683       return TRUE;
684}
685//
686//
687//           PCRExtend()
688//
689//      This function is used to extend a PCR in a specific bank.
690//
691void
692PCRExtend(
693   TPMI_DH_PCR          handle,              //   IN:    PCR handle to be extended
694   TPMI_ALG_HASH        hash,                //   IN:    hash algorithm of PCR
695   UINT32               size,                //   IN:    size of data to be extended
696   BYTE                *data                 //   IN:    data to be extended
697   )
698{
699   UINT32                    pcr = handle - PCR_FIRST;
700   BYTE                     *pcrData;
701   HASH_STATE                hashState;
702   UINT16                    pcrSize;
703   pcrData = GetPcrPointer(hash, pcr);
704   // Extend PCR if it is allocated
705   if(pcrData != NULL)
706   {
707       pcrSize = CryptGetHashDigestSize(hash);
708       CryptStartHash(hash, &hashState);
709       CryptUpdateDigest(&hashState, pcrSize, pcrData);
710       CryptUpdateDigest(&hashState, size, data);
711       CryptCompleteHash(&hashState, pcrSize, pcrData);
712          // If PCR does not belong to TCB group, increment PCR counter
713          if(!PCRBelongsTCBGroup(handle))
714              gr.pcrCounter++;
715   }
716   return;
717}
718//
719//
720//
721//          PCRComputeCurrentDigest()
722//
723//      This function computes the digest of the selected PCR.
724//      As a side-effect, selection is modified so that only the implemented PCR will have their bits still set.
725//
726void
727PCRComputeCurrentDigest(
728    TPMI_ALG_HASH             hashAlg,            // IN: hash algorithm to compute digest
729    TPML_PCR_SELECTION       *selection,          // IN/OUT: PCR selection (filtered on
730                                                  //     output)
731    TPM2B_DIGEST             *digest              // OUT: digest
732    )
733{
734    HASH_STATE                      hashState;
735    TPMS_PCR_SELECTION             *select;
736    BYTE                           *pcrData;   // will point to a digest
737    UINT32                          pcrSize;
738    UINT32                          pcr;
739    UINT32                          i;
740    // Initialize the hash
741    digest->t.size = CryptStartHash(hashAlg, &hashState);
742    pAssert(digest->t.size > 0 && digest->t.size < UINT16_MAX);
743    // Iterate through the list of PCR selection structures
744    for(i = 0; i < selection->count; i++)
745    {
746        // Point to the current selection
747        select = &selection->pcrSelections[i]; // Point to the current selection
748        FilterPcr(select);      // Clear out the bits for unimplemented PCR
749          // Need the size of each digest
750          pcrSize = CryptGetHashDigestSize(selection->pcrSelections[i].hash);
751          // Iterate through the selection
752          for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
753          {
754              if(IsPcrSelected(pcr, select))         // Is this PCR selected
755              {
756                  // Get pointer to the digest data for the bank
757                  pcrData = GetPcrPointer(selection->pcrSelections[i].hash, pcr);
758                  pAssert(pcrData != NULL);
759                  CryptUpdateDigest(&hashState, pcrSize, pcrData); // add to digest
760              }
761          }
762    }
763    // Complete hash stack
764    CryptCompleteHash2B(&hashState, &digest->b);
765    return;
766}
767//
768//
769//          PCRRead()
770//
771//      This function is used to read a list of selected PCR. If the requested PCR number exceeds the maximum
772//      number that can be output, the selection is adjusted to reflect the actual output PCR.
773//
774void
775PCRRead(
776    TPML_PCR_SELECTION       *selection,          // IN/OUT: PCR selection (filtered on
777                                                  //     output)
778    TPML_DIGEST              *digest,             // OUT: digest
779    UINT32                   *pcrCounter          // OUT: the current value of PCR generation
780                                             //     number
781   )
782{
783   TPMS_PCR_SELECTION            *select;
784   BYTE                          *pcrData;        // will point to a digest
785   UINT32                         pcr;
786   UINT32                         i;
787   digest->count = 0;
788   // Iterate through the list of PCR selection structures
789   for(i = 0; i < selection->count; i++)
790   {
791       // Point to the current selection
792       select = &selection->pcrSelections[i]; // Point to the current selection
793       FilterPcr(select);      // Clear out the bits for unimplemented PCR
794        // Iterate through the selection
795        for (pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
796        {
797            if(IsPcrSelected(pcr, select))          // Is this PCR selected
798            {
799                // Check if number of digest exceed upper bound
800                if(digest->count > 7)
801                {
802                    // Clear rest of the current select bitmap
803                    while(    pcr < IMPLEMENTATION_PCR
804                              // do not round up!
805                           && (pcr / 8) < select->sizeofSelect)
806                    {
807                        // do not round up!
808                        select->pcrSelect[pcr/8] &= (BYTE) ~(1 << (pcr % 8));
809                        pcr++;
810                    }
811                    // Exit inner loop
812                    break;;
813                }
814                // Need the size of each digest
815                digest->digests[digest->count].t.size =
816                    CryptGetHashDigestSize(selection->pcrSelections[i].hash);
817                  // Get pointer to the digest data for the bank
818                  pcrData = GetPcrPointer(selection->pcrSelections[i].hash, pcr);
819                  pAssert(pcrData != NULL);
820                  // Add to the data to digest
821                  MemoryCopy(digest->digests[digest->count].t.buffer,
822                             pcrData,
823                             digest->digests[digest->count].t.size,
824                             digest->digests[digest->count].t.size);
825                  digest->count++;
826            }
827        }
828        // If we exit inner loop because we have exceed the output upper bound
829        if(digest->count > 7 && pcr < IMPLEMENTATION_PCR)
830        {
831            // Clear rest of the selection
832            while(i < selection->count)
833            {
834                MemorySet(selection->pcrSelections[i].pcrSelect, 0,
835                          selection->pcrSelections[i].sizeofSelect);
836                i++;
837            }
838            // exit outer loop
839            break;
840        }
841   }
842   *pcrCounter = gr.pcrCounter;
843   return;
844}
845//
846//
847//          PcrWrite()
848//
849//      This function is used by _TPM_Hash_End() to set a PCR to the computed hash of the H-CRTM event.
850//
851void
852PcrWrite(
853   TPMI_DH_PCR           handle,            // IN: PCR handle to be extended
854   TPMI_ALG_HASH         hash,              // IN: hash algorithm of PCR
855   TPM2B_DIGEST         *digest             // IN: the new value
856   )
857{
858   UINT32                     pcr = handle - PCR_FIRST;
859   BYTE                      *pcrData;
860   // Copy value to the PCR if it is allocated
861   pcrData = GetPcrPointer(hash, pcr);
862   if(pcrData != NULL)
863   {
864       MemoryCopy(pcrData, digest->t.buffer, digest->t.size, digest->t.size); ;
865   }
866   return;
867}
868//
869//
870//          PCRAllocate()
871//
872//      This function is used to change the PCR allocation.
873//
874//      Error Returns                   Meaning
875//
876//      TPM_RC_SUCCESS                  allocate success
877//      TPM_RC_NO_RESULTS               allocate failed
878//      TPM_RC_PCR                      improper allocation
879//
880TPM_RC
881PCRAllocate(
882   TPML_PCR_SELECTION        *allocate,           //   IN: required allocation
883   UINT32                    *maxPCR,             //   OUT: Maximum number of PCR
884   UINT32                    *sizeNeeded,         //   OUT: required space
885   UINT32                    *sizeAvailable       //   OUT: available space
886   )
887{
888   UINT32                        i, j, k;
889   TPML_PCR_SELECTION            newAllocate;
890   // Initialize the flags       to indicate if HCRTM PCR and DRTM PCR are allocated.
891   BOOL                          pcrHcrtm = FALSE;
892   BOOL                          pcrDrtm = FALSE;
893   // Create the expected new PCR allocation based on the existing allocation
894   // and the new input:
895   // 1. if a PCR bank does not appear in the new allocation, the existing
896   //     allocation of this PCR bank will be preserved.
897   // 2. if a PCR bank appears multiple times in the new allocation, only the
898   //     last one will be in effect.
899   newAllocate = gp.pcrAllocated;
900   for(i = 0; i < allocate->count; i++)
901   {
902       for(j = 0; j < newAllocate.count; j++)
903       {
904           // If hash matches, the new allocation covers the old allocation
905           // for this particular bank.
906           // The assumption is the initial PCR allocation (from manufacture)
907           // has all the supported hash algorithms with an assigned bank
908           // (possibly empty). So there must be a match for any new bank
909           // allocation from the input.
910           if(newAllocate.pcrSelections[j].hash ==
911               allocate->pcrSelections[i].hash)
912           {
913               newAllocate.pcrSelections[j] = allocate->pcrSelections[i];
914               break;
915           }
916       }
917       // The j loop must exit with a match.
918       pAssert(j < newAllocate.count);
919   }
920   // Max PCR in a bank is MIN(implemented PCR, PCR with attributes defined)
921   *maxPCR = sizeof(s_initAttributes) / sizeof(PCR_Attributes);
922   if(*maxPCR > IMPLEMENTATION_PCR)
923       *maxPCR = IMPLEMENTATION_PCR;
924   // Compute required size for allocation
925   *sizeNeeded = 0;
926   for(i = 0; i < newAllocate.count; i++)
927   {
928       UINT32      digestSize
929           = CryptGetHashDigestSize(newAllocate.pcrSelections[i].hash);
930#if defined(DRTM_PCR)
931       // Make sure that we end up with at least one DRTM PCR
932#   define PCR_DRTM (PCR_FIRST + DRTM_PCR)     // for cosmetics
933       pcrDrtm =    pcrDrtm || TEST_BIT(PCR_DRTM, newAllocate.pcrSelections[i]);
934#else   // if DRTM PCR is not required, indicate that the allocation is OK
935       pcrDrtm = TRUE;
936#endif
937#if defined(HCRTM_PCR)
938       // and one HCRTM PCR (since this is usually PCR 0...)
939#   define PCR_HCRTM (PCR_FIRST + HCRTM_PCR)
940       pcrHcrtm =    pcrDrtm || TEST_BIT(PCR_HCRTM, newAllocate.pcrSelections[i]);
941#else
942       pcrHcrtm = TRUE;
943#endif
944       for(j = 0; j < newAllocate.pcrSelections[i].sizeofSelect; j++)
945       {
946           BYTE         mask = 1;
947           for(k = 0; k < 8; k++)
948           {
949               if((newAllocate.pcrSelections[i].pcrSelect[j] & mask) != 0)
950                   *sizeNeeded += digestSize;
951               mask = mask << 1;
952           }
953       }
954   }
955   if(!pcrDrtm || !pcrHcrtm)
956       return TPM_RC_PCR;
957   // In this particular implementation, we always have enough space to
958   // allocate PCR. Different implementation may return a sizeAvailable less
959   // than the sizeNeed.
960   *sizeAvailable = sizeof(s_pcrs);
961    // Save the required allocation to NV. Note that after NV is written, the
962    // PCR allocation in NV is no longer consistent with the RAM data
963    // gp.pcrAllocated. The NV version reflect the allocate after next
964    // TPM_RESET, while the RAM version reflects the current allocation
965    NvWriteReserved(NV_PCR_ALLOCATED, &newAllocate);
966    return TPM_RC_SUCCESS;
967}
968//
969//
970//             PCRSetValue()
971//
972//      This function is used to set the designated PCR in all banks to an initial value. The initial value is signed
973//      and will be sign extended into the entire PCR.
974//
975void
976PCRSetValue(
977    TPM_HANDLE           handle,            // IN: the handle of the PCR to set
978    INT8                 initialValue       // IN: the value to set
979    )
980{
981    int                  i;
982    UINT32               pcr = handle - PCR_FIRST;
983    TPMI_ALG_HASH        hash;
984    UINT16               digestSize;
985    BYTE                *pcrData;
986    // Iterate supported PCR bank algorithms to reset
987    for(i = 0; i < HASH_COUNT; i++)
988    {
989        hash = CryptGetHashAlgByIndex(i);
990        // Prevent runaway
991        if(hash == TPM_ALG_NULL)
992            break;
993          // Get a pointer to the data
994          pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr);
995          // If the PCR is allocated
996          if(pcrData != NULL)
997          {
998              // And the size of the digest
999              digestSize = CryptGetHashDigestSize(hash);
1000               // Set the LSO to the input value
1001               pcrData[digestSize - 1] = initialValue;
1002               // Sign extend
1003               if(initialValue >= 0)
1004                   MemorySet(pcrData, 0, digestSize - 1);
1005               else
1006                   MemorySet(pcrData, -1, digestSize - 1);
1007          }
1008    }
1009}
1010//
1011//
1012//             PCRResetDynamics
1013//
1014//      This function is used to reset a dynamic PCR to 0. This function is used in DRTM sequence.
1015//
1016void
1017PCRResetDynamics(
1018      void
1019      )
1020{
1021      UINT32                  pcr, i;
1022      // Initialize PCR values
1023      for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
1024      {
1025          // Iterate each hash algorithm bank
1026          for(i = 0; i < gp.pcrAllocated.count; i++)
1027          {
1028              BYTE    *pcrData;
1029              UINT32 pcrSize;
1030                pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr);
1031                if(pcrData != NULL)
1032                {
1033                    pcrSize =
1034                        CryptGetHashDigestSize(gp.pcrAllocated.pcrSelections[i].hash);
1035                    // Reset PCR
1036                    // Any PCR can be reset by locality 4 should be reset to 0
1037                    if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
1038                        MemorySet(pcrData, 0, pcrSize);
1039                }
1040          }
1041      }
1042      return;
1043}
1044//
1045//
1046//             PCRCapGetAllocation()
1047//
1048//      This function is used to get the current allocation of PCR banks.
1049//
1050//      Return Value                      Meaning
1051//
1052//      YES:                              if the return count is 0
1053//      NO:                               if the return count is not 0
1054//
1055TPMI_YES_NO
1056PCRCapGetAllocation(
1057      UINT32                   count,               // IN: count of return
1058      TPML_PCR_SELECTION      *pcrSelection         // OUT: PCR allocation list
1059      )
1060{
1061      if(count == 0)
1062      {
1063          pcrSelection->count = 0;
1064          return YES;
1065      }
1066      else
1067      {
1068          *pcrSelection = gp.pcrAllocated;
1069          return NO;
1070      }
1071}
1072//
1073//
1074//             PCRSetSelectBit()
1075//
1076//      This function sets a bit in a bitmap array.
1077//
1078static void
1079PCRSetSelectBit(
1080   UINT32               pcr,               // IN: PCR number
1081   BYTE                *bitmap             // OUT: bit map to be set
1082   )
1083{
1084   bitmap[pcr / 8] |= (1 << (pcr % 8));
1085   return;
1086}
1087//
1088//
1089//          PCRGetProperty()
1090//
1091//      This function returns the selected PCR property.
1092//
1093//      Return Value                    Meaning
1094//
1095//      TRUE                            the property type is implemented
1096//      FALSE                           the property type is not implemented
1097//
1098static BOOL
1099PCRGetProperty(
1100   TPM_PT_PCR                     property,
1101   TPMS_TAGGED_PCR_SELECT        *select
1102   )
1103{
1104   UINT32                    pcr;
1105   UINT32                    groupIndex;
1106   select->tag = property;
1107   // Always set the bitmap to be the size of all PCR
1108   select->sizeofSelect = (IMPLEMENTATION_PCR + 7) / 8;
1109   // Initialize bitmap
1110   MemorySet(select->pcrSelect, 0, select->sizeofSelect);
1111   // Collecting properties
1112   for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
1113   {
1114       switch(property)
1115       {
1116           case TPM_PT_PCR_SAVE:
1117               if(s_initAttributes[pcr].stateSave == SET)
1118                   PCRSetSelectBit(pcr, select->pcrSelect);
1119               break;
1120           case TPM_PT_PCR_EXTEND_L0:
1121               if((s_initAttributes[pcr].extendLocality & 0x01) != 0)
1122                   PCRSetSelectBit(pcr, select->pcrSelect);
1123               break;
1124           case TPM_PT_PCR_RESET_L0:
1125               if((s_initAttributes[pcr].resetLocality & 0x01) != 0)
1126                   PCRSetSelectBit(pcr, select->pcrSelect);
1127               break;
1128           case TPM_PT_PCR_EXTEND_L1:
1129               if((s_initAttributes[pcr].extendLocality & 0x02) != 0)
1130                   PCRSetSelectBit(pcr, select->pcrSelect);
1131               break;
1132           case TPM_PT_PCR_RESET_L1:
1133               if((s_initAttributes[pcr].resetLocality & 0x02) != 0)
1134                   PCRSetSelectBit(pcr, select->pcrSelect);
1135               break;
1136           case TPM_PT_PCR_EXTEND_L2:
1137               if((s_initAttributes[pcr].extendLocality & 0x04) != 0)
1138                   PCRSetSelectBit(pcr, select->pcrSelect);
1139//
1140               break;
1141           case TPM_PT_PCR_RESET_L2:
1142               if((s_initAttributes[pcr].resetLocality & 0x04) != 0)
1143                    PCRSetSelectBit(pcr, select->pcrSelect);
1144               break;
1145           case TPM_PT_PCR_EXTEND_L3:
1146               if((s_initAttributes[pcr].extendLocality & 0x08) != 0)
1147                    PCRSetSelectBit(pcr, select->pcrSelect);
1148               break;
1149           case TPM_PT_PCR_RESET_L3:
1150               if((s_initAttributes[pcr].resetLocality & 0x08) != 0)
1151                    PCRSetSelectBit(pcr, select->pcrSelect);
1152               break;
1153           case TPM_PT_PCR_EXTEND_L4:
1154               if((s_initAttributes[pcr].extendLocality & 0x10) != 0)
1155                    PCRSetSelectBit(pcr, select->pcrSelect);
1156               break;
1157           case TPM_PT_PCR_RESET_L4:
1158               if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
1159                    PCRSetSelectBit(pcr, select->pcrSelect);
1160               break;
1161           case TPM_PT_PCR_DRTM_RESET:
1162               // DRTM reset PCRs are the PCR reset by locality 4
1163               if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
1164                    PCRSetSelectBit(pcr, select->pcrSelect);
1165               break;
1166#if NUM_POLICY_PCR_GROUP > 0
1167           case TPM_PT_PCR_POLICY:
1168               if(PCRBelongsPolicyGroup(pcr + PCR_FIRST, &groupIndex))
1169                    PCRSetSelectBit(pcr, select->pcrSelect);
1170               break;
1171#endif
1172#if NUM_AUTHVALUE_PCR_GROUP > 0
1173           case TPM_PT_PCR_AUTH:
1174               if(PCRBelongsAuthGroup(pcr + PCR_FIRST, &groupIndex))
1175                    PCRSetSelectBit(pcr, select->pcrSelect);
1176               break;
1177#endif
1178#if ENABLE_PCR_NO_INCREMENT == YES
1179           case TPM_PT_PCR_NO_INCREMENT:
1180               if(PCRBelongsTCBGroup(pcr + PCR_FIRST))
1181                    PCRSetSelectBit(pcr, select->pcrSelect);
1182               break;
1183#endif
1184           default:
1185               // If property is not supported, stop scanning PCR attributes
1186               // and return.
1187               return FALSE;
1188               break;
1189       }
1190   }
1191   return TRUE;
1192}
1193//
1194//
1195//           PCRCapGetProperties()
1196//
1197//       This function returns a list of PCR properties starting at property.
1198//
1199//
1200//
1201//
1202//       Return Value                    Meaning
1203//
1204//       YES:                            if no more property is available
1205//       NO:                             if there are more properties not reported
1206//
1207TPMI_YES_NO
1208PCRCapGetProperties(
1209      TPM_PT_PCR                       property,             // IN: the starting PCR property
1210      UINT32                           count,                // IN: count of returned propertie
1211      TPML_TAGGED_PCR_PROPERTY        *select                // OUT: PCR select
1212      )
1213{
1214      TPMI_YES_NO      more = NO;
1215      UINT32           i;
1216      // Initialize output property list
1217      select->count = 0;
1218      // The maximum count of properties we may return is MAX_PCR_PROPERTIES
1219      if(count > MAX_PCR_PROPERTIES) count = MAX_PCR_PROPERTIES;
1220      // TPM_PT_PCR_FIRST is defined as 0 in spec. It ensures that property
1221      // value would never be less than TPM_PT_PCR_FIRST
1222      pAssert(TPM_PT_PCR_FIRST == 0);
1223      // Iterate PCR properties. TPM_PT_PCR_LAST is the index of the last property
1224      // implemented on the TPM.
1225      for(i = property; i <= TPM_PT_PCR_LAST; i++)
1226      {
1227          if(select->count < count)
1228          {
1229               // If we have not filled up the return list, add more properties to it
1230               if(PCRGetProperty(i, &select->pcrProperty[select->count]))
1231                   // only increment if the property is implemented
1232               select->count++;
1233          }
1234          else
1235          {
1236               // If the return list is full but we still have properties
1237               // available, report this and stop iterating.
1238               more = YES;
1239               break;
1240          }
1241      }
1242      return more;
1243}
1244//
1245//
1246//            PCRCapGetHandles()
1247//
1248//       This function is used to get a list of handles of PCR, started from handle. If handle exceeds the maximum
1249//       PCR handle range, an empty list will be returned and the return value will be NO.
1250//
1251//       Return Value                    Meaning
1252//
1253//       YES                             if there are more handles available
1254//       NO                              all the available handles has been returned
1255//
1256TPMI_YES_NO
1257PCRCapGetHandles(
1258      TPMI_DH_PCR       handle,             // IN: start handle
1259      UINT32            count,              // IN: count of returned handle
1260      TPML_HANDLE      *handleList          // OUT: list of handle
1261     )
1262{
1263     TPMI_YES_NO         more = NO;
1264     UINT32              i;
1265     pAssert(HandleGetType(handle) == TPM_HT_PCR);
1266     // Initialize output handle list
1267     handleList->count = 0;
1268     // The maximum count of handles we may return is MAX_CAP_HANDLES
1269     if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1270     // Iterate PCR handle range
1271     for(i = handle & HR_HANDLE_MASK; i <= PCR_LAST; i++)
1272     {
1273         if(handleList->count < count)
1274         {
1275              // If we have not filled up the return list, add this PCR
1276              // handle to it
1277              handleList->handle[handleList->count] = i + PCR_FIRST;
1278              handleList->count++;
1279         }
1280         else
1281         {
1282              // If the return list is full but we still have PCR handle
1283              // available, report this and stop iterating
1284              more = YES;
1285              break;
1286         }
1287     }
1288     return more;
1289}
1290