summaryrefslogtreecommitdiffstats
path: root/src/tpm2/ContextCommands.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm2/ContextCommands.c')
-rw-r--r--src/tpm2/ContextCommands.c458
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