/********************************************************************************/
/*										*/
/*		Accessing properties for handles of various types		*/
/*			     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 - 2024				*/
/*										*/
/********************************************************************************/

//** Description
// The functions in this file are used for accessing properties for handles of
// various types. Functions in other files require handles of a specific
// type but the functions in this file allow use of any handle type.

//** Includes

#include "Tpm.h"

//** Functions
//*** EntityGetLoadStatus()
// This function will check that all the handles access loaded entities.
//  Return Type: TPM_RC
//      TPM_RC_HANDLE           handle type does not match
//      TPM_RC_REFERENCE_Hx     entity is not present
//      TPM_RC_HIERARCHY        entity belongs to a disabled hierarchy
//      TPM_RC_OBJECT_MEMORY    handle is an evict object but there is no
//                               space to load it to RAM
TPM_RC
EntityGetLoadStatus(COMMAND* command  // IN/OUT: command parsing structure
		    )
{
    UINT32 i;
    TPM_RC result = TPM_RC_SUCCESS;
    //
    for(i = 0; i < command->handleNum; i++)
	{
	    TPM_HANDLE handle = command->handles[i];
	    switch(HandleGetType(handle))
		{
		    // For handles associated with hierarchies, the entity is present
		    // only if the associated enable is SET.
		  case TPM_HT_PERMANENT:
		    switch(handle)
			{
			    // First handle non-hierarchy cases
#if VENDOR_PERMANENT_AUTH_ENABLED == YES
			  case VENDOR_PERMANENT_AUTH_HANDLE:
			    if(!gc.ehEnable)
				result = TPM_RC_HIERARCHY;
			    break;
#endif
			    // PW session handle and lockout handle are always available
			  case TPM_RS_PW:
			    // Need to be careful for lockout. Lockout is always available
			    // for policy checks but not always available when authValue
			    // is being checked.
			  case TPM_RH_LOCKOUT:
			    // Rather than have #ifdefs all over the code,
			    // CASE_ACT_HANDLE is defined in ACT.h. It is 'case TPM_RH_ACT_x:'
			    // FOR_EACH_ACT(CASE_ACT_HANDLE) creates a simple
			    // case TPM_RH_ACT_x: // for each of the implemented ACT.
			    FOR_EACH_ACT(CASE_ACT_HANDLE)
				break;
			  default:
			    // If the implementation has a manufacturer-specific value
			    // then test for it here. Since this implementation does
			    // not have any, this implementation returns the same failure
			    // that unmarshaling of a bad handle would produce.
			    if(((TPM_RH)handle >= TPM_RH_AUTH_00)
			       && ((TPM_RH)handle <= TPM_RH_AUTH_FF))
				// if the implementation has a manufacturer-specific value
				result = TPM_RC_VALUE;
			    else
				// The handle either refers to a hierarchy or is invalid.
				result = ValidateHierarchy(handle);
			    break;
			}
		    break;
		  case TPM_HT_TRANSIENT:
		    // For a transient object, check if the handle is associated
		    // with a loaded object.
		    if(!IsObjectPresent(handle))
			result = TPM_RC_REFERENCE_H0;
		    break;
		  case TPM_HT_PERSISTENT:
		    // Persistent object
		    // Copy the persistent object to RAM and replace the handle with the
		    // handle of the assigned slot.  A TPM_RC_OBJECT_MEMORY,
		    // TPM_RC_HIERARCHY or TPM_RC_REFERENCE_H0 error may be returned by
		    // ObjectLoadEvict()
		    result = ObjectLoadEvict(&command->handles[i], command->index);
		    break;
		  case TPM_HT_HMAC_SESSION:
		    // For an HMAC session, see if the session is loaded
		    // and if the session in the session slot is actually
		    // an HMAC session.
		    if(SessionIsLoaded(handle))
			{
			    SESSION* session;
			    session = SessionGet(handle);
			    // Check if the session is a HMAC session
			    if(session->attributes.isPolicy == SET)
				result = TPM_RC_HANDLE;
			}
		    else
			result = TPM_RC_REFERENCE_H0;
		    break;
		  case TPM_HT_POLICY_SESSION:
		    // For a policy session, see if the session is loaded
		    // and if the session in the session slot is actually
		    // a policy session.
		    if(SessionIsLoaded(handle))
			{
			    SESSION* session;
			    session = SessionGet(handle);
			    // Check if the session is a policy session
			    if(session->attributes.isPolicy == CLEAR)
				result = TPM_RC_HANDLE;
			}
		    else
			result = TPM_RC_REFERENCE_H0;
		    break;
		  case TPM_HT_NV_INDEX:
		    // For an NV Index, use the TPM-specific routine
		    // to search the IN Index space.
		    result = NvIndexIsAccessible(handle);
		    break;
		  case TPM_HT_PCR:
		    // Any PCR handle that is unmarshaled successfully referenced
		    // a PCR that is defined.
		    break;
#if CC_AC_Send
		  case TPM_HT_AC:
		    // Use the TPM-specific routine to search for the AC
		    result = AcIsAccessible(handle);
		    break;
#endif
		  case TPM_HT_EXTERNAL_NV:
		  case TPM_HT_PERMANENT_NV:
		    // Not yet supported.
		    result = TPM_RC_VALUE;
		    break;
		  default:
		    // Any other handle type is a defect in the unmarshaling code.
		    FAIL(FATAL_ERROR_INTERNAL);
		    break;
		}
	    if(result != TPM_RC_SUCCESS)
		{
		    if(result == TPM_RC_REFERENCE_H0)
			result = result + i;
		    else
			result = RcSafeAddToResult(result, TPM_RC_H + g_rcIndex[i]);
		    break;
		}
	}
    return result;
}

