865 lines
32 KiB
C
865 lines
32 KiB
C
// 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;
|
|
}
|