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 //** Description
36 // This file contains the functions that are used for accessing the
37 // TPM_CAP_TPM_PROPERTY values.
38
39 //** Includes
40
41 #include "Tpm.h"
42
43 //** Functions
44
45 //*** TPMPropertyIsDefined()
46 // This function accepts a property selection and, if so, sets 'value'
47 // to the value of the property.
48 //
49 // All the fixed values are vendor dependent or determined by a
50 // platform-specific specification. The values in the table below
51 // are examples and should be changed by the vendor.
52 // Return Type: BOOL
53 // TRUE(1) referenced property exists and 'value' set
54 // FALSE(0) referenced property does not exist
55 static BOOL
TPMPropertyIsDefined(TPM_PT property,UINT32 * value)56 TPMPropertyIsDefined(
57 TPM_PT property, // IN: property
58 UINT32 *value // OUT: property value
59 )
60 {
61 switch(property)
62 {
63 case TPM_PT_FAMILY_INDICATOR:
64 // from the title page of the specification
65 // For this specification, the value is "2.0".
66 *value = TPM_SPEC_FAMILY;
67 break;
68 case TPM_PT_LEVEL:
69 // from the title page of the specification
70 *value = TPM_SPEC_LEVEL;
71 break;
72 case TPM_PT_REVISION:
73 // from the title page of the specification
74 *value = TPM_SPEC_VERSION;
75 break;
76 case TPM_PT_DAY_OF_YEAR:
77 // computed from the date value on the title page of the specification
78 *value = TPM_SPEC_DAY_OF_YEAR;
79 break;
80 case TPM_PT_YEAR:
81 // from the title page of the specification
82 *value = TPM_SPEC_YEAR;
83 break;
84 case TPM_PT_MANUFACTURER:
85 // vendor ID unique to each TPM manufacturer
86 *value = BYTE_ARRAY_TO_UINT32(MANUFACTURER);
87 break;
88 case TPM_PT_VENDOR_STRING_1:
89 // first four characters of the vendor ID string
90 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_1);
91 break;
92 case TPM_PT_VENDOR_STRING_2:
93 // second four characters of the vendor ID string
94 #ifdef VENDOR_STRING_2
95 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_2);
96 #else
97 *value = 0;
98 #endif
99 break;
100 case TPM_PT_VENDOR_STRING_3:
101 // third four characters of the vendor ID string
102 #ifdef VENDOR_STRING_3
103 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_3);
104 #else
105 *value = 0;
106 #endif
107 break;
108 case TPM_PT_VENDOR_STRING_4:
109 // fourth four characters of the vendor ID string
110 #ifdef VENDOR_STRING_4
111 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_4);
112 #else
113 *value = 0;
114 #endif
115 break;
116 case TPM_PT_VENDOR_TPM_TYPE:
117 // vendor-defined value indicating the TPM model
118 *value = 1;
119 break;
120 case TPM_PT_FIRMWARE_VERSION_1:
121 // more significant 32-bits of a vendor-specific value
122 *value = gp.firmwareV1;
123 break;
124 case TPM_PT_FIRMWARE_VERSION_2:
125 // less significant 32-bits of a vendor-specific value
126 *value = gp.firmwareV2;
127 break;
128 case TPM_PT_INPUT_BUFFER:
129 // maximum size of TPM2B_MAX_BUFFER
130 *value = MAX_DIGEST_BUFFER;
131 break;
132 case TPM_PT_HR_TRANSIENT_MIN:
133 // minimum number of transient objects that can be held in TPM
134 // RAM
135 *value = MAX_LOADED_OBJECTS;
136 break;
137 case TPM_PT_HR_PERSISTENT_MIN:
138 // minimum number of persistent objects that can be held in
139 // TPM NV memory
140 // In this implementation, there is no minimum number of
141 // persistent objects.
142 *value = MIN_EVICT_OBJECTS;
143 break;
144 case TPM_PT_HR_LOADED_MIN:
145 // minimum number of authorization sessions that can be held in
146 // TPM RAM
147 *value = MAX_LOADED_SESSIONS;
148 break;
149 case TPM_PT_ACTIVE_SESSIONS_MAX:
150 // number of authorization sessions that may be active at a time
151 *value = MAX_ACTIVE_SESSIONS;
152 break;
153 case TPM_PT_PCR_COUNT:
154 // number of PCR implemented
155 *value = IMPLEMENTATION_PCR;
156 break;
157 case TPM_PT_PCR_SELECT_MIN:
158 // minimum number of bytes in a TPMS_PCR_SELECT.sizeOfSelect
159 *value = PCR_SELECT_MIN;
160 break;
161 case TPM_PT_CONTEXT_GAP_MAX:
162 // maximum allowed difference (unsigned) between the contextID
163 // values of two saved session contexts
164 *value = ((UINT32)1 << (sizeof(CONTEXT_SLOT) * 8)) - 1;
165 break;
166 case TPM_PT_NV_COUNTERS_MAX:
167 // maximum number of NV indexes that are allowed to have the
168 // TPMA_NV_COUNTER attribute SET
169 // In this implementation, there is no limitation on the number
170 // of counters, except for the size of the NV Index memory.
171 *value = 0;
172 break;
173 case TPM_PT_NV_INDEX_MAX:
174 // maximum size of an NV index data area
175 *value = MAX_NV_INDEX_SIZE;
176 break;
177 case TPM_PT_MEMORY:
178 // a TPMA_MEMORY indicating the memory management method for the TPM
179 {
180 union
181 {
182 TPMA_MEMORY att;
183 UINT32 u32;
184 } attributes = { TPMA_ZERO_INITIALIZER() };
185 SET_ATTRIBUTE(attributes.att, TPMA_MEMORY, sharedNV);
186 SET_ATTRIBUTE(attributes.att, TPMA_MEMORY, objectCopiedToRam);
187
188 // Note: For a LSb0 machine, the bits in a bit field are in the correct
189 // order even if the machine is MSB0. For a MSb0 machine, a TPMA will
190 // be an integer manipulated by masking (USE_BIT_FIELD_STRUCTURES will
191 // be NO) so the bits are manipulate correctly.
192 *value = attributes.u32;
193 break;
194 }
195 case TPM_PT_CLOCK_UPDATE:
196 // interval, in seconds, between updates to the copy of
197 // TPMS_TIME_INFO .clock in NV
198 *value = (1 << NV_CLOCK_UPDATE_INTERVAL);
199 break;
200 case TPM_PT_CONTEXT_HASH:
201 // algorithm used for the integrity hash on saved contexts and
202 // for digesting the fuData of TPM2_FirmwareRead()
203 *value = CONTEXT_INTEGRITY_HASH_ALG;
204 break;
205 case TPM_PT_CONTEXT_SYM:
206 // algorithm used for encryption of saved contexts
207 *value = CONTEXT_ENCRYPT_ALG;
208 break;
209 case TPM_PT_CONTEXT_SYM_SIZE:
210 // size of the key used for encryption of saved contexts
211 *value = CONTEXT_ENCRYPT_KEY_BITS;
212 break;
213 case TPM_PT_ORDERLY_COUNT:
214 // maximum difference between the volatile and non-volatile
215 // versions of TPMA_NV_COUNTER that have TPMA_NV_ORDERLY SET
216 *value = MAX_ORDERLY_COUNT;
217 break;
218 case TPM_PT_MAX_COMMAND_SIZE:
219 // maximum value for 'commandSize'
220 *value = MAX_COMMAND_SIZE;
221 break;
222 case TPM_PT_MAX_RESPONSE_SIZE:
223 // maximum value for 'responseSize'
224 *value = MAX_RESPONSE_SIZE;
225 break;
226 case TPM_PT_MAX_DIGEST:
227 // maximum size of a digest that can be produced by the TPM
228 *value = sizeof(TPMU_HA);
229 break;
230 case TPM_PT_MAX_OBJECT_CONTEXT:
231 // Header has 'sequence', 'handle' and 'hierarchy'
232 #define SIZE_OF_CONTEXT_HEADER \
233 sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) + sizeof(TPMI_RH_HIERARCHY)
234 #define SIZE_OF_CONTEXT_INTEGRITY (sizeof(UINT16) + CONTEXT_INTEGRITY_HASH_SIZE)
235 #define SIZE_OF_FINGERPRINT sizeof(UINT64)
236 #define SIZE_OF_CONTEXT_BLOB_OVERHEAD \
237 (sizeof(UINT16) + SIZE_OF_CONTEXT_INTEGRITY + SIZE_OF_FINGERPRINT)
238 #define SIZE_OF_CONTEXT_OVERHEAD \
239 (SIZE_OF_CONTEXT_HEADER + SIZE_OF_CONTEXT_BLOB_OVERHEAD)
240 #if 0
241 // maximum size of a TPMS_CONTEXT that will be returned by
242 // TPM2_ContextSave for object context
243 *value = 0;
244 // adding sequence, saved handle and hierarchy
245 *value += sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) +
246 sizeof(TPMI_RH_HIERARCHY);
247 // add size field in TPM2B_CONTEXT
248 *value += sizeof(UINT16);
249 // add integrity hash size
250 *value += sizeof(UINT16) +
251 CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
252 // Add fingerprint size, which is the same as sequence size
253 *value += sizeof(UINT64);
254 // Add OBJECT structure size
255 *value += sizeof(OBJECT);
256 #else
257 // the maximum size of a TPMS_CONTEXT that will be returned by
258 // TPM2_ContextSave for object context
259 *value = SIZE_OF_CONTEXT_OVERHEAD + sizeof(OBJECT);
260 #endif
261 break;
262 case TPM_PT_MAX_SESSION_CONTEXT:
263 #if 0
264
265 // the maximum size of a TPMS_CONTEXT that will be returned by
266 // TPM2_ContextSave for object context
267 *value = 0;
268 // adding sequence, saved handle and hierarchy
269 *value += sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) +
270 sizeof(TPMI_RH_HIERARCHY);
271 // Add size field in TPM2B_CONTEXT
272 *value += sizeof(UINT16);
273 // Add integrity hash size
274 *value += sizeof(UINT16) +
275 CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
276 // Add fingerprint size, which is the same as sequence size
277 *value += sizeof(UINT64);
278 // Add SESSION structure size
279 *value += sizeof(SESSION);
280 #else
281 // the maximum size of a TPMS_CONTEXT that will be returned by
282 // TPM2_ContextSave for object context
283 *value = SIZE_OF_CONTEXT_OVERHEAD + sizeof(SESSION);
284 #endif
285 break;
286 case TPM_PT_PS_FAMILY_INDICATOR:
287 // platform specific values for the TPM_PT_PS parameters from
288 // the relevant platform-specific specification
289 // In this reference implementation, all of these values are 0.
290 *value = PLATFORM_FAMILY;
291 break;
292 case TPM_PT_PS_LEVEL:
293 // level of the platform-specific specification
294 *value = PLATFORM_LEVEL;
295 break;
296 case TPM_PT_PS_REVISION:
297 // specification Revision times 100 for the platform-specific
298 // specification
299 *value = PLATFORM_VERSION;
300 break;
301 case TPM_PT_PS_DAY_OF_YEAR:
302 // platform-specific specification day of year using TCG calendar
303 *value = PLATFORM_DAY_OF_YEAR;
304 break;
305 case TPM_PT_PS_YEAR:
306 // platform-specific specification year using the CE
307 *value = PLATFORM_YEAR;
308 break;
309 case TPM_PT_SPLIT_MAX:
310 // number of split signing operations supported by the TPM
311 *value = 0;
312 #if ALG_ECC
313 *value = sizeof(gr.commitArray) * 8;
314 #endif
315 break;
316 case TPM_PT_TOTAL_COMMANDS:
317 // total number of commands implemented in the TPM
318 // Since the reference implementation does not have any
319 // vendor-defined commands, this will be the same as the
320 // number of library commands.
321 {
322 #if COMPRESSED_LISTS
323 (*value) = COMMAND_COUNT;
324 #else
325 COMMAND_INDEX commandIndex;
326 *value = 0;
327
328 // scan all implemented commands
329 for(commandIndex = GetClosestCommandIndex(0);
330 commandIndex != UNIMPLEMENTED_COMMAND_INDEX;
331 commandIndex = GetNextCommandIndex(commandIndex))
332 {
333 (*value)++; // count of all implemented
334 }
335 #endif
336 break;
337 }
338 case TPM_PT_LIBRARY_COMMANDS:
339 // number of commands from the TPM library that are implemented
340 {
341 #if COMPRESSED_LISTS
342 *value = LIBRARY_COMMAND_ARRAY_SIZE;
343 #else
344 COMMAND_INDEX commandIndex;
345 *value = 0;
346
347 // scan all implemented commands
348 for(commandIndex = GetClosestCommandIndex(0);
349 commandIndex < LIBRARY_COMMAND_ARRAY_SIZE;
350 commandIndex = GetNextCommandIndex(commandIndex))
351 {
352 (*value)++;
353 }
354 #endif
355 break;
356 }
357 case TPM_PT_VENDOR_COMMANDS:
358 // number of vendor commands that are implemented
359 *value = VENDOR_COMMAND_ARRAY_SIZE;
360 break;
361 case TPM_PT_NV_BUFFER_MAX:
362 // Maximum data size in an NV write command
363 *value = MAX_NV_BUFFER_SIZE;
364 break;
365 case TPM_PT_MODES:
366 #if FIPS_COMPLIANT
367 *value = 1;
368 #else
369 *value = 0;
370 #endif
371 break;
372 case TPM_PT_MAX_CAP_BUFFER:
373 *value = MAX_CAP_BUFFER;
374 break;
375
376 // Start of variable commands
377 case TPM_PT_PERMANENT:
378 // TPMA_PERMANENT
379 {
380 union {
381 TPMA_PERMANENT attr;
382 UINT32 u32;
383 } flags = { TPMA_ZERO_INITIALIZER() };
384 if(gp.ownerAuth.t.size != 0)
385 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, ownerAuthSet);
386 if(gp.endorsementAuth.t.size != 0)
387 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, endorsementAuthSet);
388 if(gp.lockoutAuth.t.size != 0)
389 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, lockoutAuthSet);
390 if(gp.disableClear)
391 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, disableClear);
392 if(gp.failedTries >= gp.maxTries)
393 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, inLockout);
394 // In this implementation, EPS is always generated by TPM
395 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, tpmGeneratedEPS);
396
397 // Note: For a LSb0 machine, the bits in a bit field are in the correct
398 // order even if the machine is MSB0. For a MSb0 machine, a TPMA will
399 // be an integer manipulated by masking (USE_BIT_FIELD_STRUCTURES will
400 // be NO) so the bits are manipulate correctly.
401 *value = flags.u32;
402 break;
403 }
404 case TPM_PT_STARTUP_CLEAR:
405 // TPMA_STARTUP_CLEAR
406 {
407 union {
408 TPMA_STARTUP_CLEAR attr;
409 UINT32 u32;
410 } flags = { TPMA_ZERO_INITIALIZER() };
411 //
412 if(g_phEnable)
413 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, phEnable);
414 if(gc.shEnable)
415 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, shEnable);
416 if(gc.ehEnable)
417 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, ehEnable);
418 if(gc.phEnableNV)
419 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, phEnableNV);
420 if(g_prevOrderlyState != SU_NONE_VALUE)
421 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, orderly);
422
423 // Note: For a LSb0 machine, the bits in a bit field are in the correct
424 // order even if the machine is MSB0. For a MSb0 machine, a TPMA will
425 // be an integer manipulated by masking (USE_BIT_FIELD_STRUCTURES will
426 // be NO) so the bits are manipulate correctly.
427 *value = flags.u32;
428 break;
429 }
430 case TPM_PT_HR_NV_INDEX:
431 // number of NV indexes currently defined
432 *value = NvCapGetIndexNumber();
433 break;
434 case TPM_PT_HR_LOADED:
435 // number of authorization sessions currently loaded into TPM
436 // RAM
437 *value = SessionCapGetLoadedNumber();
438 break;
439 case TPM_PT_HR_LOADED_AVAIL:
440 // number of additional authorization sessions, of any type,
441 // that could be loaded into TPM RAM
442 *value = SessionCapGetLoadedAvail();
443 break;
444 case TPM_PT_HR_ACTIVE:
445 // number of active authorization sessions currently being
446 // tracked by the TPM
447 *value = SessionCapGetActiveNumber();
448 break;
449 case TPM_PT_HR_ACTIVE_AVAIL:
450 // number of additional authorization sessions, of any type,
451 // that could be created
452 *value = SessionCapGetActiveAvail();
453 break;
454 case TPM_PT_HR_TRANSIENT_AVAIL:
455 // estimate of the number of additional transient objects that
456 // could be loaded into TPM RAM
457 *value = ObjectCapGetTransientAvail();
458 break;
459 case TPM_PT_HR_PERSISTENT:
460 // number of persistent objects currently loaded into TPM
461 // NV memory
462 *value = NvCapGetPersistentNumber();
463 break;
464 case TPM_PT_HR_PERSISTENT_AVAIL:
465 // number of additional persistent objects that could be loaded
466 // into NV memory
467 *value = NvCapGetPersistentAvail();
468 break;
469 case TPM_PT_NV_COUNTERS:
470 // number of defined NV indexes that have NV TPMA_NV_COUNTER
471 // attribute SET
472 *value = NvCapGetCounterNumber();
473 break;
474 case TPM_PT_NV_COUNTERS_AVAIL:
475 // number of additional NV indexes that can be defined with their
476 // TPMA_NV_COUNTER attribute SET
477 *value = NvCapGetCounterAvail();
478 break;
479 case TPM_PT_ALGORITHM_SET:
480 // region code for the TPM
481 *value = gp.algorithmSet;
482 break;
483 case TPM_PT_LOADED_CURVES:
484 #if ALG_ECC
485 // number of loaded ECC curves
486 *value = ECC_CURVE_COUNT;
487 #else // ALG_ECC
488 *value = 0;
489 #endif // ALG_ECC
490 break;
491 case TPM_PT_LOCKOUT_COUNTER:
492 // current value of the lockout counter
493 *value = gp.failedTries;
494 break;
495 case TPM_PT_MAX_AUTH_FAIL:
496 // number of authorization failures before DA lockout is invoked
497 *value = gp.maxTries;
498 break;
499 case TPM_PT_LOCKOUT_INTERVAL:
500 // number of seconds before the value reported by
501 // TPM_PT_LOCKOUT_COUNTER is decremented
502 *value = gp.recoveryTime;
503 break;
504 case TPM_PT_LOCKOUT_RECOVERY:
505 // number of seconds after a lockoutAuth failure before use of
506 // lockoutAuth may be attempted again
507 *value = gp.lockoutRecovery;
508 break;
509 case TPM_PT_NV_WRITE_RECOVERY:
510 // number of milliseconds before the TPM will accept another command
511 // that will modify NV.
512 // This should make a call to the platform code that is doing rate
513 // limiting of NV. Rate limiting is not implemented in the reference
514 // code so no call is made.
515 *value = 0;
516 break;
517 case TPM_PT_AUDIT_COUNTER_0:
518 // high-order 32 bits of the command audit counter
519 *value = (UINT32)(gp.auditCounter >> 32);
520 break;
521 case TPM_PT_AUDIT_COUNTER_1:
522 // low-order 32 bits of the command audit counter
523 *value = (UINT32)(gp.auditCounter);
524 break;
525 default:
526 // property is not defined
527 return FALSE;
528 break;
529 }
530 return TRUE;
531 }
532
533 //*** TPMCapGetProperties()
534 // This function is used to get the TPM_PT values. The search of properties will
535 // start at 'property' and continue until 'propertyList' has as many values as
536 // will fit, or the last property has been reported, or the list has as many
537 // values as requested in 'count'.
538 // Return Type: TPMI_YES_NO
539 // YES more properties are available
540 // NO no more properties to be reported
541 TPMI_YES_NO
TPMCapGetProperties(TPM_PT property,UINT32 count,TPML_TAGGED_TPM_PROPERTY * propertyList)542 TPMCapGetProperties(
543 TPM_PT property, // IN: the starting TPM property
544 UINT32 count, // IN: maximum number of returned
545 // properties
546 TPML_TAGGED_TPM_PROPERTY *propertyList // OUT: property list
547 )
548 {
549 TPMI_YES_NO more = NO;
550 UINT32 i;
551 UINT32 nextGroup;
552
553 // initialize output property list
554 propertyList->count = 0;
555
556 // maximum count of properties we may return is MAX_PCR_PROPERTIES
557 if(count > MAX_TPM_PROPERTIES) count = MAX_TPM_PROPERTIES;
558
559 // if property is less than PT_FIXED, start from PT_FIXED
560 if(property < PT_FIXED)
561 property = PT_FIXED;
562 // There is only the fixed and variable groups with the variable group coming
563 // last
564 if(property >= (PT_VAR + PT_GROUP))
565 return more;
566
567 // Don't read past the end of the selected group
568 nextGroup = ((property / PT_GROUP) * PT_GROUP) + PT_GROUP;
569
570 // Scan through the TPM properties of the requested group.
571 for(i = property; i < nextGroup; i++)
572 {
573 UINT32 value;
574 // if we have hit the end of the group, quit
575 if(i != property && ((i % PT_GROUP) == 0))
576 break;
577 if(TPMPropertyIsDefined((TPM_PT)i, &value))
578 {
579 if(propertyList->count < count)
580 {
581 // If the list is not full, add this property
582 propertyList->tpmProperty[propertyList->count].property =
583 (TPM_PT)i;
584 propertyList->tpmProperty[propertyList->count].value = value;
585 propertyList->count++;
586 }
587 else
588 {
589 // If the return list is full but there are more properties
590 // available, set the indication and exit the loop.
591 more = YES;
592 break;
593 }
594 }
595 }
596 return more;
597 }