/* 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; | |
} |