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