//*** EntityGetAuthValue()
// This function is used to access the 'authValue' associated with a handle.
// This function assumes that the handle references an entity that is accessible
// and the handle is not for a persistent objects. That is EntityGetLoadStatus()
// should have been called. Also, the accessibility of the authValue should have
// been verified by IsAuthValueAvailable().
//
// This function copies the authorization value of the entity to 'auth'.
// Return Type: UINT16
//      count           number of bytes in the authValue with 0's stripped
UINT16
EntityGetAuthValue(TPMI_DH_ENTITY handle,  // IN: handle of entity
                   TPM2B_AUTH*    auth     // OUT: authValue of the entity
		   )
{
    TPM2B_AUTH* pAuth = NULL;

    auth->t.size      = 0;

    switch(HandleGetType(handle))
	{
	  case TPM_HT_PERMANENT:
	      {
		  switch(HierarchyNormalizeHandle(handle))
		      {
			case TPM_RH_OWNER:
			  // ownerAuth for TPM_RH_OWNER
			  pAuth = &gp.ownerAuth;
			  break;
			case TPM_RH_ENDORSEMENT:
			  // endorsementAuth for TPM_RH_ENDORSEMENT
			  pAuth = &gp.endorsementAuth;
			  break;

			  // The ACT use platformAuth for auth
			  FOR_EACH_ACT(CASE_ACT_HANDLE)

			case TPM_RH_PLATFORM:
			  // platformAuth for TPM_RH_PLATFORM
			  pAuth = &gc.platformAuth;
			  break;
			case TPM_RH_LOCKOUT:
			  // lockoutAuth for TPM_RH_LOCKOUT
			  pAuth = &gp.lockoutAuth;
			  break;
			case TPM_RH_NULL:
			  // nullAuth for TPM_RH_NULL. Return 0 directly here
			  return 0;
			  break;
#if VENDOR_PERMANENT_AUTH_ENABLED == YES
			case VENDOR_PERMANENT_AUTH_HANDLE:
			  // vendor authorization value
			  pAuth = &g_platformUniqueAuth;
#endif
			default:
			  // If any other permanent handle is present it is
			  // a code defect.
			  FAIL(FATAL_ERROR_INTERNAL);
			  break;
		      }
		  break;
	      }
	  case TPM_HT_TRANSIENT:
            // authValue for an object
            // A persistent object would have been copied into RAM
            // and would have an transient object handle here.
	      {
		  OBJECT* object;

		  object = HandleToObject(handle);
		  // special handling if this is a sequence object
		  if(ObjectIsSequence(object))
		      {
			  pAuth = &((HASH_OBJECT*)object)->auth;
		      }
		  else
		      {
			  // Authorization is available only when the private portion of
			  // the object is loaded.  The check should be made before
			  // this function is called
			  pAssert(object->attributes.publicOnly == CLEAR);
			  pAuth = &object->sensitive.authValue;
		      }
	      }
	      break;
	  case TPM_HT_NV_INDEX:
            // authValue for an NV index
	      {
		  NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL);
		  pAssert(nvIndex != NULL);
		  pAuth = &nvIndex->authValue;
	      }
	      break;
	  case TPM_HT_PCR:
            // authValue for PCR
            pAuth = PCRGetAuthValue(handle);
            break;
	  default:
            // If any other handle type is present here, then there is a defect
            // in the unmarshaling code.
            FAIL(FATAL_ERROR_INTERNAL);
            break;
	}
    // Copy the authValue
    MemoryCopy2B((TPM2B*)auth, (TPM2B*)pAuth, sizeof(auth->t.buffer));
    MemoryRemoveTrailingZeros(auth);
    return auth->t.size;
}

