diff options
Diffstat (limited to 'src/tpm2/HierarchyCommands.c')
-rw-r--r-- | src/tpm2/HierarchyCommands.c | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/src/tpm2/HierarchyCommands.c b/src/tpm2/HierarchyCommands.c new file mode 100644 index 0000000..cbf777d --- /dev/null +++ b/src/tpm2/HierarchyCommands.c @@ -0,0 +1,514 @@ +/********************************************************************************/ +/* */ +/* Hierarchy Commands */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: HierarchyCommands.c 1519 2019-11-15 20:43:51Z 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 - 2019 */ +/* */ +/********************************************************************************/ + +#include "Tpm.h" +#include "CreatePrimary_fp.h" +#if CC_CreatePrimary // Conditional expansion of this file +TPM_RC +TPM2_CreatePrimary( + CreatePrimary_In *in, // IN: input parameter list + CreatePrimary_Out *out // OUT: output parameter list + ) +{ + TPM_RC result = TPM_RC_SUCCESS; + TPMT_PUBLIC *publicArea; + DRBG_STATE rand; + OBJECT *newObject; + TPM2B_NAME name; + // Input Validation + // Will need a place to put the result + newObject = FindEmptyObjectSlot(&out->objectHandle); + if(newObject == NULL) + return TPM_RC_OBJECT_MEMORY; + // Get the address of the public area in the new object + // (this is just to save typing) + publicArea = &newObject->publicArea; + *publicArea = in->inPublic.publicArea; + // Check attributes in input public area. CreateChecks() checks the things that + // are unique to creation and then validates the attributes and values that are + // common to create and load. + result = CreateChecks(NULL, publicArea, + in->inSensitive.sensitive.data.t.size); + if(result != TPM_RC_SUCCESS) + return RcSafeAddToResult(result, RC_CreatePrimary_inPublic); + // Validate the sensitive area values + if(!AdjustAuthSize(&in->inSensitive.sensitive.userAuth, + publicArea->nameAlg)) + return TPM_RCS_SIZE + RC_CreatePrimary_inSensitive; + // Command output + // Compute the name using out->name as a scratch area (this is not the value + // that ultimately will be returned, then instantiate the state that will be + // used as a random number generator during the object creation. + // The caller does not know the seed values so the actual name does not have + // to be over the input, it can be over the unmarshaled structure. + result = DRBG_InstantiateSeeded(&rand, + &HierarchyGetPrimarySeed(in->primaryHandle)->b, + PRIMARY_OBJECT_CREATION, + (TPM2B *)PublicMarshalAndComputeName(publicArea, &name), + &in->inSensitive.sensitive.data.b, + HierarchyGetPrimarySeedCompatLevel(in->primaryHandle)); // libtpms added + if (result == TPM_RC_SUCCESS) + { + newObject->attributes.primary = SET; + if(in->primaryHandle == TPM_RH_ENDORSEMENT) + newObject->attributes.epsHierarchy = SET; + // Create the primary object. + result = CryptCreateObject(newObject, &in->inSensitive.sensitive, + (RAND_STATE *)&rand); + } + if(result != TPM_RC_SUCCESS) + return result; + // Set the publicArea and name from the computed values + out->outPublic.publicArea = newObject->publicArea; + out->name = newObject->name; + // Fill in creation data + FillInCreationData(in->primaryHandle, publicArea->nameAlg, + &in->creationPCR, &in->outsideInfo, &out->creationData, + &out->creationHash); + // Compute creation ticket + TicketComputeCreation(EntityGetHierarchy(in->primaryHandle), &out->name, + &out->creationHash, &out->creationTicket); + // Set the remaining attributes for a loaded object + ObjectSetLoadedAttributes(newObject, in->primaryHandle, + HierarchyGetPrimarySeedCompatLevel(in->primaryHandle)); // libtpms added + return result; +} +#endif // CC_CreatePrimary +#include "Tpm.h" +#include "HierarchyControl_fp.h" +#if CC_HierarchyControl // Conditional expansion of this file +TPM_RC +TPM2_HierarchyControl( + HierarchyControl_In *in // IN: input parameter list + ) +{ + BOOL select = (in->state == YES); + BOOL *selected = NULL; + // Input Validation + switch(in->enable) + { + // Platform hierarchy has to be disabled by PlatformAuth + // If the platform hierarchy has already been disabled, only a reboot + // can enable it again + case TPM_RH_PLATFORM: + case TPM_RH_PLATFORM_NV: + if(in->authHandle != TPM_RH_PLATFORM) + return TPM_RC_AUTH_TYPE; + break; + // ShEnable may be disabled if PlatformAuth/PlatformPolicy or + // OwnerAuth/OwnerPolicy is provided. If ShEnable is disabled, then it + // may only be enabled if PlatformAuth/PlatformPolicy is provided. + case TPM_RH_OWNER: + if(in->authHandle != TPM_RH_PLATFORM + && in->authHandle != TPM_RH_OWNER) + return TPM_RC_AUTH_TYPE; + if(gc.shEnable == FALSE && in->state == YES + && in->authHandle != TPM_RH_PLATFORM) + return TPM_RC_AUTH_TYPE; + break; + // EhEnable may be disabled if either PlatformAuth/PlatformPolicy or + // EndosementAuth/EndorsementPolicy is provided. If EhEnable is disabled, + // then it may only be enabled if PlatformAuth/PlatformPolicy is + // provided. + case TPM_RH_ENDORSEMENT: + if(in->authHandle != TPM_RH_PLATFORM + && in->authHandle != TPM_RH_ENDORSEMENT) + return TPM_RC_AUTH_TYPE; + if(gc.ehEnable == FALSE && in->state == YES + && in->authHandle != TPM_RH_PLATFORM) + return TPM_RC_AUTH_TYPE; + break; + default: + FAIL(FATAL_ERROR_INTERNAL); + break; + } + // Internal Data Update + // Enable or disable the selected hierarchy + // Note: the authorization processing for this command may keep these + // command actions from being executed. For example, if phEnable is + // CLEAR, then platformAuth cannot be used for authorization. This + // means that would not be possible to use platformAuth to change the + // state of phEnable from CLEAR to SET. + // If it is decided that platformPolicy can still be used when phEnable + // is CLEAR, then this code could SET phEnable when proper platform + // policy is provided. + switch(in->enable) + { + case TPM_RH_OWNER: + selected = &gc.shEnable; + break; + case TPM_RH_ENDORSEMENT: + selected = &gc.ehEnable; + break; + case TPM_RH_PLATFORM: + selected = &g_phEnable; + break; + case TPM_RH_PLATFORM_NV: + selected = &gc.phEnableNV; + break; + default: + FAIL(FATAL_ERROR_INTERNAL); + break; + } + if(selected != NULL && *selected != select) + { + // Before changing the internal state, make sure that NV is available. + // Only need to update NV if changing the orderly state + RETURN_IF_ORDERLY; + // state is changing and NV is available so modify + *selected = select; + // If a hierarchy was just disabled, flush it + if(select == CLEAR && in->enable != TPM_RH_PLATFORM_NV) + // Flush hierarchy + ObjectFlushHierarchy(in->enable); + // orderly state should be cleared because of the update to state clear data + // This gets processed in ExecuteCommand() on the way out. + g_clearOrderly = TRUE; + } + return TPM_RC_SUCCESS; +} +#endif // CC_HierarchyControl +#include "Tpm.h" +#include "SetPrimaryPolicy_fp.h" +#if CC_SetPrimaryPolicy // Conditional expansion of this file +TPM_RC +TPM2_SetPrimaryPolicy( + SetPrimaryPolicy_In *in // IN: input parameter list + ) +{ + // Input Validation + // Check the authPolicy consistent with hash algorithm. If the policy size is + // zero, then the algorithm is required to be TPM_ALG_NULL + if(in->authPolicy.t.size != CryptHashGetDigestSize(in->hashAlg)) + return TPM_RCS_SIZE + RC_SetPrimaryPolicy_authPolicy; + // The command need NV update for OWNER and ENDORSEMENT hierarchy, and + // might need orderlyState update for PLATFORM hierarchy. + // Check if NV is available. A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE + // error may be returned at this point + RETURN_IF_NV_IS_NOT_AVAILABLE; + // Internal Data Update + // Set hierarchy policy + switch(in->authHandle) + { + case TPM_RH_OWNER: + gp.ownerAlg = in->hashAlg; + gp.ownerPolicy = in->authPolicy; + NV_SYNC_PERSISTENT(ownerAlg); + NV_SYNC_PERSISTENT(ownerPolicy); + break; + case TPM_RH_ENDORSEMENT: + gp.endorsementAlg = in->hashAlg; + gp.endorsementPolicy = in->authPolicy; + NV_SYNC_PERSISTENT(endorsementAlg); + NV_SYNC_PERSISTENT(endorsementPolicy); + break; + case TPM_RH_PLATFORM: + gc.platformAlg = in->hashAlg; + gc.platformPolicy = in->authPolicy; + // need to update orderly state + g_clearOrderly = TRUE; + break; + case TPM_RH_LOCKOUT: + gp.lockoutAlg = in->hashAlg; + gp.lockoutPolicy = in->authPolicy; + NV_SYNC_PERSISTENT(lockoutAlg); + NV_SYNC_PERSISTENT(lockoutPolicy); + break; + +#define SET_ACT_POLICY(N) \ + case TPM_RH_ACT_##N: \ + go.ACT_##N.hashAlg = in->hashAlg; \ + go.ACT_##N.authPolicy = in->authPolicy; \ + g_clearOrderly = TRUE; \ + break; + + FOR_EACH_ACT(SET_ACT_POLICY) + + default: + FAIL(FATAL_ERROR_INTERNAL); + break; + } + return TPM_RC_SUCCESS; +} +#endif // CC_SetPrimaryPolicy +#include "Tpm.h" +#include "ChangePPS_fp.h" +#if CC_ChangePPS // Conditional expansion of this file +TPM_RC +TPM2_ChangePPS( + ChangePPS_In *in // IN: input parameter list + ) +{ + UINT32 i; + // Check if NV is available. A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE + // error may be returned at this point + RETURN_IF_NV_IS_NOT_AVAILABLE; + // Input parameter is not reference in command action + NOT_REFERENCED(in); + // Internal Data Update + // Reset platform hierarchy seed from RNG + CryptRandomGenerate(sizeof(gp.PPSeed.t.buffer), gp.PPSeed.t.buffer); + gp.PPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added + // Create a new phProof value from RNG to prevent the saved platform + // hierarchy contexts being loaded + CryptRandomGenerate(sizeof(gp.phProof.t.buffer), gp.phProof.t.buffer); + // Set platform authPolicy to null + gc.platformAlg = TPM_ALG_NULL; + gc.platformPolicy.t.size = 0; + // Flush loaded object in platform hierarchy + ObjectFlushHierarchy(TPM_RH_PLATFORM); + // Flush platform evict object and index in NV + NvFlushHierarchy(TPM_RH_PLATFORM); + // Save hierarchy changes to NV + NV_SYNC_PERSISTENT(PPSeed); + NV_SYNC_PERSISTENT(PPSeedCompatLevel); // libtpms added + NV_SYNC_PERSISTENT(phProof); + // Re-initialize PCR policies +#if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0 + for(i = 0; i < NUM_POLICY_PCR_GROUP; i++) + { + gp.pcrPolicies.hashAlg[i] = TPM_ALG_NULL; + gp.pcrPolicies.policy[i].t.size = 0; + } + NV_SYNC_PERSISTENT(pcrPolicies); +#endif + // orderly state should be cleared because of the update to state clear data + g_clearOrderly = TRUE; + return TPM_RC_SUCCESS; +} +#endif // CC_ChangePPS +#include "Tpm.h" +#include "ChangeEPS_fp.h" +#if CC_ChangeEPS // Conditional expansion of this file +TPM_RC +TPM2_ChangeEPS( + ChangeEPS_In *in // IN: input parameter list + ) +{ + // 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 + RETURN_IF_NV_IS_NOT_AVAILABLE; + // Input parameter is not reference in command action + NOT_REFERENCED(in); + // Internal Data Update + // Reset endorsement hierarchy seed from RNG + CryptRandomGenerate(sizeof(gp.EPSeed.t.buffer), gp.EPSeed.t.buffer); + gp.EPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added + // Create new ehProof value from RNG + CryptRandomGenerate(sizeof(gp.ehProof.t.buffer), gp.ehProof.t.buffer); + // Enable endorsement hierarchy + gc.ehEnable = TRUE; + // set authValue buffer to zeros + MemorySet(gp.endorsementAuth.t.buffer, 0, gp.endorsementAuth.t.size); + // Set endorsement authValue to null + gp.endorsementAuth.t.size = 0; + // Set endorsement authPolicy to null + gp.endorsementAlg = TPM_ALG_NULL; + gp.endorsementPolicy.t.size = 0; + // Flush loaded object in endorsement hierarchy + ObjectFlushHierarchy(TPM_RH_ENDORSEMENT); + // Flush evict object of endorsement hierarchy stored in NV + NvFlushHierarchy(TPM_RH_ENDORSEMENT); + // Save hierarchy changes to NV + NV_SYNC_PERSISTENT(EPSeed); + NV_SYNC_PERSISTENT(EPSeedCompatLevel); // libtpms added + NV_SYNC_PERSISTENT(ehProof); + NV_SYNC_PERSISTENT(endorsementAuth); + NV_SYNC_PERSISTENT(endorsementAlg); + NV_SYNC_PERSISTENT(endorsementPolicy); + // orderly state should be cleared because of the update to state clear data + g_clearOrderly = TRUE; + return TPM_RC_SUCCESS; +} +#endif // CC_ChangeEPS +#include "Tpm.h" +#include "Clear_fp.h" +#if CC_Clear // Conditional expansion of this file +TPM_RC +TPM2_Clear( + Clear_In *in // IN: input parameter list + ) +{ + // Input parameter is not reference in command action + NOT_REFERENCED(in); + // 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 + RETURN_IF_NV_IS_NOT_AVAILABLE; + // Input Validation + // If Clear command is disabled, return an error + if(gp.disableClear) + return TPM_RC_DISABLED; + // Internal Data Update + // Reset storage hierarchy seed from RNG + CryptRandomGenerate(sizeof(gp.SPSeed.t.buffer), gp.SPSeed.t.buffer); + gp.SPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added + // Create new shProof and ehProof value from RNG + CryptRandomGenerate(sizeof(gp.shProof.t.buffer), gp.shProof.t.buffer); + CryptRandomGenerate(sizeof(gp.ehProof.t.buffer), gp.ehProof.t.buffer); + // Enable storage and endorsement hierarchy + gc.shEnable = gc.ehEnable = TRUE; + // set the authValue buffers to zero + MemorySet(&gp.ownerAuth, 0, sizeof(gp.ownerAuth)); + MemorySet(&gp.endorsementAuth, 0, sizeof(gp.endorsementAuth)); + MemorySet(&gp.lockoutAuth, 0, sizeof(gp.lockoutAuth)); + // Set storage, endorsement, and lockout authPolicy to null + gp.ownerAlg = gp.endorsementAlg = gp.lockoutAlg = TPM_ALG_NULL; + MemorySet(&gp.ownerPolicy, 0, sizeof(gp.ownerPolicy)); + MemorySet(&gp.endorsementPolicy, 0, sizeof(gp.endorsementPolicy)); + MemorySet(&gp.lockoutPolicy, 0, sizeof(gp.lockoutPolicy)); + // Flush loaded object in storage and endorsement hierarchy + ObjectFlushHierarchy(TPM_RH_OWNER); + ObjectFlushHierarchy(TPM_RH_ENDORSEMENT); + // Flush owner and endorsement object and owner index in NV + NvFlushHierarchy(TPM_RH_OWNER); + NvFlushHierarchy(TPM_RH_ENDORSEMENT); + // Initialize dictionary attack parameters + DAPreInstall_Init(); + // Reset clock + go.clock = 0; + go.clockSafe = YES; + NvWrite(NV_ORDERLY_DATA, sizeof(ORDERLY_DATA), &go); + // Reset counters + gp.resetCount = gr.restartCount = gr.clearCount = 0; + gp.auditCounter = 0; + // Save persistent data changes to NV + // Note: since there are so many changes to the persistent data structure, the + // entire PERSISTENT_DATA structure is written as a unit + NvWrite(NV_PERSISTENT_DATA, sizeof(PERSISTENT_DATA), &gp); + // Reset the PCR authValues (this does not change the PCRs) + PCR_ClearAuth(); + // Bump the PCR counter + PCRChanged(0); + // orderly state should be cleared because of the update to state clear data + g_clearOrderly = TRUE; + return TPM_RC_SUCCESS; +} +#endif // CC_Clear +#include "Tpm.h" +#include "ClearControl_fp.h" +#if CC_ClearControl // Conditional expansion of this file +TPM_RC +TPM2_ClearControl( + ClearControl_In *in // IN: input parameter list + ) +{ + // The command needs NV update. + RETURN_IF_NV_IS_NOT_AVAILABLE; + // Input Validation + // LockoutAuth may be used to set disableLockoutClear to TRUE but not to FALSE + if(in->auth == TPM_RH_LOCKOUT && in->disable == NO) + return TPM_RC_AUTH_FAIL; + // Internal Data Update + if(in->disable == YES) + gp.disableClear = TRUE; + else + gp.disableClear = FALSE; + // Record the change to NV + NV_SYNC_PERSISTENT(disableClear); + return TPM_RC_SUCCESS; +} +#endif // CC_ClearControl +#include "Tpm.h" +#include "HierarchyChangeAuth_fp.h" +#if CC_HierarchyChangeAuth // Conditional expansion of this file +#include "Object_spt_fp.h" +TPM_RC +TPM2_HierarchyChangeAuth( + HierarchyChangeAuth_In *in // IN: input parameter list + ) +{ + // The command needs NV update. + RETURN_IF_NV_IS_NOT_AVAILABLE; + // Make sure that the authorization value is a reasonable size (not larger than + // the size of the digest produced by the integrity hash. The integrity + // hash is assumed to produce the longest digest of any hash implemented + // on the TPM. This will also remove trailing zeros from the authValue. + if(MemoryRemoveTrailingZeros(&in->newAuth) > CONTEXT_INTEGRITY_HASH_SIZE) + return TPM_RCS_SIZE + RC_HierarchyChangeAuth_newAuth; + // Set hierarchy authValue + switch(in->authHandle) + { + case TPM_RH_OWNER: + gp.ownerAuth = in->newAuth; + NV_SYNC_PERSISTENT(ownerAuth); + break; + case TPM_RH_ENDORSEMENT: + gp.endorsementAuth = in->newAuth; + NV_SYNC_PERSISTENT(endorsementAuth); + break; + case TPM_RH_PLATFORM: + gc.platformAuth = in->newAuth; + // orderly state should be cleared + g_clearOrderly = TRUE; + break; + case TPM_RH_LOCKOUT: + gp.lockoutAuth = in->newAuth; + NV_SYNC_PERSISTENT(lockoutAuth); + break; + default: + FAIL(FATAL_ERROR_INTERNAL); + break; + } + return TPM_RC_SUCCESS; +} +#endif // CC_HierarchyChangeAuth |