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