//*** EntityGetAuthPolicy()
// This function is used to access the 'authPolicy' associated with a handle.
// This function assumes that the handle references an entity that is accessible
// and the handle is not for a persistent objects. That is EntityGetLoadStatus()
// should have been called. Also, the accessibility of the authPolicy should have
// been verified by IsAuthPolicyAvailable().
//
// This function copies the authorization policy of the entity to 'authPolicy'.
//
//  The return value is the hash algorithm for the policy.
TPMI_ALG_HASH
EntityGetAuthPolicy(TPMI_DH_ENTITY handle,     // IN: handle of entity
                    TPM2B_DIGEST*  authPolicy  // OUT: authPolicy of the entity
		    )
{
    TPMI_ALG_HASH hashAlg = TPM_ALG_NULL;
    authPolicy->t.size    = 0;

    switch(HandleGetType(handle))
	{
	  case TPM_HT_PERMANENT:
            switch(HierarchyNormalizeHandle(handle))
		{
		  case TPM_RH_OWNER:
                    // ownerPolicy for TPM_RH_OWNER
                    *authPolicy = gp.ownerPolicy;
                    hashAlg     = gp.ownerAlg;
                    break;
		  case TPM_RH_ENDORSEMENT:
                    // endorsementPolicy for TPM_RH_ENDORSEMENT
                    *authPolicy = gp.endorsementPolicy;
                    hashAlg     = gp.endorsementAlg;
                    break;
		  case TPM_RH_PLATFORM:
                    // platformPolicy for TPM_RH_PLATFORM
                    *authPolicy = gc.platformPolicy;
                    hashAlg     = gc.platformAlg;
                    break;
		  case TPM_RH_LOCKOUT:
                    // lockoutPolicy for TPM_RH_LOCKOUT
                    *authPolicy = gp.lockoutPolicy;
                    hashAlg     = gp.lockoutAlg;
                    break;
#define ACT_GET_POLICY(N)					\
		    case TPM_RH_ACT_##N:			\
		      *authPolicy = go.ACT_##N.authPolicy;	\
		      hashAlg     = go.ACT_##N.hashAlg;		\
		      break;
                    // Get the policy for each implemented ACT
                    FOR_EACH_ACT(ACT_GET_POLICY)
		  default:
                    hashAlg = TPM_ALG_ERROR;
                    break;
		}
            break;
	  case TPM_HT_TRANSIENT:
            // authPolicy for an object
	      {
		  OBJECT* object = HandleToObject(handle);
		  *authPolicy    = object->publicArea.authPolicy;
		  hashAlg        = object->publicArea.nameAlg;
	      }
	      break;
	  case TPM_HT_NV_INDEX:
            // authPolicy for a NV index
	      {
		  NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL);
		  pAssert(nvIndex != 0);
		  *authPolicy = nvIndex->publicArea.authPolicy;
		  hashAlg     = nvIndex->publicArea.nameAlg;
	      }
	      break;
	  case TPM_HT_PCR:
            // authPolicy for a PCR
            hashAlg = PCRGetAuthPolicy(handle, authPolicy);
            break;
	  default:
            // If any other handle type is present it is a code defect.
            FAIL(FATAL_ERROR_INTERNAL);
            break;
	}
    return hashAlg;
}

