895 lines
30 KiB
C
895 lines
30 KiB
C
// This file was extracted from the TCG Published
|
|
// Trusted Platform Module Library
|
|
// Part 4: Supporting Routines
|
|
// Family "2.0"
|
|
// Level 00 Revision 01.16
|
|
// October 30, 2014
|
|
|
|
#define OBJECT_C
|
|
#include "InternalRoutines.h"
|
|
#include "Platform.h"
|
|
//
|
|
//
|
|
// Functions
|
|
//
|
|
// ObjectStartup()
|
|
//
|
|
// This function is called at TPM2_Startup() to initialize the object subsystem.
|
|
//
|
|
void
|
|
ObjectStartup(
|
|
void
|
|
)
|
|
{
|
|
UINT32 i;
|
|
// object slots initialization
|
|
for(i = 0; i < MAX_LOADED_OBJECTS; i++)
|
|
{
|
|
//Set the slot to not occupied
|
|
s_objects[i].occupied = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// 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
|
|
if(s_objects[i].object.entity.attributes.evict == SET)
|
|
s_objects[i].occupied = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// ObjectIsPresent()
|
|
//
|
|
// 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 Value Meaning
|
|
//
|
|
// TRUE if the handle references a loaded object
|
|
// FALSE if the handle is not an object handle, or it does not reference to a
|
|
// loaded object
|
|
//
|
|
BOOL
|
|
ObjectIsPresent(
|
|
TPMI_DH_OBJECT handle // IN: handle to be checked
|
|
)
|
|
{
|
|
UINT32 slotIndex; // index of object slot
|
|
pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT);
|
|
// The index in the loaded object array is found by subtracting the first
|
|
// object handle number from the input handle number. If the indicated
|
|
// slot is occupied, then indicate that there is already is a loaded
|
|
// object associated with the handle.
|
|
slotIndex = handle - TRANSIENT_FIRST;
|
|
if(slotIndex >= MAX_LOADED_OBJECTS)
|
|
return FALSE;
|
|
return s_objects[slotIndex].occupied;
|
|
}
|
|
//
|
|
//
|
|
// 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 Value Meaning
|
|
//
|
|
// TRUE object is an HMAC, hash, or event sequence object
|
|
// FALSE object is not an HMAC, hash, or event sequence object
|
|
//
|
|
BOOL
|
|
ObjectIsSequence(
|
|
OBJECT *object // IN: handle to be checked
|
|
)
|
|
{
|
|
pAssert (object != NULL);
|
|
if( object->attributes.hmacSeq == SET
|
|
|| object->attributes.hashSeq == SET
|
|
|| object->attributes.eventSeq == SET)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
//
|
|
//
|
|
// ObjectGet()
|
|
//
|
|
// This function is used to find the object structure associated with a handle.
|
|
// This function requires that handle references a loaded object.
|
|
//
|
|
OBJECT*
|
|
ObjectGet(
|
|
TPMI_DH_OBJECT handle // IN: handle of the object
|
|
)
|
|
{
|
|
pAssert( handle >= TRANSIENT_FIRST
|
|
&& handle - TRANSIENT_FIRST < MAX_LOADED_OBJECTS);
|
|
pAssert(s_objects[handle - TRANSIENT_FIRST].occupied == TRUE);
|
|
// In this implementation, the handle is determined by the slot occupied by the
|
|
// object.
|
|
return &s_objects[handle - TRANSIENT_FIRST].object.entity;
|
|
}
|
|
//
|
|
//
|
|
// ObjectGetName()
|
|
//
|
|
// This function is used to access the Name of the object. In this implementation, the Name is computed
|
|
// when the object is loaded and is saved in the internal representation of the object. This function copies
|
|
// the Name data from the object into the buffer at name and returns the number of octets copied.
|
|
// This function requires that handle references a loaded object.
|
|
//
|
|
UINT16
|
|
ObjectGetName(
|
|
TPMI_DH_OBJECT handle, // IN: handle of the object
|
|
NAME *name // OUT: name of the object
|
|
)
|
|
{
|
|
OBJECT *object = ObjectGet(handle);
|
|
if(object->publicArea.nameAlg == TPM_ALG_NULL)
|
|
return 0;
|
|
// Copy the Name data to the output
|
|
MemoryCopy(name, object->name.t.name, object->name.t.size, sizeof(NAME));
|
|
return object->name.t.size;
|
|
}
|
|
//
|
|
//
|
|
// ObjectGetNameAlg()
|
|
//
|
|
// This function is used to get the Name algorithm of a object.
|
|
// This function requires that handle references a loaded object.
|
|
//
|
|
TPMI_ALG_HASH
|
|
ObjectGetNameAlg(
|
|
TPMI_DH_OBJECT handle // IN: handle of the object
|
|
)
|
|
{
|
|
OBJECT *object = ObjectGet(handle);
|
|
return object->publicArea.nameAlg;
|
|
}
|
|
//
|
|
//
|
|
//
|
|
// ObjectGetQualifiedName()
|
|
//
|
|
// 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
|
|
ObjectGetQualifiedName(
|
|
TPMI_DH_OBJECT handle, // IN: handle of the object
|
|
TPM2B_NAME *qualifiedName // OUT: qualified name of the object
|
|
)
|
|
{
|
|
OBJECT *object = ObjectGet(handle);
|
|
if(object->publicArea.nameAlg == TPM_ALG_NULL)
|
|
qualifiedName->t.size = 0;
|
|
else
|
|
// Copy the name
|
|
*qualifiedName = object->qualifiedName;
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// ObjectDataGetHierarchy()
|
|
//
|
|
// This function returns the handle for the hierarchy of an object.
|
|
//
|
|
TPMI_RH_HIERARCHY
|
|
ObjectDataGetHierarchy(
|
|
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;
|
|
}
|
|
}
|
|
//
|
|
//
|
|
// ObjectGetHierarchy()
|
|
//
|
|
// This function returns the handle of the hierarchy to which a handle belongs. This function is similar to
|
|
// ObjectDataGetHierarchy() but this routine takes a handle but ObjectDataGetHierarchy() takes an pointer
|
|
// to an object.
|
|
// This function requires that handle references a loaded object.
|
|
//
|
|
TPMI_RH_HIERARCHY
|
|
ObjectGetHierarchy(
|
|
TPMI_DH_OBJECT handle // IN :object handle
|
|
)
|
|
{
|
|
OBJECT *object = ObjectGet(handle);
|
|
return ObjectDataGetHierarchy(object);
|
|
}
|
|
//
|
|
//
|
|
// ObjectAllocateSlot()
|
|
//
|
|
// This function is used to allocate a slot in internal object array.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// TRUE allocate success
|
|
// FALSE do not have free slot
|
|
//
|
|
static BOOL
|
|
ObjectAllocateSlot(
|
|
TPMI_DH_OBJECT *handle, // OUT: handle of allocated object
|
|
OBJECT **object // OUT: points to the allocated object
|
|
)
|
|
{
|
|
UINT32 i;
|
|
// find an unoccupied handle slot
|
|
for(i = 0; i < MAX_LOADED_OBJECTS; i++)
|
|
{
|
|
if(!s_objects[i].occupied) // If found a free slot
|
|
{
|
|
// Mark the slot as occupied
|
|
s_objects[i].occupied = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
// If we reach the end of object slot without finding a free one, return
|
|
// error.
|
|
if(i == MAX_LOADED_OBJECTS) return FALSE;
|
|
*handle = i + TRANSIENT_FIRST;
|
|
*object = &s_objects[i].object.entity;
|
|
// Initialize the container.
|
|
MemorySet(*object, 0, sizeof(**object));
|
|
return TRUE;
|
|
}
|
|
//
|
|
//
|
|
// ObjectLoad()
|
|
//
|
|
// This function loads an object into an internal object structure. If an error is returned, the internal state is
|
|
// unchanged.
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_BINDING if the public and sensitive parts of the object are not matched
|
|
// TPM_RC_KEY if the parameters in the public area of the object are not consistent
|
|
// TPM_RC_OBJECT_MEMORY if there is no free slot for an object
|
|
// TPM_RC_TYPE the public and private parts are not the same type
|
|
//
|
|
TPM_RC
|
|
ObjectLoad(
|
|
TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy to which the object belongs
|
|
TPMT_PUBLIC *publicArea, // IN: public area
|
|
TPMT_SENSITIVE *sensitive, // IN: sensitive area (may be null)
|
|
TPM2B_NAME *name, // IN: object's name (may be null)
|
|
TPM_HANDLE parentHandle, // IN: handle of parent
|
|
BOOL skipChecks, // IN: flag to indicate if it is OK to skip
|
|
// consistency checks.
|
|
TPMI_DH_OBJECT *handle // OUT: object handle
|
|
)
|
|
{
|
|
OBJECT *object = NULL;
|
|
OBJECT *parent = NULL;
|
|
TPM_RC result = TPM_RC_SUCCESS;
|
|
TPM2B_NAME parentQN; // Parent qualified name
|
|
// Try to allocate a slot for new object
|
|
if(!ObjectAllocateSlot(handle, &object))
|
|
return TPM_RC_OBJECT_MEMORY;
|
|
// Initialize public
|
|
object->publicArea = *publicArea;
|
|
if(sensitive != NULL)
|
|
object->sensitive = *sensitive;
|
|
// Are the consistency checks needed
|
|
if(!skipChecks)
|
|
{
|
|
// Check if key size matches
|
|
if(!CryptObjectIsPublicConsistent(&object->publicArea))
|
|
{
|
|
result = TPM_RC_KEY;
|
|
goto ErrorExit;
|
|
}
|
|
if(sensitive != NULL)
|
|
{
|
|
// Check if public type matches sensitive type
|
|
result = CryptObjectPublicPrivateMatch(object);
|
|
if(result != TPM_RC_SUCCESS)
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
object->attributes.publicOnly = (sensitive == NULL);
|
|
// If 'name' is NULL, then there is nothing left to do for this
|
|
// object as it has no qualified name and it is not a member of any
|
|
// hierarchy and it is temporary
|
|
if(name == NULL || name->t.size == 0)
|
|
{
|
|
object->qualifiedName.t.size = 0;
|
|
object->name.t.size = 0;
|
|
object->attributes.temporary = SET;
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
// If parent handle is a permanent handle, it is a primary or temporary
|
|
// object
|
|
if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
|
|
{
|
|
// initialize QN
|
|
parentQN.t.size = 4;
|
|
// for a primary key, parent qualified name is the handle of hierarchy
|
|
UINT32_TO_BYTE_ARRAY(parentHandle, parentQN.t.name);
|
|
}
|
|
else
|
|
{
|
|
// Get hierarchy and qualified name of parent
|
|
ObjectGetQualifiedName(parentHandle, &parentQN);
|
|
// Check for stClear object
|
|
parent = ObjectGet(parentHandle);
|
|
if( publicArea->objectAttributes.stClear == SET
|
|
|| parent->attributes.stClear == SET)
|
|
object->attributes.stClear = SET;
|
|
}
|
|
object->name = *name;
|
|
// Compute object qualified name
|
|
ObjectComputeQualifiedName(&parentQN, publicArea->nameAlg,
|
|
name, &object->qualifiedName);
|
|
// Any object in TPM_RH_NULL hierarchy is temporary
|
|
if(hierarchy == TPM_RH_NULL)
|
|
{
|
|
object->attributes.temporary = SET;
|
|
}
|
|
else if(parentQN.t.size == sizeof(TPM_HANDLE))
|
|
{
|
|
// Otherwise, if the size of parent's qualified name is the size of a
|
|
// handle, this object is a primary object
|
|
object->attributes.primary = SET;
|
|
}
|
|
switch(hierarchy)
|
|
{
|
|
case TPM_RH_PLATFORM:
|
|
object->attributes.ppsHierarchy = SET;
|
|
break;
|
|
case TPM_RH_OWNER:
|
|
object->attributes.spsHierarchy = SET;
|
|
break;
|
|
case TPM_RH_ENDORSEMENT:
|
|
object->attributes.epsHierarchy = SET;
|
|
break;
|
|
case TPM_RH_NULL:
|
|
break;
|
|
default:
|
|
pAssert(FALSE);
|
|
break;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
ErrorExit:
|
|
ObjectFlush(*handle);
|
|
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 BOOL
|
|
AllocateSequenceSlot(
|
|
TPM_HANDLE *newHandle, // OUT: receives the allocated handle
|
|
HASH_OBJECT **object, // OUT: receives pointer to allocated object
|
|
TPM2B_AUTH *auth // IN: the authValue for the slot
|
|
)
|
|
{
|
|
OBJECT *objectHash; // the hash as an object
|
|
if(!ObjectAllocateSlot(newHandle, &objectHash))
|
|
return FALSE;
|
|
*object = (HASH_OBJECT *)objectHash;
|
|
// Validate that the proper location of the hash state data relative to the
|
|
// object state data.
|
|
pAssert(&((*object)->auth) == &objectHash->publicArea.authPolicy);
|
|
// Set the common values that a sequence object shares with an ordinary 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;
|
|
// Clear the attributes
|
|
MemorySet(&((*object)->objectAttributes), 0, sizeof(TPMA_OBJECT));
|
|
// 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.
|
|
(*object)->objectAttributes.noDA = SET;
|
|
if(auth != NULL)
|
|
{
|
|
MemoryRemoveTrailingZeros(auth);
|
|
(*object)->auth = *auth;
|
|
}
|
|
else
|
|
(*object)->auth.t.size = 0;
|
|
return TRUE;
|
|
}
|
|
//
|
|
//
|
|
// ObjectCreateHMACSequence()
|
|
//
|
|
// This function creates an internal HMAC sequence object.
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_OBJECT_MEMORY if there is no free slot for an object
|
|
//
|
|
TPM_RC
|
|
ObjectCreateHMACSequence(
|
|
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
|
|
TPM_HANDLE handle, // IN: the handle associated with sequence
|
|
// object
|
|
TPM2B_AUTH *auth, // IN: authValue
|
|
TPMI_DH_OBJECT *newHandle // OUT: HMAC sequence object handle
|
|
)
|
|
{
|
|
HASH_OBJECT *hmacObject;
|
|
OBJECT *keyObject;
|
|
// Try to allocate a slot for new object
|
|
if(!AllocateSequenceSlot(newHandle, &hmacObject, auth))
|
|
return TPM_RC_OBJECT_MEMORY;
|
|
// Set HMAC sequence bit
|
|
hmacObject->attributes.hmacSeq = SET;
|
|
// Get pointer to the HMAC key object
|
|
keyObject = ObjectGet(handle);
|
|
CryptStartHMACSequence2B(hashAlg, &keyObject->sensitive.sensitive.bits.b,
|
|
&hmacObject->state.hmacState);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// ObjectCreateHashSequence()
|
|
//
|
|
// This function creates a hash sequence object.
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_OBJECT_MEMORY if there is no free slot for an object
|
|
//
|
|
TPM_RC
|
|
ObjectCreateHashSequence(
|
|
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
|
|
TPM2B_AUTH *auth, // IN: authValue
|
|
TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
|
|
)
|
|
{
|
|
HASH_OBJECT *hashObject;
|
|
// Try to allocate a slot for new object
|
|
if(!AllocateSequenceSlot(newHandle, &hashObject, auth))
|
|
return TPM_RC_OBJECT_MEMORY;
|
|
// Set hash sequence bit
|
|
hashObject->attributes.hashSeq = SET;
|
|
// Start hash for hash sequence
|
|
CryptStartHashSequence(hashAlg, &hashObject->state.hashState[0]);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// ObjectCreateEventSequence()
|
|
//
|
|
// This function creates an event sequence object.
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_OBJECT_MEMORY if there is no free slot for an object
|
|
//
|
|
TPM_RC
|
|
ObjectCreateEventSequence(
|
|
TPM2B_AUTH *auth, // IN: authValue
|
|
TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
|
|
)
|
|
{
|
|
HASH_OBJECT *hashObject;
|
|
UINT32 count;
|
|
TPM_ALG_ID hash;
|
|
// Try to allocate a slot for new object
|
|
if(!AllocateSequenceSlot(newHandle, &hashObject, auth))
|
|
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 = CryptGetHashAlgByIndex(count)) != TPM_ALG_NULL; count++)
|
|
{
|
|
// If this is a _TPM_Init or _TPM_HashStart, the sequence object will
|
|
// not leave the TPM so it doesn't need the sequence handling
|
|
if(auth == NULL)
|
|
CryptStartHash(hash, &hashObject->state.hashState[count]);
|
|
else
|
|
CryptStartHashSequence(hash, &hashObject->state.hashState[count]);
|
|
}
|
|
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 *)ObjectGet(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 crypto implementation has some context values that need to be
|
|
// cleaned up (hygiene).
|
|
//
|
|
for(count = 0; CryptGetHashAlgByIndex(count) != TPM_ALG_NULL; count++)
|
|
{
|
|
CryptCompleteHash(&hashObject->state.hashState[count], 0, buffer);
|
|
}
|
|
// Flush sequence object
|
|
ObjectFlush(g_DRTMHandle);
|
|
}
|
|
g_DRTMHandle = TPM_RH_UNASSIGNED;
|
|
}
|
|
//
|
|
//
|
|
//
|
|
// ObjectContextLoad()
|
|
//
|
|
// This function loads an object from a saved object context.
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_OBJECT_MEMORY if there is no free slot for an object
|
|
//
|
|
TPM_RC
|
|
ObjectContextLoad(
|
|
OBJECT *object, // IN: object structure from saved context
|
|
TPMI_DH_OBJECT *handle // OUT: object handle
|
|
)
|
|
{
|
|
OBJECT *newObject;
|
|
// Try to allocate a slot for new object
|
|
if(!ObjectAllocateSlot(handle, &newObject))
|
|
return TPM_RC_OBJECT_MEMORY;
|
|
// Copy input object data to internal structure
|
|
*newObject = *object;
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// ObjectFlush()
|
|
//
|
|
// This function frees an object slot.
|
|
// This function requires that the object is loaded.
|
|
//
|
|
void
|
|
ObjectFlush(
|
|
TPMI_DH_OBJECT handle // IN: handle to be freed
|
|
)
|
|
{
|
|
UINT32 index = handle - TRANSIENT_FIRST;
|
|
pAssert(ObjectIsPresent(handle));
|
|
// Mark the handle slot as unoccupied
|
|
s_objects[index].occupied = FALSE;
|
|
// With no attributes
|
|
MemorySet((BYTE*)&(s_objects[index].object.entity.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].occupied) // If found an occupied slot
|
|
{
|
|
switch(hierarchy)
|
|
{
|
|
case TPM_RH_PLATFORM:
|
|
if(s_objects[i].object.entity.attributes.ppsHierarchy == SET)
|
|
s_objects[i].occupied = FALSE;
|
|
break;
|
|
case TPM_RH_OWNER:
|
|
if(s_objects[i].object.entity.attributes.spsHierarchy == SET)
|
|
s_objects[i].occupied = FALSE;
|
|
break;
|
|
case TPM_RH_ENDORSEMENT:
|
|
if(s_objects[i].object.entity.attributes.epsHierarchy == SET)
|
|
s_objects[i].occupied = FALSE;
|
|
break;
|
|
default:
|
|
pAssert(FALSE);
|
|
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.
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_HANDLE the persistent object does not exist or the associated hierarchy is
|
|
// disabled.
|
|
// TPM_RC_OBJECT_MEMORY no object slot
|
|
//
|
|
TPM_RC
|
|
ObjectLoadEvict(
|
|
TPM_HANDLE *handle, // IN:OUT: evict object handle. If success, it
|
|
// will be replace by the loaded object handle
|
|
TPM_CC commandCode // 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
|
|
if(!ObjectAllocateSlot(handle, &object))
|
|
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( ObjectDataGetHierarchy(object) == TPM_RH_ENDORSEMENT
|
|
&& gc.ehEnable == CLEAR
|
|
&& commandCode != TPM_CC_EvictControl
|
|
)
|
|
return TPM_RC_HANDLE;
|
|
return result;
|
|
}
|
|
//
|
|
//
|
|
// ObjectComputeName()
|
|
//
|
|
// This function computes the Name of an object from its public area.
|
|
//
|
|
void
|
|
ObjectComputeName(
|
|
TPMT_PUBLIC *publicArea, // IN: public area of an object
|
|
TPM2B_NAME *name // OUT: name of the object
|
|
)
|
|
{
|
|
TPM2B_PUBLIC marshalBuffer;
|
|
BYTE *buffer; // auxiliary marshal buffer pointer
|
|
INT32 bufferSize;
|
|
HASH_STATE hashState; // hash state
|
|
// if the nameAlg is NULL then there is no name.
|
|
if(publicArea->nameAlg == TPM_ALG_NULL)
|
|
{
|
|
name->t.size = 0;
|
|
return;
|
|
}
|
|
// Start hash stack
|
|
name->t.size = CryptStartHash(publicArea->nameAlg, &hashState);
|
|
// Marshal the public area into its canonical form
|
|
buffer = marshalBuffer.b.buffer;
|
|
bufferSize = sizeof(TPMT_PUBLIC);
|
|
marshalBuffer.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, &bufferSize);
|
|
// Adding public area
|
|
CryptUpdateDigest2B(&hashState, &marshalBuffer.b);
|
|
// Complete hash leaving room for the name algorithm
|
|
CryptCompleteHash(&hashState, name->t.size, &name->t.name[2]);
|
|
// set the nameAlg
|
|
UINT16_TO_BYTE_ARRAY(publicArea->nameAlg, name->t.name);
|
|
//
|
|
name->t.size += 2;
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// ObjectComputeQualifiedName()
|
|
//
|
|
// This function computes the qualified name of an object.
|
|
//
|
|
void
|
|
ObjectComputeQualifiedName(
|
|
TPM2B_NAME *parentQN, // IN: parent's qualified name
|
|
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
|
|
// QN_A = hash_A (QN of parent || NAME_A)
|
|
// Start hash
|
|
qualifiedName->t.size = CryptStartHash(nameAlg, &hashState);
|
|
// Add parent's qualified name
|
|
CryptUpdateDigest2B(&hashState, &parentQN->b);
|
|
// Add self name
|
|
CryptUpdateDigest2B(&hashState, &name->b);
|
|
// Complete hash leaving room for the name algorithm
|
|
CryptCompleteHash(&hashState, qualifiedName->t.size,
|
|
&qualifiedName->t.name[2]);
|
|
UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name);
|
|
qualifiedName->t.size += 2;
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// ObjectDataIsStorage()
|
|
//
|
|
// This function determines if a public area has the attributes associated with a storage key. A storage key is
|
|
// an asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// TRUE if the object is a storage key
|
|
// FALSE if the object is not a storage key
|
|
//
|
|
BOOL
|
|
ObjectDataIsStorage(
|
|
TPMT_PUBLIC *publicArea // IN: public area of the object
|
|
)
|
|
{
|
|
if( CryptIsAsymAlgorithm(publicArea->type) // must be asymmetric,
|
|
&& publicArea->objectAttributes.restricted == SET // restricted,
|
|
&& publicArea->objectAttributes.decrypt == SET // decryption key
|
|
&& publicArea->objectAttributes.sign == CLEAR // can not be sign key
|
|
)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
//
|
|
// ObjectIsStorage()
|
|
//
|
|
// This function determines if an object has the attributes associated with a storage key. A storage key is an
|
|
// asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// TRUE if the object is a storage key
|
|
// FALSE if the object is not a storage key
|
|
//
|
|
BOOL
|
|
ObjectIsStorage(
|
|
TPMI_DH_OBJECT handle // IN: object handle
|
|
)
|
|
{
|
|
OBJECT *object = ObjectGet(handle);
|
|
return ObjectDataIsStorage(&object->publicArea);
|
|
}
|
|
//
|
|
//
|
|
// 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 Value Meaning
|
|
//
|
|
// YES if there are more handles available
|
|
// NO all the available handles has been returned
|
|
//
|
|
TPMI_YES_NO
|
|
ObjectCapGetLoaded(
|
|
TPMI_DH_OBJECT handle, // IN: start handle
|
|
UINT32 count, // IN: count of returned handles
|
|
TPML_HANDLE *handleList // OUT: list of handle
|
|
)
|
|
{
|
|
TPMI_YES_NO more = NO;
|
|
UINT32 i;
|
|
pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT);
|
|
// Initialize output handle list
|
|
handleList->count = 0;
|
|
// The maximum count of handles we may return is MAX_CAP_HANDLES
|
|
if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
|
|
// Iterate object slots to get loaded object handles
|
|
for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++)
|
|
{
|
|
if(s_objects[i].occupied == TRUE)
|
|
{
|
|
// A valid transient object can not be the copy of a persistent object
|
|
pAssert(s_objects[i].object.entity.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].occupied == FALSE) num++;
|
|
}
|
|
return num;
|
|
}
|