/********************************************************************************/
/*										*/
/*		Manage the object store of the TPM.    				*/
/*			     Written by Ken Goldman				*/
/*		       IBM Thomas J. Watson Research Center			*/
/*										*/
/*  Licenses and Notices							*/
/*										*/
/*  1. Copyright Licenses:							*/
/*										*/
/*  - Trusted Computing Group (TCG) grants to the user of the source code in	*/
/*    this specification (the "Source Code") a worldwide, irrevocable, 		*/
/*    nonexclusive, royalty free, copyright license to reproduce, create 	*/
/*    derivative works, distribute, display and perform the Source Code and	*/
/*    derivative works thereof, and to grant others the rights granted herein.	*/
/*										*/
/*  - The TCG grants to the user of the other parts of the specification 	*/
/*    (other than the Source Code) the rights to reproduce, distribute, 	*/
/*    display, and perform the specification solely for the purpose of 		*/
/*    developing products based on such documents.				*/
/*										*/
/*  2. Source Code Distribution Conditions:					*/
/*										*/
/*  - Redistributions of Source Code must retain the above copyright licenses, 	*/
/*    this list of conditions and the following disclaimers.			*/
/*										*/
/*  - Redistributions in binary form must reproduce the above copyright 	*/
/*    licenses, this list of conditions	and the following disclaimers in the 	*/
/*    documentation and/or other materials provided with the distribution.	*/
/*										*/
/*  3. Disclaimers:								*/
/*										*/
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF	*/
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH	*/
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)	*/
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.		*/
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for 		*/
/*  information on specification licensing rights available through TCG 	*/
/*  membership agreements.							*/
/*										*/
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED 	*/
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR 	*/
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR 		*/
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY 		*/
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.		*/
/*										*/
/*  - Without limitation, TCG and its members and licensors disclaim all 	*/
/*    liability, including liability for infringement of any proprietary 	*/
/*    rights, relating to use of information in this specification and to the	*/
/*    implementation of this specification, and TCG disclaims all liability for	*/
/*    cost of procurement of substitute goods or services, lost profits, loss 	*/
/*    of use, loss of data or any incidental, consequential, direct, indirect, 	*/
/*    or special damages, whether under contract, tort, warranty or otherwise, 	*/
/*    arising in any way out of use or reliance upon this specification or any 	*/
/*    information herein.							*/
/*										*/
/*  (c) Copyright IBM Corp. and others, 2016 - 2023				*/
/*										*/
/********************************************************************************/

//** 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"
#include "NVMarshal.h" // libtpms added
#include "BackwardsCompatibilityObject.h" // libtpms added

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

//*** GetHierarchy()
// This function returns the handle of the hierarchy to which a handle belongs.
//
// This function requires that 'handle' references a loaded object.
TPMI_RH_HIERARCHY
GetHierarchy(TPMI_DH_OBJECT handle  // IN :object handle
	     )
{
    return HandleToObject(handle)->hierarchy;
}

//*** 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));
		    MemorySet(object, 0, sizeof(*object)); // libtpms added: Initialize the whole object
		    object->hierarchy = TPM_RH_NULL;
		    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
			       SEED_COMPAT_LEVEL seedCompatLevel // IN: seed compat level to use for children
			       )
{
    OBJECT*     parent           = HandleToObject(parentHandle);
    TPMA_OBJECT objectAttributes = object->publicArea.objectAttributes;

    object->seedCompatLevel = seedCompatLevel; // libtpms added
    //
    // 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->hierarchy          = parentHandle;
	    object->attributes.primary = SET;
	    switch(HierarchyNormalizeHandle(object->hierarchy))
		{
		  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;
	    object->hierarchy = parent->hierarchy;
	}
    // 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 a non-primary object (i.e., either an Ordinary Object,
// or an External 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
	    // For the purposes of attributes validation on this non-primary object,
	    // either:
	    // - parent is not NULL and therefore its attributes are checked for
	    //   consistency with the parent, OR
	    // - parent is NULL but the object is not a primary object, either
	    result =
		PublicAttributesValidation(parent, /*primaryHierarchy = */ 0, publicArea);
	}
    if(result != TPM_RC_SUCCESS)
	return RcSafeAddToResult(result, blamePublic);

    // Sensitive area and binding checks

    // On load, check nothing if the parent is fixedTPM.
    // If the parent is fixedTPM, then this TPM produced this key blob (either
    // by import, or creation). If the parent is not fixedTPM, then an external
    // copy of the parent's protection seed might have been used to create the
    // blob, and we have to validate it.
    // NOTE: By the time a TPMT_SENSITIVE has been decrypted and passed to this
    // function, it has been validated against the corresponding TPMT_PUBLIC.
    // For more information about this check, see PrivateToSensitive.
    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, object); // libtpms: Added object (may be NULL)
	    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.
    MUST_BE(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;
}

#if 0			// libtpms added
//*** 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;
}
#endif 			// libtpms added begin

OBJECT *
ObjectContextLoadLibtpms(BYTE           *buffer,
                         INT32           size,
                         TPMI_DH_OBJECT *handle
                         )
{
    OBJECT      *newObject = ObjectAllocateSlot(handle);
    TPM_RC       rc;
    BYTE        *mybuf  = buffer;
    INT32        mysize = size;

    pAssert(handle);

    // Try to allocate a slot for new object
    if(newObject != NULL)
	{
	    rc = ANY_OBJECT_Unmarshal(newObject, &mybuf, &mysize, false);
	    if (rc) {
	         /* Attempt to load an old OBJECT that was copied out directly from
	          * an older version of OBJECT.
	          */
		rc = RSA2048_OBJECT_Buffer_To_OBJECT(newObject, buffer, size);
		if (rc) {
		    FlushObject(*handle);
		    newObject = NULL;
		}
	    }
	}
    return newObject;
}			// libtpms added end

//*** 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(HierarchyNormalizeHandle(object->hierarchy) == 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 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;
}

//*** ObjectCapGetOneLoaded()
// This function returns whether a handle is loaded.
BOOL ObjectCapGetOneLoaded(TPMI_DH_OBJECT handle)  // IN: handle
{
    UINT32 i;

    pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT);

    // 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);

		    return TRUE;
		}
	}

    return FALSE;
}

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

#if 0 /* libtpms added */
OBJECT_ATTRIBUTES
ObjectGetProperties(TPM_HANDLE handle)
{
    return HandleToObject(handle)->attributes;
}
#endif /* libtpms added */
