diff options
Diffstat (limited to 'src/tpm2/Session.c')
-rw-r--r-- | src/tpm2/Session.c | 835 |
1 files changed, 835 insertions, 0 deletions
diff --git a/src/tpm2/Session.c b/src/tpm2/Session.c new file mode 100644 index 0000000..991a146 --- /dev/null +++ b/src/tpm2/Session.c @@ -0,0 +1,835 @@ +/********************************************************************************/ +/* */ +/* Manage the session context counter */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: Session.c 1594 2020-03-26 22:15:48Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + + +/* 8.9.2 Includes, Defines, and Local Variables */ +#define SESSION_C +#include "Tpm.h" + +/* 8.9.3 File Scope Function -- ContextIdSetOldest() */ + +static void +ContextIdSetOldest( + void + ) +{ + CONTEXT_SLOT lowBits; + CONTEXT_SLOT entry; + CONTEXT_SLOT smallest = CONTEXT_SLOT_MASKED(~0); // libtpms changed + UINT32 i; + pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added + // Set oldestSaveContext to a value indicating none assigned + s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1; + lowBits = CONTEXT_SLOT_MASKED(gr.contextCounter); // libtpms changed + 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_MASKED(entry - lowBits) <= smallest) // libtpms changed + { + smallest = CONTEXT_SLOT_MASKED(entry - lowBits); // libtpms changed + 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. +} +/* 8.9.4 Startup Function -- SessionStartup() */ +/* This function initializes the session subsystem on TPM2_Startup(). */ +BOOL +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; + + // Initialize the context slot mask for UINT16 + s_ContextSlotMask = 0xffff; // libtpms added + } + return TRUE; +} +/* 8.9.5 Access Functions */ +/* 8.9.5.1 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 Values 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; +} +/* 8.9.5.2 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: A password authorization does not have a session. */ +/* This function requires that the handle be a valid session handle. */ +/* Return Values 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; +} +/* 8.9.5.3 SequenceNumberForSavedContextIsValid() */ +BOOL +SequenceNumberForSavedContextIsValid( + TPMS_CONTEXT *context // IN: pointer to a context + // structure to be validated + ) +{ +#define MAX_CONTEXT_GAP ((UINT64)(CONTEXT_SLOT_MASKED(~0) + 1)) /* libtpms changed */ + pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added + + TPM_HANDLE handle = context->savedHandle & HR_HANDLE_MASK; + if(// Handle must be with the range of active sessions + handle >= MAX_ACTIVE_SESSIONS + // the array entry must be for a saved context + || gr.contextArray[handle] <= MAX_LOADED_SESSIONS + // the array entry must agree with the sequence number + || gr.contextArray[handle] != CONTEXT_SLOT_MASKED(context->sequence) // libtpms changed + // the provided sequence number has to be less than the current counter + || context->sequence > gr.contextCounter + // but not so much that it could not be a valid sequence number + || gr.contextCounter - context->sequence > MAX_CONTEXT_GAP) + return FALSE; + return TRUE; +} +/* 8.9.5.4 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 Values Meaning */ +/* TRUE if PCR value is current */ +/* FALSE if PCR value is not current */ +BOOL +SessionPCRValueIsCurrent( + SESSION *session // IN: session structure + ) +{ + if(session->pcrCounter != 0 + && session->pcrCounter != gr.pcrCounter + ) + return FALSE; + else + return TRUE; +} +/* 8.9.5.5 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 + ) +{ + size_t slotIndex; + CONTEXT_SLOT sessionIndex; + pAssert(HandleGetType(handle) == TPM_HT_POLICY_SESSION + || HandleGetType(handle) == TPM_HT_HMAC_SESSION + ); + slotIndex = handle & HR_HANDLE_MASK; + pAssert(slotIndex < MAX_ACTIVE_SESSIONS); + // get the contents of the session array. Because session is loaded, we + // should always get a valid sessionIndex + sessionIndex = gr.contextArray[slotIndex] - 1; + pAssert(sessionIndex < MAX_LOADED_SESSIONS); + return &s_sessions[sessionIndex].session; +} +/* 8.9.6 Utility Functions */ +/* 8.9.6.1 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. */ +/* 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 + // The current value of the contextCounter will be assigned to the next + // saved context. If the value to be assigned would make the same as an + // existing context, then we can't use it because of the ambiguity it would + // create. + if(CONTEXT_SLOT_MASKED(gr.contextCounter) // libtpms changed + == gr.contextArray[s_oldestSavedSession]) + 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_MASKED(sessionIndex + 1); // libtpms changed + return TPM_RC_SUCCESS; + } + } + return TPM_RC_SESSION_HANDLES; +} +/* 8.9.6.2 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 + TPM2B_NONCE *nonceTpm // OUT: the session nonce + ) +{ + 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 + if(slotIndex >= MAX_LOADED_SESSIONS) { // libtpms changed + FAIL(FATAL_ERROR_INTERNAL); + // should never get here due to longjmp in FAIL() libtpms added begin; cppcheck + return TPM_RC_FAILURE; + } // libtpms added end + // 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; + SessionSetStartTime(session); + // Initialize policyDigest. policyDigest is initialized with a string of 0 + // of session algorithm digest size. Since the session is already clear. + // Just need to set the size + session->u2.policyDigest.t.size = + CryptHashGetDigestSize(session->authHashAlg); + } + // Create initial session nonce + session->nonceTPM.t.size = nonceCaller->t.size; + CryptRandomGenerate(session->nonceTPM.t.size, session->nonceTPM.t.buffer); + MemoryCopy2B(&nonceTpm->b, &session->nonceTPM.b, + sizeof(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; + // Get hash size, which is also the length of sessionKey + session->sessionKey.t.size = CryptHashGetDigestSize(session->authHashAlg); + // Get authValue of associated entity + EntityGetAuthValue(bind, (TPM2B_AUTH *)&key); + pAssert(key.t.size + seed->t.size <= sizeof(key.t.buffer)); + // Concatenate authValue and seed + MemoryConcat2B(&key.b, &seed->b, sizeof(key.t.buffer)); + // Compute the session key + CryptKDFa(session->authHashAlg, &key.b, SESSION_KEY, &session->nonceTPM.b, + &nonceCaller->b, + session->sessionKey.t.size * 8, session->sessionKey.t.buffer, + NULL, FALSE); + } + // 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; +} +/* 8.9.6.3 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)); + pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added + // 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_MASKED(gr.contextCounter)) // libtpms changed + return TPM_RC_CONTEXT_GAP; + // if the caller wants the context counter, set it + if(contextID != NULL) + *contextID = gr.contextCounter; + contextIndex = handle & HR_HANDLE_MASK; + pAssert(contextIndex < MAX_ACTIVE_SESSIONS); + // 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_MASKED(gr.contextCounter); // libtpms changed + // 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_MASKED(gr.contextCounter) == 0) // libtpms changed + 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; +} +/* 8.9.6.4 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_BUF *session, // IN: session structure from saved context + TPM_HANDLE *handle // IN/OUT: session handle + ) +{ + UINT32 contextIndex; + CONTEXT_SLOT slotIndex; + pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added + 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); + // libtpms: besides the s_freeSessionSlots guard add another array index guard + if (slotIndex >= MAX_LOADED_SESSIONS) { // libtpms added begin; cppcheck + FAIL(FATAL_ERROR_INTERNAL); + // should never get here due to longjmp in FAIL() + return TPM_RC_FAILURE; + } // libtpms added end + 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_MASKED(gr.contextCounter) == gr.contextArray[s_oldestSavedSession] // libtpms changed + && 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 + MemoryCopy(&s_sessions[slotIndex].session, session, sizeof(SESSION)); + // Set session slot as occupied + s_sessions[slotIndex].occupied = TRUE; + // Reduce the number of open spots + s_freeSessionSlots--; + return TPM_RC_SUCCESS; +} +/* 8.9.6.5 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; +} +/* 8.9.6.6 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; + BYTE *pAuth = auth.t.buffer; + UINT16 i; + // Get name + EntityGetName(entityHandle, bind); + // // 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 authorization value to the name. + // Get a local copy of the authorization value because some overlapping + // may be necessary. + EntityGetAuthValue(entityHandle, &auth); + // Make sure that the extra space is zeroed + MemorySet(&bind->t.name[bind->t.size], 0, sizeof(bind->t.name) - bind->t.size); + // XOR the authValue at the end of the name + for(i = sizeof(bind->t.name) - auth.t.size; i < sizeof(bind->t.name); i++) + bind->t.name[i] ^= *pAuth++; + // Set the bind value to the maximum size + bind->t.size = sizeof(bind->t.name); + return; +} +/* 8.9.6.7 SessionSetStartTime() */ +/* This function is used to initialize the session timing */ +void +SessionSetStartTime( + SESSION *session // IN: the session to update + ) +{ + session->startTime = g_time; + session->epoch = g_timeEpoch; + session->timeout = 0; +} +/* 8.9.6.8 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_ATTRIBUTES oldAttributes; + pAssert(session != NULL); + // Will need later + oldAttributes = session->attributes; + // No command + session->commandCode = 0; + // 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)); + // Restore the policy attributes + session->attributes.isPolicy = SET; + session->attributes.isTrialPolicy = oldAttributes.isTrialPolicy; + // Restore the bind attributes + session->attributes.isDaBound = oldAttributes.isDaBound; + session->attributes.isLockoutBound = oldAttributes.isLockoutBound; +} +/* 8.9.6.9 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 Values 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 handles + 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; +} +/* 8.9.6.10 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 Values 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 handles + TPML_HANDLE *handleList // OUT: list of handle + ) +{ + TPMI_YES_NO more = NO; + UINT32 i; +#ifdef TPM_HT_SAVED_SESSION + pAssert(HandleGetType(handle) == TPM_HT_SAVED_SESSION); +#else + pAssert(HandleGetType(handle) == TPM_HT_ACTIVE_SESSION); +#endif + // 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; +} +/* 8.9.6.11 SessionCapGetLoadedNumber() */ +/* This function return the number of authorization sessions currently loaded into TPM RAM. */ +UINT32 +SessionCapGetLoadedNumber( + void + ) +{ + return MAX_LOADED_SESSIONS - s_freeSessionSlots; +} +/* 8.9.6.12 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; +} +/* 8.9.6.13 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; +} +/* 8.9.6.14 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; +} |