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

#include "InternalRoutines.h"
//
//
//
//          Functions
//
//          EntityGetLoadStatus()
//
//     This function will indicate if the entity associated with a handle is present in TPM memory. If the handle is
//     a persistent object handle, and the object exists, the persistent object is moved from NV memory into a
//     RAM object slot and the persistent handle is replaced with the transient object handle for the slot.
//
//     Error Returns                     Meaning
//
//     TPM_RC_HANDLE                     handle type does not match
//     TPM_RC_REFERENCE_H0               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(
    TPM_HANDLE          *handle,              // IN/OUT: handle of the entity
    TPM_CC               commandCode          // IN: the commmandCode
    )
{
    TPM_RC              result = TPM_RC_SUCCESS;
    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)
            {
                case TPM_RH_OWNER:
                    if(!gc.shEnable)
                        result = TPM_RC_HIERARCHY;
                    break;
#ifdef    VENDOR_PERMANENT
                 case VENDOR_PERMANENT:
#endif
                   case TPM_RH_ENDORSEMENT:
                       if(!gc.ehEnable)
                            result = TPM_RC_HIERARCHY;
                       break;
                   case TPM_RH_PLATFORM:
                       if(!g_phEnable)
                            result = TPM_RC_HIERARCHY;
                       break;
                       // null handle, PW session handle and lockout
                       // handle are always available
                   case TPM_RH_NULL:
                   case TPM_RS_PW:
                   case TPM_RH_LOCKOUT:
                       break;
                   default:
                       // handling of the manufacture_specific handles
                       if(      ((TPM_RH)*handle >= TPM_RH_FIRST)
                            && ((TPM_RH)*handle <= TPM_RH_LAST))
                            // use the value that would have been returned from
                            // unmarshaling if it did the handle filtering
                                result = TPM_RC_VALUE;
                       else
                            pAssert(FALSE);
                       break;
            }
            break;
        case TPM_HT_TRANSIENT:
            // For a transient object, check if the handle is associated
            // with a loaded object.
            if(!ObjectIsPresent(*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(handle, commandCode);
            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 platform-specific routine
            // to search the IN Index space.
            result = NvIndexIsAccessible(*handle, commandCode);
            break;
        case TPM_HT_PCR:
            // Any PCR handle that is unmarshaled successfully referenced
            // a PCR that is defined.
            break;
        default:
            // Any other handle type is a defect in the unmarshaling code.
            pAssert(FALSE);
            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 value is the number of octets copied to auth.
//
UINT16
EntityGetAuthValue(
    TPMI_DH_ENTITY       handle,             // IN: handle of entity
    AUTH_VALUE          *auth                // OUT: authValue of the entity
    )
{
    TPM2B_AUTH           authValue = {};
   switch(HandleGetType(handle))
   {
       case TPM_HT_PERMANENT:
           switch(handle)
           {
               case TPM_RH_OWNER:
                   // ownerAuth for TPM_RH_OWNER
                   authValue = gp.ownerAuth;
                   break;
               case TPM_RH_ENDORSEMENT:
                   // endorsementAuth for TPM_RH_ENDORSEMENT
                   authValue = gp.endorsementAuth;
                   break;
               case TPM_RH_PLATFORM:
                   // platformAuth for TPM_RH_PLATFORM
                   authValue = gc.platformAuth;
                   break;
               case TPM_RH_LOCKOUT:
                   // lockoutAuth for TPM_RH_LOCKOUT
                   authValue = gp.lockoutAuth;
                   break;
               case TPM_RH_NULL:
                   // nullAuth for TPM_RH_NULL. Return 0 directly here
                   return 0;
                   break;
#ifdef VENDOR_PERMANENT
               case VENDOR_PERMANENT:
                   // vendor auth value
                   authValue = g_platformUniqueDetails;
#endif
               default:
                   // If any other permanent handle is present it is
                   // a code defect.
                   pAssert(FALSE);
                   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 = ObjectGet(handle);
               // special handling if this is a sequence object
               if(ObjectIsSequence(object))
                   {
                       authValue = ((HASH_OBJECT *)object)->auth;
                   }
                   else
                   {
                       // Auth value 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);
                       authValue = object->sensitive.authValue;
                   }
             }
             break;
         case TPM_HT_NV_INDEX:
             // authValue for an NV index
             {
                  NV_INDEX        nvIndex;
                  NvGetIndexInfo(handle, &nvIndex);
                  authValue = nvIndex.authValue;
             }
             break;
         case TPM_HT_PCR:
             // authValue for PCR
             PCRGetAuthValue(handle, &authValue);
             break;
         default:
             // If any other handle type is present here, then there is a defect
             // in the unmarshaling code.
             pAssert(FALSE);
             break;
    }
    // Copy the authValue
    pAssert(authValue.t.size <= sizeof(authValue.t.buffer));
    MemoryCopy(auth, authValue.t.buffer, authValue.t.size, sizeof(TPMU_HA));
    return authValue.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;
    switch(HandleGetType(handle))
    {
        case TPM_HT_PERMANENT:
            switch(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;
                  default:
                      // If any other permanent handle is present it is
                      // a code defect.
                      pAssert(FALSE);
                      break;
             }
             break;
         case TPM_HT_TRANSIENT:
             // authPolicy for an object
             {
                  OBJECT *object = ObjectGet(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, &nvIndex);
                  *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.
             pAssert(FALSE);
             break;
   }
   return hashAlg;
}
//
//
//           EntityGetName()
//
//      This function returns the Name associated with a handle. It will set name to the Name and return the size
//      of the Name string.
//
UINT16
EntityGetName(
   TPMI_DH_ENTITY       handle,           // IN: handle of entity
   NAME                *name              // OUT: name of entity
    )
{
    UINT16              nameSize;
    INT32 bufferSize = sizeof(TPM_HANDLE);
    switch(HandleGetType(handle))
    {
        case TPM_HT_TRANSIENT:
            // Name for an object
            nameSize = ObjectGetName(handle, name);
            break;
        case TPM_HT_NV_INDEX:
            // Name for a NV index
            nameSize = NvGetName(handle, name);
            break;
        default:
            // For all other types, the handle is the Name
            nameSize = TPM_HANDLE_Marshal(&handle, (BYTE **)&name, &bufferSize);
            break;
    }
    return nameSize;
}
//
//
//           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. All other handles belong to the platform hierarchy. or an NV
//         Index.
//
TPMI_RH_HIERARCHY
EntityGetHierarchy(
    TPMI_DH_ENTITY       handle             // IN :handle of entity
    )
{
    TPMI_RH_HIERARCHY             hierarcy = TPM_RH_NULL;
    switch(HandleGetType(handle))
    {
        case TPM_HT_PERMANENT:
            // hierarchy for a permanent handle
            switch(handle)
            {
                case TPM_RH_PLATFORM:
                case TPM_RH_ENDORSEMENT:
                case TPM_RH_NULL:
                    hierarcy = handle;
                    break;
                // all other permanent handles are associated with the owner
                // hierarchy. (should only be TPM_RH_OWNER and TPM_RH_LOCKOUT)
                default:
                    hierarcy = TPM_RH_OWNER;
                    break;
            }
            break;
        case TPM_HT_NV_INDEX:
            // hierarchy for NV index
            {
                NV_INDEX        nvIndex;
                NvGetIndexInfo(handle, &nvIndex);
                // 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(nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == SET)
                      hierarcy = TPM_RH_PLATFORM;
                  else
                      hierarcy = TPM_RH_OWNER;
             }
             break;
         case TPM_HT_TRANSIENT:
             // hierarchy for an object
             {
                 OBJECT          *object;
                 object = ObjectGet(handle);
                 if(object->attributes.ppsHierarchy)
                 {
                     hierarcy = TPM_RH_PLATFORM;
                 }
                 else if(object->attributes.epsHierarchy)
                 {
                     hierarcy = TPM_RH_ENDORSEMENT;
                 }
                 else if(object->attributes.spsHierarchy)
                 {
                     hierarcy = TPM_RH_OWNER;
                 }
             }
             break;
         case TPM_HT_PCR:
             hierarcy = TPM_RH_OWNER;
             break;
         default:
             pAssert(0);
             break;
     }
     // this is unreachable but it provides a return value for the default
     // case which makes the complier happy
     return hierarcy;
}