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 //
15 static 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 //
47 BOOL
PCRBelongsAuthGroup(TPMI_DH_PCR handle,UINT32 * groupIndex)48 PCRBelongsAuthGroup(
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 //
79 BOOL
PCRBelongsPolicyGroup(TPMI_DH_PCR handle,UINT32 * groupIndex)80 PCRBelongsPolicyGroup(
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 //
104 static BOOL
PCRBelongsTCBGroup(TPMI_DH_PCR handle)105 PCRBelongsTCBGroup(
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 //
133 BOOL
PCRPolicyIsAvailable(TPMI_DH_PCR handle)134 PCRPolicyIsAvailable(
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 //
148 void
PCRGetAuthValue(TPMI_DH_PCR handle,TPM2B_AUTH * auth)149 PCRGetAuthValue(
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 //
172 TPMI_ALG_HASH
PCRGetAuthPolicy(TPMI_DH_PCR handle,TPM2B_DIGEST * policy)173 PCRGetAuthPolicy(
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 //
197 void
PCRSimStart(void)198 PCRSimStart(
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 //
242 static BYTE *
GetSavedPcrPointer(TPM_ALG_ID alg,UINT32 pcrIndex)243 GetSavedPcrPointer (
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 //
291 BOOL
PcrIsAllocated(UINT32 pcr,TPMI_ALG_HASH hashAlg)292 PcrIsAllocated (
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 //
328 static BYTE *
GetPcrPointer(TPM_ALG_ID alg,UINT32 pcrNumber)329 GetPcrPointer (
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 //
382 static BOOL
IsPcrSelected(UINT32 pcr,TPMS_PCR_SELECTION * selection)383 IsPcrSelected (
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 //
400 static void
FilterPcr(TPMS_PCR_SELECTION * selection)401 FilterPcr(
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 //
437 void
PcrDrtm(const TPMI_DH_PCR pcrHandle,const TPMI_ALG_HASH hash,const TPM2B_DIGEST * digest)438 PcrDrtm(
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 //
465 void
PCRStartup(STARTUP_TYPE type,BYTE locality)466 PCRStartup(
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 //
541 void
PCRStateSave(TPM_SU type)542 PCRStateSave(
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 //
592 BOOL
PCRIsStateSaved(TPMI_DH_PCR handle)593 PCRIsStateSaved(
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 //
616 BOOL
PCRIsResetAllowed(TPMI_DH_PCR handle)617 PCRIsResetAllowed(
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 //
644 void
PCRChanged(TPM_HANDLE pcrHandle)645 PCRChanged(
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 //
669 BOOL
PCRIsExtendAllowed(TPMI_DH_PCR handle)670 PCRIsExtendAllowed(
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 //
691 void
PCRExtend(TPMI_DH_PCR handle,TPMI_ALG_HASH hash,UINT32 size,BYTE * data)692 PCRExtend(
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 //
726 void
PCRComputeCurrentDigest(TPMI_ALG_HASH hashAlg,TPML_PCR_SELECTION * selection,TPM2B_DIGEST * digest)727 PCRComputeCurrentDigest(
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 //
774 void
PCRRead(TPML_PCR_SELECTION * selection,TPML_DIGEST * digest,UINT32 * pcrCounter)775 PCRRead(
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 //
851 void
PcrWrite(TPMI_DH_PCR handle,TPMI_ALG_HASH hash,TPM2B_DIGEST * digest)852 PcrWrite(
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 //
880 TPM_RC
PCRAllocate(TPML_PCR_SELECTION * allocate,UINT32 * maxPCR,UINT32 * sizeNeeded,UINT32 * sizeAvailable)881 PCRAllocate(
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 //
975 void
PCRSetValue(TPM_HANDLE handle,INT8 initialValue)976 PCRSetValue(
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 //
1016 void
PCRResetDynamics(void)1017 PCRResetDynamics(
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 //
1055 TPMI_YES_NO
PCRCapGetAllocation(UINT32 count,TPML_PCR_SELECTION * pcrSelection)1056 PCRCapGetAllocation(
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 //
1078 static void
PCRSetSelectBit(UINT32 pcr,BYTE * bitmap)1079 PCRSetSelectBit(
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 //
1098 static BOOL
PCRGetProperty(TPM_PT_PCR property,TPMS_TAGGED_PCR_SELECT * select)1099 PCRGetProperty(
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 //
1207 TPMI_YES_NO
PCRCapGetProperties(TPM_PT_PCR property,UINT32 count,TPML_TAGGED_PCR_PROPERTY * select)1208 PCRCapGetProperties(
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 //
1256 TPMI_YES_NO
PCRCapGetHandles(TPMI_DH_PCR handle,UINT32 count,TPML_HANDLE * handleList)1257 PCRCapGetHandles(
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