| // 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; |
| |
| // 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; |
| TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL); |
| |
| // orderly state should be cleared because of the update of state reset and |
| // state clear data |
| g_clearOrderly = TRUE; |
| |
| return TPM_RC_SUCCESS; |
| } |