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 // This file contains the functions that manage the object store of the TPM.
37
38 //** Includes and Data Definitions
39 #define OBJECT_C
40
41 #include "Tpm.h"
42
43 //** Functions
44
45 //*** ObjectFlush()
46 // This function marks an object slot as available.
47 // Since there is no checking of the input parameters, it should be used
48 // judiciously.
49 // Note: This could be converted to a macro.
50 void
ObjectFlush(OBJECT * object)51 ObjectFlush(
52 OBJECT *object
53 )
54 {
55 object->attributes.occupied = CLEAR;
56 }
57
58 //*** ObjectSetInUse()
59 // This access function sets the occupied attribute of an object slot.
60 void
ObjectSetInUse(OBJECT * object)61 ObjectSetInUse(
62 OBJECT *object
63 )
64 {
65 object->attributes.occupied = SET;
66 }
67
68 //*** ObjectStartup()
69 // This function is called at TPM2_Startup() to initialize the object subsystem.
70 BOOL
ObjectStartup(void)71 ObjectStartup(
72 void
73 )
74 {
75 UINT32 i;
76 //
77 // object slots initialization
78 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
79 {
80 //Set the slot to not occupied
81 ObjectFlush(&s_objects[i]);
82 }
83 return TRUE;
84 }
85
86 //*** ObjectCleanupEvict()
87 //
88 // In this implementation, a persistent object is moved from NV into an object slot
89 // for processing. It is flushed after command execution. This function is called
90 // from ExecuteCommand().
91 void
ObjectCleanupEvict(void)92 ObjectCleanupEvict(
93 void
94 )
95 {
96 UINT32 i;
97 //
98 // This has to be iterated because a command may have two handles
99 // and they may both be persistent.
100 // This could be made to be more efficient so that a search is not needed.
101 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
102 {
103 // If an object is a temporary evict object, flush it from slot
104 OBJECT *object = &s_objects[i];
105 if(object->attributes.evict == SET)
106 ObjectFlush(object);
107 }
108 return;
109 }
110
111 //*** IsObjectPresent()
112 // This function checks to see if a transient handle references a loaded
113 // object. This routine should not be called if the handle is not a
114 // transient handle. The function validates that the handle is in the
115 // implementation-dependent allowed in range for loaded transient objects.
116 // Return Type: BOOL
117 // TRUE(1) handle references a loaded object
118 // FALSE(0) handle is not an object handle, or it does not
119 // reference to a loaded object
120 BOOL
IsObjectPresent(TPMI_DH_OBJECT handle)121 IsObjectPresent(
122 TPMI_DH_OBJECT handle // IN: handle to be checked
123 )
124 {
125 UINT32 slotIndex = handle - TRANSIENT_FIRST;
126 // Since the handle is just an index into the array that is zero based, any
127 // handle value outsize of the range of:
128 // TRANSIENT_FIRST -- (TRANSIENT_FIRST + MAX_LOADED_OBJECT - 1)
129 // will now be greater than or equal to MAX_LOADED_OBJECTS
130 if(slotIndex >= MAX_LOADED_OBJECTS)
131 return FALSE;
132 // Indicate if the slot is occupied
133 return (s_objects[slotIndex].attributes.occupied == TRUE);
134 }
135
136 //*** ObjectIsSequence()
137 // This function is used to check if the object is a sequence object. This function
138 // should not be called if the handle does not reference a loaded object.
139 // Return Type: BOOL
140 // TRUE(1) object is an HMAC, hash, or event sequence object
141 // FALSE(0) object is not an HMAC, hash, or event sequence object
142 BOOL
ObjectIsSequence(OBJECT * object)143 ObjectIsSequence(
144 OBJECT *object // IN: handle to be checked
145 )
146 {
147 pAssert(object != NULL);
148 return (object->attributes.hmacSeq == SET
149 || object->attributes.hashSeq == SET
150 || object->attributes.eventSeq == SET);
151 }
152
153 //*** HandleToObject()
154 // This function is used to find the object structure associated with a handle.
155 //
156 // This function requires that 'handle' references a loaded object or a permanent
157 // handle.
158 OBJECT*
HandleToObject(TPMI_DH_OBJECT handle)159 HandleToObject(
160 TPMI_DH_OBJECT handle // IN: handle of the object
161 )
162 {
163 UINT32 index;
164 //
165 // Return NULL if the handle references a permanent handle because there is no
166 // associated OBJECT.
167 if(HandleGetType(handle) == TPM_HT_PERMANENT)
168 return NULL;
169 // In this implementation, the handle is determined by the slot occupied by the
170 // object.
171 index = handle - TRANSIENT_FIRST;
172 pAssert(index < MAX_LOADED_OBJECTS);
173 pAssert(s_objects[index].attributes.occupied);
174 return &s_objects[index];
175 }
176
177
178 //*** GetQualifiedName()
179 // This function returns the Qualified Name of the object. In this implementation,
180 // the Qualified Name is computed when the object is loaded and is saved in the
181 // internal representation of the object. The alternative would be to retain the
182 // Name of the parent and compute the QN when needed. This would take the same
183 // amount of space so it is not recommended that the alternate be used.
184 //
185 // This function requires that 'handle' references a loaded object.
186 void
GetQualifiedName(TPMI_DH_OBJECT handle,TPM2B_NAME * qualifiedName)187 GetQualifiedName(
188 TPMI_DH_OBJECT handle, // IN: handle of the object
189 TPM2B_NAME *qualifiedName // OUT: qualified name of the object
190 )
191 {
192 OBJECT *object;
193 //
194 switch(HandleGetType(handle))
195 {
196 case TPM_HT_PERMANENT:
197 qualifiedName->t.size = sizeof(TPM_HANDLE);
198 UINT32_TO_BYTE_ARRAY(handle, qualifiedName->t.name);
199 break;
200 case TPM_HT_TRANSIENT:
201 object = HandleToObject(handle);
202 if(object == NULL || object->publicArea.nameAlg == TPM_ALG_NULL)
203 qualifiedName->t.size = 0;
204 else
205 // Copy the name
206 *qualifiedName = object->qualifiedName;
207 break;
208 default:
209 FAIL(FATAL_ERROR_INTERNAL);
210 }
211 return;
212 }
213
214 //*** ObjectGetHierarchy()
215 // This function returns the handle for the hierarchy of an object.
216 TPMI_RH_HIERARCHY
ObjectGetHierarchy(OBJECT * object)217 ObjectGetHierarchy(
218 OBJECT *object // IN :object
219 )
220 {
221 if(object->attributes.spsHierarchy)
222 {
223 return TPM_RH_OWNER;
224 }
225 else if(object->attributes.epsHierarchy)
226 {
227 return TPM_RH_ENDORSEMENT;
228 }
229 else if(object->attributes.ppsHierarchy)
230 {
231 return TPM_RH_PLATFORM;
232 }
233 else
234 {
235 return TPM_RH_NULL;
236 }
237 }
238
239 //*** GetHierarchy()
240 // This function returns the handle of the hierarchy to which a handle belongs.
241 // This function is similar to ObjectGetHierarchy() but this routine takes
242 // a handle but ObjectGetHierarchy() takes an pointer to an object.
243 //
244 // This function requires that 'handle' references a loaded object.
245 TPMI_RH_HIERARCHY
GetHierarchy(TPMI_DH_OBJECT handle)246 GetHierarchy(
247 TPMI_DH_OBJECT handle // IN :object handle
248 )
249 {
250 OBJECT *object = HandleToObject(handle);
251 //
252 return ObjectGetHierarchy(object);
253 }
254
255 //*** FindEmptyObjectSlot()
256 // This function finds an open object slot, if any. It will clear the attributes
257 // but will not set the occupied attribute. This is so that a slot may be used
258 // and discarded if everything does not go as planned.
259 // Return Type: OBJECT *
260 // NULL no open slot found
261 // != NULL pointer to available slot
262 OBJECT *
FindEmptyObjectSlot(TPMI_DH_OBJECT * handle)263 FindEmptyObjectSlot(
264 TPMI_DH_OBJECT *handle // OUT: (optional)
265 )
266 {
267 UINT32 i;
268 OBJECT *object;
269 //
270 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
271 {
272 object = &s_objects[i];
273 if(object->attributes.occupied == CLEAR)
274 {
275 if(handle)
276 *handle = i + TRANSIENT_FIRST;
277 // Initialize the object attributes
278 MemorySet(&object->attributes, 0, sizeof(OBJECT_ATTRIBUTES));
279 return object;
280 }
281 }
282 return NULL;
283 }
284
285 //*** ObjectAllocateSlot()
286 // This function is used to allocate a slot in internal object array.
287 OBJECT *
ObjectAllocateSlot(TPMI_DH_OBJECT * handle)288 ObjectAllocateSlot(
289 TPMI_DH_OBJECT *handle // OUT: handle of allocated object
290 )
291 {
292 OBJECT *object = FindEmptyObjectSlot(handle);
293 //
294 if(object != NULL)
295 {
296 // if found, mark as occupied
297 ObjectSetInUse(object);
298 }
299 return object;
300 }
301
302 //*** ObjectSetLoadedAttributes()
303 // This function sets the internal attributes for a loaded object. It is called to
304 // finalize the OBJECT attributes (not the TPMA_OBJECT attributes) for a loaded
305 // object.
306 void
ObjectSetLoadedAttributes(OBJECT * object,TPM_HANDLE parentHandle)307 ObjectSetLoadedAttributes(
308 OBJECT *object, // IN: object attributes to finalize
309 TPM_HANDLE parentHandle // IN: the parent handle
310 )
311 {
312 OBJECT *parent = HandleToObject(parentHandle);
313 TPMA_OBJECT objectAttributes = object->publicArea.objectAttributes;
314 //
315 // Copy the stClear attribute from the public area. This could be overwritten
316 // if the parent has stClear SET
317 object->attributes.stClear =
318 IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear);
319 // If parent handle is a permanent handle, it is a primary (unless it is NULL
320 if(parent == NULL)
321 {
322 object->attributes.primary = SET;
323 switch(parentHandle)
324 {
325 case TPM_RH_ENDORSEMENT:
326 object->attributes.epsHierarchy = SET;
327 break;
328 case TPM_RH_OWNER:
329 object->attributes.spsHierarchy = SET;
330 break;
331 case TPM_RH_PLATFORM:
332 object->attributes.ppsHierarchy = SET;
333 break;
334 default:
335 // Treat the temporary attribute as a hierarchy
336 object->attributes.temporary = SET;
337 object->attributes.primary = CLEAR;
338 break;
339 }
340 }
341 else
342 {
343 // is this a stClear object
344 object->attributes.stClear =
345 (IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear)
346 || (parent->attributes.stClear == SET));
347 object->attributes.epsHierarchy = parent->attributes.epsHierarchy;
348 object->attributes.spsHierarchy = parent->attributes.spsHierarchy;
349 object->attributes.ppsHierarchy = parent->attributes.ppsHierarchy;
350 // An object is temporary if its parent is temporary or if the object
351 // is external
352 object->attributes.temporary = parent->attributes.temporary
353 || object->attributes.external;
354 }
355 // If this is an external object, set the QN == name but don't SET other
356 // key properties ('parent' or 'derived')
357 if(object->attributes.external)
358 object->qualifiedName = object->name;
359 else
360 {
361 // check attributes for different types of parents
362 if(IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, restricted)
363 && !object->attributes.publicOnly
364 && IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, decrypt)
365 && object->publicArea.nameAlg != TPM_ALG_NULL)
366 {
367 // This is a parent. If it is not a KEYEDHASH, it is an ordinary parent.
368 // Otherwise, it is a derivation parent.
369 if(object->publicArea.type == TPM_ALG_KEYEDHASH)
370 object->attributes.derivation = SET;
371 else
372 object->attributes.isParent = SET;
373 }
374 ComputeQualifiedName(parentHandle, object->publicArea.nameAlg,
375 &object->name, &object->qualifiedName);
376 }
377 // Set slot occupied
378 ObjectSetInUse(object);
379 return;
380 }
381
382 //*** ObjectLoad()
383 // Common function to load an object. A loaded object has its public area validated
384 // (unless its 'nameAlg' is TPM_ALG_NULL). If a sensitive part is loaded, it is
385 // verified to be correct and if both public and sensitive parts are loaded, then
386 // the cryptographic binding between the objects is validated. This function does
387 // not cause the allocated slot to be marked as in use.
388 TPM_RC
ObjectLoad(OBJECT * object,OBJECT * parent,TPMT_PUBLIC * publicArea,TPMT_SENSITIVE * sensitive,TPM_RC blamePublic,TPM_RC blameSensitive,TPM2B_NAME * name)389 ObjectLoad(
390 OBJECT *object, // IN: pointer to object slot
391 // object
392 OBJECT *parent, // IN: (optional) the parent object
393 TPMT_PUBLIC *publicArea, // IN: public area to be installed in the object
394 TPMT_SENSITIVE *sensitive, // IN: (optional) sensitive area to be
395 // installed in the object
396 TPM_RC blamePublic, // IN: parameter number to associate with the
397 // publicArea errors
398 TPM_RC blameSensitive,// IN: parameter number to associate with the
399 // sensitive area errors
400 TPM2B_NAME *name // IN: (optional)
401 )
402 {
403 TPM_RC result = TPM_RC_SUCCESS;
404 //
405 // Do validations of public area object descriptions
406 pAssert(publicArea != NULL);
407
408 // Is this public only or a no-name object?
409 if(sensitive == NULL || publicArea->nameAlg == TPM_ALG_NULL)
410 {
411 // Need to have schemes checked so that we do the right thing with the
412 // public key.
413 result = SchemeChecks(NULL, publicArea);
414 }
415 else
416 {
417 // For any sensitive area, make sure that the seedSize is no larger than the
418 // digest size of nameAlg
419 if(sensitive->seedValue.t.size > CryptHashGetDigestSize(publicArea->nameAlg))
420 return TPM_RCS_KEY_SIZE + blameSensitive;
421 // Check attributes and schemes for consistency
422 result = PublicAttributesValidation(parent, publicArea);
423 }
424 if(result != TPM_RC_SUCCESS)
425 return RcSafeAddToResult(result, blamePublic);
426
427 // Sensitive area and binding checks
428
429 // On load, check nothing if the parent is fixedTPM. For all other cases, validate
430 // the keys.
431 if((parent == NULL)
432 || ((parent != NULL) && !IS_ATTRIBUTE(parent->publicArea.objectAttributes,
433 TPMA_OBJECT, fixedTPM)))
434 {
435 // Do the cryptographic key validation
436 result = CryptValidateKeys(publicArea, sensitive, blamePublic,
437 blameSensitive);
438 if(result != TPM_RC_SUCCESS)
439 return result;
440 }
441 #if ALG_RSA
442 // If this is an RSA key, then expand the private exponent.
443 // Note: ObjectLoad() is only called by TPM2_Import() if the parent is fixedTPM.
444 // For any key that does not have a fixedTPM parent, the exponent is computed
445 // whenever it is loaded
446 if((publicArea->type == TPM_ALG_RSA) && (sensitive != NULL))
447 {
448 result = CryptRsaLoadPrivateExponent(publicArea, sensitive);
449 if(result != TPM_RC_SUCCESS)
450 return result;
451 }
452 #endif // ALG_RSA
453 // See if there is an object to populate
454 if((result == TPM_RC_SUCCESS) && (object != NULL))
455 {
456 // Initialize public
457 object->publicArea = *publicArea;
458 // Copy sensitive if there is one
459 if(sensitive == NULL)
460 object->attributes.publicOnly = SET;
461 else
462 object->sensitive = *sensitive;
463 // Set the name, if one was provided
464 if(name != NULL)
465 object->name = *name;
466 else
467 object->name.t.size = 0;
468 }
469 return result;
470 }
471
472 //*** AllocateSequenceSlot()
473 // This function allocates a sequence slot and initializes the parts that
474 // are used by the normal objects so that a sequence object is not inadvertently
475 // used for an operation that is not appropriate for a sequence.
476 //
477 static HASH_OBJECT *
AllocateSequenceSlot(TPM_HANDLE * newHandle,TPM2B_AUTH * auth)478 AllocateSequenceSlot(
479 TPM_HANDLE *newHandle, // OUT: receives the allocated handle
480 TPM2B_AUTH *auth // IN: the authValue for the slot
481 )
482 {
483 HASH_OBJECT *object = (HASH_OBJECT *)ObjectAllocateSlot(newHandle);
484 //
485 // Validate that the proper location of the hash state data relative to the
486 // object state data. It would be good if this could have been done at compile
487 // time but it can't so do it in something that can be removed after debug.
488 cAssert(offsetof(HASH_OBJECT, auth) == offsetof(OBJECT, publicArea.authPolicy));
489
490 if(object != NULL)
491 {
492
493 // Set the common values that a sequence object shares with an ordinary object
494 // First, clear all attributes
495 MemorySet(&object->objectAttributes, 0, sizeof(TPMA_OBJECT));
496
497 // The type is TPM_ALG_NULL
498 object->type = TPM_ALG_NULL;
499
500 // This has no name algorithm and the name is the Empty Buffer
501 object->nameAlg = TPM_ALG_NULL;
502
503 // A sequence object is considered to be in the NULL hierarchy so it should
504 // be marked as temporary so that it can't be persisted
505 object->attributes.temporary = SET;
506
507 // A sequence object is DA exempt.
508 SET_ATTRIBUTE(object->objectAttributes, TPMA_OBJECT, noDA);
509
510 // Copy the authorization value
511 if(auth != NULL)
512 object->auth = *auth;
513 else
514 object->auth.t.size = 0;
515 }
516 return object;
517 }
518
519
520 #if CC_HMAC_Start || CC_MAC_Start
521 //*** ObjectCreateHMACSequence()
522 // This function creates an internal HMAC sequence object.
523 // Return Type: TPM_RC
524 // TPM_RC_OBJECT_MEMORY if there is no free slot for an object
525 TPM_RC
ObjectCreateHMACSequence(TPMI_ALG_HASH hashAlg,OBJECT * keyObject,TPM2B_AUTH * auth,TPMI_DH_OBJECT * newHandle)526 ObjectCreateHMACSequence(
527 TPMI_ALG_HASH hashAlg, // IN: hash algorithm
528 OBJECT *keyObject, // IN: the object containing the HMAC key
529 TPM2B_AUTH *auth, // IN: authValue
530 TPMI_DH_OBJECT *newHandle // OUT: HMAC sequence object handle
531 )
532 {
533 HASH_OBJECT *hmacObject;
534 //
535 // Try to allocate a slot for new object
536 hmacObject = AllocateSequenceSlot(newHandle, auth);
537
538 if(hmacObject == NULL)
539 return TPM_RC_OBJECT_MEMORY;
540 // Set HMAC sequence bit
541 hmacObject->attributes.hmacSeq = SET;
542
543 #if !SMAC_IMPLEMENTED
544 if(CryptHmacStart(&hmacObject->state.hmacState, hashAlg,
545 keyObject->sensitive.sensitive.bits.b.size,
546 keyObject->sensitive.sensitive.bits.b.buffer) == 0)
547 #else
548 if(CryptMacStart(&hmacObject->state.hmacState,
549 &keyObject->publicArea.parameters,
550 hashAlg, &keyObject->sensitive.sensitive.any.b) == 0)
551 #endif // SMAC_IMPLEMENTED
552 return TPM_RC_FAILURE;
553 return TPM_RC_SUCCESS;
554 }
555 #endif
556
557 //*** ObjectCreateHashSequence()
558 // This function creates a hash sequence object.
559 // Return Type: TPM_RC
560 // TPM_RC_OBJECT_MEMORY if there is no free slot for an object
561 TPM_RC
ObjectCreateHashSequence(TPMI_ALG_HASH hashAlg,TPM2B_AUTH * auth,TPMI_DH_OBJECT * newHandle)562 ObjectCreateHashSequence(
563 TPMI_ALG_HASH hashAlg, // IN: hash algorithm
564 TPM2B_AUTH *auth, // IN: authValue
565 TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
566 )
567 {
568 HASH_OBJECT *hashObject = AllocateSequenceSlot(newHandle, auth);
569 //
570 // See if slot allocated
571 if(hashObject == NULL)
572 return TPM_RC_OBJECT_MEMORY;
573 // Set hash sequence bit
574 hashObject->attributes.hashSeq = SET;
575
576 // Start hash for hash sequence
577 CryptHashStart(&hashObject->state.hashState[0], hashAlg);
578
579 return TPM_RC_SUCCESS;
580 }
581
582 //*** ObjectCreateEventSequence()
583 // This function creates an event sequence object.
584 // Return Type: TPM_RC
585 // TPM_RC_OBJECT_MEMORY if there is no free slot for an object
586 TPM_RC
ObjectCreateEventSequence(TPM2B_AUTH * auth,TPMI_DH_OBJECT * newHandle)587 ObjectCreateEventSequence(
588 TPM2B_AUTH *auth, // IN: authValue
589 TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
590 )
591 {
592 HASH_OBJECT *hashObject = AllocateSequenceSlot(newHandle, auth);
593 UINT32 count;
594 TPM_ALG_ID hash;
595 //
596 // See if slot allocated
597 if(hashObject == NULL)
598 return TPM_RC_OBJECT_MEMORY;
599 // Set the event sequence attribute
600 hashObject->attributes.eventSeq = SET;
601
602 // Initialize hash states for each implemented PCR algorithms
603 for(count = 0; (hash = CryptHashGetAlgByIndex(count)) != TPM_ALG_NULL; count++)
604 CryptHashStart(&hashObject->state.hashState[count], hash);
605 return TPM_RC_SUCCESS;
606 }
607
608 //*** ObjectTerminateEvent()
609 // This function is called to close out the event sequence and clean up the hash
610 // context states.
611 void
ObjectTerminateEvent(void)612 ObjectTerminateEvent(
613 void
614 )
615 {
616 HASH_OBJECT *hashObject;
617 int count;
618 BYTE buffer[MAX_DIGEST_SIZE];
619 //
620 hashObject = (HASH_OBJECT *)HandleToObject(g_DRTMHandle);
621
622 // Don't assume that this is a proper sequence object
623 if(hashObject->attributes.eventSeq)
624 {
625 // If it is, close any open hash contexts. This is done in case
626 // the cryptographic implementation has some context values that need to be
627 // cleaned up (hygiene).
628 //
629 for(count = 0; CryptHashGetAlgByIndex(count) != TPM_ALG_NULL; count++)
630 {
631 CryptHashEnd(&hashObject->state.hashState[count], 0, buffer);
632 }
633 // Flush sequence object
634 FlushObject(g_DRTMHandle);
635 }
636 g_DRTMHandle = TPM_RH_UNASSIGNED;
637 }
638
639 //*** ObjectContextLoad()
640 // This function loads an object from a saved object context.
641 // Return Type: OBJECT *
642 // NULL if there is no free slot for an object
643 // != NULL points to the loaded object
644 OBJECT *
ObjectContextLoad(ANY_OBJECT_BUFFER * object,TPMI_DH_OBJECT * handle)645 ObjectContextLoad(
646 ANY_OBJECT_BUFFER *object, // IN: pointer to object structure in saved
647 // context
648 TPMI_DH_OBJECT *handle // OUT: object handle
649 )
650 {
651 OBJECT *newObject = ObjectAllocateSlot(handle);
652 //
653 // Try to allocate a slot for new object
654 if(newObject != NULL)
655 {
656 // Copy the first part of the object
657 MemoryCopy(newObject, object, offsetof(HASH_OBJECT, state));
658 // See if this is a sequence object
659 if(ObjectIsSequence(newObject))
660 {
661 // If this is a sequence object, import the data
662 SequenceDataImport((HASH_OBJECT *)newObject,
663 (HASH_OBJECT_BUFFER *)object);
664 }
665 else
666 {
667 // Copy input object data to internal structure
668 MemoryCopy(newObject, object, sizeof(OBJECT));
669 }
670 }
671 return newObject;
672 }
673
674 //*** FlushObject()
675 // This function frees an object slot.
676 //
677 // This function requires that the object is loaded.
678 void
FlushObject(TPMI_DH_OBJECT handle)679 FlushObject(
680 TPMI_DH_OBJECT handle // IN: handle to be freed
681 )
682 {
683 UINT32 index = handle - TRANSIENT_FIRST;
684 //
685 pAssert(index < MAX_LOADED_OBJECTS);
686 // Clear all the object attributes
687 MemorySet((BYTE*)&(s_objects[index].attributes),
688 0, sizeof(OBJECT_ATTRIBUTES));
689 return;
690 }
691
692 //*** ObjectFlushHierarchy()
693 // This function is called to flush all the loaded transient objects associated
694 // with a hierarchy when the hierarchy is disabled.
695 void
ObjectFlushHierarchy(TPMI_RH_HIERARCHY hierarchy)696 ObjectFlushHierarchy(
697 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flush
698 )
699 {
700 UINT16 i;
701 //
702 // iterate object slots
703 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
704 {
705 if(s_objects[i].attributes.occupied) // If found an occupied slot
706 {
707 switch(hierarchy)
708 {
709 case TPM_RH_PLATFORM:
710 if(s_objects[i].attributes.ppsHierarchy == SET)
711 s_objects[i].attributes.occupied = FALSE;
712 break;
713 case TPM_RH_OWNER:
714 if(s_objects[i].attributes.spsHierarchy == SET)
715 s_objects[i].attributes.occupied = FALSE;
716 break;
717 case TPM_RH_ENDORSEMENT:
718 if(s_objects[i].attributes.epsHierarchy == SET)
719 s_objects[i].attributes.occupied = FALSE;
720 break;
721 default:
722 FAIL(FATAL_ERROR_INTERNAL);
723 break;
724 }
725 }
726 }
727
728 return;
729 }
730
731 //*** ObjectLoadEvict()
732 // This function loads a persistent object into a transient object slot.
733 //
734 // This function requires that 'handle' is associated with a persistent object.
735 // Return Type: TPM_RC
736 // TPM_RC_HANDLE the persistent object does not exist
737 // or the associated hierarchy is disabled.
738 // TPM_RC_OBJECT_MEMORY no object slot
739 TPM_RC
ObjectLoadEvict(TPM_HANDLE * handle,COMMAND_INDEX commandIndex)740 ObjectLoadEvict(
741 TPM_HANDLE *handle, // IN:OUT: evict object handle. If success, it
742 // will be replace by the loaded object handle
743 COMMAND_INDEX commandIndex // IN: the command being processed
744 )
745 {
746 TPM_RC result;
747 TPM_HANDLE evictHandle = *handle; // Save the evict handle
748 OBJECT *object;
749 //
750 // If this is an index that references a persistent object created by
751 // the platform, then return TPM_RH_HANDLE if the phEnable is FALSE
752 if(*handle >= PLATFORM_PERSISTENT)
753 {
754 // belongs to platform
755 if(g_phEnable == CLEAR)
756 return TPM_RC_HANDLE;
757 }
758 // belongs to owner
759 else if(gc.shEnable == CLEAR)
760 return TPM_RC_HANDLE;
761 // Try to allocate a slot for an object
762 object = ObjectAllocateSlot(handle);
763 if(object == NULL)
764 return TPM_RC_OBJECT_MEMORY;
765 // Copy persistent object to transient object slot. A TPM_RC_HANDLE
766 // may be returned at this point. This will mark the slot as containing
767 // a transient object so that it will be flushed at the end of the
768 // command
769 result = NvGetEvictObject(evictHandle, object);
770
771 // Bail out if this failed
772 if(result != TPM_RC_SUCCESS)
773 return result;
774 // check the object to see if it is in the endorsement hierarchy
775 // if it is and this is not a TPM2_EvictControl() command, indicate
776 // that the hierarchy is disabled.
777 // If the associated hierarchy is disabled, make it look like the
778 // handle is not defined
779 if(ObjectGetHierarchy(object) == TPM_RH_ENDORSEMENT
780 && gc.ehEnable == CLEAR
781 && GetCommandCode(commandIndex) != TPM_CC_EvictControl)
782 return TPM_RC_HANDLE;
783
784 return result;
785 }
786
787 //*** ObjectComputeName()
788 // This does the name computation from a public area (can be marshaled or not).
789 TPM2B_NAME *
ObjectComputeName(UINT32 size,BYTE * publicArea,TPM_ALG_ID nameAlg,TPM2B_NAME * name)790 ObjectComputeName(
791 UINT32 size, // IN: the size of the area to digest
792 BYTE *publicArea, // IN: the public area to digest
793 TPM_ALG_ID nameAlg, // IN: the hash algorithm to use
794 TPM2B_NAME *name // OUT: Computed name
795 )
796 {
797 // Hash the publicArea into the name buffer leaving room for the nameAlg
798 name->t.size = CryptHashBlock(nameAlg, size, publicArea,
799 sizeof(name->t.name) - 2,
800 &name->t.name[2]);
801 // set the nameAlg
802 UINT16_TO_BYTE_ARRAY(nameAlg, name->t.name);
803 name->t.size += 2;
804 return name;
805 }
806
807 //*** PublicMarshalAndComputeName()
808 // This function computes the Name of an object from its public area.
809 TPM2B_NAME *
PublicMarshalAndComputeName(TPMT_PUBLIC * publicArea,TPM2B_NAME * name)810 PublicMarshalAndComputeName(
811 TPMT_PUBLIC *publicArea, // IN: public area of an object
812 TPM2B_NAME *name // OUT: name of the object
813 )
814 {
815 // Will marshal a public area into a template. This is because the internal
816 // format for a TPM2B_PUBLIC is a structure and not a simple BYTE buffer.
817 TPM2B_TEMPLATE marshaled; // this is big enough to hold a
818 // marshaled TPMT_PUBLIC
819 BYTE *buffer = (BYTE *)&marshaled.t.buffer;
820 //
821 // if the nameAlg is NULL then there is no name.
822 if(publicArea->nameAlg == TPM_ALG_NULL)
823 name->t.size = 0;
824 else
825 {
826 // Marshal the public area into its canonical form
827 marshaled.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, NULL);
828 // and compute the name
829 ObjectComputeName(marshaled.t.size, marshaled.t.buffer,
830 publicArea->nameAlg, name);
831 }
832 return name;
833 }
834
835 //*** ComputeQualifiedName()
836 // This function computes the qualified name of an object.
837 void
ComputeQualifiedName(TPM_HANDLE parentHandle,TPM_ALG_ID nameAlg,TPM2B_NAME * name,TPM2B_NAME * qualifiedName)838 ComputeQualifiedName(
839 TPM_HANDLE parentHandle, // IN: parent's handle
840 TPM_ALG_ID nameAlg, // IN: name hash
841 TPM2B_NAME *name, // IN: name of the object
842 TPM2B_NAME *qualifiedName // OUT: qualified name of the object
843 )
844 {
845 HASH_STATE hashState; // hash state
846 TPM2B_NAME parentName;
847 //
848 if(parentHandle == TPM_RH_UNASSIGNED)
849 {
850 MemoryCopy2B(&qualifiedName->b, &name->b, sizeof(qualifiedName->t.name));
851 *qualifiedName = *name;
852 }
853 else
854 {
855 GetQualifiedName(parentHandle, &parentName);
856
857 // QN_A = hash_A (QN of parent || NAME_A)
858
859 // Start hash
860 qualifiedName->t.size = CryptHashStart(&hashState, nameAlg);
861
862 // Add parent's qualified name
863 CryptDigestUpdate2B(&hashState, &parentName.b);
864
865 // Add self name
866 CryptDigestUpdate2B(&hashState, &name->b);
867
868 // Complete hash leaving room for the name algorithm
869 CryptHashEnd(&hashState, qualifiedName->t.size,
870 &qualifiedName->t.name[2]);
871 UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name);
872 qualifiedName->t.size += 2;
873 }
874 return;
875 }
876
877 //*** ObjectIsStorage()
878 // This function determines if an object has the attributes associated
879 // with a parent. A parent is an asymmetric or symmetric block cipher key
880 // that has its 'restricted' and 'decrypt' attributes SET, and 'sign' CLEAR.
881 // Return Type: BOOL
882 // TRUE(1) object is a storage key
883 // FALSE(0) object is not a storage key
884 BOOL
ObjectIsStorage(TPMI_DH_OBJECT handle)885 ObjectIsStorage(
886 TPMI_DH_OBJECT handle // IN: object handle
887 )
888 {
889 OBJECT *object = HandleToObject(handle);
890 TPMT_PUBLIC *publicArea = ((object != NULL) ? &object->publicArea : NULL);
891 //
892 return (publicArea != NULL
893 && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted)
894 && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt)
895 && !IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign)
896 && (object->publicArea.type == TPM_ALG_RSA
897 || object->publicArea.type == TPM_ALG_ECC));
898 }
899
900 //*** ObjectCapGetLoaded()
901 // This function returns a a list of handles of loaded object, starting from
902 // 'handle'. 'Handle' must be in the range of valid transient object handles,
903 // but does not have to be the handle of a loaded transient object.
904 // Return Type: TPMI_YES_NO
905 // YES if there are more handles available
906 // NO all the available handles has been returned
907 TPMI_YES_NO
ObjectCapGetLoaded(TPMI_DH_OBJECT handle,UINT32 count,TPML_HANDLE * handleList)908 ObjectCapGetLoaded(
909 TPMI_DH_OBJECT handle, // IN: start handle
910 UINT32 count, // IN: count of returned handles
911 TPML_HANDLE *handleList // OUT: list of handle
912 )
913 {
914 TPMI_YES_NO more = NO;
915 UINT32 i;
916 //
917 pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT);
918
919 // Initialize output handle list
920 handleList->count = 0;
921
922 // The maximum count of handles we may return is MAX_CAP_HANDLES
923 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
924
925 // Iterate object slots to get loaded object handles
926 for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++)
927 {
928 if(s_objects[i].attributes.occupied == TRUE)
929 {
930 // A valid transient object can not be the copy of a persistent object
931 pAssert(s_objects[i].attributes.evict == CLEAR);
932
933 if(handleList->count < count)
934 {
935 // If we have not filled up the return list, add this object
936 // handle to it
937 handleList->handle[handleList->count] = i + TRANSIENT_FIRST;
938 handleList->count++;
939 }
940 else
941 {
942 // If the return list is full but we still have loaded object
943 // available, report this and stop iterating
944 more = YES;
945 break;
946 }
947 }
948 }
949
950 return more;
951 }
952
953 //*** ObjectCapGetTransientAvail()
954 // This function returns an estimate of the number of additional transient
955 // objects that could be loaded into the TPM.
956 UINT32
ObjectCapGetTransientAvail(void)957 ObjectCapGetTransientAvail(
958 void
959 )
960 {
961 UINT32 i;
962 UINT32 num = 0;
963 //
964 // Iterate object slot to get the number of unoccupied slots
965 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
966 {
967 if(s_objects[i].attributes.occupied == FALSE) num++;
968 }
969
970 return num;
971 }
972
973 //*** ObjectGetPublicAttributes()
974 // Returns the attributes associated with an object handles.
975 TPMA_OBJECT
ObjectGetPublicAttributes(TPM_HANDLE handle)976 ObjectGetPublicAttributes(
977 TPM_HANDLE handle
978 )
979 {
980 return HandleToObject(handle)->publicArea.objectAttributes;
981 }
982
983 OBJECT_ATTRIBUTES
ObjectGetProperties(TPM_HANDLE handle)984 ObjectGetProperties(
985 TPM_HANDLE handle
986 )
987 {
988 return HandleToObject(handle)->attributes;
989 }