/* Microsoft Reference Implementation for TPM 2.0 * * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and * contributor rights, including patent rights, and no such rights are granted * under this license. * * Copyright (c) Microsoft Corporation * * All rights reserved. * * BSD License * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //** Description // The functions in this file are used for accessing properties for handles of // various types. Functions in other files require handles of a specific // type but the functions in this file allow use of any handle type. //** Includes #include "Tpm.h" //** Functions //*** EntityGetLoadStatus() // This function will check that all the handles access loaded entities. // Return Type: TPM_RC // TPM_RC_HANDLE handle type does not match // TPM_RC_REFERENCE_Hx entity is not present // TPM_RC_HIERARCHY entity belongs to a disabled hierarchy // TPM_RC_OBJECT_MEMORY handle is an evict object but there is no // space to load it to RAM TPM_RC EntityGetLoadStatus( COMMAND *command // IN/OUT: command parsing structure ) { UINT32 i; TPM_RC result = TPM_RC_SUCCESS; // for(i = 0; i < command->handleNum; i++) { TPM_HANDLE handle = command->handles[i]; switch(HandleGetType(handle)) { // For handles associated with hierarchies, the entity is present // only if the associated enable is SET. case TPM_HT_PERMANENT: switch(handle) { case TPM_RH_OWNER: if(!gc.shEnable) result = TPM_RC_HIERARCHY; break; #ifdef VENDOR_PERMANENT case VENDOR_PERMANENT: #endif case TPM_RH_ENDORSEMENT: if(!gc.ehEnable) result = TPM_RC_HIERARCHY; break; case TPM_RH_PLATFORM: if(!g_phEnable) result = TPM_RC_HIERARCHY; break; // null handle, PW session handle and lockout // handle are always available case TPM_RH_NULL: case TPM_RS_PW: // Need to be careful for lockout. Lockout is always available // for policy checks but not always available when authValue // is being checked. case TPM_RH_LOCKOUT: // Rather than have #ifdefs all over the code, // CASE_ACT_HANDLE is defined in ACT.h. It is 'case TPM_RH_ACT_x:' // FOR_EACH_ACT(CASE_ACT_HANDLE) creates a simple // case TPM_RH_ACT_x: // for each of the implemented ACT. FOR_EACH_ACT(CASE_ACT_HANDLE) break; default: // If the implementation has a manufacturer-specific value // then test for it here. Since this implementation does // not have any, this implementation returns the same failure // that unmarshaling of a bad handle would produce. if(((TPM_RH)handle >= TPM_RH_AUTH_00) && ((TPM_RH)handle <= TPM_RH_AUTH_FF)) // if the implementation has a manufacturer-specific value result = TPM_RC_VALUE; else // The handle is in the range of reserved handles but is // not implemented in this TPM. result = TPM_RC_VALUE; break; } break; case TPM_HT_TRANSIENT: // For a transient object, check if the handle is associated // with a loaded object. if(!IsObjectPresent(handle)) result = TPM_RC_REFERENCE_H0; break; case TPM_HT_PERSISTENT: // Persistent object // Copy the persistent object to RAM and replace the handle with the // handle of the assigned slot. A TPM_RC_OBJECT_MEMORY, // TPM_RC_HIERARCHY or TPM_RC_REFERENCE_H0 error may be returned by // ObjectLoadEvict() result = ObjectLoadEvict(&command->handles[i], command->index); break; case TPM_HT_HMAC_SESSION: // For an HMAC session, see if the session is loaded // and if the session in the session slot is actually // an HMAC session. if(SessionIsLoaded(handle)) { SESSION *session; session = SessionGet(handle); // Check if the session is a HMAC session if(session->attributes.isPolicy == SET) result = TPM_RC_HANDLE; } else result = TPM_RC_REFERENCE_H0; break; case TPM_HT_POLICY_SESSION: // For a policy session, see if the session is loaded // and if the session in the session slot is actually // a policy session. if(SessionIsLoaded(handle)) { SESSION *session; session = SessionGet(handle); // Check if the session is a policy session if(session->attributes.isPolicy == CLEAR) result = TPM_RC_HANDLE; } else result = TPM_RC_REFERENCE_H0; break; case TPM_HT_NV_INDEX: // For an NV Index, use the TPM-specific routine // to search the IN Index space. result = NvIndexIsAccessible(handle); break; case TPM_HT_PCR: // Any PCR handle that is unmarshaled successfully referenced // a PCR that is defined. break; #if CC_AC_Send case TPM_HT_AC: // Use the TPM-specific routine to search for the AC result = AcIsAccessible(handle); break; #endif default: // Any other handle type is a defect in the unmarshaling code. FAIL(FATAL_ERROR_INTERNAL); break; } if(result != TPM_RC_SUCCESS) { if(result == TPM_RC_REFERENCE_H0) result = result + i; else result = RcSafeAddToResult(result, TPM_RC_H + g_rcIndex[i]); break; } } return result; } //*** EntityGetAuthValue() // This function is used to access the 'authValue' associated with a handle. // This function assumes that the handle references an entity that is accessible // and the handle is not for a persistent objects. That is EntityGetLoadStatus() // should have been called. Also, the accessibility of the authValue should have // been verified by IsAuthValueAvailable(). // // This function copies the authorization value of the entity to 'auth'. // Return Type: UINT16 // count number of bytes in the authValue with 0's stripped UINT16 EntityGetAuthValue( TPMI_DH_ENTITY handle, // IN: handle of entity TPM2B_AUTH *auth // OUT: authValue of the entity ) { TPM2B_AUTH *pAuth = NULL; auth->t.size = 0; switch(HandleGetType(handle)) { case TPM_HT_PERMANENT: { switch(handle) { case TPM_RH_OWNER: // ownerAuth for TPM_RH_OWNER pAuth = &gp.ownerAuth; break; case TPM_RH_ENDORSEMENT: // endorsementAuth for TPM_RH_ENDORSEMENT pAuth = &gp.endorsementAuth; break; // The ACT use platformAuth for auth FOR_EACH_ACT(CASE_ACT_HANDLE) case TPM_RH_PLATFORM: // platformAuth for TPM_RH_PLATFORM pAuth = &gc.platformAuth; break; case TPM_RH_LOCKOUT: // lockoutAuth for TPM_RH_LOCKOUT pAuth = &gp.lockoutAuth; break; case TPM_RH_NULL: // nullAuth for TPM_RH_NULL. Return 0 directly here return 0; break; #ifdef VENDOR_PERMANENT case VENDOR_PERMANENT: // vendor authorization value pAuth = &g_platformUniqueDetails; #endif default: // If any other permanent handle is present it is // a code defect. FAIL(FATAL_ERROR_INTERNAL); break; } break; } case TPM_HT_TRANSIENT: // authValue for an object // A persistent object would have been copied into RAM // and would have an transient object handle here. { OBJECT *object; object = HandleToObject(handle); // special handling if this is a sequence object if(ObjectIsSequence(object)) { pAuth = &((HASH_OBJECT *)object)->auth; } else { // Authorization is available only when the private portion of // the object is loaded. The check should be made before // this function is called pAssert(object->attributes.publicOnly == CLEAR); pAuth = &object->sensitive.authValue; } } break; case TPM_HT_NV_INDEX: // authValue for an NV index { NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL); pAssert(nvIndex != NULL); pAuth = &nvIndex->authValue; } break; case TPM_HT_PCR: // authValue for PCR pAuth = PCRGetAuthValue(handle); break; default: // If any other handle type is present here, then there is a defect // in the unmarshaling code. FAIL(FATAL_ERROR_INTERNAL); break; } // Copy the authValue MemoryCopy2B((TPM2B *)auth, (TPM2B *)pAuth, sizeof(auth->t.buffer)); MemoryRemoveTrailingZeros(auth); return auth->t.size; } //*** EntityGetAuthPolicy() // This function is used to access the 'authPolicy' associated with a handle. // This function assumes that the handle references an entity that is accessible // and the handle is not for a persistent objects. That is EntityGetLoadStatus() // should have been called. Also, the accessibility of the authPolicy should have // been verified by IsAuthPolicyAvailable(). // // This function copies the authorization policy of the entity to 'authPolicy'. // // The return value is the hash algorithm for the policy. TPMI_ALG_HASH EntityGetAuthPolicy( TPMI_DH_ENTITY handle, // IN: handle of entity TPM2B_DIGEST *authPolicy // OUT: authPolicy of the entity ) { TPMI_ALG_HASH hashAlg = TPM_ALG_NULL; authPolicy->t.size = 0; switch(HandleGetType(handle)) { case TPM_HT_PERMANENT: switch(handle) { case TPM_RH_OWNER: // ownerPolicy for TPM_RH_OWNER *authPolicy = gp.ownerPolicy; hashAlg = gp.ownerAlg; break; case TPM_RH_ENDORSEMENT: // endorsementPolicy for TPM_RH_ENDORSEMENT *authPolicy = gp.endorsementPolicy; hashAlg = gp.endorsementAlg; break; case TPM_RH_PLATFORM: // platformPolicy for TPM_RH_PLATFORM *authPolicy = gc.platformPolicy; hashAlg = gc.platformAlg; break; case TPM_RH_LOCKOUT: // lockoutPolicy for TPM_RH_LOCKOUT *authPolicy = gp.lockoutPolicy; hashAlg = gp.lockoutAlg; break; #define ACT_GET_POLICY(N) \ case TPM_RH_ACT_##N: \ *authPolicy = go.ACT_##N.authPolicy; \ hashAlg = go.ACT_##N.hashAlg; \ break; // Get the policy for each implemented ACT FOR_EACH_ACT(ACT_GET_POLICY) default: hashAlg = TPM_ALG_ERROR; break; } break; case TPM_HT_TRANSIENT: // authPolicy for an object { OBJECT *object = HandleToObject(handle); *authPolicy = object->publicArea.authPolicy; hashAlg = object->publicArea.nameAlg; } break; case TPM_HT_NV_INDEX: // authPolicy for a NV index { NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL); pAssert(nvIndex != 0); *authPolicy = nvIndex->publicArea.authPolicy; hashAlg = nvIndex->publicArea.nameAlg; } break; case TPM_HT_PCR: // authPolicy for a PCR hashAlg = PCRGetAuthPolicy(handle, authPolicy); break; default: // If any other handle type is present it is a code defect. FAIL(FATAL_ERROR_INTERNAL); break; } return hashAlg; } //*** EntityGetName() // This function returns the Name associated with a handle. TPM2B_NAME * EntityGetName( TPMI_DH_ENTITY handle, // IN: handle of entity TPM2B_NAME *name // OUT: name of entity ) { switch(HandleGetType(handle)) { case TPM_HT_TRANSIENT: { // Name for an object OBJECT *object = HandleToObject(handle); // an object with no nameAlg has no name if(object->publicArea.nameAlg == TPM_ALG_NULL) name->b.size = 0; else *name = object->name; break; } case TPM_HT_NV_INDEX: // Name for a NV index NvGetNameByIndexHandle(handle, name); break; default: // For all other types, the handle is the Name name->t.size = sizeof(TPM_HANDLE); UINT32_TO_BYTE_ARRAY(handle, name->t.name); break; } return name; } //*** EntityGetHierarchy() // This function returns the hierarchy handle associated with an entity. // a) A handle that is a hierarchy handle is associated with itself. // b) An NV index belongs to TPM_RH_PLATFORM if TPMA_NV_PLATFORMCREATE, // is SET, otherwise it belongs to TPM_RH_OWNER // c) An object handle belongs to its hierarchy. TPMI_RH_HIERARCHY EntityGetHierarchy( TPMI_DH_ENTITY handle // IN :handle of entity ) { TPMI_RH_HIERARCHY hierarchy = TPM_RH_NULL; switch(HandleGetType(handle)) { case TPM_HT_PERMANENT: // hierarchy for a permanent handle switch(handle) { case TPM_RH_PLATFORM: case TPM_RH_ENDORSEMENT: case TPM_RH_NULL: hierarchy = handle; break; // all other permanent handles are associated with the owner // hierarchy. (should only be TPM_RH_OWNER and TPM_RH_LOCKOUT) default: hierarchy = TPM_RH_OWNER; break; } break; case TPM_HT_NV_INDEX: // hierarchy for NV index { NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL); pAssert(nvIndex != NULL); // If only the platform can delete the index, then it is // considered to be in the platform hierarchy, otherwise it // is in the owner hierarchy. if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, PLATFORMCREATE)) hierarchy = TPM_RH_PLATFORM; else hierarchy = TPM_RH_OWNER; } break; case TPM_HT_TRANSIENT: // hierarchy for an object { OBJECT *object; object = HandleToObject(handle); if(object->attributes.ppsHierarchy) { hierarchy = TPM_RH_PLATFORM; } else if(object->attributes.epsHierarchy) { hierarchy = TPM_RH_ENDORSEMENT; } else if(object->attributes.spsHierarchy) { hierarchy = TPM_RH_OWNER; } } break; case TPM_HT_PCR: hierarchy = TPM_RH_OWNER; break; default: FAIL(FATAL_ERROR_INTERNAL); break; } // this is unreachable but it provides a return value for the default // case which makes the complier happy return hierarchy; }