/* 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"
#include "Marshal.h"

//** Functions

//*** ObjectFlush()
// This function marks an object slot as available.
// Since there is no checking of the input parameters, it should be used
// judiciously.
// Note: This could be converted to a macro.
void ObjectFlush(OBJECT* object)
{
    object->attributes.occupied = CLEAR;
}

//*** ObjectSetInUse()
// This access function sets the occupied attribute of an object slot.
void ObjectSetInUse(OBJECT* object)
{
    object->attributes.occupied = SET;
}

//*** ObjectStartup()
// This function is called at TPM2_Startup() to initialize the object subsystem.
BOOL ObjectStartup(void)
{
    UINT32 i;
    //
    // object slots initialization
    for(i = 0; i < MAX_LOADED_OBJECTS; i++)
    {
        //Set the slot to not occupied
        ObjectFlush(&s_objects[i]);
    }
    return TRUE;
}

//*** ObjectCleanupEvict()
//
// In this implementation, a persistent object is moved from NV into an object slot
// for processing. It is flushed after command execution. This function is called
// from ExecuteCommand().
void ObjectCleanupEvict(void)
{
    UINT32 i;
    //
    // This has to be iterated because a command may have two handles
    // and they may both be persistent.
    // This could be made to be more efficient so that a search is not needed.
    for(i = 0; i < MAX_LOADED_OBJECTS; i++)
    {
        // If an object is a temporary evict object, flush it from slot
        OBJECT* object = &s_objects[i];
        if(object->attributes.evict == SET)
            ObjectFlush(object);
    }
    return;
}

//*** IsObjectPresent()
// This function checks to see if a transient handle references a loaded
// object.  This routine should not be called if the handle is not a
// transient handle. The function validates that the handle is in the
// implementation-dependent allowed in range for loaded transient objects.
//  Return Type: BOOL
//      TRUE(1)         handle references a loaded object
//      FALSE(0)        handle is not an object handle, or it does not
//                      reference to a loaded object
BOOL IsObjectPresent(TPMI_DH_OBJECT handle  // IN: handle to be checked
)
{
    UINT32 slotIndex = handle - TRANSIENT_FIRST;
    // Since the handle is just an index into the array that is zero based, any
    // handle value outsize of the range of:
    //    TRANSIENT_FIRST -- (TRANSIENT_FIRST + MAX_LOADED_OBJECT - 1)
    // will now be greater than or equal to MAX_LOADED_OBJECTS
    if(slotIndex >= MAX_LOADED_OBJECTS)
        return FALSE;
    // Indicate if the slot is occupied
    return (s_objects[slotIndex].attributes.occupied == TRUE);
}

//*** ObjectIsSequence()
// This function is used to check if the object is a sequence object. This function
// should not be called if the handle does not reference a loaded object.
//  Return Type: BOOL
//      TRUE(1)         object is an HMAC, hash, or event sequence object
//      FALSE(0)        object is not an HMAC, hash, or event sequence object
BOOL ObjectIsSequence(OBJECT* object  // IN: handle to be checked
)
{
    pAssert(object != NULL);
    return (object->attributes.hmacSeq == SET || object->attributes.hashSeq == SET
            || object->attributes.eventSeq == SET);
}

//*** HandleToObject()
// This function is used to find the object structure associated with a handle.
//
// This function requires that 'handle' references a loaded object or a permanent
// handle.
OBJECT* HandleToObject(TPMI_DH_OBJECT handle  // IN: handle of the object
)
{
    UINT32 index;
    //
    // Return NULL if the handle references a permanent handle because there is no
    // associated OBJECT.
    if(HandleGetType(handle) == TPM_HT_PERMANENT)
        return NULL;
    // In this implementation, the handle is determined by the slot occupied by the
    // object.
    index = handle - TRANSIENT_FIRST;
    pAssert(index < MAX_LOADED_OBJECTS);
    pAssert(s_objects[index].attributes.occupied);
    return &s_objects[index];
}

//*** GetQualifiedName()
// This function returns the Qualified Name of the object. In this implementation,
// the Qualified Name is computed when the object is loaded and is saved in the
// internal representation of the object. The alternative would be to retain the
// Name of the parent and compute the QN when needed. This would take the same
// amount of space so it is not recommended that the alternate be used.
//
// This function requires that 'handle' references a loaded object.
void GetQualifiedName(TPMI_DH_OBJECT handle,     // IN: handle of the object
                      TPM2B_NAME* qualifiedName  // OUT: qualified name of the object
)
{
    OBJECT* object;
    //
    switch(HandleGetType(handle))
    {
        case TPM_HT_PERMANENT:
            qualifiedName->t.size = sizeof(TPM_HANDLE);
            UINT32_TO_BYTE_ARRAY(handle, qualifiedName->t.name);
            break;
        case TPM_HT_TRANSIENT:
            object = HandleToObject(handle);
            if(object == NULL || object->publicArea.nameAlg == TPM_ALG_NULL)
                qualifiedName->t.size = 0;
            else
                // Copy the name
                *qualifiedName = object->qualifiedName;
            break;
        default:
            FAIL(FATAL_ERROR_INTERNAL);
    }
    return;
}

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