/********************************************************************************/ /* */ /* Manage the object store of the TPM. */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* */ /* 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 - 2023 */ /* */ /********************************************************************************/ //** Introduction // This file contains the functions that manage the object store of the TPM. //** Includes and Data Definitions #define OBJECT_C #include "Tpm.h" #include "Marshal.h" //** Functions //*** 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; } //*** ObjectSetInUse() // This access function sets the occupied attribute of an object slot. void ObjectSetInUse(OBJECT* object) { object->attributes.occupied = SET; } //*** 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; } //*** 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; } //*** 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 Type: BOOL // TRUE(1) handle references a loaded object // FALSE(0) 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); } //*** 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 Type: BOOL // TRUE(1) object is an HMAC, hash, or event sequence object // FALSE(0) 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); } //*** 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]; } //*** 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; } //*** GetHierarchy() // This function returns the handle of the hierarchy to which a handle belongs. // // This function requires that 'handle' references a loaded object. TPMI_RH_HIERARCHY GetHierarchy(TPMI_DH_OBJECT handle // IN :object handle ) { return HandleToObject(handle)->hierarchy; } //*** 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 Type: OBJECT * // 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)); object->hierarchy = TPM_RH_NULL; return object; } } return NULL; } //*** ObjectAllocateSlot() // This function is used to allocate a slot in internal object array. 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; } //*** 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->hierarchy = parentHandle; object->attributes.primary = SET; switch(HierarchyNormalizeHandle(object->hierarchy)) { 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; object->hierarchy = parent->hierarchy; } // 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; } //*** ObjectLoad() // Common function to load a non-primary object (i.e., either an Ordinary Object, // or an External 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; // // Do validations of public area object descriptions pAssert(publicArea != NULL); // 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 // For the purposes of attributes validation on this non-primary object, // either: // - parent is not NULL and therefore its attributes are checked for // consistency with the parent, OR // - parent is NULL but the object is not a primary object, either result = PublicAttributesValidation(parent, /*primaryHierarchy = */ 0, publicArea); } if(result != TPM_RC_SUCCESS) return RcSafeAddToResult(result, blamePublic); // Sensitive area and binding checks // On load, check nothing if the parent is fixedTPM. // If the parent is fixedTPM, then this TPM produced this key blob (either // by import, or creation). If the parent is not fixedTPM, then an external // copy of the parent's protection seed might have been used to create the // blob, and we have to validate it. // NOTE: By the time a TPMT_SENSITIVE has been decrypted and passed to this // function, it has been validated against the corresponding TPMT_PUBLIC. // For more information about this check, see PrivateToSensitive. if((parent == NULL) || ((parent != NULL) && !IS_ATTRIBUTE( parent->publicArea.objectAttributes, TPMA_OBJECT, fixedTPM))) { // Do the cryptographic key validation result = CryptValidateKeys(publicArea, sensitive, blamePublic, blameSensitive); if(result != TPM_RC_SUCCESS) return result; } #if ALG_RSA // If this is an RSA key, then expand the private exponent. // Note: ObjectLoad() is only called by TPM2_Import() if the parent is fixedTPM. // For any key that does not have a fixedTPM parent, the exponent is computed // whenever it is loaded if((publicArea->type == TPM_ALG_RSA) && (sensitive != NULL)) { result = CryptRsaLoadPrivateExponent(publicArea, sensitive); if(result != TPM_RC_SUCCESS) return result; } #endif // ALG_RSA // See if there is an object to populate if((result == TPM_RC_SUCCESS) && (object != NULL)) { // Initialize public object->publicArea = *publicArea; // Copy sensitive if there is one if(sensitive == NULL) object->attributes.publicOnly = SET; else object->sensitive = *sensitive; // Set the name, if one was provided if(name != NULL) object->name = *name; else object->name.t.size = 0; } return result; } //*** 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. MUST_BE(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; } #if CC_HMAC_Start || CC_MAC_Start //*** ObjectCreateHMACSequence() // This function creates an internal HMAC sequence object. // Return Type: TPM_RC // TPM_RC_OBJECT_MEMORY if there is no free slot for an object 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 //*** ObjectCreateHashSequence() // This function creates a hash sequence object. // Return Type: TPM_RC // 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; } //*** ObjectCreateEventSequence() // This function creates an event sequence object. // Return Type: TPM_RC // 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; } //*** 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; } //*** ObjectContextLoad() // This function loads an object from a saved object context. // Return Type: OBJECT * // NULL if there is no free slot for an object // != 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; } //*** 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; } //*** 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; } //*** ObjectLoadEvict() // This function loads a persistent object into a transient object slot. // // This function requires that 'handle' is associated with a persistent object. // Return Type: TPM_RC // 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(HierarchyNormalizeHandle(object->hierarchy) == TPM_RH_ENDORSEMENT && gc.ehEnable == CLEAR && GetCommandCode(commandIndex) != TPM_CC_EvictControl) return TPM_RC_HANDLE; return result; } //*** 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; } //*** 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; } //*** 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; } //*** 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 Type: BOOL // TRUE(1) object is a storage key // FALSE(0) 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 == TPM_ALG_RSA || object->publicArea.type == TPM_ALG_ECC)); } //*** ObjectCapGetLoaded() // This function returns 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 Type: TPMI_YES_NO // 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; } //*** ObjectCapGetOneLoaded() // This function returns whether a handle is loaded. BOOL ObjectCapGetOneLoaded(TPMI_DH_OBJECT handle) // IN: handle { UINT32 i; pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); // 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); return TRUE; } } return FALSE; } //*** 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; } //*** 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; }