blob: 06d717fa60f48e39361da4d70d3c20255833e429 [file] [log] [blame]
// 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 object attributes
MemorySet(&((*object)->attributes), 0, sizeof(OBJECT_ATTRIBUTES));
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;
}