| /* Microsoft Reference Implementation for TPM 2.0 | |
| * | |
| * The copyright in this software is being made available under the BSD License, | |
| * included below. This software may be subject to other third party and | |
| * contributor rights, including patent rights, and no such rights are granted | |
| * under this license. | |
| * | |
| * Copyright (c) Microsoft Corporation | |
| * | |
| * All rights reserved. | |
| * | |
| * BSD License | |
| * | |
| * Redistribution and use in source and binary forms, with or without modification, | |
| * are permitted provided that the following conditions are met: | |
| * | |
| * Redistributions of source code must retain the above copyright notice, this list | |
| * of conditions and the following disclaimer. | |
| * | |
| * Redistributions in binary form must reproduce the above copyright notice, this | |
| * list of conditions and the following disclaimer in the documentation and/or | |
| * other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" | |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| //** Introduction | |
| // This file contains the functions that manage the object store of the TPM. | |
| //** Includes and Data Definitions | |
| #define OBJECT_C | |
| #include "Tpm.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; | |
| } | |
| //*** 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; | |
| } | |
| } | |
| //*** 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 but ObjectGetHierarchy() takes an pointer to an object. | |
| // | |
| // This function requires that 'handle' references a loaded object. | |
| TPMI_RH_HIERARCHY | |
| GetHierarchy( | |
| TPMI_DH_OBJECT handle // IN :object handle | |
| ) | |
| { | |
| OBJECT *object = HandleToObject(handle); | |
| // | |
| return ObjectGetHierarchy(object); | |
| } | |
| //*** 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)); | |
| 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->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; | |
| } | |
| //*** 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; | |
| // | |
| // 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 | |
| result = PublicAttributesValidation(parent, publicArea); | |
| } | |
| if(result != TPM_RC_SUCCESS) | |
| return RcSafeAddToResult(result, blamePublic); | |
| // Sensitive area and binding checks | |
| // On load, check nothing if the parent is fixedTPM. For all other cases, validate | |
| // the keys. | |
| 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. | |
| 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; | |
| } | |
| #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(ObjectGetHierarchy(object) == 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 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; | |
| } | |
| //*** 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; | |
| } |