// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 3: Commands
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014
#include "InternalRoutines.h"
#include "ContextLoad_fp.h"
#include "Context_spt_fp.h"
//
//
// Error Returns Meaning
//
// TPM_RC_CONTEXT_GAP there is only one available slot and this is not the oldest saved
// session context
// TPM_RC_HANDLE 'context. savedHandle' does not reference a saved session
// TPM_RC_HIERARCHY 'context.hierarchy' is disabled
// TPM_RC_INTEGRITY context integrity check fail
// TPM_RC_OBJECT_MEMORY no free slot for an object
// TPM_RC_SESSION_MEMORY no free session slots
// TPM_RC_SIZE incorrect context blob size
//
TPM_RC
TPM2_ContextLoad(
ContextLoad_In *in, // IN: input parameter list
ContextLoad_Out *out // OUT: output parameter list
)
{
// Local Variables
TPM_RC result = TPM_RC_SUCCESS;
TPM2B_DIGEST integrityToCompare;
TPM2B_DIGEST integrity;
UINT16 integritySize;
UINT64 fingerprint;
BYTE *buffer;
INT32 size;
TPM_HT handleType;
TPM2B_SYM_KEY symKey;
TPM2B_IV iv;
// Input Validation
// Check context blob size
handleType = HandleGetType(in->context.savedHandle);
// Check integrity
// In this implementation, the same routine is used for both sessions
// and objects.
integritySize = CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
// Get integrity from context blob
buffer = in->context.contextBlob.t.buffer;
size = (INT32) in->context.contextBlob.t.size;
result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
if(result != TPM_RC_SUCCESS)
return result;
if(integrity.t.size != integritySize)
return TPM_RC_SIZE;
integritySize += sizeof(integrity.t.size);
//
// Compute context integrity
ComputeContextIntegrity(&in->context, &integrityToCompare);
// Compare integrity
if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
return TPM_RC_INTEGRITY + RC_ContextLoad_context;
// Compute context encryption key
ComputeContextProtectionKey(&in->context, &symKey, &iv);
// Decrypt context data in place
CryptSymmetricDecrypt(in->context.contextBlob.t.buffer + integritySize,
CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS,
TPM_ALG_CFB, symKey.t.buffer, &iv,
in->context.contextBlob.t.size - integritySize,
in->context.contextBlob.t.buffer + integritySize);
// Read the fingerprint value, skip the leading integrity size
MemoryCopy(&fingerprint, in->context.contextBlob.t.buffer + integritySize,
sizeof(fingerprint), sizeof(fingerprint));
// Check fingerprint. If the check fails, TPM should be put to failure mode
if(fingerprint != in->context.sequence)
FAIL(FATAL_ERROR_INTERNAL);
// Perform object or session specific input check
switch(handleType)
{
case TPM_HT_TRANSIENT:
{
// Get a pointer to the object in the context blob
OBJECT *outObject = (OBJECT *)(in->context.contextBlob.t.buffer
+ integritySize + sizeof(fingerprint));
// Discard any changes to the handle that the TRM might have made
in->context.savedHandle = TRANSIENT_FIRST;
// If hierarchy is disabled, no object context can be loaded in this
// hierarchy
if(!HierarchyIsEnabled(in->context.hierarchy))
return TPM_RC_HIERARCHY + RC_ContextLoad_context;
// Restore object. A TPM_RC_OBJECT_MEMORY error may be returned at
// this point
result = ObjectContextLoad(outObject, &out->loadedHandle);
if(result != TPM_RC_SUCCESS)
return result;
// If this is a sequence object, the crypto library may need to
// reformat the data into an internal format
if(ObjectIsSequence(outObject))
SequenceDataImportExport(ObjectGet(out->loadedHandle),
outObject, IMPORT_STATE);
break;
}
case TPM_HT_POLICY_SESSION:
case TPM_HT_HMAC_SESSION:
{
SESSION *session = (SESSION *)(in->context.contextBlob.t.buffer
+ integritySize + sizeof(fingerprint));
// This command may cause the orderlyState to be cleared due to
// the update of state reset data. If this is the case, check if NV is
// available first
if(gp.orderlyState != SHUTDOWN_NONE)
{
// The command needs NV update. Check if NV is available.
// A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned
// at this point
result = NvIsAvailable();
if(result != TPM_RC_SUCCESS)
return result;
}
// Check if input handle points to a valid saved session
if(!SessionIsSaved(in->context.savedHandle))
return TPM_RC_HANDLE + RC_ContextLoad_context;
// Restore session. A TPM_RC_SESSION_MEMORY, TPM_RC_CONTEXT_GAP error
// may be returned at this point
result = SessionContextLoad(session, &in->context.savedHandle);
if(result != TPM_RC_SUCCESS)
return result;
out->loadedHandle = in->context.savedHandle;
// orderly state should be cleared because of the update of state
// reset and state clear data
g_clearOrderly = TRUE;
break;
}
default:
// Context blob may only have an object handle or a session handle.
// All the other handle type should be filtered out at unmarshal
pAssert(FALSE);
break;
}
return TPM_RC_SUCCESS;
}