/********************************************************************************/ /* */ /* Manage the object store of the TPM. */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* $Id: Object.c 1658 2021-01-22 23:14:01Z kgoldman $ */ /* */ /* Licenses and Notices */ /* */ /* 1. Copyright Licenses: */ /* */ /* - Trusted Computing Group (TCG) grants to the user of the source code in */ /* this specification (the "Source Code") a worldwide, irrevocable, */ /* nonexclusive, royalty free, copyright license to reproduce, create */ /* derivative works, distribute, display and perform the Source Code and */ /* derivative works thereof, and to grant others the rights granted herein. */ /* */ /* - The TCG grants to the user of the other parts of the specification */ /* (other than the Source Code) the rights to reproduce, distribute, */ /* display, and perform the specification solely for the purpose of */ /* developing products based on such documents. */ /* */ /* 2. Source Code Distribution Conditions: */ /* */ /* - Redistributions of Source Code must retain the above copyright licenses, */ /* this list of conditions and the following disclaimers. */ /* */ /* - Redistributions in binary form must reproduce the above copyright */ /* licenses, this list of conditions and the following disclaimers in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* 3. Disclaimers: */ /* */ /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ /* information on specification licensing rights available through TCG */ /* membership agreements. */ /* */ /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ /* */ /* - Without limitation, TCG and its members and licensors disclaim all */ /* liability, including liability for infringement of any proprietary */ /* rights, relating to use of information in this specification and to the */ /* implementation of this specification, and TCG disclaims all liability for */ /* cost of procurement of substitute goods or services, lost profits, loss */ /* of use, loss of data or any incidental, consequential, direct, indirect, */ /* or special damages, whether under contract, tort, warranty or otherwise, */ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ /* (c) Copyright IBM Corp. and others, 2016 - 2021 */ /* */ /********************************************************************************/ /* 8.6 Object.c */ /* 8.6.1 Introduction */ /* This file contains the functions that manage the object store of the TPM. */ /* 8.6.2 Includes and Data Definitions */ #define OBJECT_C #include "Tpm.h" /* 8.6.3 Functions */ /* 8.6.3.1 ObjectFlush() */ /* This function marks an object slot as available. Since there is no checking of the input parameters, it should be used judiciously. */ /* NOTE: This could be converted to a macro. */ void ObjectFlush( OBJECT *object ) { object->attributes.occupied = CLEAR; } /* 8.6.3.2 ObjectSetInUse() */ /* This access function sets the occupied attribute of an object slot. */ void ObjectSetInUse( OBJECT *object ) { object->attributes.occupied = SET; } /* 8.6.3.3 ObjectStartup() */ /* This function is called at TPM2_Startup() to initialize the object subsystem. */ BOOL ObjectStartup( void ) { UINT32 i; // object slots initialization for(i = 0; i < MAX_LOADED_OBJECTS; i++) { //Set the slot to not occupied ObjectFlush(&s_objects[i]); } return TRUE; } /* 8.6.3.4 ObjectCleanupEvict() */ /* In this implementation, a persistent object is moved from NV into an object slot for processing. It is flushed after command execution. This function is called from ExecuteCommand(). */ void ObjectCleanupEvict( void ) { UINT32 i; // This has to be iterated because a command may have two handles // and they may both be persistent. // This could be made to be more efficient so that a search is not needed. for(i = 0; i < MAX_LOADED_OBJECTS; i++) { // If an object is a temporary evict object, flush it from slot OBJECT *object = &s_objects[i]; if(object->attributes.evict == SET) ObjectFlush(object); } return; } /* 8.6.3.5 IsObjectPresent() */ /* This function checks to see if a transient handle references a loaded object. This routine should not be called if the handle is not a transient handle. The function validates that the handle is in the implementation-dependent allowed in range for loaded transient objects. */ /* Return Values Meaning */ /* TRUE if the handle references a loaded object */ /* FALSE if the handle is not an object handle, or it does not reference to a loaded object */ BOOL IsObjectPresent( TPMI_DH_OBJECT handle // IN: handle to be checked ) { UINT32 slotIndex = handle - TRANSIENT_FIRST; // Since the handle is just an index into the array that is zero based, any // handle value outsize of the range of: // TRANSIENT_FIRST -- (TRANSIENT_FIRST + MAX_LOADED_OBJECT - 1) // will now be greater than or equal to MAX_LOADED_OBJECTS if(slotIndex >= MAX_LOADED_OBJECTS) return FALSE; // Indicate if the slot is occupied return (s_objects[slotIndex].attributes.occupied == TRUE); } /* 8.6.3.6 ObjectIsSequence() */ /* This function is used to check if the object is a sequence object. This function should not be called if the handle does not reference a loaded object. */ /* Return Values Meaning */ /* TRUE object is an HMAC, hash, or event sequence object */ /* FALSE object is not an HMAC, hash, or event sequence object */ BOOL ObjectIsSequence( OBJECT *object // IN: handle to be checked ) { pAssert(object != NULL); return (object->attributes.hmacSeq == SET || object->attributes.hashSeq == SET || object->attributes.eventSeq == SET); } /* 8.6.3.7 HandleToObject() */ /* This function is used to find the object structure associated with a handle. */ /* This function requires that handle references a loaded object or a permanent handle. */ OBJECT* HandleToObject( TPMI_DH_OBJECT handle // IN: handle of the object ) { UINT32 index; // Return NULL if the handle references a permanent handle because there is no // associated OBJECT. if(HandleGetType(handle) == TPM_HT_PERMANENT) return NULL; // In this implementation, the handle is determined by the slot occupied by the // object. index = handle - TRANSIENT_FIRST; pAssert(index < MAX_LOADED_OBJECTS); pAssert(s_objects[index].attributes.occupied); return &s_objects[index]; } /* 8.6.3.9 GetQualifiedName() */ /* This function returns the Qualified Name of the object. In this implementation, the Qualified Name is computed when the object is loaded and is saved in the internal representation of the object. The alternative would be to retain the Name of the parent and compute the QN when needed. This would take the same amount of space so it is not recommended that the alternate be used. */ /* This function requires that handle references a loaded object. */ void GetQualifiedName( TPMI_DH_OBJECT handle, // IN: handle of the object TPM2B_NAME *qualifiedName // OUT: qualified name of the object ) { OBJECT *object; switch(HandleGetType(handle)) { case TPM_HT_PERMANENT: qualifiedName->t.size = sizeof(TPM_HANDLE); UINT32_TO_BYTE_ARRAY(handle, qualifiedName->t.name); break; case TPM_HT_TRANSIENT: object = HandleToObject(handle); if(object == NULL || object->publicArea.nameAlg == TPM_ALG_NULL) qualifiedName->t.size = 0; else // Copy the name *qualifiedName = object->qualifiedName; break; default: FAIL(FATAL_ERROR_INTERNAL); } return; } /* 8.6.3.10 ObjectGetHierarchy() */ /* This function returns the handle for the hierarchy of an object. */ TPMI_RH_HIERARCHY ObjectGetHierarchy( OBJECT *object // IN :object ) { if(object->attributes.spsHierarchy) { return TPM_RH_OWNER; } else if(object->attributes.epsHierarchy) { return TPM_RH_ENDORSEMENT; } else if(object->attributes.ppsHierarchy) { return TPM_RH_PLATFORM; } else { return TPM_RH_NULL; } } /* 8.6.3.11 GetHierarchy() */ /* This function returns the handle of the hierarchy to which a handle belongs. This function is similar to ObjectGetHierarchy() but this routine takes a handle while ObjectGetHierarchy() takes a pointer to an object. */ /* This function requires that handle references a loaded object. */ TPMI_RH_HIERARCHY GetHieriarchy( TPMI_DH_OBJECT handle // IN :object handle ) { OBJECT *object = HandleToObject(handle); return ObjectGetHierarchy(object); } /* 8.6.3.12 FindEmptyObjectSlot() */ /* This function finds an open object slot, if any. It will clear the attributes but will not set the occupied attribute. This is so that a slot may be used and discarded if everything does not go as planned. */ /* Return Values Meaning */ /* null no open slot found */ /* !=null pointer to available slot */ OBJECT * FindEmptyObjectSlot( TPMI_DH_OBJECT *handle // OUT: (optional) ) { UINT32 i; OBJECT *object; for(i = 0; i < MAX_LOADED_OBJECTS; i++) { object = &s_objects[i]; if(object->attributes.occupied == CLEAR) { if(handle) *handle = i + TRANSIENT_FIRST; // Initialize the object attributes MemorySet(&object->attributes, 0, sizeof(OBJECT_ATTRIBUTES)); return object; } } return NULL; } /* 8.6.3.13 ObjectAllocateSlot() */ /* This function is used to allocate a slot in internal object array. */ /* Return Values Meaning */ OBJECT * ObjectAllocateSlot( TPMI_DH_OBJECT *handle // OUT: handle of allocated object ) { OBJECT *object = FindEmptyObjectSlot(handle); if(object != NULL) { // if found, mark as occupied ObjectSetInUse(object); } return object; } /* 8.6.3.14 ObjectSetLoadedAttributes() */ /* This function sets the internal attributes for a loaded object. It is called to finalize the OBJECT attributes (not the TPMA_OBJECT attributes) for a loaded object. */ void ObjectSetLoadedAttributes( OBJECT *object, // IN: object attributes to finalize TPM_HANDLE parentHandle // IN: the parent handle ) { OBJECT *parent = HandleToObject(parentHandle); TPMA_OBJECT objectAttributes = object->publicArea.objectAttributes; // // Copy the stClear attribute from the public area. This could be overwritten // if the parent has stClear SET object->attributes.stClear = IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear); // If parent handle is a permanent handle, it is a primary (unless it is NULL if(parent == NULL) { object->attributes.primary = SET; switch(parentHandle) { case TPM_RH_ENDORSEMENT: object->attributes.epsHierarchy = SET; break; case TPM_RH_OWNER: object->attributes.spsHierarchy = SET; break; case TPM_RH_PLATFORM: object->attributes.ppsHierarchy = SET; break; default: // Treat the temporary attribute as a hierarchy object->attributes.temporary = SET; object->attributes.primary = CLEAR; break; } } else { // is this a stClear object object->attributes.stClear = (IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear) || (parent->attributes.stClear == SET)); object->attributes.epsHierarchy = parent->attributes.epsHierarchy; object->attributes.spsHierarchy = parent->attributes.spsHierarchy; object->attributes.ppsHierarchy = parent->attributes.ppsHierarchy; // An object is temporary if its parent is temporary or if the object // is external object->attributes.temporary = parent->attributes.temporary || object->attributes.external; } // If this is an external object, set the QN == name but don't SET other // key properties ('parent' or 'derived') if(object->attributes.external) object->qualifiedName = object->name; else { // check attributes for different types of parents if(IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, restricted) && !object->attributes.publicOnly && IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, decrypt) && object->publicArea.nameAlg != TPM_ALG_NULL) { // This is a parent. If it is not a KEYEDHASH, it is an ordinary parent. // Otherwise, it is a derivation parent. if(object->publicArea.type == TPM_ALG_KEYEDHASH) object->attributes.derivation = SET; else object->attributes.isParent = SET; } ComputeQualifiedName(parentHandle, object->publicArea.nameAlg, &object->name, &object->qualifiedName); } // Set slot occupied ObjectSetInUse(object); return; } /* 8.6.3.15 ObjectLoad() */ /* Common function to load an object. A loaded object has its public area validated (unless its nameAlg is TPM_ALG_NULL). If a sensitive part is loaded, it is verified to be correct and if both public and sensitive parts are loaded, then the cryptographic binding between the objects is validated. This function does not cause the allocated slot to be marked as in use. */ TPM_RC ObjectLoad( OBJECT *object, // IN: pointer to object slot // object OBJECT *parent, // IN: (optional) the parent object TPMT_PUBLIC *publicArea, // IN: public area to be installed in the object TPMT_SENSITIVE *sensitive, // IN: (optional) sensitive area to be // installed in the object TPM_RC blamePublic, // IN: parameter number to associate with the // publicArea errors TPM_RC blameSensitive,// IN: parameter number to associate with the // sensitive area errors TPM2B_NAME *name // IN: (optional) ) { TPM_RC result = TPM_RC_SUCCESS; BOOL doCheck; // // Do validations of public area object descriptions // Is this public only or a no-name object? if(sensitive == NULL || publicArea->nameAlg == TPM_ALG_NULL) { // Need to have schemes checked so that we do the right thing with the // public key. result = SchemeChecks(NULL, publicArea); } else { // For any sensitive area, make sure that the seedSize is no larger than the // digest size of nameAlg if(sensitive->seedValue.t.size > CryptHashGetDigestSize(publicArea->nameAlg)) return TPM_RCS_KEY_SIZE + blameSensitive; // Check attributes and schemes for consistency result = PublicAttributesValidation(parent, publicArea); } if(result != TPM_RC_SUCCESS) return RcSafeAddToResult(result, blamePublic); // If object == NULL, then this is am import. For import, load is not called // unless the parent is fixedTPM. if(object == NULL) doCheck = TRUE;// // // If the parent is not NULL, then this is an ordinary load and we only check // if the parent is not fixedTPM else if(parent != NULL) doCheck = !IS_ATTRIBUTE(parent->publicArea.objectAttributes, TPMA_OBJECT, fixedTPM); else // This is a loadExternal. Check everything. // Note: the check functions will filter things based on the name algorithm // and whether or not both parts are loaded. doCheck = TRUE; // Note: the parent will be NULL if this is a load external. CryptValidateKeys() // will only check the parts that need to be checked based on the settings // of publicOnly and nameAlg. // Note: For an RSA key, the keys sizes are checked but the binding is not // checked. if(doCheck) { // Do the cryptographic key validation result = CryptValidateKeys(publicArea, sensitive, blamePublic, blameSensitive); } // If this is an import, we are done if(object == NULL || result != TPM_RC_SUCCESS) return result; // Set the name, if one was provided if(name != NULL) object->name = *name; else object->name.t.size = 0; // Initialize public object->publicArea = *publicArea; // If there is a sensitive area, load it if(sensitive == NULL) object->attributes.publicOnly = SET; else { object->sensitive = *sensitive; #if ALG_RSA // If this is an RSA key that is not a parent, complete the load by // computing the private exponent. if(publicArea->type == ALG_RSA_VALUE) result = CryptRsaLoadPrivateExponent(object); #endif } return result; } /* 8.6.3.16 AllocateSequenceSlot() */ /* This function allocates a sequence slot and initializes the parts that are used by the normal objects so that a sequence object is not inadvertently used for an operation that is not appropriate for a sequence. */ static HASH_OBJECT * AllocateSequenceSlot( TPM_HANDLE *newHandle, // OUT: receives the allocated handle TPM2B_AUTH *auth // IN: the authValue for the slot ) { HASH_OBJECT *object = (HASH_OBJECT *)ObjectAllocateSlot(newHandle); // // Validate that the proper location of the hash state data relative to the // object state data. It would be good if this could have been done at compile // time but it can't so do it in something that can be removed after debug. cAssert(offsetof(HASH_OBJECT, auth) == offsetof(OBJECT, publicArea.authPolicy)); if(object != NULL) { // Set the common values that a sequence object shares with an ordinary object // First, clear all attributes MemorySet(&object->objectAttributes, 0, sizeof(TPMA_OBJECT)); // The type is TPM_ALG_NULL object->type = TPM_ALG_NULL; // This has no name algorithm and the name is the Empty Buffer object->nameAlg = TPM_ALG_NULL; // A sequence object is considered to be in the NULL hierarchy so it should // be marked as temporary so that it can't be persisted object->attributes.temporary = SET; // A sequence object is DA exempt. SET_ATTRIBUTE(object->objectAttributes, TPMA_OBJECT, noDA); // Copy the authorization value if(auth != NULL) object->auth = *auth; else object->auth.t.size = 0; } return object; } /* 8.6.3.17 ObjectCreateHMACSequence() */ /* This function creates an internal HMAC sequence object. */ /* Error Returns Meaning */ /* TPM_RC_OBJECT_MEMORY if there is no free slot for an object */ #if CC_HMAC_Start || CC_MAC_Start TPM_RC ObjectCreateHMACSequence( TPMI_ALG_HASH hashAlg, // IN: hash algorithm OBJECT *keyObject, // IN: the object containing the HMAC key TPM2B_AUTH *auth, // IN: authValue TPMI_DH_OBJECT *newHandle // OUT: HMAC sequence object handle ) { HASH_OBJECT *hmacObject; // // Try to allocate a slot for new object hmacObject = AllocateSequenceSlot(newHandle, auth); if(hmacObject == NULL) return TPM_RC_OBJECT_MEMORY; // Set HMAC sequence bit hmacObject->attributes.hmacSeq = SET; #if !SMAC_IMPLEMENTED if(CryptHmacStart(&hmacObject->state.hmacState, hashAlg, keyObject->sensitive.sensitive.bits.b.size, keyObject->sensitive.sensitive.bits.b.buffer) == 0) #else if(CryptMacStart(&hmacObject->state.hmacState, &keyObject->publicArea.parameters, hashAlg, &keyObject->sensitive.sensitive.any.b) == 0) #endif // SMAC_IMPLEMENTED return TPM_RC_FAILURE; return TPM_RC_SUCCESS; } #endif /* 8.6.3.18 ObjectCreateHashSequence() */ /* This function creates a hash sequence object. */ /* Error Returns Meaning */ /* TPM_RC_OBJECT_MEMORY if there is no free slot for an object */ TPM_RC ObjectCreateHashSequence( TPMI_ALG_HASH hashAlg, // IN: hash algorithm TPM2B_AUTH *auth, // IN: authValue TPMI_DH_OBJECT *newHandle // OUT: sequence object handle ) { HASH_OBJECT *hashObject = AllocateSequenceSlot(newHandle, auth); // See if slot allocated if(hashObject == NULL) return TPM_RC_OBJECT_MEMORY; // Set hash sequence bit hashObject->attributes.hashSeq = SET; // Start hash for hash sequence CryptHashStart(&hashObject->state.hashState[0], hashAlg); return TPM_RC_SUCCESS; } /* 8.6.3.19 ObjectCreateEventSequence() */ /* This function creates an event sequence object. */ /* Error Returns Meaning */ /* TPM_RC_OBJECT_MEMORY if there is no free slot for an object */ TPM_RC ObjectCreateEventSequence( TPM2B_AUTH *auth, // IN: authValue TPMI_DH_OBJECT *newHandle // OUT: sequence object handle ) { HASH_OBJECT *hashObject = AllocateSequenceSlot(newHandle, auth); UINT32 count; TPM_ALG_ID hash; // See if slot allocated if(hashObject == NULL) return TPM_RC_OBJECT_MEMORY; // Set the event sequence attribute hashObject->attributes.eventSeq = SET; // Initialize hash states for each implemented PCR algorithms for(count = 0; (hash = CryptHashGetAlgByIndex(count)) != TPM_ALG_NULL; count++) CryptHashStart(&hashObject->state.hashState[count], hash); return TPM_RC_SUCCESS; } /* 8.6.3.20 ObjectTerminateEvent() */ /* This function is called to close out the event sequence and clean up the hash context states. */ void ObjectTerminateEvent( void ) { HASH_OBJECT *hashObject; int count; BYTE buffer[MAX_DIGEST_SIZE]; hashObject = (HASH_OBJECT *)HandleToObject(g_DRTMHandle); // Don't assume that this is a proper sequence object if(hashObject->attributes.eventSeq) { // If it is, close any open hash contexts. This is done in case // the cryptographic implementation has some context values that need to be // cleaned up (hygiene). // for(count = 0; CryptHashGetAlgByIndex(count) != TPM_ALG_NULL; count++) { CryptHashEnd(&hashObject->state.hashState[count], 0, buffer); } // Flush sequence object FlushObject(g_DRTMHandle); } g_DRTMHandle = TPM_RH_UNASSIGNED; } /* 8.6.3.21 ObjectContextLoad() */ /* This function loads an object from a saved object context. */ /* Return Values Meaning */ /* NULL if there is no free slot for an object */ /* NON_NULL points to the loaded object */ OBJECT * ObjectContextLoad( ANY_OBJECT_BUFFER *object, // IN: pointer to object structure in saved // context TPMI_DH_OBJECT *handle // OUT: object handle ) { OBJECT *newObject = ObjectAllocateSlot(handle); // Try to allocate a slot for new object if(newObject != NULL) { // Copy the first part of the object MemoryCopy(newObject, object, offsetof(HASH_OBJECT, state)); // See if this is a sequence object if(ObjectIsSequence(newObject)) { // If this is a sequence object, import the data SequenceDataImport((HASH_OBJECT *)newObject, (HASH_OBJECT_BUFFER *)object); } else { // Copy input object data to internal structure MemoryCopy(newObject, object, sizeof(OBJECT)); } } return newObject; } /* 8.6.3.22 FlushObject() */ /* This function frees an object slot. */ /* This function requires that the object is loaded. */ void FlushObject( TPMI_DH_OBJECT handle // IN: handle to be freed ) { UINT32 index = handle - TRANSIENT_FIRST; pAssert(index < MAX_LOADED_OBJECTS); // Clear all the object attributes MemorySet((BYTE*)&(s_objects[index].attributes), 0, sizeof(OBJECT_ATTRIBUTES)); return; } /* 8.6.3.23 ObjectFlushHierarchy() */ /* This function is called to flush all the loaded transient objects associated with a hierarchy when the hierarchy is disabled. */ void ObjectFlushHierarchy( TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flush ) { UINT16 i; // iterate object slots for(i = 0; i < MAX_LOADED_OBJECTS; i++) { if(s_objects[i].attributes.occupied) // If found an occupied slot { switch(hierarchy) { case TPM_RH_PLATFORM: if(s_objects[i].attributes.ppsHierarchy == SET) s_objects[i].attributes.occupied = FALSE; break; case TPM_RH_OWNER: if(s_objects[i].attributes.spsHierarchy == SET) s_objects[i].attributes.occupied = FALSE; break; case TPM_RH_ENDORSEMENT: if(s_objects[i].attributes.epsHierarchy == SET) s_objects[i].attributes.occupied = FALSE; break; default: FAIL(FATAL_ERROR_INTERNAL); break; } } } return; } /* 8.6.3.24 ObjectLoadEvict() */ /* This function loads a persistent object into a transient object slot. */ /* This function requires that handle is associated with a persistent object. */ /* Error Returns Meaning */ /* TPM_RC_HANDLE the persistent object does not exist or the associated hierarchy is disabled. */ /* TPM_RC_OBJECT_MEMORY no object slot */ TPM_RC ObjectLoadEvict( TPM_HANDLE *handle, // IN:OUT: evict object handle. If success, it // will be replace by the loaded object handle COMMAND_INDEX commandIndex // IN: the command being processed ) { TPM_RC result; TPM_HANDLE evictHandle = *handle; // Save the evict handle OBJECT *object; // If this is an index that references a persistent object created by // the platform, then return TPM_RH_HANDLE if the phEnable is FALSE if(*handle >= PLATFORM_PERSISTENT) { // belongs to platform if(g_phEnable == CLEAR) return TPM_RC_HANDLE; } // belongs to owner else if(gc.shEnable == CLEAR) return TPM_RC_HANDLE; // Try to allocate a slot for an object object = ObjectAllocateSlot(handle); if(object == NULL) return TPM_RC_OBJECT_MEMORY; // Copy persistent object to transient object slot. A TPM_RC_HANDLE // may be returned at this point. This will mark the slot as containing // a transient object so that it will be flushed at the end of the // command result = NvGetEvictObject(evictHandle, object); // Bail out if this failed if(result != TPM_RC_SUCCESS) return result; // check the object to see if it is in the endorsement hierarchy // if it is and this is not a TPM2_EvictControl() command, indicate // that the hierarchy is disabled. // If the associated hierarchy is disabled, make it look like the // handle is not defined if(ObjectGetHierarchy(object) == TPM_RH_ENDORSEMENT && gc.ehEnable == CLEAR && GetCommandCode(commandIndex) != TPM_CC_EvictControl) return TPM_RC_HANDLE; return result; } /* 8.6.3.25 ObjectComputeName() */ /* This does the name computation from a public area (can be marshaled or not). */ TPM2B_NAME * ObjectComputeName( UINT32 size, // IN: the size of the area to digest BYTE *publicArea, // IN: the public area to digest TPM_ALG_ID nameAlg, // IN: the hash algorithm to use TPM2B_NAME *name // OUT: Computed name ) { // Hash the publicArea into the name buffer leaving room for the nameAlg name->t.size = CryptHashBlock(nameAlg, size, publicArea, sizeof(name->t.name) - 2, &name->t.name[2]); // set the nameAlg UINT16_TO_BYTE_ARRAY(nameAlg, name->t.name); name->t.size += 2; return name; } /* 8.6.3.26 PublicMarshalAndComputeName() */ /* This function computes the Name of an object from its public area. */ TPM2B_NAME * PublicMarshalAndComputeName( TPMT_PUBLIC *publicArea, // IN: public area of an object TPM2B_NAME *name // OUT: name of the object ) { // Will marshal a public area into a template. This is because the internal // format for a TPM2B_PUBLIC is a structure and not a simple BYTE buffer. TPM2B_TEMPLATE marshaled; // this is big enough to hold a // marshaled TPMT_PUBLIC BYTE *buffer = (BYTE *)&marshaled.t.buffer; // if the nameAlg is NULL then there is no name. if(publicArea->nameAlg == TPM_ALG_NULL) name->t.size = 0; else { // Marshal the public area into its canonical form marshaled.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, NULL); // and compute the name ObjectComputeName(marshaled.t.size, marshaled.t.buffer, publicArea->nameAlg, name); } return name; } /* 8.6.3.28 ComputeQualifiedName() */ /* This function computes the qualified name of an object. */ void ComputeQualifiedName( TPM_HANDLE parentHandle, // IN: parent's handle TPM_ALG_ID nameAlg, // IN: name hash TPM2B_NAME *name, // IN: name of the object TPM2B_NAME *qualifiedName // OUT: qualified name of the object ) { HASH_STATE hashState; // hash state TPM2B_NAME parentName; if(parentHandle == TPM_RH_UNASSIGNED) { MemoryCopy2B(&qualifiedName->b, &name->b, sizeof(qualifiedName->t.name)); *qualifiedName = *name; } else { GetQualifiedName(parentHandle, &parentName); // QN_A = hash_A (QN of parent || NAME_A) // Start hash qualifiedName->t.size = CryptHashStart(&hashState, nameAlg); // Add parent's qualified name CryptDigestUpdate2B(&hashState, &parentName.b); // Add self name CryptDigestUpdate2B(&hashState, &name->b); // Complete hash leaving room for the name algorithm CryptHashEnd(&hashState, qualifiedName->t.size, &qualifiedName->t.name[2]); UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name); qualifiedName->t.size += 2; } return; } /* 8.6.3.29 ObjectIsStorage() */ /* This function determines if an object has the attributes associated with a parent. A parent is an asymmetric or symmetric block cipher key that has its restricted and decrypt attributes SET, and sign CLEAR. */ /* Return Values Meaning */ /* TRUE if the object is a storage key */ /* FALSE if the object is not a storage key */ BOOL ObjectIsStorage( TPMI_DH_OBJECT handle // IN: object handle ) { OBJECT *object = HandleToObject(handle); TPMT_PUBLIC *publicArea = ((object != NULL) ? &object->publicArea : NULL); // return (publicArea != NULL && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted) && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt) && !IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign) && (object->publicArea.type == ALG_RSA_VALUE || object->publicArea.type == ALG_ECC_VALUE)); } /* 8.6.3.30 ObjectCapGetLoaded() */ /* This function returns a a list of handles of loaded object, starting from handle. Handle must be in the range of valid transient object handles, but does not have to be the handle of a loaded transient object. */ /* Return Values Meaning */ /* YES if there are more handles available */ /* NO all the available handles has been returned */ TPMI_YES_NO ObjectCapGetLoaded( TPMI_DH_OBJECT handle, // IN: start handle UINT32 count, // IN: count of returned handles TPML_HANDLE *handleList // OUT: list of handle ) { TPMI_YES_NO more = NO; UINT32 i; pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); // Initialize output handle list handleList->count = 0; // The maximum count of handles we may return is MAX_CAP_HANDLES if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; // Iterate object slots to get loaded object handles for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++) { if(s_objects[i].attributes.occupied == TRUE) { // A valid transient object can not be the copy of a persistent object pAssert(s_objects[i].attributes.evict == CLEAR); if(handleList->count < count) { // If we have not filled up the return list, add this object // handle to it handleList->handle[handleList->count] = i + TRANSIENT_FIRST; handleList->count++; } else { // If the return list is full but we still have loaded object // available, report this and stop iterating more = YES; break; } } } return more; } /* 8.6.3.31 ObjectCapGetTransientAvail() */ /* This function returns an estimate of the number of additional transient objects that could be loaded into the TPM. */ UINT32 ObjectCapGetTransientAvail( void ) { UINT32 i; UINT32 num = 0; // Iterate object slot to get the number of unoccupied slots for(i = 0; i < MAX_LOADED_OBJECTS; i++) { if(s_objects[i].attributes.occupied == FALSE) num++; } return num; } /* 8.6.3.32 ObjectGetPublicAttributes() */ /* Returns the attributes associated with an object handles. */ TPMA_OBJECT ObjectGetPublicAttributes( TPM_HANDLE handle ) { return HandleToObject(handle)->publicArea.objectAttributes; } OBJECT_ATTRIBUTES ObjectGetProperties( TPM_HANDLE handle ) { return HandleToObject(handle)->attributes; }