diff options
Diffstat (limited to 'src/tpm2/ContextCommands.c')
-rw-r--r-- | src/tpm2/ContextCommands.c | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/src/tpm2/ContextCommands.c b/src/tpm2/ContextCommands.c new file mode 100644 index 0000000..c557c88 --- /dev/null +++ b/src/tpm2/ContextCommands.c @@ -0,0 +1,458 @@ +/********************************************************************************/ +/* */ +/* Context Management */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: ContextCommands.c 1658 2021-01-22 23:14:01Z 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 - 2021 */ +/* */ +/********************************************************************************/ + +#include "Tpm.h" +#include "ContextSave_fp.h" +#include "NVMarshal.h" // libtpms added +#if CC_ContextSave // Conditional expansion of this file +#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 = TPM_RC_SUCCESS; + 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 the state is orderly and + // cannot be changed, exit early. + RETURN_IF_ORDERLY; + + // Internal Data Update + + // This implementation does not do things in quite the same way as described in + // Part 2 of the specification. In Part 2, it indicates that the + // TPMS_CONTEXT_DATA contains two TPM2B values. That is not how this is + // implemented. Rather, the size field of the TPM2B_CONTEXT_DATA is used to + // determine the amount of data in the encrypted data. That part is not + // independently sized. This makes the actual size 2 bytes smaller than + // calculated using Part 2. Since this is opaque to the caller, it is not + // necessary to fix. The actual size is returned by TPM2_GetCapabilties(). + + // 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) + + CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG); + // Perform object or session specific context save + switch(HandleGetType(in->saveHandle)) + { + case TPM_HT_TRANSIENT: + { + OBJECT *object = HandleToObject(in->saveHandle); + ANY_OBJECT_BUFFER *outObject; + unsigned char buffer[sizeof(OBJECT) * 2]; // libtpms changed begin + BYTE *bufptr = &buffer[0]; + INT32 size = sizeof(buffer); + UINT16 written = ANY_OBJECT_Marshal(object, &bufptr, &size); + UINT16 objectSize = written; // libtpms changed end + outObject = (ANY_OBJECT_BUFFER *)(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 + objectSize; + // 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 + MemoryCopy(outObject, buffer, written); // libtpms changed + // 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; + /* ANY_OBJECT_Marshal already wrote it // libtpms changed begin + SequenceDataExport((HASH_OBJECT *)object, + (HASH_OBJECT_BUFFER *)outObject); + */ // libtpms changed end + } + else + out->context.savedHandle = (object->attributes.stClear == SET) + ? 0x80000002 : 0x80000000; + // Get object hierarchy + out->context.hierarchy = ObjectGetHierarchy(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 + pAssert(sizeof(*session) <= sizeof(out->context.contextBlob.t.buffer) + - integritySize - fingerprintSize); + MemoryCopy(out->context.contextBlob.t.buffer + integritySize + + fingerprintSize, session, sizeof(*session)); + // 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 + FAIL(FATAL_ERROR_INTERNAL); + break; + } + // Save fingerprint at the beginning of encrypted area of context blob. + // Reserve the integrity space + pAssert(sizeof(out->context.sequence) <= + sizeof(out->context.contextBlob.t.buffer) - integritySize); + MemoryCopy(out->context.contextBlob.t.buffer + integritySize, + &out->context.sequence, sizeof(out->context.sequence)); + // 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, + symKey.t.buffer, &iv, TPM_ALG_CFB, + 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 result; +} +#endif // CC_ContextSave +#include "Tpm.h" +#include "ContextLoad_fp.h" +#if CC_ContextLoad // Conditional expansion of this file +#include "Context_spt_fp.h" +TPM_RC +TPM2_ContextLoad( + ContextLoad_In *in, // IN: input parameter list + ContextLoad_Out *out // OUT: output parameter list + ) +{ + TPM_RC result; + TPM2B_DIGEST integrityToCompare; + TPM2B_DIGEST integrity; + BYTE *buffer; // defined to save some typing + INT32 size; // defined to save some typing + TPM_HT handleType; + TPM2B_SYM_KEY symKey; + TPM2B_IV iv; + // Input Validation + + // See discussion about the context format in TPM2_ContextSave Detailed Actions + + // IF this is a session context, make sure that the sequence number is + // consistent with the version in the slot + // Check context blob size + handleType = HandleGetType(in->context.savedHandle); + // 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; + // the size of the integrity value has to match the size of digest produced + // by the integrity hash + if(integrity.t.size != CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG)) + return TPM_RCS_SIZE + RC_ContextLoad_context; + // Make sure that the context blob has enough space for the fingerprint. This + // is elastic pants to go with the belt and suspenders we already have to make + // sure that the context is complete and untampered. + if((unsigned)size < sizeof(in->context.sequence)) + return TPM_RCS_SIZE + RC_ContextLoad_context; + // After unmarshaling the integrity value, 'buffer' is pointing at the first + // byte of the integrity protected and encrypted buffer and 'size' is the number + // of integrity protected and encrypted bytes. + // Compute context integrity + ComputeContextIntegrity(&in->context, &integrityToCompare); + // Compare integrity + if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b)) + return TPM_RCS_INTEGRITY + RC_ContextLoad_context; + // Compute context encryption key + ComputeContextProtectionKey(&in->context, &symKey, &iv); + // Decrypt context data in place + CryptSymmetricDecrypt(buffer, CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS, + symKey.t.buffer, &iv, TPM_ALG_CFB, size, buffer); + // See if the fingerprint value matches. If not, it is symptomatic of either + // a broken TPM or that the TPM is under attack so go into failure mode. + if(!MemoryEqual(buffer, &in->context.sequence, sizeof(in->context.sequence))) + FAIL(FATAL_ERROR_INTERNAL); + // step over fingerprint + buffer += sizeof(in->context.sequence); + // set the remaining size of the context + size -= sizeof(in->context.sequence); + // Perform object or session specific input check + switch(handleType) + { + case TPM_HT_TRANSIENT: + { + OBJECT *outObject; + if(size > (INT32)sizeof(OBJECT)) + FAIL(FATAL_ERROR_INTERNAL); + // 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_RCS_HIERARCHY + RC_ContextLoad_context; + // Restore object. If there is no empty space, indicate as much + outObject = ObjectContextLoadLibtpms(buffer, size, // libtpms changed + &out->loadedHandle); + if(outObject == NULL) + return TPM_RC_OBJECT_MEMORY; + break; + } + case TPM_HT_POLICY_SESSION: + case TPM_HT_HMAC_SESSION: + { + if(size != sizeof(SESSION)) + FAIL(FATAL_ERROR_INTERNAL); + // 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 + RETURN_IF_ORDERLY; + // Check if input handle points to a valid saved session and that the + // sequence number makes sense + if(!SequenceNumberForSavedContextIsValid(&in->context)) + return TPM_RCS_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_BUF *)buffer, + &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 + FAIL(FATAL_ERROR_INTERNAL); + break; + } + return TPM_RC_SUCCESS; +} +#endif // CC_ContextLoad +#include "Tpm.h" +#include "FlushContext_fp.h" +#if CC_FlushContext // Conditional expansion of this file +TPM_RC +TPM2_FlushContext( + FlushContext_In *in // IN: input parameter list + ) +{ + // Internal Data Update + // Call object or session specific routine to flush + switch(HandleGetType(in->flushHandle)) + { + case TPM_HT_TRANSIENT: + if(!IsObjectPresent(in->flushHandle)) + return TPM_RCS_HANDLE + RC_FlushContext_flushHandle; + // Flush object + FlushObject(in->flushHandle); + break; + case TPM_HT_HMAC_SESSION: + case TPM_HT_POLICY_SESSION: + if(!SessionIsLoaded(in->flushHandle) + && !SessionIsSaved(in->flushHandle) + ) + return TPM_RCS_HANDLE + RC_FlushContext_flushHandle; + // If the session to be flushed is the exclusive audit session, then + // indicate that there is no exclusive audit session any longer. + if(in->flushHandle == g_exclusiveAuditSession) + g_exclusiveAuditSession = TPM_RH_UNASSIGNED; + // Flush session + SessionFlush(in->flushHandle); + break; + default: + // This command only takes object or session handle. Other handles + // should be filtered out at handle unmarshal + FAIL(FATAL_ERROR_INTERNAL); + break; + } + return TPM_RC_SUCCESS; +} +#endif // CC_FlushContext +#include "Tpm.h" +#include "EvictControl_fp.h" +#if CC_EvictControl // Conditional expansion of this file +TPM_RC +TPM2_EvictControl( + EvictControl_In *in // IN: input parameter list + ) +{ + TPM_RC result; + OBJECT *evictObject; + // Input Validation + // Get internal object pointer + evictObject = HandleToObject(in->objectHandle); + // Temporary, stClear or public only objects can not be made persistent + if(evictObject->attributes.temporary == SET + || evictObject->attributes.stClear == SET + || evictObject->attributes.publicOnly == SET) + return TPM_RCS_ATTRIBUTES + RC_EvictControl_objectHandle; + // If objectHandle refers to a persistent object, it should be the same as + // input persistentHandle + if(evictObject->attributes.evict == SET + && evictObject->evictHandle != in->persistentHandle) + return TPM_RCS_HANDLE + RC_EvictControl_objectHandle; + // Additional authorization validation + if(in->auth == TPM_RH_PLATFORM) + { + // To make persistent + if(evictObject->attributes.evict == CLEAR) + { + // PlatformAuth can not set evict object in storage or endorsement + // hierarchy + if(evictObject->attributes.ppsHierarchy == CLEAR) + return TPM_RCS_HIERARCHY + RC_EvictControl_objectHandle; + // Platform cannot use a handle outside of platform persistent range. + if(!NvIsPlatformPersistentHandle(in->persistentHandle)) + return TPM_RCS_RANGE + RC_EvictControl_persistentHandle; + } + // PlatformAuth can delete any persistent object + } + else if(in->auth == TPM_RH_OWNER) + { + // OwnerAuth can not set or clear evict object in platform hierarchy + if(evictObject->attributes.ppsHierarchy == SET) + return TPM_RCS_HIERARCHY + RC_EvictControl_objectHandle; + // Owner cannot use a handle outside of owner persistent range. + if(evictObject->attributes.evict == CLEAR + && !NvIsOwnerPersistentHandle(in->persistentHandle)) + return TPM_RCS_RANGE + RC_EvictControl_persistentHandle; + } + else + { + // Other authorization is not allowed in this command and should have been + // filtered out in unmarshal process + FAIL(FATAL_ERROR_INTERNAL); + } + // Internal Data Update + // Change evict state + if(evictObject->attributes.evict == CLEAR) + { + // Make object persistent + if(NvFindHandle(in->persistentHandle) != 0) + return TPM_RC_NV_DEFINED; + // A TPM_RC_NV_HANDLE or TPM_RC_NV_SPACE error may be returned at this + // point + result = NvAddEvictObject(in->persistentHandle, evictObject); + } + else + { + // Delete the persistent object in NV + result = NvDeleteEvict(evictObject->evictHandle); + } + return result; +} +#endif // CC_EvictControl |