// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 4: Supporting Routines
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014

#define SESSION_C
#include "InternalRoutines.h"
#include "Platform.h"
#include "SessionProcess_fp.h"
//
//
//           File Scope Function -- ContextIdSetOldest()
//
//     This function is called when the oldest contextID is being loaded or deleted. Once a saved context
//     becomes the oldest, it stays the oldest until it is deleted.
//     Finding the oldest is a bit tricky. It is not just the numeric comparison of values but is dependent on the
//     value of contextCounter.
//     Assume we have a small contextArray with 8, 4-bit values with values 1 and 2 used to indicate the loaded
//     context slot number. Also assume that the array contains hex values of (0 0 1 0 3 0 9 F) and that the
//     contextCounter is an 8-bit counter with a value of 0x37. Since the low nibble is 7, that means that values
//     above 7 are older than values below it and, in this example, 9 is the oldest value.
//     Note if we subtract the counter value, from each slot that contains a saved contextID we get (- - - - B - 2 -
//     8) and the oldest entry is now easy to find.
//
static void
ContextIdSetOldest(
    void
    )
{
    CONTEXT_SLOT         lowBits;
    CONTEXT_SLOT         entry;
    CONTEXT_SLOT         smallest = ((CONTEXT_SLOT) ~0);
    UINT32 i;
//
   // Set oldestSaveContext to a value indicating none assigned
   s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
   lowBits = (CONTEXT_SLOT)gr.contextCounter;
   for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
   {
       entry = gr.contextArray[i];
        // only look at entries that are saved contexts
        if(entry > MAX_LOADED_SESSIONS)
        {
            // Use a less than or equal in case the oldest
            // is brand new (= lowBits-1) and equal to our initial
            // value for smallest.
            if(((CONTEXT_SLOT) (entry - lowBits)) <= smallest)
            {
                smallest = (entry - lowBits);
                s_oldestSavedSession = i;
            }
        }
   }
   // When we finish, either the s_oldestSavedSession still has its initial
   // value, or it has the index of the oldest saved context.
}
//
//
//         Startup Function -- SessionStartup()
//
//     This function initializes the session subsystem on TPM2_Startup().
//
void
SessionStartup(
   STARTUP_TYPE         type
   )
{
   UINT32                    i;
   // Initialize session slots. At startup, all the in-memory session slots
   // are cleared and marked as not occupied
   for(i = 0; i < MAX_LOADED_SESSIONS; i++)
       s_sessions[i].occupied = FALSE;   // session slot is not occupied
   // The free session slots the number of maximum allowed loaded sessions
   s_freeSessionSlots = MAX_LOADED_SESSIONS;
   // Initialize context ID data. On a ST_SAVE or hibernate sequence, it             will
   // scan the saved array of session context counts, and clear any entry            that
   // references a session that was in memory during the state save since            that
   // memory was not preserved over the ST_SAVE.
   if(type == SU_RESUME || type == SU_RESTART)
   {
       // On ST_SAVE we preserve the contexts that were saved but not the            ones
       // in memory
       for (i = 0; i < MAX_ACTIVE_SESSIONS; i++)
       {
           // If the array value is unused or references a loaded session            then
           // that loaded session context is lost and the array entry is
           // reclaimed.
           if (gr.contextArray[i] <= MAX_LOADED_SESSIONS)
               gr.contextArray[i] = 0;
       }
       // Find the oldest session in context ID data and set it in
       // s_oldestSavedSession
       ContextIdSetOldest();
//
   }
   else
   {
       // For STARTUP_CLEAR, clear out the contextArray
       for (i = 0; i < MAX_ACTIVE_SESSIONS; i++)
           gr.contextArray[i] = 0;
         // reset the context counter
         gr.contextCounter = MAX_LOADED_SESSIONS + 1;
         // Initialize oldest saved session
         s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
   }
   return;
}
//
//
//           Access Functions
//
//           SessionIsLoaded()
//
//      This function test a session handle references a loaded session. The handle must have previously been
//      checked to make sure that it is a valid handle for an authorization session.
//
//      NOTE:           A PWAP authorization does not have a session.
//
//
//      Return Value                       Meaning
//
//      TRUE                               if session is loaded
//      FALSE                              if it is not loaded
//
BOOL
SessionIsLoaded(
   TPM_HANDLE             handle                // IN: session handle
   )
{
   pAssert(   HandleGetType(handle) == TPM_HT_POLICY_SESSION
           || HandleGetType(handle) == TPM_HT_HMAC_SESSION);
   handle = handle & HR_HANDLE_MASK;
   // if out of range of possible active session, or not assigned to a loaded
   // session return false
   if(   handle >= MAX_ACTIVE_SESSIONS
      || gr.contextArray[handle] == 0
      || gr.contextArray[handle] > MAX_LOADED_SESSIONS
     )
       return FALSE;
   return TRUE;
}
//
//
//           SessionIsSaved()
//
//      This function test a session handle references a saved session. The handle must have previously been
//      checked to make sure that it is a valid handle for an authorization session.
//
//      NOTE:           An password authorization does not have a session.
//
//      This function requires that the handle be a valid session handle.
//
//
//      Return Value                     Meaning
//
//      TRUE                             if session is saved
//      FALSE                            if it is not saved
//
BOOL
SessionIsSaved(
   TPM_HANDLE            handle                // IN: session handle
   )
{
   pAssert(   HandleGetType(handle) == TPM_HT_POLICY_SESSION
           || HandleGetType(handle) == TPM_HT_HMAC_SESSION);
   handle = handle & HR_HANDLE_MASK;
   // if out of range of possible active session, or not assigned, or
   // assigned to a loaded session, return false
   if(   handle >= MAX_ACTIVE_SESSIONS
      || gr.contextArray[handle] == 0
      || gr.contextArray[handle] <= MAX_LOADED_SESSIONS
     )
       return FALSE;
   return TRUE;
}
//
//
//           SessionPCRValueIsCurrent()
//
//      This function is used to check if PCR values have been updated since the last time they were checked in
//      a policy session.
//      This function requires the session is loaded.
//
//      Return Value                     Meaning
//
//      TRUE                             if PCR value is current
//      FALSE                            if PCR value is not current
//
BOOL
SessionPCRValueIsCurrent(
   TPMI_SH_POLICY        handle                // IN: session handle
   )
{
   SESSION                   *session;
   pAssert(SessionIsLoaded(handle));
   session = SessionGet(handle);
   if(   session->pcrCounter != 0
      && session->pcrCounter != gr.pcrCounter
     )
       return FALSE;
   else
       return TRUE;
}
//
//
//           SessionGet()
//
//      This function returns a pointer to the session object associated with a session handle.
//      The function requires that the session is loaded.
//
SESSION *
SessionGet(
    TPM_HANDLE           handle              // IN: session handle
    )
{
    CONTEXT_SLOT        sessionIndex;
    pAssert(   HandleGetType(handle) == TPM_HT_POLICY_SESSION
            || HandleGetType(handle) == TPM_HT_HMAC_SESSION
           );
    pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS);
    // get the contents of the session array. Because session is loaded, we
    // should always get a valid sessionIndex
    sessionIndex = gr.contextArray[handle & HR_HANDLE_MASK] - 1;
    pAssert(sessionIndex < MAX_LOADED_SESSIONS);
    return &s_sessions[sessionIndex].session;
}
//
//
//           Utility Functions
//
//             ContextIdSessionCreate()
//
//      This function is called when a session is created. It will check to see if the current gap would prevent a
//      context from being saved. If so it will return TPM_RC_CONTEXT_GAP. Otherwise, it will try to find an
//      open slot in contextArray, set contextArray to the slot.
//      This routine requires that the caller has determined the session array index for the session.
//
//      return type                       TPM_RC
//
//      TPM_RC_SUCCESS                    context ID was assigned
//      TPM_RC_CONTEXT_GAP                can't assign a new contextID until the oldest saved session context is
//                                        recycled
//      TPM_RC_SESSION_HANDLE             there is no slot available in the context array for tracking of this
//                                        session context
//
static TPM_RC
ContextIdSessionCreate (
    TPM_HANDLE          *handle,             // OUT: receives the assigned handle. This will
                                             //     be an index that must be adjusted by the
                                             //     caller according to the type of the
                                             //     session created
    UINT32               sessionIndex        // IN: The session context array entry that will
                                             //     be occupied by the created session
    )
{
    pAssert(sessionIndex < MAX_LOADED_SESSIONS);
    // check to see if creating the context is safe
    // Is this going to be an assignment for the last session context
    // array entry? If so, then there will be no room to recycle the
    // oldest context if needed. If the gap is not at maximum, then
    // it will be possible to save a context if it becomes necessary.
    if(   s_oldestSavedSession < MAX_ACTIVE_SESSIONS
       && s_freeSessionSlots == 1)
    {
        // See if the gap is at maximum
         if(      (CONTEXT_SLOT)gr.contextCounter
               == gr.contextArray[s_oldestSavedSession])
               // Note: if this is being used on a TPM.combined, this return
               //       code should be transformed to an appropriate 1.2 error
               //       code for this case.
               return TPM_RC_CONTEXT_GAP;
   }
   // Find an unoccupied entry in the contextArray
   for(*handle = 0; *handle < MAX_ACTIVE_SESSIONS; (*handle)++)
   {
       if(gr.contextArray[*handle] == 0)
       {
           // indicate that the session associated with this handle
           // references a loaded session
           gr.contextArray[*handle] = (CONTEXT_SLOT)(sessionIndex+1);
           return TPM_RC_SUCCESS;
       }
   }
   return TPM_RC_SESSION_HANDLES;
}
//
//
//           SessionCreate()
//
//      This function does the detailed work for starting an authorization session. This is done in a support
//      routine rather than in the action code because the session management may differ in implementations.
//      This implementation uses a fixed memory allocation to hold sessions and a fixed allocation to hold the
//      contextID for the saved contexts.
//
//      Error Returns                   Meaning
//
//      TPM_RC_CONTEXT_GAP              need to recycle sessions
//      TPM_RC_SESSION_HANDLE           active session space is full
//      TPM_RC_SESSION_MEMORY           loaded session space is full
//
TPM_RC
SessionCreate(
   TPM_SE               sessionType,        //   IN: the session type
   TPMI_ALG_HASH        authHash,           //   IN: the hash algorithm
   TPM2B_NONCE         *nonceCaller,        //   IN: initial nonceCaller
   TPMT_SYM_DEF        *symmetric,          //   IN: the symmetric algorithm
   TPMI_DH_ENTITY       bind,               //   IN: the bind object
   TPM2B_DATA          *seed,               //   IN: seed data
   TPM_HANDLE          *sessionHandle       //   OUT: the session handle
   )
{
   TPM_RC                     result = TPM_RC_SUCCESS;
   CONTEXT_SLOT               slotIndex;
   SESSION                   *session = NULL;
   pAssert(   sessionType == TPM_SE_HMAC
           || sessionType == TPM_SE_POLICY
           || sessionType == TPM_SE_TRIAL);
   // If there are no open spots in the session array, then no point in searching
   if(s_freeSessionSlots == 0)
       return TPM_RC_SESSION_MEMORY;
   // Find a space for loading a session
   for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
   {
        // Is this available?
        if(s_sessions[slotIndex].occupied == FALSE)
        {
            session = &s_sessions[slotIndex].session;
            break;
        }
   }
   // if no spot found, then this is an internal error
   pAssert (slotIndex < MAX_LOADED_SESSIONS);
   // Call context ID function to get a handle. TPM_RC_SESSION_HANDLE may be
   // returned from ContextIdHandelAssign()
   result = ContextIdSessionCreate(sessionHandle, slotIndex);
   if(result != TPM_RC_SUCCESS)
       return result;
   //*** Only return from this point on is TPM_RC_SUCCESS
   // Can now indicate that the session array entry is occupied.
   s_freeSessionSlots--;
   s_sessions[slotIndex].occupied = TRUE;
   // Initialize the session data
   MemorySet(session, 0, sizeof(SESSION));
   // Initialize internal session data
   session->authHashAlg = authHash;
   // Initialize session type
   if(sessionType == TPM_SE_HMAC)
   {
       *sessionHandle += HMAC_SESSION_FIRST;
   }
   else
   {
       *sessionHandle += POLICY_SESSION_FIRST;
        // For TPM_SE_POLICY or TPM_SE_TRIAL
        session->attributes.isPolicy = SET;
        if(sessionType == TPM_SE_TRIAL)
            session->attributes.isTrialPolicy = SET;
        // Initialize policy session data
        SessionInitPolicyData(session);
   }
   // Create initial session nonce
   session->nonceTPM.t.size = nonceCaller->t.size;
   CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
   // Set up session parameter encryption algorithm
   session->symmetric = *symmetric;
   // If there is a bind object or a session secret, then need to compute
   // a sessionKey.
   if(bind != TPM_RH_NULL || seed->t.size != 0)
   {
       // sessionKey = KDFa(hash, (authValue || seed), "ATH", nonceTPM,
       //                      nonceCaller, bits)
       // The HMAC key for generating the sessionSecret can be the concatenation
       // of an authorization value and a seed value
       TPM2B_TYPE(KEY, (sizeof(TPMT_HA) + sizeof(seed->t.buffer)));
       TPM2B_KEY            key;
        UINT16                   hashSize;     // The size of the hash used by the
                                               // session crated by this command
        TPM2B_AUTH    entityAuth;              // The authValue of the entity
                                                     // associated with HMAC session
         // Get hash size, which is also the length of sessionKey
         hashSize = CryptGetHashDigestSize(session->authHashAlg);
         // Get authValue of associated entity
         entityAuth.t.size = EntityGetAuthValue(bind, &entityAuth.t.buffer);
         // Concatenate authValue and seed
         pAssert(entityAuth.t.size + seed->t.size <= sizeof(key.t.buffer));
         MemoryCopy2B(&key.b, &entityAuth.b, sizeof(key.t.buffer));
         MemoryConcat2B(&key.b, &seed->b, sizeof(key.t.buffer));
         session->sessionKey.t.size = hashSize;
         // Compute the session key
         KDFa(session->authHashAlg, &key.b, "ATH", &session->nonceTPM.b,
              &nonceCaller->b, hashSize * 8, session->sessionKey.t.buffer, NULL);
   }
   // Copy the name of the entity that the HMAC session is bound to
   // Policy session is not bound to an entity
   if(bind != TPM_RH_NULL && sessionType == TPM_SE_HMAC)
   {
       session->attributes.isBound = SET;
       SessionComputeBoundEntity(bind, &session->u1.boundEntity);
   }
   // If there is a bind object and it is subject to DA, then use of this session
   // is subject to DA regardless of how it is used.
   session->attributes.isDaBound =    (bind != TPM_RH_NULL)
                                   && (IsDAExempted(bind) == FALSE);
   // If the session is bound, then check to see if it is bound to lockoutAuth
   session->attributes.isLockoutBound =    (session->attributes.isDaBound == SET)
                                        && (bind == TPM_RH_LOCKOUT);
   return TPM_RC_SUCCESS;
}
//
//
//           SessionContextSave()
//
//      This function is called when a session context is to be saved. The contextID of the saved session is
//      returned. If no contextID can be assigned, then the routine returns TPM_RC_CONTEXT_GAP. If the
//      function completes normally, the session slot will be freed.
//      This function requires that handle references a loaded session. Otherwise, it should not be called at the
//      first place.
//
//      Error Returns                      Meaning
//
//      TPM_RC_CONTEXT_GAP                 a contextID could not be assigned.
//      TPM_RC_TOO_MANY_CONTEXTS           the counter maxed out
//
TPM_RC
SessionContextSave (
   TPM_HANDLE                 handle,           // IN: session handle
   CONTEXT_COUNTER           *contextID         // OUT: assigned contextID
   )
{
   UINT32                            contextIndex;
   CONTEXT_SLOT                      slotIndex;
   pAssert(SessionIsLoaded(handle));
   // check to see if the gap is already maxed out
   // Need to have a saved session
   if(   s_oldestSavedSession < MAX_ACTIVE_SESSIONS
         // if the oldest saved session has the same value as the low bits
         // of the contextCounter, then the GAP is maxed out.
      && gr.contextArray[s_oldestSavedSession] == (CONTEXT_SLOT)gr.contextCounter)
       return TPM_RC_CONTEXT_GAP;
   // if the caller wants the context counter, set it
   if(contextID != NULL)
       *contextID = gr.contextCounter;
   pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS);
   contextIndex = handle & HR_HANDLE_MASK;
   // Extract the session slot number referenced by the contextArray
   // because we are going to overwrite this with the low order
   // contextID value.
   slotIndex = gr.contextArray[contextIndex] - 1;
   // Set the contextID for the contextArray
   gr.contextArray[contextIndex] = (CONTEXT_SLOT)gr.contextCounter;
   // Increment the counter
   gr.contextCounter++;
   // In the unlikely event that the 64-bit context counter rolls over...
   if(gr.contextCounter == 0)
   {
       // back it up
       gr.contextCounter--;
       // return an error
       return TPM_RC_TOO_MANY_CONTEXTS;
   }
   // if the low-order bits wrapped, need to advance the value to skip over
   // the values used to indicate that a session is loaded
   if(((CONTEXT_SLOT)gr.contextCounter) == 0)
       gr.contextCounter += MAX_LOADED_SESSIONS + 1;
   // If no other sessions are saved, this is now the oldest.
   if(s_oldestSavedSession >= MAX_ACTIVE_SESSIONS)
       s_oldestSavedSession = contextIndex;
   // Mark the session slot as unoccupied
   s_sessions[slotIndex].occupied = FALSE;
   // and indicate that there is an additional open slot
   s_freeSessionSlots++;
   return TPM_RC_SUCCESS;
}
//
//
//           SessionContextLoad()
//
//      This function is used to load a session from saved context. The session handle must be for a saved
//      context.
//      If the gap is at a maximum, then the only session that can be loaded is the oldest session, otherwise
//      TPM_RC_CONTEXT_GAP is returned.
//      This function requires that handle references a valid saved session.
//
//
//
//      Error Returns                   Meaning
//
//      TPM_RC_SESSION_MEMORY           no free session slots
//      TPM_RC_CONTEXT_GAP              the gap count is maximum and this is not the oldest saved context
//
TPM_RC
SessionContextLoad(
   SESSION            *session,            // IN: session structure from saved context
   TPM_HANDLE         *handle              // IN/OUT: session handle
   )
{
   UINT32                    contextIndex;
   CONTEXT_SLOT              slotIndex;
   pAssert(   HandleGetType(*handle) == TPM_HT_POLICY_SESSION
           || HandleGetType(*handle) == TPM_HT_HMAC_SESSION);
   // Don't bother looking if no openings
   if(s_freeSessionSlots == 0)
       return TPM_RC_SESSION_MEMORY;
   // Find a free session slot to load the session
   for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
       if(s_sessions[slotIndex].occupied == FALSE) break;
   // if no spot found, then this is an internal error
   pAssert (slotIndex < MAX_LOADED_SESSIONS);
   contextIndex = *handle & HR_HANDLE_MASK;               // extract the index
   // If there is only one slot left, and the gap is at maximum, the only session
   // context that we can safely load is the oldest one.
   if(   s_oldestSavedSession < MAX_ACTIVE_SESSIONS
      && s_freeSessionSlots == 1
      && (CONTEXT_SLOT)gr.contextCounter == gr.contextArray[s_oldestSavedSession]
      && contextIndex != s_oldestSavedSession
     )
       return TPM_RC_CONTEXT_GAP;
   pAssert(contextIndex < MAX_ACTIVE_SESSIONS);
   // set the contextArray value to point to the session slot where
   // the context is loaded
   gr.contextArray[contextIndex] = slotIndex + 1;
   // if this was the oldest context, find the new oldest
   if(contextIndex == s_oldestSavedSession)
       ContextIdSetOldest();
   // Copy session data to session slot
   s_sessions[slotIndex].session = *session;
   // Set session slot as occupied
   s_sessions[slotIndex].occupied = TRUE;
   // Reduce the number of open spots
   s_freeSessionSlots--;
   return TPM_RC_SUCCESS;
}
//
//
//
//           SessionFlush()
//
//      This function is used to flush a session referenced by its handle. If the session associated with handle is
//      loaded, the session array entry is marked as available.
//      This function requires that handle be a valid active session.
//
void
SessionFlush(
    TPM_HANDLE           handle             // IN: loaded or saved session handle
    )
{
    CONTEXT_SLOT              slotIndex;
    UINT32                    contextIndex;       // Index into contextArray
    pAssert(      (    HandleGetType(handle) == TPM_HT_POLICY_SESSION
                    || HandleGetType(handle) == TPM_HT_HMAC_SESSION
                  )
               && (SessionIsLoaded(handle) || SessionIsSaved(handle))
              );
    // Flush context ID of this session
    // Convert handle to an index into the contextArray
    contextIndex = handle & HR_HANDLE_MASK;
    pAssert(contextIndex < sizeof(gr.contextArray)/sizeof(gr.contextArray[0]));
    // Get the current contents of the array
    slotIndex = gr.contextArray[contextIndex];
    // Mark context array entry as available
    gr.contextArray[contextIndex] = 0;
    // Is this a saved session being flushed
    if(slotIndex > MAX_LOADED_SESSIONS)
    {
        // Flushing the oldest session?
        if(contextIndex == s_oldestSavedSession)
            // If so, find a new value for oldest.
            ContextIdSetOldest();
    }
    else
    {
        // Adjust slot index to point to session array index
        slotIndex -= 1;
         // Free session array index
         s_sessions[slotIndex].occupied = FALSE;
         s_freeSessionSlots++;
    }
    return;
}
//
//
//           SessionComputeBoundEntity()
//
//      This function computes the binding value for a session. The binding value for a reserved handle is the
//      handle itself. For all the other entities, the authValue at the time of binding is included to prevent
//      squatting. For those values, the Name and the authValue are concatenated into the bind buffer. If they
//      will not both fit, the will be overlapped by XORing() bytes. If XOR is required, the bind value will be full.
//
void
SessionComputeBoundEntity(
    TPMI_DH_ENTITY      entityHandle,     // IN: handle of entity
    TPM2B_NAME         *bind              // OUT: binding value
    )
{
    TPM2B_AUTH               auth;
    INT16                    overlap;
    // Get name
    bind->t.size = EntityGetName(entityHandle, &bind->t.name);
//     // The bound value of a reserved handle is the handle itself
//     if(bind->t.size == sizeof(TPM_HANDLE)) return;
    // For all the other entities, concatenate the auth value to the name.
    // Get a local copy of the auth value because some overlapping
    // may be necessary.
    auth.t.size = EntityGetAuthValue(entityHandle, &auth.t.buffer);
    pAssert(auth.t.size <= sizeof(TPMU_HA));
    // Figure out if there will be any overlap
    overlap = bind->t.size + auth.t.size - sizeof(bind->t.name);
    // There is overlap if the combined sizes are greater than will fit
    if(overlap > 0)
    {
        // The overlap area is at the end of the Name
        BYTE    *result = &bind->t.name[bind->t.size - overlap];
        int     i;
         // XOR the auth value into the Name for the overlap area
         for(i = 0; i < overlap; i++)
             result[i] ^= auth.t.buffer[i];
    }
    else
    {
        // There is no overlap
        overlap = 0;
    }
    //copy the remainder of the authData to the end of the name
    MemoryCopy(&bind->t.name[bind->t.size], &auth.t.buffer[overlap],
               auth.t.size - overlap, sizeof(bind->t.name) - bind->t.size);
    // Increase the size of the bind data by the size of the auth - the overlap
    bind->t.size += auth.t.size-overlap;
    return;
}
//
//
//           SessionInitPolicyData()
//
//      This function initializes the portions of the session policy data that are not set by the allocation of a
//      session.
//
void
SessionInitPolicyData(
    SESSION            *session           // IN: session handle
    )
{
    // Initialize start time
    session->startTime = go.clock;
    // Initialize policyDigest. policyDigest is initialized with a string of 0 of
    // session algorithm digest size. Since the policy already contains all zeros
    // it is only necessary to set the size
     session->u2.policyDigest.t.size = CryptGetHashDigestSize(session->authHashAlg);
     return;
}
//
//
//           SessionResetPolicyData()
//
//      This function is used to reset the policy data without changing the nonce or the start time of the session.
//
void
SessionResetPolicyData(
     SESSION            *session             // IN: the session to reset
     )
{
     session->commandCode = 0;              // No command
     // No locality selected
     MemorySet(&session->commandLocality, 0, sizeof(session->commandLocality));
     // The cpHash size to zero
     session->u1.cpHash.b.size = 0;
     // No timeout
     session->timeOut = 0;
     // Reset the pcrCounter
     session->pcrCounter = 0;
     // Reset the policy hash
     MemorySet(&session->u2.policyDigest.t.buffer, 0,
               session->u2.policyDigest.t.size);
     // Reset the session attributes
     MemorySet(&session->attributes, 0, sizeof(SESSION_ATTRIBUTES));
     // set the policy attribute
     session->attributes.isPolicy = SET;
}
//
//
//           SessionCapGetLoaded()
//
//      This function returns a list of handles of loaded session, started from input handle
//      Handle must be in valid loaded session handle range, but does not have to point to a loaded session.
//
//      Return Value                      Meaning
//
//      YES                               if there are more handles available
//      NO                                all the available handles has been returned
//
TPMI_YES_NO
SessionCapGetLoaded(
     TPMI_SH_POLICY      handle,             // IN: start handle
     UINT32              count,              // IN: count of returned handle
     TPML_HANDLE        *handleList          // OUT: list of handle
     )
{
     TPMI_YES_NO        more = NO;
     UINT32             i;
     pAssert(HandleGetType(handle) == TPM_HT_LOADED_SESSION);
     // 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 session context ID slots to get loaded session handles
     for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++)
     {
         // If session is active
         if(gr.contextArray[i] != 0)
         {
             // If session is loaded
             if (gr.contextArray[i] <= MAX_LOADED_SESSIONS)
             {
                 if(handleList->count < count)
                 {
                     SESSION         *session;
                        // If we have not filled up the return list, add this
                        // session handle to it
                        // assume that this is going to be an HMAC session
                        handle = i + HMAC_SESSION_FIRST;
                        session = SessionGet(handle);
                        if(session->attributes.isPolicy)
                            handle = i + POLICY_SESSION_FIRST;
                        handleList->handle[handleList->count] = handle;
                        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;
}
//
//
//             SessionCapGetSaved()
//
//      This function returns a list of handles for saved session, starting at handle.
//      Handle must be in a valid handle range, but does not have to point to a saved session
//
//      Return Value                      Meaning
//
//      YES                               if there are more handles available
//      NO                                all the available handles has been returned
//
TPMI_YES_NO
SessionCapGetSaved(
     TPMI_SH_HMAC        handle,             // IN: start handle
     UINT32              count,              // IN: count of returned handle
     TPML_HANDLE        *handleList          // OUT: list of handle
     )
{
     TPMI_YES_NO        more = NO;
     UINT32             i;
   pAssert(HandleGetType(handle) == TPM_HT_ACTIVE_SESSION);
   // 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 session context ID slots to get loaded session handles
   for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++)
   {
       // If session is active
       if(gr.contextArray[i] != 0)
       {
           // If session is saved
           if (gr.contextArray[i] > MAX_LOADED_SESSIONS)
           {
               if(handleList->count < count)
               {
                   // If we have not filled up the return list, add this
                   // session handle to it
                   handleList->handle[handleList->count] = i + HMAC_SESSION_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;
}
//
//
//          SessionCapGetLoadedNumber()
//
//      This function return the number of authorization sessions currently loaded into TPM RAM.
//
UINT32
SessionCapGetLoadedNumber(
   void
   )
{
   return MAX_LOADED_SESSIONS - s_freeSessionSlots;
}
//
//
//          SessionCapGetLoadedAvail()
//
//      This function returns the number of additional authorization sessions, of any type, that could be loaded
//      into TPM RAM.
//
//      NOTE:           In other implementations, this number may just be an estimate. The only requirement for the estimate is, if it is
//                      one or more, then at least one session must be loadable.
//
UINT32
SessionCapGetLoadedAvail(
   void
   )
{
     return s_freeSessionSlots;
}
//
//
//           SessionCapGetActiveNumber()
//
//      This function returns the number of active authorization sessions currently being tracked by the TPM.
//
UINT32
SessionCapGetActiveNumber(
     void
     )
{
     UINT32                  i;
     UINT32                  num = 0;
     // Iterate the context array to find the number of non-zero slots
     for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
     {
         if(gr.contextArray[i] != 0) num++;
     }
     return num;
}
//
//
//           SessionCapGetActiveAvail()
//
//      This function returns the number of additional authorization sessions, of any type, that could be created.
//      This not the number of slots for sessions, but the number of additional sessions that the TPM is capable
//      of tracking.
//
UINT32
SessionCapGetActiveAvail(
     void
     )
{
     UINT32                  i;
     UINT32                  num = 0;
     // Iterate the context array to find the number of zero slots
     for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
     {
         if(gr.contextArray[i] == 0) num++;
     }
     return num;
}