196 lines
7.3 KiB
C
196 lines
7.3 KiB
C
// 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 "ContextSave_fp.h"
|
|
#include "Context_spt_fp.h"
|
|
//
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_CONTEXT_GAP a contextID could not be assigned for a session context save
|
|
// TPM_RC_TOO_MANY_CONTEXTS no more contexts can be saved as the counter has maxed out
|
|
//
|
|
TPM_RC
|
|
TPM2_ContextSave(
|
|
ContextSave_In *in, // IN: input parameter list
|
|
ContextSave_Out *out // OUT: output parameter list
|
|
)
|
|
{
|
|
TPM_RC result;
|
|
UINT16 fingerprintSize; // The size of fingerprint in context
|
|
// blob.
|
|
UINT64 contextID = 0; // session context ID
|
|
TPM2B_SYM_KEY symKey;
|
|
TPM2B_IV iv;
|
|
|
|
TPM2B_DIGEST integrity;
|
|
UINT16 integritySize;
|
|
BYTE *buffer;
|
|
INT32 bufferSize;
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Internal Data Update
|
|
|
|
// Initialize output handle. At the end of command action, the output
|
|
// handle of an object will be replaced, while the output handle
|
|
// for a session will be the same as input
|
|
out->context.savedHandle = in->saveHandle;
|
|
|
|
// Get the size of fingerprint in context blob. The sequence value in
|
|
// TPMS_CONTEXT structure is used as the fingerprint
|
|
fingerprintSize = sizeof(out->context.sequence);
|
|
|
|
// Compute the integrity size at the beginning of context blob
|
|
integritySize = sizeof(integrity.t.size)
|
|
+ CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
|
|
|
|
// Perform object or session specific context save
|
|
switch(HandleGetType(in->saveHandle))
|
|
{
|
|
case TPM_HT_TRANSIENT:
|
|
{
|
|
OBJECT *object = ObjectGet(in->saveHandle);
|
|
OBJECT *outObject =
|
|
(OBJECT *)(out->context.contextBlob.t.buffer
|
|
+ integritySize + fingerprintSize);
|
|
|
|
// Set size of the context data. The contents of context blob is vendor
|
|
// defined. In this implementation, the size is size of integrity
|
|
// plus fingerprint plus the whole internal OBJECT structure
|
|
out->context.contextBlob.t.size = integritySize +
|
|
fingerprintSize + sizeof(OBJECT);
|
|
// Make sure things fit
|
|
pAssert(out->context.contextBlob.t.size
|
|
< sizeof(out->context.contextBlob.t.buffer));
|
|
|
|
// Copy the whole internal OBJECT structure to context blob, leave
|
|
// the size for fingerprint
|
|
*outObject = *object;
|
|
|
|
// Increment object context ID
|
|
gr.objectContextID++;
|
|
// If object context ID overflows, TPM should be put in failure mode
|
|
if(gr.objectContextID == 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
|
|
// Fill in other return values for an object.
|
|
out->context.sequence = gr.objectContextID;
|
|
// For regular object, savedHandle is 0x80000000. For sequence object,
|
|
// savedHandle is 0x80000001. For object with stClear, savedHandle
|
|
// is 0x80000002
|
|
if(ObjectIsSequence(object))
|
|
{
|
|
out->context.savedHandle = 0x80000001;
|
|
SequenceDataImportExport(object, outObject, EXPORT_STATE);
|
|
}
|
|
else if(object->attributes.stClear == SET)
|
|
{
|
|
out->context.savedHandle = 0x80000002;
|
|
}
|
|
else
|
|
{
|
|
out->context.savedHandle = 0x80000000;
|
|
}
|
|
|
|
// Get object hierarchy
|
|
out->context.hierarchy = ObjectDataGetHierarchy(object);
|
|
|
|
break;
|
|
}
|
|
case TPM_HT_HMAC_SESSION:
|
|
case TPM_HT_POLICY_SESSION:
|
|
{
|
|
SESSION *session = SessionGet(in->saveHandle);
|
|
|
|
// Set size of the context data. The contents of context blob is vendor
|
|
// defined. In this implementation, the size of context blob is the
|
|
// size of a internal session structure plus the size of
|
|
// fingerprint plus the size of integrity
|
|
out->context.contextBlob.t.size = integritySize +
|
|
fingerprintSize + sizeof(*session);
|
|
|
|
// Make sure things fit
|
|
pAssert(out->context.contextBlob.t.size
|
|
< sizeof(out->context.contextBlob.t.buffer));
|
|
|
|
// Copy the whole internal SESSION structure to context blob.
|
|
// Save space for fingerprint at the beginning of the buffer
|
|
// This is done before anything else so that the actual context
|
|
// can be reclaimed after this call
|
|
MemoryCopy(out->context.contextBlob.t.buffer
|
|
+ integritySize + fingerprintSize,
|
|
session, sizeof(*session),
|
|
sizeof(out->context.contextBlob.t.buffer)
|
|
- integritySize - fingerprintSize);
|
|
|
|
// Fill in the other return parameters for a session
|
|
// Get a context ID and set the session tracking values appropriately
|
|
// TPM_RC_CONTEXT_GAP is a possible error.
|
|
// SessionContextSave() will flush the in-memory context
|
|
// so no additional errors may occur after this call.
|
|
result = SessionContextSave(out->context.savedHandle, &contextID);
|
|
if(result != TPM_RC_SUCCESS) return result;
|
|
|
|
// sequence number is the current session contextID
|
|
out->context.sequence = contextID;
|
|
|
|
// use TPM_RH_NULL as hierarchy for session context
|
|
out->context.hierarchy = TPM_RH_NULL;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
// SaveContext may only take an object handle or a session handle.
|
|
// All the other handle type should be filtered out at unmarshal
|
|
pAssert(FALSE);
|
|
break;
|
|
}
|
|
|
|
// Save fingerprint at the beginning of encrypted area of context blob.
|
|
// Reserve the integrity space
|
|
MemoryCopy(out->context.contextBlob.t.buffer + integritySize,
|
|
&out->context.sequence, sizeof(out->context.sequence),
|
|
sizeof(out->context.contextBlob.t.buffer) - integritySize);
|
|
|
|
// Compute context encryption key
|
|
ComputeContextProtectionKey(&out->context, &symKey, &iv);
|
|
|
|
// Encrypt context blob
|
|
CryptSymmetricEncrypt(out->context.contextBlob.t.buffer + integritySize,
|
|
CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS,
|
|
TPM_ALG_CFB, symKey.t.buffer, &iv,
|
|
out->context.contextBlob.t.size - integritySize,
|
|
out->context.contextBlob.t.buffer + integritySize);
|
|
|
|
// Compute integrity hash for the object
|
|
// In this implementation, the same routine is used for both sessions
|
|
// and objects.
|
|
ComputeContextIntegrity(&out->context, &integrity);
|
|
|
|
// add integrity at the beginning of context blob
|
|
buffer = out->context.contextBlob.t.buffer;
|
|
bufferSize = sizeof(TPM2B_DIGEST);
|
|
TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize);
|
|
|
|
// orderly state should be cleared because of the update of state reset and
|
|
// state clear data
|
|
g_clearOrderly = TRUE;
|
|
|
|
return TPM_RC_SUCCESS;
|
|
}
|