// 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; }