Line | Count | Source (jump to first uncovered line) |
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 OBJECT_C |
9 | | #include "InternalRoutines.h" |
10 | | #include "Platform.h" |
11 | | // |
12 | | // |
13 | | // Functions |
14 | | // |
15 | | // ObjectStartup() |
16 | | // |
17 | | // This function is called at TPM2_Startup() to initialize the object subsystem. |
18 | | // |
19 | | void |
20 | | ObjectStartup( |
21 | | void |
22 | | ) |
23 | 253 | { |
24 | 253 | UINT32 i; |
25 | | // object slots initialization |
26 | 1.01k | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
27 | 759 | { |
28 | | //Set the slot to not occupied |
29 | 759 | s_objects[i].occupied = FALSE; |
30 | 759 | } |
31 | 253 | return; |
32 | 253 | } |
33 | | // |
34 | | // |
35 | | // ObjectCleanupEvict() |
36 | | // |
37 | | // In this implementation, a persistent object is moved from NV into an object slot for processing. It is |
38 | | // flushed after command execution. This function is called from ExecuteCommand(). |
39 | | // |
40 | | void |
41 | | ObjectCleanupEvict( |
42 | | void |
43 | | ) |
44 | 506 | { |
45 | 506 | UINT32 i; |
46 | | // This has to be iterated because a command may have two handles |
47 | | // and they may both be persistent. |
48 | | // This could be made to be more efficient so that a search is not needed. |
49 | 2.02k | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
50 | 1.51k | { |
51 | | // If an object is a temporary evict object, flush it from slot |
52 | 1.51k | if(s_objects[i].object.entity.attributes.evict == SET) |
53 | 0 | s_objects[i].occupied = FALSE; |
54 | 1.51k | } |
55 | 506 | return; |
56 | 506 | } |
57 | | // |
58 | | // |
59 | | // ObjectIsPresent() |
60 | | // |
61 | | // This function checks to see if a transient handle references a loaded object. This routine should not be |
62 | | // called if the handle is not a transient handle. The function validates that the handle is in the |
63 | | // implementation-dependent allowed in range for loaded transient objects. |
64 | | // |
65 | | // Return Value Meaning |
66 | | // |
67 | | // TRUE if the handle references a loaded object |
68 | | // FALSE if the handle is not an object handle, or it does not reference to a |
69 | | // loaded object |
70 | | // |
71 | | BOOL |
72 | | ObjectIsPresent( |
73 | | TPMI_DH_OBJECT handle // IN: handle to be checked |
74 | | ) |
75 | 48 | { |
76 | 48 | UINT32 slotIndex; // index of object slot |
77 | 48 | pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); |
78 | | // The index in the loaded object array is found by subtracting the first |
79 | | // object handle number from the input handle number. If the indicated |
80 | | // slot is occupied, then indicate that there is already is a loaded |
81 | | // object associated with the handle. |
82 | 48 | slotIndex = handle - TRANSIENT_FIRST; |
83 | 48 | if(slotIndex >= MAX_LOADED_OBJECTS) |
84 | 0 | return FALSE; |
85 | 48 | return s_objects[slotIndex].occupied; |
86 | 48 | } |
87 | | // |
88 | | // |
89 | | // ObjectIsSequence() |
90 | | // |
91 | | // This function is used to check if the object is a sequence object. This function should not be called if the |
92 | | // handle does not reference a loaded object. |
93 | | // |
94 | | // Return Value Meaning |
95 | | // |
96 | | // TRUE object is an HMAC, hash, or event sequence object |
97 | | // FALSE object is not an HMAC, hash, or event sequence object |
98 | | // |
99 | | BOOL |
100 | | ObjectIsSequence( |
101 | | OBJECT *object // IN: handle to be checked |
102 | | ) |
103 | 0 | { |
104 | 0 | pAssert (object != NULL); |
105 | 0 | if( object->attributes.hmacSeq == SET |
106 | 0 | || object->attributes.hashSeq == SET |
107 | 0 | || object->attributes.eventSeq == SET) |
108 | 0 | return TRUE; |
109 | 0 | else |
110 | 0 | return FALSE; |
111 | 0 | } |
112 | | // |
113 | | // |
114 | | // ObjectGet() |
115 | | // |
116 | | // This function is used to find the object structure associated with a handle. |
117 | | // This function requires that handle references a loaded object. |
118 | | // |
119 | | OBJECT* |
120 | | ObjectGet( |
121 | | TPMI_DH_OBJECT handle // IN: handle of the object |
122 | | ) |
123 | 0 | { |
124 | 0 | pAssert( handle >= TRANSIENT_FIRST |
125 | 0 | && handle - TRANSIENT_FIRST < MAX_LOADED_OBJECTS); |
126 | 0 | pAssert(s_objects[handle - TRANSIENT_FIRST].occupied == TRUE); |
127 | | // In this implementation, the handle is determined by the slot occupied by the |
128 | | // object. |
129 | 0 | return &s_objects[handle - TRANSIENT_FIRST].object.entity; |
130 | 0 | } |
131 | | // |
132 | | // |
133 | | // ObjectGetName() |
134 | | // |
135 | | // This function is used to access the Name of the object. In this implementation, the Name is computed |
136 | | // when the object is loaded and is saved in the internal representation of the object. This function copies |
137 | | // the Name data from the object into the buffer at name and returns the number of octets copied. |
138 | | // This function requires that handle references a loaded object. |
139 | | // |
140 | | UINT16 |
141 | | ObjectGetName( |
142 | | TPMI_DH_OBJECT handle, // IN: handle of the object |
143 | | NAME *name // OUT: name of the object |
144 | | ) |
145 | 0 | { |
146 | 0 | OBJECT *object = ObjectGet(handle); |
147 | 0 | if(object->publicArea.nameAlg == TPM_ALG_NULL) |
148 | 0 | return 0; |
149 | | // Copy the Name data to the output |
150 | 0 | MemoryCopy(name, object->name.t.name, object->name.t.size, sizeof(NAME)); |
151 | 0 | return object->name.t.size; |
152 | 0 | } |
153 | | // |
154 | | // |
155 | | // ObjectGetNameAlg() |
156 | | // |
157 | | // This function is used to get the Name algorithm of a object. |
158 | | // This function requires that handle references a loaded object. |
159 | | // |
160 | | TPMI_ALG_HASH |
161 | | ObjectGetNameAlg( |
162 | | TPMI_DH_OBJECT handle // IN: handle of the object |
163 | | ) |
164 | 0 | { |
165 | 0 | OBJECT *object = ObjectGet(handle); |
166 | 0 | return object->publicArea.nameAlg; |
167 | 0 | } |
168 | | // |
169 | | // |
170 | | // |
171 | | // ObjectGetQualifiedName() |
172 | | // |
173 | | // This function returns the Qualified Name of the object. In this implementation, the Qualified Name is |
174 | | // computed when the object is loaded and is saved in the internal representation of the object. The |
175 | | // alternative would be to retain the Name of the parent and compute the QN when needed. This would take |
176 | | // the same amount of space so it is not recommended that the alternate be used. |
177 | | // This function requires that handle references a loaded object. |
178 | | // |
179 | | void |
180 | | ObjectGetQualifiedName( |
181 | | TPMI_DH_OBJECT handle, // IN: handle of the object |
182 | | TPM2B_NAME *qualifiedName // OUT: qualified name of the object |
183 | | ) |
184 | 0 | { |
185 | 0 | OBJECT *object = ObjectGet(handle); |
186 | 0 | if(object->publicArea.nameAlg == TPM_ALG_NULL) |
187 | 0 | qualifiedName->t.size = 0; |
188 | 0 | else |
189 | | // Copy the name |
190 | 0 | *qualifiedName = object->qualifiedName; |
191 | 0 | return; |
192 | 0 | } |
193 | | // |
194 | | // |
195 | | // ObjectDataGetHierarchy() |
196 | | // |
197 | | // This function returns the handle for the hierarchy of an object. |
198 | | // |
199 | | TPMI_RH_HIERARCHY |
200 | | ObjectDataGetHierarchy( |
201 | | OBJECT *object // IN :object |
202 | | ) |
203 | 0 | { |
204 | 0 | if(object->attributes.spsHierarchy) |
205 | 0 | { |
206 | 0 | return TPM_RH_OWNER; |
207 | 0 | } |
208 | 0 | else if(object->attributes.epsHierarchy) |
209 | 0 | { |
210 | 0 | return TPM_RH_ENDORSEMENT; |
211 | 0 | } |
212 | 0 | else if(object->attributes.ppsHierarchy) |
213 | 0 | { |
214 | 0 | return TPM_RH_PLATFORM; |
215 | 0 | } |
216 | 0 | else |
217 | 0 | { |
218 | 0 | return TPM_RH_NULL; |
219 | 0 | } |
220 | 0 | } |
221 | | // |
222 | | // |
223 | | // ObjectGetHierarchy() |
224 | | // |
225 | | // This function returns the handle of the hierarchy to which a handle belongs. This function is similar to |
226 | | // ObjectDataGetHierarchy() but this routine takes a handle but ObjectDataGetHierarchy() takes an pointer |
227 | | // to an object. |
228 | | // This function requires that handle references a loaded object. |
229 | | // |
230 | | TPMI_RH_HIERARCHY |
231 | | ObjectGetHierarchy( |
232 | | TPMI_DH_OBJECT handle // IN :object handle |
233 | | ) |
234 | 0 | { |
235 | 0 | OBJECT *object = ObjectGet(handle); |
236 | 0 | return ObjectDataGetHierarchy(object); |
237 | 0 | } |
238 | | // |
239 | | // |
240 | | // ObjectAllocateSlot() |
241 | | // |
242 | | // This function is used to allocate a slot in internal object array. |
243 | | // |
244 | | // Return Value Meaning |
245 | | // |
246 | | // TRUE allocate success |
247 | | // FALSE do not have free slot |
248 | | // |
249 | | static BOOL |
250 | | ObjectAllocateSlot( |
251 | | TPMI_DH_OBJECT *handle, // OUT: handle of allocated object |
252 | | OBJECT **object // OUT: points to the allocated object |
253 | | ) |
254 | 53 | { |
255 | 53 | UINT32 i; |
256 | | // find an unoccupied handle slot |
257 | 53 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
258 | 53 | { |
259 | 53 | if(!s_objects[i].occupied) // If found a free slot |
260 | 53 | { |
261 | | // Mark the slot as occupied |
262 | 53 | s_objects[i].occupied = TRUE; |
263 | 53 | break; |
264 | 53 | } |
265 | 53 | } |
266 | | // If we reach the end of object slot without finding a free one, return |
267 | | // error. |
268 | 53 | if(i == MAX_LOADED_OBJECTS) return FALSE; |
269 | 53 | *handle = i + TRANSIENT_FIRST; |
270 | 53 | *object = &s_objects[i].object.entity; |
271 | | // Initialize the container. |
272 | 53 | MemorySet(*object, 0, sizeof(**object)); |
273 | 53 | return TRUE; |
274 | 53 | } |
275 | | // |
276 | | // |
277 | | // ObjectLoad() |
278 | | // |
279 | | // This function loads an object into an internal object structure. If an error is returned, the internal state is |
280 | | // unchanged. |
281 | | // |
282 | | // |
283 | | // |
284 | | // |
285 | | // Error Returns Meaning |
286 | | // |
287 | | // TPM_RC_BINDING if the public and sensitive parts of the object are not matched |
288 | | // TPM_RC_KEY if the parameters in the public area of the object are not consistent |
289 | | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
290 | | // TPM_RC_TYPE the public and private parts are not the same type |
291 | | // |
292 | | TPM_RC |
293 | | ObjectLoad( |
294 | | TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy to which the object belongs |
295 | | TPMT_PUBLIC *publicArea, // IN: public area |
296 | | TPMT_SENSITIVE *sensitive, // IN: sensitive area (may be null) |
297 | | TPM2B_NAME *name, // IN: object's name (may be null) |
298 | | TPM_HANDLE parentHandle, // IN: handle of parent |
299 | | BOOL skipChecks, // IN: flag to indicate if it is OK to skip |
300 | | // consistency checks. |
301 | | TPMI_DH_OBJECT *handle // OUT: object handle |
302 | | ) |
303 | 53 | { |
304 | 53 | OBJECT *object = NULL; |
305 | 53 | OBJECT *parent = NULL; |
306 | 53 | TPM_RC result = TPM_RC_SUCCESS; |
307 | 53 | TPM2B_NAME parentQN; // Parent qualified name |
308 | | // Try to allocate a slot for new object |
309 | 53 | if(!ObjectAllocateSlot(handle, &object)) |
310 | 0 | return TPM_RC_OBJECT_MEMORY; |
311 | | // Initialize public |
312 | 53 | object->publicArea = *publicArea; |
313 | 53 | if(sensitive != NULL) |
314 | 53 | object->sensitive = *sensitive; |
315 | | // Are the consistency checks needed |
316 | 53 | if(!skipChecks) |
317 | 49 | { |
318 | | // Check if key size matches |
319 | 49 | if(!CryptObjectIsPublicConsistent(&object->publicArea)) |
320 | 0 | { |
321 | 0 | result = TPM_RC_KEY; |
322 | 0 | goto ErrorExit; |
323 | 0 | } |
324 | 49 | if(sensitive != NULL) |
325 | 49 | { |
326 | | // Check if public type matches sensitive type |
327 | 49 | result = CryptObjectPublicPrivateMatch(object); |
328 | 49 | if(result != TPM_RC_SUCCESS) |
329 | 48 | goto ErrorExit; |
330 | 49 | } |
331 | 49 | } |
332 | 5 | object->attributes.publicOnly = (sensitive == NULL); |
333 | | // If 'name' is NULL, then there is nothing left to do for this |
334 | | // object as it has no qualified name and it is not a member of any |
335 | | // hierarchy and it is temporary |
336 | 5 | if(name == NULL || name->t.size == 0) |
337 | 0 | { |
338 | 0 | object->qualifiedName.t.size = 0; |
339 | 0 | object->name.t.size = 0; |
340 | 0 | object->attributes.temporary = SET; |
341 | 0 | return TPM_RC_SUCCESS; |
342 | 0 | } |
343 | | // If parent handle is a permanent handle, it is a primary or temporary |
344 | | // object |
345 | 5 | if(HandleGetType(parentHandle) == TPM_HT_PERMANENT) |
346 | 5 | { |
347 | | // initialize QN |
348 | 5 | parentQN.t.size = 4; |
349 | | // for a primary key, parent qualified name is the handle of hierarchy |
350 | 5 | UINT32_TO_BYTE_ARRAY(parentHandle, parentQN.t.name); |
351 | 5 | } |
352 | 0 | else |
353 | 0 | { |
354 | | // Get hierarchy and qualified name of parent |
355 | 0 | ObjectGetQualifiedName(parentHandle, &parentQN); |
356 | | // Check for stClear object |
357 | 0 | parent = ObjectGet(parentHandle); |
358 | 0 | if( publicArea->objectAttributes.stClear == SET |
359 | 0 | || parent->attributes.stClear == SET) |
360 | 0 | object->attributes.stClear = SET; |
361 | 0 | } |
362 | 5 | object->name = *name; |
363 | | // Compute object qualified name |
364 | 5 | ObjectComputeQualifiedName(&parentQN, publicArea->nameAlg, |
365 | 5 | name, &object->qualifiedName); |
366 | | // Any object in TPM_RH_NULL hierarchy is temporary |
367 | 5 | if(hierarchy == TPM_RH_NULL) |
368 | 3 | { |
369 | 3 | object->attributes.temporary = SET; |
370 | 3 | } |
371 | 2 | else if(parentQN.t.size == sizeof(TPM_HANDLE)) |
372 | 2 | { |
373 | | // Otherwise, if the size of parent's qualified name is the size of a |
374 | | // handle, this object is a primary object |
375 | 2 | object->attributes.primary = SET; |
376 | 2 | } |
377 | 5 | switch(hierarchy) |
378 | 5 | { |
379 | 0 | case TPM_RH_PLATFORM: |
380 | 0 | object->attributes.ppsHierarchy = SET; |
381 | 0 | break; |
382 | 0 | case TPM_RH_OWNER: |
383 | 0 | object->attributes.spsHierarchy = SET; |
384 | 0 | break; |
385 | 2 | case TPM_RH_ENDORSEMENT: |
386 | 2 | object->attributes.epsHierarchy = SET; |
387 | 2 | break; |
388 | 3 | case TPM_RH_NULL: |
389 | 3 | break; |
390 | 0 | default: |
391 | 0 | pAssert(FALSE); |
392 | 0 | break; |
393 | 5 | } |
394 | 5 | return TPM_RC_SUCCESS; |
395 | 48 | ErrorExit: |
396 | 48 | ObjectFlush(*handle); |
397 | 48 | return result; |
398 | 5 | } |
399 | | // |
400 | | // |
401 | | // |
402 | | // AllocateSequenceSlot() |
403 | | // |
404 | | // This function allocates a sequence slot and initializes the parts that are used by the normal objects so |
405 | | // that a sequence object is not inadvertently used for an operation that is not appropriate for a sequence. |
406 | | // |
407 | | static BOOL |
408 | | AllocateSequenceSlot( |
409 | | TPM_HANDLE *newHandle, // OUT: receives the allocated handle |
410 | | HASH_OBJECT **object, // OUT: receives pointer to allocated object |
411 | | TPM2B_AUTH *auth // IN: the authValue for the slot |
412 | | ) |
413 | 0 | { |
414 | 0 | OBJECT *objectHash; // the hash as an object |
415 | 0 | if(!ObjectAllocateSlot(newHandle, &objectHash)) |
416 | 0 | return FALSE; |
417 | 0 | *object = (HASH_OBJECT *)objectHash; |
418 | | // Validate that the proper location of the hash state data relative to the |
419 | | // object state data. |
420 | 0 | pAssert(&((*object)->auth) == &objectHash->publicArea.authPolicy); |
421 | | // Set the common values that a sequence object shares with an ordinary object |
422 | | // The type is TPM_ALG_NULL |
423 | 0 | (*object)->type = TPM_ALG_NULL; |
424 | | // This has no name algorithm and the name is the Empty Buffer |
425 | 0 | (*object)->nameAlg = TPM_ALG_NULL; |
426 | | // Clear the attributes |
427 | 0 | MemorySet(&((*object)->objectAttributes), 0, sizeof(TPMA_OBJECT)); |
428 | | // A sequence object is considered to be in the NULL hierarchy so it should |
429 | | // be marked as temporary so that it can't be persisted |
430 | 0 | (*object)->attributes.temporary = SET; |
431 | | // A sequence object is DA exempt. |
432 | 0 | (*object)->objectAttributes.noDA = SET; |
433 | 0 | if(auth != NULL) |
434 | 0 | { |
435 | 0 | MemoryRemoveTrailingZeros(auth); |
436 | 0 | (*object)->auth = *auth; |
437 | 0 | } |
438 | 0 | else |
439 | 0 | (*object)->auth.t.size = 0; |
440 | 0 | return TRUE; |
441 | 0 | } |
442 | | // |
443 | | // |
444 | | // ObjectCreateHMACSequence() |
445 | | // |
446 | | // This function creates an internal HMAC sequence object. |
447 | | // |
448 | | // Error Returns Meaning |
449 | | // |
450 | | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
451 | | // |
452 | | TPM_RC |
453 | | ObjectCreateHMACSequence( |
454 | | TPMI_ALG_HASH hashAlg, // IN: hash algorithm |
455 | | TPM_HANDLE handle, // IN: the handle associated with sequence |
456 | | // object |
457 | | TPM2B_AUTH *auth, // IN: authValue |
458 | | TPMI_DH_OBJECT *newHandle // OUT: HMAC sequence object handle |
459 | | ) |
460 | 0 | { |
461 | 0 | HASH_OBJECT *hmacObject; |
462 | 0 | OBJECT *keyObject; |
463 | | // Try to allocate a slot for new object |
464 | 0 | if(!AllocateSequenceSlot(newHandle, &hmacObject, auth)) |
465 | 0 | return TPM_RC_OBJECT_MEMORY; |
466 | | // Set HMAC sequence bit |
467 | 0 | hmacObject->attributes.hmacSeq = SET; |
468 | | // Get pointer to the HMAC key object |
469 | 0 | keyObject = ObjectGet(handle); |
470 | 0 | CryptStartHMACSequence2B(hashAlg, &keyObject->sensitive.sensitive.bits.b, |
471 | 0 | &hmacObject->state.hmacState); |
472 | 0 | return TPM_RC_SUCCESS; |
473 | 0 | } |
474 | | // |
475 | | // |
476 | | // ObjectCreateHashSequence() |
477 | | // |
478 | | // This function creates a hash sequence object. |
479 | | // |
480 | | // Error Returns Meaning |
481 | | // |
482 | | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
483 | | // |
484 | | TPM_RC |
485 | | ObjectCreateHashSequence( |
486 | | TPMI_ALG_HASH hashAlg, // IN: hash algorithm |
487 | | TPM2B_AUTH *auth, // IN: authValue |
488 | | TPMI_DH_OBJECT *newHandle // OUT: sequence object handle |
489 | | ) |
490 | 0 | { |
491 | 0 | HASH_OBJECT *hashObject; |
492 | | // Try to allocate a slot for new object |
493 | 0 | if(!AllocateSequenceSlot(newHandle, &hashObject, auth)) |
494 | 0 | return TPM_RC_OBJECT_MEMORY; |
495 | | // Set hash sequence bit |
496 | 0 | hashObject->attributes.hashSeq = SET; |
497 | | // Start hash for hash sequence |
498 | 0 | CryptStartHashSequence(hashAlg, &hashObject->state.hashState[0]); |
499 | 0 | return TPM_RC_SUCCESS; |
500 | 0 | } |
501 | | // |
502 | | // |
503 | | // ObjectCreateEventSequence() |
504 | | // |
505 | | // This function creates an event sequence object. |
506 | | // |
507 | | // Error Returns Meaning |
508 | | // |
509 | | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
510 | | // |
511 | | TPM_RC |
512 | | ObjectCreateEventSequence( |
513 | | TPM2B_AUTH *auth, // IN: authValue |
514 | | TPMI_DH_OBJECT *newHandle // OUT: sequence object handle |
515 | | ) |
516 | 0 | { |
517 | 0 | HASH_OBJECT *hashObject; |
518 | 0 | UINT32 count; |
519 | 0 | TPM_ALG_ID hash; |
520 | | // Try to allocate a slot for new object |
521 | 0 | if(!AllocateSequenceSlot(newHandle, &hashObject, auth)) |
522 | 0 | return TPM_RC_OBJECT_MEMORY; |
523 | | // Set the event sequence attribute |
524 | 0 | hashObject->attributes.eventSeq = SET; |
525 | | // Initialize hash states for each implemented PCR algorithms |
526 | 0 | for(count = 0; (hash = CryptGetHashAlgByIndex(count)) != TPM_ALG_NULL; count++) |
527 | 0 | { |
528 | | // If this is a _TPM_Init or _TPM_HashStart, the sequence object will |
529 | | // not leave the TPM so it doesn't need the sequence handling |
530 | 0 | if(auth == NULL) |
531 | 0 | CryptStartHash(hash, &hashObject->state.hashState[count]); |
532 | 0 | else |
533 | 0 | CryptStartHashSequence(hash, &hashObject->state.hashState[count]); |
534 | 0 | } |
535 | 0 | return TPM_RC_SUCCESS; |
536 | 0 | } |
537 | | // |
538 | | // |
539 | | // ObjectTerminateEvent() |
540 | | // |
541 | | // This function is called to close out the event sequence and clean up the hash context states. |
542 | | // |
543 | | void |
544 | | ObjectTerminateEvent( |
545 | | void |
546 | | ) |
547 | 0 | { |
548 | 0 | HASH_OBJECT *hashObject; |
549 | 0 | int count; |
550 | 0 | BYTE buffer[MAX_DIGEST_SIZE]; |
551 | 0 | hashObject = (HASH_OBJECT *)ObjectGet(g_DRTMHandle); |
552 | | // Don't assume that this is a proper sequence object |
553 | 0 | if(hashObject->attributes.eventSeq) |
554 | 0 | { |
555 | | // If it is, close any open hash contexts. This is done in case |
556 | | // the crypto implementation has some context values that need to be |
557 | | // cleaned up (hygiene). |
558 | | // |
559 | 0 | for(count = 0; CryptGetHashAlgByIndex(count) != TPM_ALG_NULL; count++) |
560 | 0 | { |
561 | 0 | CryptCompleteHash(&hashObject->state.hashState[count], 0, buffer); |
562 | 0 | } |
563 | | // Flush sequence object |
564 | 0 | ObjectFlush(g_DRTMHandle); |
565 | 0 | } |
566 | 0 | g_DRTMHandle = TPM_RH_UNASSIGNED; |
567 | 0 | } |
568 | | // |
569 | | // |
570 | | // |
571 | | // ObjectContextLoad() |
572 | | // |
573 | | // This function loads an object from a saved object context. |
574 | | // |
575 | | // Error Returns Meaning |
576 | | // |
577 | | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
578 | | // |
579 | | TPM_RC |
580 | | ObjectContextLoad( |
581 | | OBJECT *object, // IN: object structure from saved context |
582 | | TPMI_DH_OBJECT *handle // OUT: object handle |
583 | | ) |
584 | 0 | { |
585 | 0 | OBJECT *newObject; |
586 | | // Try to allocate a slot for new object |
587 | 0 | if(!ObjectAllocateSlot(handle, &newObject)) |
588 | 0 | return TPM_RC_OBJECT_MEMORY; |
589 | | // Copy input object data to internal structure |
590 | 0 | *newObject = *object; |
591 | 0 | return TPM_RC_SUCCESS; |
592 | 0 | } |
593 | | // |
594 | | // |
595 | | // ObjectFlush() |
596 | | // |
597 | | // This function frees an object slot. |
598 | | // This function requires that the object is loaded. |
599 | | // |
600 | | void |
601 | | ObjectFlush( |
602 | | TPMI_DH_OBJECT handle // IN: handle to be freed |
603 | | ) |
604 | 48 | { |
605 | 48 | UINT32 index = handle - TRANSIENT_FIRST; |
606 | 48 | pAssert(ObjectIsPresent(handle)); |
607 | | // Mark the handle slot as unoccupied |
608 | 48 | s_objects[index].occupied = FALSE; |
609 | | // With no attributes |
610 | 48 | MemorySet((BYTE*)&(s_objects[index].object.entity.attributes), |
611 | 48 | 0, sizeof(OBJECT_ATTRIBUTES)); |
612 | 48 | return; |
613 | 48 | } |
614 | | // |
615 | | // |
616 | | // ObjectFlushHierarchy() |
617 | | // |
618 | | // This function is called to flush all the loaded transient objects associated with a hierarchy when the |
619 | | // hierarchy is disabled. |
620 | | // |
621 | | void |
622 | | ObjectFlushHierarchy( |
623 | | TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flush |
624 | | ) |
625 | 0 | { |
626 | 0 | UINT16 i; |
627 | | // iterate object slots |
628 | 0 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
629 | 0 | { |
630 | 0 | if(s_objects[i].occupied) // If found an occupied slot |
631 | 0 | { |
632 | 0 | switch(hierarchy) |
633 | 0 | { |
634 | 0 | case TPM_RH_PLATFORM: |
635 | 0 | if(s_objects[i].object.entity.attributes.ppsHierarchy == SET) |
636 | 0 | s_objects[i].occupied = FALSE; |
637 | 0 | break; |
638 | 0 | case TPM_RH_OWNER: |
639 | 0 | if(s_objects[i].object.entity.attributes.spsHierarchy == SET) |
640 | 0 | s_objects[i].occupied = FALSE; |
641 | 0 | break; |
642 | 0 | case TPM_RH_ENDORSEMENT: |
643 | 0 | if(s_objects[i].object.entity.attributes.epsHierarchy == SET) |
644 | 0 | s_objects[i].occupied = FALSE; |
645 | 0 | break; |
646 | 0 | default: |
647 | 0 | pAssert(FALSE); |
648 | 0 | break; |
649 | 0 | } |
650 | 0 | } |
651 | 0 | } |
652 | 0 | return; |
653 | 0 | } |
654 | | // |
655 | | // |
656 | | // ObjectLoadEvict() |
657 | | // |
658 | | // This function loads a persistent object into a transient object slot. |
659 | | // This function requires that handle is associated with a persistent object. |
660 | | // |
661 | | // Error Returns Meaning |
662 | | // |
663 | | // TPM_RC_HANDLE the persistent object does not exist or the associated hierarchy is |
664 | | // disabled. |
665 | | // TPM_RC_OBJECT_MEMORY no object slot |
666 | | // |
667 | | TPM_RC |
668 | | ObjectLoadEvict( |
669 | | TPM_HANDLE *handle, // IN:OUT: evict object handle. If success, it |
670 | | // will be replace by the loaded object handle |
671 | | TPM_CC commandCode // IN: the command being processed |
672 | | ) |
673 | 0 | { |
674 | 0 | TPM_RC result; |
675 | 0 | TPM_HANDLE evictHandle = *handle; // Save the evict handle |
676 | 0 | OBJECT *object; |
677 | | // If this is an index that references a persistent object created by |
678 | | // the platform, then return TPM_RH_HANDLE if the phEnable is FALSE |
679 | 0 | if(*handle >= PLATFORM_PERSISTENT) |
680 | 0 | { |
681 | | // belongs to platform |
682 | 0 | if(g_phEnable == CLEAR) |
683 | 0 | return TPM_RC_HANDLE; |
684 | 0 | } |
685 | | // belongs to owner |
686 | 0 | else if(gc.shEnable == CLEAR) |
687 | 0 | return TPM_RC_HANDLE; |
688 | | // Try to allocate a slot for an object |
689 | 0 | if(!ObjectAllocateSlot(handle, &object)) |
690 | 0 | return TPM_RC_OBJECT_MEMORY; |
691 | | // Copy persistent object to transient object slot. A TPM_RC_HANDLE |
692 | | // may be returned at this point. This will mark the slot as containing |
693 | | // a transient object so that it will be flushed at the end of the |
694 | | // command |
695 | 0 | result = NvGetEvictObject(evictHandle, object); |
696 | | // Bail out if this failed |
697 | 0 | if(result != TPM_RC_SUCCESS) |
698 | 0 | return result; |
699 | | // check the object to see if it is in the endorsement hierarchy |
700 | | // if it is and this is not a TPM2_EvictControl() command, indicate |
701 | | // that the hierarchy is disabled. |
702 | | // If the associated hierarchy is disabled, make it look like the |
703 | | // handle is not defined |
704 | 0 | if( ObjectDataGetHierarchy(object) == TPM_RH_ENDORSEMENT |
705 | 0 | && gc.ehEnable == CLEAR |
706 | 0 | && commandCode != TPM_CC_EvictControl |
707 | 0 | ) |
708 | 0 | return TPM_RC_HANDLE; |
709 | 0 | return result; |
710 | 0 | } |
711 | | // |
712 | | // |
713 | | // ObjectComputeName() |
714 | | // |
715 | | // This function computes the Name of an object from its public area. |
716 | | // |
717 | | void |
718 | | ObjectComputeName( |
719 | | TPMT_PUBLIC *publicArea, // IN: public area of an object |
720 | | TPM2B_NAME *name // OUT: name of the object |
721 | | ) |
722 | 57 | { |
723 | 57 | TPM2B_PUBLIC marshalBuffer; |
724 | 57 | BYTE *buffer; // auxiliary marshal buffer pointer |
725 | 57 | INT32 bufferSize; |
726 | 57 | HASH_STATE hashState; // hash state |
727 | | // if the nameAlg is NULL then there is no name. |
728 | 57 | if(publicArea->nameAlg == TPM_ALG_NULL) |
729 | 0 | { |
730 | 0 | name->t.size = 0; |
731 | 0 | return; |
732 | 0 | } |
733 | | // Start hash stack |
734 | 57 | name->t.size = CryptStartHash(publicArea->nameAlg, &hashState); |
735 | | // Marshal the public area into its canonical form |
736 | 57 | buffer = marshalBuffer.b.buffer; |
737 | 57 | bufferSize = sizeof(TPMT_PUBLIC); |
738 | 57 | marshalBuffer.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, &bufferSize); |
739 | | // Adding public area |
740 | 57 | CryptUpdateDigest2B(&hashState, &marshalBuffer.b); |
741 | | // Complete hash leaving room for the name algorithm |
742 | 57 | CryptCompleteHash(&hashState, name->t.size, &name->t.name[2]); |
743 | | // set the nameAlg |
744 | 57 | UINT16_TO_BYTE_ARRAY(publicArea->nameAlg, name->t.name); |
745 | | // |
746 | 57 | name->t.size += 2; |
747 | 57 | return; |
748 | 57 | } |
749 | | // |
750 | | // |
751 | | // ObjectComputeQualifiedName() |
752 | | // |
753 | | // This function computes the qualified name of an object. |
754 | | // |
755 | | void |
756 | | ObjectComputeQualifiedName( |
757 | | TPM2B_NAME *parentQN, // IN: parent's qualified name |
758 | | TPM_ALG_ID nameAlg, // IN: name hash |
759 | | TPM2B_NAME *name, // IN: name of the object |
760 | | TPM2B_NAME *qualifiedName // OUT: qualified name of the object |
761 | | ) |
762 | 5 | { |
763 | 5 | HASH_STATE hashState; // hash state |
764 | | // QN_A = hash_A (QN of parent || NAME_A) |
765 | | // Start hash |
766 | 5 | qualifiedName->t.size = CryptStartHash(nameAlg, &hashState); |
767 | | // Add parent's qualified name |
768 | 5 | CryptUpdateDigest2B(&hashState, &parentQN->b); |
769 | | // Add self name |
770 | 5 | CryptUpdateDigest2B(&hashState, &name->b); |
771 | | // Complete hash leaving room for the name algorithm |
772 | 5 | CryptCompleteHash(&hashState, qualifiedName->t.size, |
773 | 5 | &qualifiedName->t.name[2]); |
774 | 5 | UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name); |
775 | 5 | qualifiedName->t.size += 2; |
776 | 5 | return; |
777 | 5 | } |
778 | | // |
779 | | // |
780 | | // ObjectDataIsStorage() |
781 | | // |
782 | | // This function determines if a public area has the attributes associated with a storage key. A storage key is |
783 | | // an asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR. |
784 | | // |
785 | | // Return Value Meaning |
786 | | // |
787 | | // TRUE if the object is a storage key |
788 | | // FALSE if the object is not a storage key |
789 | | // |
790 | | BOOL |
791 | | ObjectDataIsStorage( |
792 | | TPMT_PUBLIC *publicArea // IN: public area of the object |
793 | | ) |
794 | 0 | { |
795 | 0 | if( CryptIsAsymAlgorithm(publicArea->type) // must be asymmetric, |
796 | 0 | && publicArea->objectAttributes.restricted == SET // restricted, |
797 | 0 | && publicArea->objectAttributes.decrypt == SET // decryption key |
798 | 0 | && publicArea->objectAttributes.sign == CLEAR // can not be sign key |
799 | 0 | ) |
800 | 0 | return TRUE; |
801 | 0 | else |
802 | 0 | return FALSE; |
803 | 0 | } |
804 | | // |
805 | | // ObjectIsStorage() |
806 | | // |
807 | | // This function determines if an object has the attributes associated with a storage key. A storage key is an |
808 | | // asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR. |
809 | | // |
810 | | // Return Value Meaning |
811 | | // |
812 | | // TRUE if the object is a storage key |
813 | | // FALSE if the object is not a storage key |
814 | | // |
815 | | BOOL |
816 | | ObjectIsStorage( |
817 | | TPMI_DH_OBJECT handle // IN: object handle |
818 | | ) |
819 | 0 | { |
820 | 0 | OBJECT *object = ObjectGet(handle); |
821 | 0 | return ObjectDataIsStorage(&object->publicArea); |
822 | 0 | } |
823 | | // |
824 | | // |
825 | | // ObjectCapGetLoaded() |
826 | | // |
827 | | // This function returns a a list of handles of loaded object, starting from handle. Handle must be in the |
828 | | // range of valid transient object handles, but does not have to be the handle of a loaded transient object. |
829 | | // |
830 | | // Return Value Meaning |
831 | | // |
832 | | // YES if there are more handles available |
833 | | // NO all the available handles has been returned |
834 | | // |
835 | | TPMI_YES_NO |
836 | | ObjectCapGetLoaded( |
837 | | TPMI_DH_OBJECT handle, // IN: start handle |
838 | | UINT32 count, // IN: count of returned handles |
839 | | TPML_HANDLE *handleList // OUT: list of handle |
840 | | ) |
841 | 0 | { |
842 | 0 | TPMI_YES_NO more = NO; |
843 | 0 | UINT32 i; |
844 | 0 | pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); |
845 | | // Initialize output handle list |
846 | 0 | handleList->count = 0; |
847 | | // The maximum count of handles we may return is MAX_CAP_HANDLES |
848 | 0 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
849 | | // Iterate object slots to get loaded object handles |
850 | 0 | for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++) |
851 | 0 | { |
852 | 0 | if(s_objects[i].occupied == TRUE) |
853 | 0 | { |
854 | | // A valid transient object can not be the copy of a persistent object |
855 | 0 | pAssert(s_objects[i].object.entity.attributes.evict == CLEAR); |
856 | 0 | if(handleList->count < count) |
857 | 0 | { |
858 | | // If we have not filled up the return list, add this object |
859 | | // handle to it |
860 | 0 | handleList->handle[handleList->count] = i + TRANSIENT_FIRST; |
861 | 0 | handleList->count++; |
862 | | // |
863 | 0 | } |
864 | 0 | else |
865 | 0 | { |
866 | | // If the return list is full but we still have loaded object |
867 | | // available, report this and stop iterating |
868 | 0 | more = YES; |
869 | 0 | break; |
870 | 0 | } |
871 | 0 | } |
872 | 0 | } |
873 | 0 | return more; |
874 | 0 | } |
875 | | // |
876 | | // |
877 | | // ObjectCapGetTransientAvail() |
878 | | // |
879 | | // This function returns an estimate of the number of additional transient objects that could be loaded into |
880 | | // the TPM. |
881 | | // |
882 | | UINT32 |
883 | | ObjectCapGetTransientAvail( |
884 | | void |
885 | | ) |
886 | 0 | { |
887 | 0 | UINT32 i; |
888 | 0 | UINT32 num = 0; |
889 | | // Iterate object slot to get the number of unoccupied slots |
890 | 0 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
891 | 0 | { |
892 | 0 | if(s_objects[i].occupied == FALSE) num++; |
893 | 0 | } |
894 | 0 | return num; |
895 | 0 | } |