//*** EntityGetName()
// This function returns the Name associated with a handle.
TPM2B_NAME* EntityGetName(TPMI_DH_ENTITY handle,  // IN: handle of entity
                          TPM2B_NAME*    name     // OUT: name of entity
			  )
{
    switch(HandleGetType(handle))
	{
	  case TPM_HT_TRANSIENT:
	      {
		  // Name for an object
		  OBJECT* object = HandleToObject(handle);
		  // an object with no nameAlg has no name
		  if(object->publicArea.nameAlg == TPM_ALG_NULL)
		      name->b.size = 0;
		  else
		      *name = object->name;
		  break;
	      }
	  case TPM_HT_NV_INDEX:
            // Name for a NV index
            NvGetNameByIndexHandle(handle, name);
            break;
	  default:
            // For all other types, the handle is the Name
            name->t.size = sizeof(TPM_HANDLE);
            UINT32_TO_BYTE_ARRAY(handle, name->t.name);
            break;
	}
    return name;
}

//*** EntityGetHierarchy()
// This function returns the hierarchy handle associated with an entity.
// a) A handle that is a hierarchy handle is associated with itself.
// b) An NV index belongs to TPM_RH_PLATFORM if TPMA_NV_PLATFORMCREATE,
//    is SET, otherwise it belongs to TPM_RH_OWNER
// c) An object handle belongs to its hierarchy.
TPMI_RH_HIERARCHY
EntityGetHierarchy(TPMI_DH_ENTITY handle  // IN :handle of entity
		   )
{
    TPMI_RH_HIERARCHY hierarchy = TPM_RH_NULL;

    switch(HandleGetType(handle))
	{
	  case TPM_HT_PERMANENT:
            // hierarchy for a permanent handle

            if(HierarchyIsFirmwareLimited(handle) || HierarchyIsSvnLimited(handle))
		{
		    hierarchy = handle;
		    break;
		}

            switch(handle)
		{
		  case TPM_RH_PLATFORM:
		  case TPM_RH_ENDORSEMENT:
		  case TPM_RH_NULL:
                    hierarchy = handle;
                    break;
		    // all other permanent handles are associated with the owner
		    // hierarchy. (should only be TPM_RH_OWNER and TPM_RH_LOCKOUT)
		  default:
                    hierarchy = TPM_RH_OWNER;
                    break;
		}
            break;
	  case TPM_HT_NV_INDEX:
            // hierarchy for NV index
	      {
		  NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL);
		  pAssert(nvIndex != NULL);

		  // If only the platform can delete the index, then it is
		  // considered to be in the platform hierarchy, otherwise it
		  // is in the owner hierarchy.
		  if(IS_ATTRIBUTE(
				  nvIndex->publicArea.attributes, TPMA_NV, PLATFORMCREATE))
		      hierarchy = TPM_RH_PLATFORM;
		  else
		      hierarchy = TPM_RH_OWNER;
	      }
	      break;
	  case TPM_HT_TRANSIENT:
            // hierarchy for an object
	      {
		  OBJECT* object;
		  object = HandleToObject(handle);
		  if(object->attributes.ppsHierarchy)
		      {
			  hierarchy = TPM_RH_PLATFORM;
		      }
		  else if(object->attributes.epsHierarchy)
		      {
			  hierarchy = TPM_RH_ENDORSEMENT;
		      }
		  else if(object->attributes.spsHierarchy)
		      {
			  hierarchy = TPM_RH_OWNER;
		      }
	      }
	      break;
	  case TPM_HT_PCR:
            hierarchy = TPM_RH_OWNER;
            break;
	  default:
            FAIL(FATAL_ERROR_INTERNAL);
            break;
	}
    // this is unreachable but it provides a return value for the default
    // case which makes the complier happy
    return hierarchy;
}
