Home | History | Annotate | Download | only in tpm2
      1 // This file was extracted from the TCG Published
      2 // Trusted Platform Module Library
      3 // Part 4: Supporting Routines
      4 // Family "2.0"
      5 // Level 00 Revision 01.16
      6 // October 30, 2014
      7 
      8 #define SESSION_C
      9 #include "InternalRoutines.h"
     10 #include "Platform.h"
     11 #include "SessionProcess_fp.h"
     12 //
     13 //
     14 //           File Scope Function -- ContextIdSetOldest()
     15 //
     16 //     This function is called when the oldest contextID is being loaded or deleted. Once a saved context
     17 //     becomes the oldest, it stays the oldest until it is deleted.
     18 //     Finding the oldest is a bit tricky. It is not just the numeric comparison of values but is dependent on the
     19 //     value of contextCounter.
     20 //     Assume we have a small contextArray with 8, 4-bit values with values 1 and 2 used to indicate the loaded
     21 //     context slot number. Also assume that the array contains hex values of (0 0 1 0 3 0 9 F) and that the
     22 //     contextCounter is an 8-bit counter with a value of 0x37. Since the low nibble is 7, that means that values
     23 //     above 7 are older than values below it and, in this example, 9 is the oldest value.
     24 //     Note if we subtract the counter value, from each slot that contains a saved contextID we get (- - - - B - 2 -
     25 //     8) and the oldest entry is now easy to find.
     26 //
     27 static void
     28 ContextIdSetOldest(
     29     void
     30     )
     31 {
     32     CONTEXT_SLOT         lowBits;
     33     CONTEXT_SLOT         entry;
     34     CONTEXT_SLOT         smallest = ((CONTEXT_SLOT) ~0);
     35     UINT32 i;
     36 //
     37    // Set oldestSaveContext to a value indicating none assigned
     38    s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
     39    lowBits = (CONTEXT_SLOT)gr.contextCounter;
     40    for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
     41    {
     42        entry = gr.contextArray[i];
     43         // only look at entries that are saved contexts
     44         if(entry > MAX_LOADED_SESSIONS)
     45         {
     46             // Use a less than or equal in case the oldest
     47             // is brand new (= lowBits-1) and equal to our initial
     48             // value for smallest.
     49             if(((CONTEXT_SLOT) (entry - lowBits)) <= smallest)
     50             {
     51                 smallest = (entry - lowBits);
     52                 s_oldestSavedSession = i;
     53             }
     54         }
     55    }
     56    // When we finish, either the s_oldestSavedSession still has its initial
     57    // value, or it has the index of the oldest saved context.
     58 }
     59 //
     60 //
     61 //         Startup Function -- SessionStartup()
     62 //
     63 //     This function initializes the session subsystem on TPM2_Startup().
     64 //
     65 void
     66 SessionStartup(
     67    STARTUP_TYPE         type
     68    )
     69 {
     70    UINT32                    i;
     71    // Initialize session slots. At startup, all the in-memory session slots
     72    // are cleared and marked as not occupied
     73    for(i = 0; i < MAX_LOADED_SESSIONS; i++)
     74        s_sessions[i].occupied = FALSE;   // session slot is not occupied
     75    // The free session slots the number of maximum allowed loaded sessions
     76    s_freeSessionSlots = MAX_LOADED_SESSIONS;
     77    // Initialize context ID data. On a ST_SAVE or hibernate sequence, it             will
     78    // scan the saved array of session context counts, and clear any entry            that
     79    // references a session that was in memory during the state save since            that
     80    // memory was not preserved over the ST_SAVE.
     81    if(type == SU_RESUME || type == SU_RESTART)
     82    {
     83        // On ST_SAVE we preserve the contexts that were saved but not the            ones
     84        // in memory
     85        for (i = 0; i < MAX_ACTIVE_SESSIONS; i++)
     86        {
     87            // If the array value is unused or references a loaded session            then
     88            // that loaded session context is lost and the array entry is
     89            // reclaimed.
     90            if (gr.contextArray[i] <= MAX_LOADED_SESSIONS)
     91                gr.contextArray[i] = 0;
     92        }
     93        // Find the oldest session in context ID data and set it in
     94        // s_oldestSavedSession
     95        ContextIdSetOldest();
     96 //
     97    }
     98    else
     99    {
    100        // For STARTUP_CLEAR, clear out the contextArray
    101        for (i = 0; i < MAX_ACTIVE_SESSIONS; i++)
    102            gr.contextArray[i] = 0;
    103          // reset the context counter
    104          gr.contextCounter = MAX_LOADED_SESSIONS + 1;
    105          // Initialize oldest saved session
    106          s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
    107    }
    108    return;
    109 }
    110 //
    111 //
    112 //           Access Functions
    113 //
    114 //           SessionIsLoaded()
    115 //
    116 //      This function test a session handle references a loaded session. The handle must have previously been
    117 //      checked to make sure that it is a valid handle for an authorization session.
    118 //
    119 //      NOTE:           A PWAP authorization does not have a session.
    120 //
    121 //
    122 //      Return Value                       Meaning
    123 //
    124 //      TRUE                               if session is loaded
    125 //      FALSE                              if it is not loaded
    126 //
    127 BOOL
    128 SessionIsLoaded(
    129    TPM_HANDLE             handle                // IN: session handle
    130    )
    131 {
    132    pAssert(   HandleGetType(handle) == TPM_HT_POLICY_SESSION
    133            || HandleGetType(handle) == TPM_HT_HMAC_SESSION);
    134    handle = handle & HR_HANDLE_MASK;
    135    // if out of range of possible active session, or not assigned to a loaded
    136    // session return false
    137    if(   handle >= MAX_ACTIVE_SESSIONS
    138       || gr.contextArray[handle] == 0
    139       || gr.contextArray[handle] > MAX_LOADED_SESSIONS
    140      )
    141        return FALSE;
    142    return TRUE;
    143 }
    144 //
    145 //
    146 //           SessionIsSaved()
    147 //
    148 //      This function test a session handle references a saved session. The handle must have previously been
    149 //      checked to make sure that it is a valid handle for an authorization session.
    150 //
    151 //      NOTE:           An password authorization does not have a session.
    152 //
    153 //      This function requires that the handle be a valid session handle.
    154 //
    155 //
    156 //      Return Value                     Meaning
    157 //
    158 //      TRUE                             if session is saved
    159 //      FALSE                            if it is not saved
    160 //
    161 BOOL
    162 SessionIsSaved(
    163    TPM_HANDLE            handle                // IN: session handle
    164    )
    165 {
    166    pAssert(   HandleGetType(handle) == TPM_HT_POLICY_SESSION
    167            || HandleGetType(handle) == TPM_HT_HMAC_SESSION);
    168    handle = handle & HR_HANDLE_MASK;
    169    // if out of range of possible active session, or not assigned, or
    170    // assigned to a loaded session, return false
    171    if(   handle >= MAX_ACTIVE_SESSIONS
    172       || gr.contextArray[handle] == 0
    173       || gr.contextArray[handle] <= MAX_LOADED_SESSIONS
    174      )
    175        return FALSE;
    176    return TRUE;
    177 }
    178 //
    179 //
    180 //           SessionPCRValueIsCurrent()
    181 //
    182 //      This function is used to check if PCR values have been updated since the last time they were checked in
    183 //      a policy session.
    184 //      This function requires the session is loaded.
    185 //
    186 //      Return Value                     Meaning
    187 //
    188 //      TRUE                             if PCR value is current
    189 //      FALSE                            if PCR value is not current
    190 //
    191 BOOL
    192 SessionPCRValueIsCurrent(
    193    TPMI_SH_POLICY        handle                // IN: session handle
    194    )
    195 {
    196    SESSION                   *session;
    197    pAssert(SessionIsLoaded(handle));
    198    session = SessionGet(handle);
    199    if(   session->pcrCounter != 0
    200       && session->pcrCounter != gr.pcrCounter
    201      )
    202        return FALSE;
    203    else
    204        return TRUE;
    205 }
    206 //
    207 //
    208 //           SessionGet()
    209 //
    210 //      This function returns a pointer to the session object associated with a session handle.
    211 //      The function requires that the session is loaded.
    212 //
    213 SESSION *
    214 SessionGet(
    215     TPM_HANDLE           handle              // IN: session handle
    216     )
    217 {
    218     CONTEXT_SLOT        sessionIndex;
    219     pAssert(   HandleGetType(handle) == TPM_HT_POLICY_SESSION
    220             || HandleGetType(handle) == TPM_HT_HMAC_SESSION
    221            );
    222     pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS);
    223     // get the contents of the session array. Because session is loaded, we
    224     // should always get a valid sessionIndex
    225     sessionIndex = gr.contextArray[handle & HR_HANDLE_MASK] - 1;
    226     pAssert(sessionIndex < MAX_LOADED_SESSIONS);
    227     return &s_sessions[sessionIndex].session;
    228 }
    229 //
    230 //
    231 //           Utility Functions
    232 //
    233 //             ContextIdSessionCreate()
    234 //
    235 //      This function is called when a session is created. It will check to see if the current gap would prevent a
    236 //      context from being saved. If so it will return TPM_RC_CONTEXT_GAP. Otherwise, it will try to find an
    237 //      open slot in contextArray, set contextArray to the slot.
    238 //      This routine requires that the caller has determined the session array index for the session.
    239 //
    240 //      return type                       TPM_RC
    241 //
    242 //      TPM_RC_SUCCESS                    context ID was assigned
    243 //      TPM_RC_CONTEXT_GAP                can't assign a new contextID until the oldest saved session context is
    244 //                                        recycled
    245 //      TPM_RC_SESSION_HANDLE             there is no slot available in the context array for tracking of this
    246 //                                        session context
    247 //
    248 static TPM_RC
    249 ContextIdSessionCreate (
    250     TPM_HANDLE          *handle,             // OUT: receives the assigned handle. This will
    251                                              //     be an index that must be adjusted by the
    252                                              //     caller according to the type of the
    253                                              //     session created
    254     UINT32               sessionIndex        // IN: The session context array entry that will
    255                                              //     be occupied by the created session
    256     )
    257 {
    258     pAssert(sessionIndex < MAX_LOADED_SESSIONS);
    259     // check to see if creating the context is safe
    260     // Is this going to be an assignment for the last session context
    261     // array entry? If so, then there will be no room to recycle the
    262     // oldest context if needed. If the gap is not at maximum, then
    263     // it will be possible to save a context if it becomes necessary.
    264     if(   s_oldestSavedSession < MAX_ACTIVE_SESSIONS
    265        && s_freeSessionSlots == 1)
    266     {
    267         // See if the gap is at maximum
    268          if(      (CONTEXT_SLOT)gr.contextCounter
    269                == gr.contextArray[s_oldestSavedSession])
    270                // Note: if this is being used on a TPM.combined, this return
    271                //       code should be transformed to an appropriate 1.2 error
    272                //       code for this case.
    273                return TPM_RC_CONTEXT_GAP;
    274    }
    275    // Find an unoccupied entry in the contextArray
    276    for(*handle = 0; *handle < MAX_ACTIVE_SESSIONS; (*handle)++)
    277    {
    278        if(gr.contextArray[*handle] == 0)
    279        {
    280            // indicate that the session associated with this handle
    281            // references a loaded session
    282            gr.contextArray[*handle] = (CONTEXT_SLOT)(sessionIndex+1);
    283            return TPM_RC_SUCCESS;
    284        }
    285    }
    286    return TPM_RC_SESSION_HANDLES;
    287 }
    288 //
    289 //
    290 //           SessionCreate()
    291 //
    292 //      This function does the detailed work for starting an authorization session. This is done in a support
    293 //      routine rather than in the action code because the session management may differ in implementations.
    294 //      This implementation uses a fixed memory allocation to hold sessions and a fixed allocation to hold the
    295 //      contextID for the saved contexts.
    296 //
    297 //      Error Returns                   Meaning
    298 //
    299 //      TPM_RC_CONTEXT_GAP              need to recycle sessions
    300 //      TPM_RC_SESSION_HANDLE           active session space is full
    301 //      TPM_RC_SESSION_MEMORY           loaded session space is full
    302 //
    303 TPM_RC
    304 SessionCreate(
    305    TPM_SE               sessionType,        //   IN: the session type
    306    TPMI_ALG_HASH        authHash,           //   IN: the hash algorithm
    307    TPM2B_NONCE         *nonceCaller,        //   IN: initial nonceCaller
    308    TPMT_SYM_DEF        *symmetric,          //   IN: the symmetric algorithm
    309    TPMI_DH_ENTITY       bind,               //   IN: the bind object
    310    TPM2B_DATA          *seed,               //   IN: seed data
    311    TPM_HANDLE          *sessionHandle       //   OUT: the session handle
    312    )
    313 {
    314    TPM_RC                     result = TPM_RC_SUCCESS;
    315    CONTEXT_SLOT               slotIndex;
    316    SESSION                   *session = NULL;
    317    pAssert(   sessionType == TPM_SE_HMAC
    318            || sessionType == TPM_SE_POLICY
    319            || sessionType == TPM_SE_TRIAL);
    320    // If there are no open spots in the session array, then no point in searching
    321    if(s_freeSessionSlots == 0)
    322        return TPM_RC_SESSION_MEMORY;
    323    // Find a space for loading a session
    324    for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
    325    {
    326         // Is this available?
    327         if(s_sessions[slotIndex].occupied == FALSE)
    328         {
    329             session = &s_sessions[slotIndex].session;
    330             break;
    331         }
    332    }
    333    // if no spot found, then this is an internal error
    334    pAssert (slotIndex < MAX_LOADED_SESSIONS);
    335    // Call context ID function to get a handle. TPM_RC_SESSION_HANDLE may be
    336    // returned from ContextIdHandelAssign()
    337    result = ContextIdSessionCreate(sessionHandle, slotIndex);
    338    if(result != TPM_RC_SUCCESS)
    339        return result;
    340    //*** Only return from this point on is TPM_RC_SUCCESS
    341    // Can now indicate that the session array entry is occupied.
    342    s_freeSessionSlots--;
    343    s_sessions[slotIndex].occupied = TRUE;
    344    // Initialize the session data
    345    MemorySet(session, 0, sizeof(SESSION));
    346    // Initialize internal session data
    347    session->authHashAlg = authHash;
    348    // Initialize session type
    349    if(sessionType == TPM_SE_HMAC)
    350    {
    351        *sessionHandle += HMAC_SESSION_FIRST;
    352    }
    353    else
    354    {
    355        *sessionHandle += POLICY_SESSION_FIRST;
    356         // For TPM_SE_POLICY or TPM_SE_TRIAL
    357         session->attributes.isPolicy = SET;
    358         if(sessionType == TPM_SE_TRIAL)
    359             session->attributes.isTrialPolicy = SET;
    360         // Initialize policy session data
    361         SessionInitPolicyData(session);
    362    }
    363    // Create initial session nonce
    364    session->nonceTPM.t.size = nonceCaller->t.size;
    365    CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
    366    // Set up session parameter encryption algorithm
    367    session->symmetric = *symmetric;
    368    // If there is a bind object or a session secret, then need to compute
    369    // a sessionKey.
    370    if(bind != TPM_RH_NULL || seed->t.size != 0)
    371    {
    372        // sessionKey = KDFa(hash, (authValue || seed), "ATH", nonceTPM,
    373        //                      nonceCaller, bits)
    374        // The HMAC key for generating the sessionSecret can be the concatenation
    375        // of an authorization value and a seed value
    376        TPM2B_TYPE(KEY, (sizeof(TPMT_HA) + sizeof(seed->t.buffer)));
    377        TPM2B_KEY            key;
    378         UINT16                   hashSize;     // The size of the hash used by the
    379                                                // session crated by this command
    380         TPM2B_AUTH    entityAuth;              // The authValue of the entity
    381                                                      // associated with HMAC session
    382          // Get hash size, which is also the length of sessionKey
    383          hashSize = CryptGetHashDigestSize(session->authHashAlg);
    384          // Get authValue of associated entity
    385          entityAuth.t.size = EntityGetAuthValue(bind, &entityAuth.t.buffer);
    386          // Concatenate authValue and seed
    387          pAssert(entityAuth.t.size + seed->t.size <= sizeof(key.t.buffer));
    388          MemoryCopy2B(&key.b, &entityAuth.b, sizeof(key.t.buffer));
    389          MemoryConcat2B(&key.b, &seed->b, sizeof(key.t.buffer));
    390          session->sessionKey.t.size = hashSize;
    391          // Compute the session key
    392          KDFa(session->authHashAlg, &key.b, "ATH", &session->nonceTPM.b,
    393               &nonceCaller->b, hashSize * 8, session->sessionKey.t.buffer, NULL);
    394    }
    395    // Copy the name of the entity that the HMAC session is bound to
    396    // Policy session is not bound to an entity
    397    if(bind != TPM_RH_NULL && sessionType == TPM_SE_HMAC)
    398    {
    399        session->attributes.isBound = SET;
    400        SessionComputeBoundEntity(bind, &session->u1.boundEntity);
    401    }
    402    // If there is a bind object and it is subject to DA, then use of this session
    403    // is subject to DA regardless of how it is used.
    404    session->attributes.isDaBound =    (bind != TPM_RH_NULL)
    405                                    && (IsDAExempted(bind) == FALSE);
    406    // If the session is bound, then check to see if it is bound to lockoutAuth
    407    session->attributes.isLockoutBound =    (session->attributes.isDaBound == SET)
    408                                         && (bind == TPM_RH_LOCKOUT);
    409    return TPM_RC_SUCCESS;
    410 }
    411 //
    412 //
    413 //           SessionContextSave()
    414 //
    415 //      This function is called when a session context is to be saved. The contextID of the saved session is
    416 //      returned. If no contextID can be assigned, then the routine returns TPM_RC_CONTEXT_GAP. If the
    417 //      function completes normally, the session slot will be freed.
    418 //      This function requires that handle references a loaded session. Otherwise, it should not be called at the
    419 //      first place.
    420 //
    421 //      Error Returns                      Meaning
    422 //
    423 //      TPM_RC_CONTEXT_GAP                 a contextID could not be assigned.
    424 //      TPM_RC_TOO_MANY_CONTEXTS           the counter maxed out
    425 //
    426 TPM_RC
    427 SessionContextSave (
    428    TPM_HANDLE                 handle,           // IN: session handle
    429    CONTEXT_COUNTER           *contextID         // OUT: assigned contextID
    430    )
    431 {
    432    UINT32                            contextIndex;
    433    CONTEXT_SLOT                      slotIndex;
    434    pAssert(SessionIsLoaded(handle));
    435    // check to see if the gap is already maxed out
    436    // Need to have a saved session
    437    if(   s_oldestSavedSession < MAX_ACTIVE_SESSIONS
    438          // if the oldest saved session has the same value as the low bits
    439          // of the contextCounter, then the GAP is maxed out.
    440       && gr.contextArray[s_oldestSavedSession] == (CONTEXT_SLOT)gr.contextCounter)
    441        return TPM_RC_CONTEXT_GAP;
    442    // if the caller wants the context counter, set it
    443    if(contextID != NULL)
    444        *contextID = gr.contextCounter;
    445    pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS);
    446    contextIndex = handle & HR_HANDLE_MASK;
    447    // Extract the session slot number referenced by the contextArray
    448    // because we are going to overwrite this with the low order
    449    // contextID value.
    450    slotIndex = gr.contextArray[contextIndex] - 1;
    451    // Set the contextID for the contextArray
    452    gr.contextArray[contextIndex] = (CONTEXT_SLOT)gr.contextCounter;
    453    // Increment the counter
    454    gr.contextCounter++;
    455    // In the unlikely event that the 64-bit context counter rolls over...
    456    if(gr.contextCounter == 0)
    457    {
    458        // back it up
    459        gr.contextCounter--;
    460        // return an error
    461        return TPM_RC_TOO_MANY_CONTEXTS;
    462    }
    463    // if the low-order bits wrapped, need to advance the value to skip over
    464    // the values used to indicate that a session is loaded
    465    if(((CONTEXT_SLOT)gr.contextCounter) == 0)
    466        gr.contextCounter += MAX_LOADED_SESSIONS + 1;
    467    // If no other sessions are saved, this is now the oldest.
    468    if(s_oldestSavedSession >= MAX_ACTIVE_SESSIONS)
    469        s_oldestSavedSession = contextIndex;
    470    // Mark the session slot as unoccupied
    471    s_sessions[slotIndex].occupied = FALSE;
    472    // and indicate that there is an additional open slot
    473    s_freeSessionSlots++;
    474    return TPM_RC_SUCCESS;
    475 }
    476 //
    477 //
    478 //           SessionContextLoad()
    479 //
    480 //      This function is used to load a session from saved context. The session handle must be for a saved
    481 //      context.
    482 //      If the gap is at a maximum, then the only session that can be loaded is the oldest session, otherwise
    483 //      TPM_RC_CONTEXT_GAP is returned.
    484 //      This function requires that handle references a valid saved session.
    485 //
    486 //
    487 //
    488 //      Error Returns                   Meaning
    489 //
    490 //      TPM_RC_SESSION_MEMORY           no free session slots
    491 //      TPM_RC_CONTEXT_GAP              the gap count is maximum and this is not the oldest saved context
    492 //
    493 TPM_RC
    494 SessionContextLoad(
    495    SESSION            *session,            // IN: session structure from saved context
    496    TPM_HANDLE         *handle              // IN/OUT: session handle
    497    )
    498 {
    499    UINT32                    contextIndex;
    500    CONTEXT_SLOT              slotIndex;
    501    pAssert(   HandleGetType(*handle) == TPM_HT_POLICY_SESSION
    502            || HandleGetType(*handle) == TPM_HT_HMAC_SESSION);
    503    // Don't bother looking if no openings
    504    if(s_freeSessionSlots == 0)
    505        return TPM_RC_SESSION_MEMORY;
    506    // Find a free session slot to load the session
    507    for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
    508        if(s_sessions[slotIndex].occupied == FALSE) break;
    509    // if no spot found, then this is an internal error
    510    pAssert (slotIndex < MAX_LOADED_SESSIONS);
    511    contextIndex = *handle & HR_HANDLE_MASK;               // extract the index
    512    // If there is only one slot left, and the gap is at maximum, the only session
    513    // context that we can safely load is the oldest one.
    514    if(   s_oldestSavedSession < MAX_ACTIVE_SESSIONS
    515       && s_freeSessionSlots == 1
    516       && (CONTEXT_SLOT)gr.contextCounter == gr.contextArray[s_oldestSavedSession]
    517       && contextIndex != s_oldestSavedSession
    518      )
    519        return TPM_RC_CONTEXT_GAP;
    520    pAssert(contextIndex < MAX_ACTIVE_SESSIONS);
    521    // set the contextArray value to point to the session slot where
    522    // the context is loaded
    523    gr.contextArray[contextIndex] = slotIndex + 1;
    524    // if this was the oldest context, find the new oldest
    525    if(contextIndex == s_oldestSavedSession)
    526        ContextIdSetOldest();
    527    // Copy session data to session slot
    528    s_sessions[slotIndex].session = *session;
    529    // Set session slot as occupied
    530    s_sessions[slotIndex].occupied = TRUE;
    531    // Reduce the number of open spots
    532    s_freeSessionSlots--;
    533    return TPM_RC_SUCCESS;
    534 }
    535 //
    536 //
    537 //
    538 //           SessionFlush()
    539 //
    540 //      This function is used to flush a session referenced by its handle. If the session associated with handle is
    541 //      loaded, the session array entry is marked as available.
    542 //      This function requires that handle be a valid active session.
    543 //
    544 void
    545 SessionFlush(
    546     TPM_HANDLE           handle             // IN: loaded or saved session handle
    547     )
    548 {
    549     CONTEXT_SLOT              slotIndex;
    550     UINT32                    contextIndex;       // Index into contextArray
    551     pAssert(      (    HandleGetType(handle) == TPM_HT_POLICY_SESSION
    552                     || HandleGetType(handle) == TPM_HT_HMAC_SESSION
    553                   )
    554                && (SessionIsLoaded(handle) || SessionIsSaved(handle))
    555               );
    556     // Flush context ID of this session
    557     // Convert handle to an index into the contextArray
    558     contextIndex = handle & HR_HANDLE_MASK;
    559     pAssert(contextIndex < sizeof(gr.contextArray)/sizeof(gr.contextArray[0]));
    560     // Get the current contents of the array
    561     slotIndex = gr.contextArray[contextIndex];
    562     // Mark context array entry as available
    563     gr.contextArray[contextIndex] = 0;
    564     // Is this a saved session being flushed
    565     if(slotIndex > MAX_LOADED_SESSIONS)
    566     {
    567         // Flushing the oldest session?
    568         if(contextIndex == s_oldestSavedSession)
    569             // If so, find a new value for oldest.
    570             ContextIdSetOldest();
    571     }
    572     else
    573     {
    574         // Adjust slot index to point to session array index
    575         slotIndex -= 1;
    576          // Free session array index
    577          s_sessions[slotIndex].occupied = FALSE;
    578          s_freeSessionSlots++;
    579     }
    580     return;
    581 }
    582 //
    583 //
    584 //           SessionComputeBoundEntity()
    585 //
    586 //      This function computes the binding value for a session. The binding value for a reserved handle is the
    587 //      handle itself. For all the other entities, the authValue at the time of binding is included to prevent
    588 //      squatting. For those values, the Name and the authValue are concatenated into the bind buffer. If they
    589 //      will not both fit, the will be overlapped by XORing() bytes. If XOR is required, the bind value will be full.
    590 //
    591 void
    592 SessionComputeBoundEntity(
    593     TPMI_DH_ENTITY      entityHandle,     // IN: handle of entity
    594     TPM2B_NAME         *bind              // OUT: binding value
    595     )
    596 {
    597     TPM2B_AUTH               auth;
    598     INT16                    overlap;
    599     // Get name
    600     bind->t.size = EntityGetName(entityHandle, &bind->t.name);
    601 //     // The bound value of a reserved handle is the handle itself
    602 //     if(bind->t.size == sizeof(TPM_HANDLE)) return;
    603     // For all the other entities, concatenate the auth value to the name.
    604     // Get a local copy of the auth value because some overlapping
    605     // may be necessary.
    606     auth.t.size = EntityGetAuthValue(entityHandle, &auth.t.buffer);
    607     pAssert(auth.t.size <= sizeof(TPMU_HA));
    608     // Figure out if there will be any overlap
    609     overlap = bind->t.size + auth.t.size - sizeof(bind->t.name);
    610     // There is overlap if the combined sizes are greater than will fit
    611     if(overlap > 0)
    612     {
    613         // The overlap area is at the end of the Name
    614         BYTE    *result = &bind->t.name[bind->t.size - overlap];
    615         int     i;
    616          // XOR the auth value into the Name for the overlap area
    617          for(i = 0; i < overlap; i++)
    618              result[i] ^= auth.t.buffer[i];
    619     }
    620     else
    621     {
    622         // There is no overlap
    623         overlap = 0;
    624     }
    625     //copy the remainder of the authData to the end of the name
    626     MemoryCopy(&bind->t.name[bind->t.size], &auth.t.buffer[overlap],
    627                auth.t.size - overlap, sizeof(bind->t.name) - bind->t.size);
    628     // Increase the size of the bind data by the size of the auth - the overlap
    629     bind->t.size += auth.t.size-overlap;
    630     return;
    631 }
    632 //
    633 //
    634 //           SessionInitPolicyData()
    635 //
    636 //      This function initializes the portions of the session policy data that are not set by the allocation of a
    637 //      session.
    638 //
    639 void
    640 SessionInitPolicyData(
    641     SESSION            *session           // IN: session handle
    642     )
    643 {
    644     // Initialize start time
    645     session->startTime = go.clock;
    646     // Initialize policyDigest. policyDigest is initialized with a string of 0 of
    647     // session algorithm digest size. Since the policy already contains all zeros
    648     // it is only necessary to set the size
    649      session->u2.policyDigest.t.size = CryptGetHashDigestSize(session->authHashAlg);
    650      return;
    651 }
    652 //
    653 //
    654 //           SessionResetPolicyData()
    655 //
    656 //      This function is used to reset the policy data without changing the nonce or the start time of the session.
    657 //
    658 void
    659 SessionResetPolicyData(
    660      SESSION            *session             // IN: the session to reset
    661      )
    662 {
    663      session->commandCode = 0;              // No command
    664      // No locality selected
    665      MemorySet(&session->commandLocality, 0, sizeof(session->commandLocality));
    666      // The cpHash size to zero
    667      session->u1.cpHash.b.size = 0;
    668      // No timeout
    669      session->timeOut = 0;
    670      // Reset the pcrCounter
    671      session->pcrCounter = 0;
    672      // Reset the policy hash
    673      MemorySet(&session->u2.policyDigest.t.buffer, 0,
    674                session->u2.policyDigest.t.size);
    675      // Reset the session attributes
    676      MemorySet(&session->attributes, 0, sizeof(SESSION_ATTRIBUTES));
    677      // set the policy attribute
    678      session->attributes.isPolicy = SET;
    679 }
    680 //
    681 //
    682 //           SessionCapGetLoaded()
    683 //
    684 //      This function returns a list of handles of loaded session, started from input handle
    685 //      Handle must be in valid loaded session handle range, but does not have to point to a loaded session.
    686 //
    687 //      Return Value                      Meaning
    688 //
    689 //      YES                               if there are more handles available
    690 //      NO                                all the available handles has been returned
    691 //
    692 TPMI_YES_NO
    693 SessionCapGetLoaded(
    694      TPMI_SH_POLICY      handle,             // IN: start handle
    695      UINT32              count,              // IN: count of returned handle
    696      TPML_HANDLE        *handleList          // OUT: list of handle
    697      )
    698 {
    699      TPMI_YES_NO        more = NO;
    700      UINT32             i;
    701      pAssert(HandleGetType(handle) == TPM_HT_LOADED_SESSION);
    702      // Initialize output handle list
    703      handleList->count = 0;
    704      // The maximum count of handles we may return is MAX_CAP_HANDLES
    705      if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
    706      // Iterate session context ID slots to get loaded session handles
    707      for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++)
    708      {
    709          // If session is active
    710          if(gr.contextArray[i] != 0)
    711          {
    712              // If session is loaded
    713              if (gr.contextArray[i] <= MAX_LOADED_SESSIONS)
    714              {
    715                  if(handleList->count < count)
    716                  {
    717                      SESSION         *session;
    718                         // If we have not filled up the return list, add this
    719                         // session handle to it
    720                         // assume that this is going to be an HMAC session
    721                         handle = i + HMAC_SESSION_FIRST;
    722                         session = SessionGet(handle);
    723                         if(session->attributes.isPolicy)
    724                             handle = i + POLICY_SESSION_FIRST;
    725                         handleList->handle[handleList->count] = handle;
    726                         handleList->count++;
    727                    }
    728                    else
    729                    {
    730                        // If the return list is full but we still have loaded object
    731                        // available, report this and stop iterating
    732                        more = YES;
    733                        break;
    734                    }
    735                }
    736           }
    737      }
    738      return more;
    739 }
    740 //
    741 //
    742 //             SessionCapGetSaved()
    743 //
    744 //      This function returns a list of handles for saved session, starting at handle.
    745 //      Handle must be in a valid handle range, but does not have to point to a saved session
    746 //
    747 //      Return Value                      Meaning
    748 //
    749 //      YES                               if there are more handles available
    750 //      NO                                all the available handles has been returned
    751 //
    752 TPMI_YES_NO
    753 SessionCapGetSaved(
    754      TPMI_SH_HMAC        handle,             // IN: start handle
    755      UINT32              count,              // IN: count of returned handle
    756      TPML_HANDLE        *handleList          // OUT: list of handle
    757      )
    758 {
    759      TPMI_YES_NO        more = NO;
    760      UINT32             i;
    761    pAssert(HandleGetType(handle) == TPM_HT_ACTIVE_SESSION);
    762    // Initialize output handle list
    763    handleList->count = 0;
    764    // The maximum count of handles we may return is MAX_CAP_HANDLES
    765    if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
    766    // Iterate session context ID slots to get loaded session handles
    767    for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++)
    768    {
    769        // If session is active
    770        if(gr.contextArray[i] != 0)
    771        {
    772            // If session is saved
    773            if (gr.contextArray[i] > MAX_LOADED_SESSIONS)
    774            {
    775                if(handleList->count < count)
    776                {
    777                    // If we have not filled up the return list, add this
    778                    // session handle to it
    779                    handleList->handle[handleList->count] = i + HMAC_SESSION_FIRST;
    780                    handleList->count++;
    781                }
    782                else
    783                {
    784                    // If the return list is full but we still have loaded object
    785                    // available, report this and stop iterating
    786                    more = YES;
    787                    break;
    788                }
    789            }
    790        }
    791    }
    792    return more;
    793 }
    794 //
    795 //
    796 //          SessionCapGetLoadedNumber()
    797 //
    798 //      This function return the number of authorization sessions currently loaded into TPM RAM.
    799 //
    800 UINT32
    801 SessionCapGetLoadedNumber(
    802    void
    803    )
    804 {
    805    return MAX_LOADED_SESSIONS - s_freeSessionSlots;
    806 }
    807 //
    808 //
    809 //          SessionCapGetLoadedAvail()
    810 //
    811 //      This function returns the number of additional authorization sessions, of any type, that could be loaded
    812 //      into TPM RAM.
    813 //
    814 //      NOTE:           In other implementations, this number may just be an estimate. The only requirement for the estimate is, if it is
    815 //                      one or more, then at least one session must be loadable.
    816 //
    817 UINT32
    818 SessionCapGetLoadedAvail(
    819    void
    820    )
    821 {
    822      return s_freeSessionSlots;
    823 }
    824 //
    825 //
    826 //           SessionCapGetActiveNumber()
    827 //
    828 //      This function returns the number of active authorization sessions currently being tracked by the TPM.
    829 //
    830 UINT32
    831 SessionCapGetActiveNumber(
    832      void
    833      )
    834 {
    835      UINT32                  i;
    836      UINT32                  num = 0;
    837      // Iterate the context array to find the number of non-zero slots
    838      for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
    839      {
    840          if(gr.contextArray[i] != 0) num++;
    841      }
    842      return num;
    843 }
    844 //
    845 //
    846 //           SessionCapGetActiveAvail()
    847 //
    848 //      This function returns the number of additional authorization sessions, of any type, that could be created.
    849 //      This not the number of slots for sessions, but the number of additional sessions that the TPM is capable
    850 //      of tracking.
    851 //
    852 UINT32
    853 SessionCapGetActiveAvail(
    854      void
    855      )
    856 {
    857      UINT32                  i;
    858      UINT32                  num = 0;
    859      // Iterate the context array to find the number of zero slots
    860      for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
    861      {
    862          if(gr.contextArray[i] == 0) num++;
    863      }
    864      return num;
    865 }
    866