/* 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 // This file contains the functions that are used for accessing the // TPM_CAP_TPM_PROPERTY values. //** Includes #include "Tpm.h" //** Functions //*** TPMPropertyIsDefined() // This function accepts a property selection and, if so, sets 'value' // to the value of the property. // // All the fixed values are vendor dependent or determined by a // platform-specific specification. The values in the table below // are examples and should be changed by the vendor. // Return Type: BOOL // TRUE(1) referenced property exists and 'value' set // FALSE(0) referenced property does not exist static BOOL TPMPropertyIsDefined( TPM_PT property, // IN: property UINT32 *value // OUT: property value ) { switch(property) { case TPM_PT_FAMILY_INDICATOR: // from the title page of the specification // For this specification, the value is "2.0". *value = TPM_SPEC_FAMILY; break; case TPM_PT_LEVEL: // from the title page of the specification *value = TPM_SPEC_LEVEL; break; case TPM_PT_REVISION: // from the title page of the specification *value = TPM_SPEC_VERSION; break; case TPM_PT_DAY_OF_YEAR: // computed from the date value on the title page of the specification *value = TPM_SPEC_DAY_OF_YEAR; break; case TPM_PT_YEAR: // from the title page of the specification *value = TPM_SPEC_YEAR; break; case TPM_PT_MANUFACTURER: // vendor ID unique to each TPM manufacturer *value = BYTE_ARRAY_TO_UINT32(MANUFACTURER); break; case TPM_PT_VENDOR_STRING_1: // first four characters of the vendor ID string *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_1); break; case TPM_PT_VENDOR_STRING_2: // second four characters of the vendor ID string #ifdef VENDOR_STRING_2 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_2); #else *value = 0; #endif break; case TPM_PT_VENDOR_STRING_3: // third four characters of the vendor ID string #ifdef VENDOR_STRING_3 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_3); #else *value = 0; #endif break; case TPM_PT_VENDOR_STRING_4: // fourth four characters of the vendor ID string #ifdef VENDOR_STRING_4 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_4); #else *value = 0; #endif break; case TPM_PT_VENDOR_TPM_TYPE: // vendor-defined value indicating the TPM model *value = 1; break; case TPM_PT_FIRMWARE_VERSION_1: // more significant 32-bits of a vendor-specific value *value = gp.firmwareV1; break; case TPM_PT_FIRMWARE_VERSION_2: // less significant 32-bits of a vendor-specific value *value = gp.firmwareV2; break; case TPM_PT_INPUT_BUFFER: // maximum size of TPM2B_MAX_BUFFER *value = MAX_DIGEST_BUFFER; break; case TPM_PT_HR_TRANSIENT_MIN: // minimum number of transient objects that can be held in TPM // RAM *value = MAX_LOADED_OBJECTS; break; case TPM_PT_HR_PERSISTENT_MIN: // minimum number of persistent objects that can be held in // TPM NV memory // In this implementation, there is no minimum number of // persistent objects. *value = MIN_EVICT_OBJECTS; break; case TPM_PT_HR_LOADED_MIN: // minimum number of authorization sessions that can be held in // TPM RAM *value = MAX_LOADED_SESSIONS; break; case TPM_PT_ACTIVE_SESSIONS_MAX: // number of authorization sessions that may be active at a time *value = MAX_ACTIVE_SESSIONS; break; case TPM_PT_PCR_COUNT: // number of PCR implemented *value = IMPLEMENTATION_PCR; break; case TPM_PT_PCR_SELECT_MIN: // minimum number of bytes in a TPMS_PCR_SELECT.sizeOfSelect *value = PCR_SELECT_MIN; break; case TPM_PT_CONTEXT_GAP_MAX: // maximum allowed difference (unsigned) between the contextID // values of two saved session contexts *value = ((UINT32)1 << (sizeof(CONTEXT_SLOT) * 8)) - 1; break; case TPM_PT_NV_COUNTERS_MAX: // maximum number of NV indexes that are allowed to have the // TPMA_NV_COUNTER attribute SET // In this implementation, there is no limitation on the number // of counters, except for the size of the NV Index memory. *value = 0; break; case TPM_PT_NV_INDEX_MAX: // maximum size of an NV index data area *value = MAX_NV_INDEX_SIZE; break; case TPM_PT_MEMORY: // a TPMA_MEMORY indicating the memory management method for the TPM { union { TPMA_MEMORY att; UINT32 u32; } attributes = { TPMA_ZERO_INITIALIZER() }; SET_ATTRIBUTE(attributes.att, TPMA_MEMORY, sharedNV); SET_ATTRIBUTE(attributes.att, TPMA_MEMORY, objectCopiedToRam); // Note: For a LSb0 machine, the bits in a bit field are in the correct // order even if the machine is MSB0. For a MSb0 machine, a TPMA will // be an integer manipulated by masking (USE_BIT_FIELD_STRUCTURES will // be NO) so the bits are manipulate correctly. *value = attributes.u32; break; } case TPM_PT_CLOCK_UPDATE: // interval, in seconds, between updates to the copy of // TPMS_TIME_INFO .clock in NV *value = (1 << NV_CLOCK_UPDATE_INTERVAL); break; case TPM_PT_CONTEXT_HASH: // algorithm used for the integrity hash on saved contexts and // for digesting the fuData of TPM2_FirmwareRead() *value = CONTEXT_INTEGRITY_HASH_ALG; break; case TPM_PT_CONTEXT_SYM: // algorithm used for encryption of saved contexts *value = CONTEXT_ENCRYPT_ALG; break; case TPM_PT_CONTEXT_SYM_SIZE: // size of the key used for encryption of saved contexts *value = CONTEXT_ENCRYPT_KEY_BITS; break; case TPM_PT_ORDERLY_COUNT: // maximum difference between the volatile and non-volatile // versions of TPMA_NV_COUNTER that have TPMA_NV_ORDERLY SET *value = MAX_ORDERLY_COUNT; break; case TPM_PT_MAX_COMMAND_SIZE: // maximum value for 'commandSize' *value = MAX_COMMAND_SIZE; break; case TPM_PT_MAX_RESPONSE_SIZE: // maximum value for 'responseSize' *value = MAX_RESPONSE_SIZE; break; case TPM_PT_MAX_DIGEST: // maximum size of a digest that can be produced by the TPM *value = sizeof(TPMU_HA); break; case TPM_PT_MAX_OBJECT_CONTEXT: // Header has 'sequence', 'handle' and 'hierarchy' #define SIZE_OF_CONTEXT_HEADER \ sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) + sizeof(TPMI_RH_HIERARCHY) #define SIZE_OF_CONTEXT_INTEGRITY (sizeof(UINT16) + CONTEXT_INTEGRITY_HASH_SIZE) #define SIZE_OF_FINGERPRINT sizeof(UINT64) #define SIZE_OF_CONTEXT_BLOB_OVERHEAD \ (sizeof(UINT16) + SIZE_OF_CONTEXT_INTEGRITY + SIZE_OF_FINGERPRINT) #define SIZE_OF_CONTEXT_OVERHEAD \ (SIZE_OF_CONTEXT_HEADER + SIZE_OF_CONTEXT_BLOB_OVERHEAD) #if 0 // maximum size of a TPMS_CONTEXT that will be returned by // TPM2_ContextSave for object context *value = 0; // adding sequence, saved handle and hierarchy *value += sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) + sizeof(TPMI_RH_HIERARCHY); // add size field in TPM2B_CONTEXT *value += sizeof(UINT16); // add integrity hash size *value += sizeof(UINT16) + CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG); // Add fingerprint size, which is the same as sequence size *value += sizeof(UINT64); // Add OBJECT structure size *value += sizeof(OBJECT); #else // the maximum size of a TPMS_CONTEXT that will be returned by // TPM2_ContextSave for object context *value = SIZE_OF_CONTEXT_OVERHEAD + sizeof(OBJECT); #endif break; case TPM_PT_MAX_SESSION_CONTEXT: #if 0 // the maximum size of a TPMS_CONTEXT that will be returned by // TPM2_ContextSave for object context *value = 0; // adding sequence, saved handle and hierarchy *value += sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) + sizeof(TPMI_RH_HIERARCHY); // Add size field in TPM2B_CONTEXT *value += sizeof(UINT16); // Add integrity hash size *value += sizeof(UINT16) + CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG); // Add fingerprint size, which is the same as sequence size *value += sizeof(UINT64); // Add SESSION structure size *value += sizeof(SESSION); #else // the maximum size of a TPMS_CONTEXT that will be returned by // TPM2_ContextSave for object context *value = SIZE_OF_CONTEXT_OVERHEAD + sizeof(SESSION); #endif break; case TPM_PT_PS_FAMILY_INDICATOR: // platform specific values for the TPM_PT_PS parameters from // the relevant platform-specific specification // In this reference implementation, all of these values are 0. *value = PLATFORM_FAMILY; break; case TPM_PT_PS_LEVEL: // level of the platform-specific specification *value = PLATFORM_LEVEL; break; case TPM_PT_PS_REVISION: // specification Revision times 100 for the platform-specific // specification *value = PLATFORM_VERSION; break; case TPM_PT_PS_DAY_OF_YEAR: // platform-specific specification day of year using TCG calendar *value = PLATFORM_DAY_OF_YEAR; break; case TPM_PT_PS_YEAR: // platform-specific specification year using the CE *value = PLATFORM_YEAR; break; case TPM_PT_SPLIT_MAX: // number of split signing operations supported by the TPM *value = 0; #if ALG_ECC *value = sizeof(gr.commitArray) * 8; #endif break; case TPM_PT_TOTAL_COMMANDS: // total number of commands implemented in the TPM // Since the reference implementation does not have any // vendor-defined commands, this will be the same as the // number of library commands. { #if COMPRESSED_LISTS (*value) = COMMAND_COUNT; #else COMMAND_INDEX commandIndex; *value = 0; // scan all implemented commands for(commandIndex = GetClosestCommandIndex(0); commandIndex != UNIMPLEMENTED_COMMAND_INDEX; commandIndex = GetNextCommandIndex(commandIndex)) { (*value)++; // count of all implemented } #endif break; } case TPM_PT_LIBRARY_COMMANDS: // number of commands from the TPM library that are implemented { #if COMPRESSED_LISTS *value = LIBRARY_COMMAND_ARRAY_SIZE; #else COMMAND_INDEX commandIndex; *value = 0; // scan all implemented commands for(commandIndex = GetClosestCommandIndex(0); commandIndex < LIBRARY_COMMAND_ARRAY_SIZE; commandIndex = GetNextCommandIndex(commandIndex)) { (*value)++; } #endif break; } case TPM_PT_VENDOR_COMMANDS: // number of vendor commands that are implemented *value = VENDOR_COMMAND_ARRAY_SIZE; break; case TPM_PT_NV_BUFFER_MAX: // Maximum data size in an NV write command *value = MAX_NV_BUFFER_SIZE; break; case TPM_PT_MODES: #if FIPS_COMPLIANT *value = 1; #else *value = 0; #endif break; case TPM_PT_MAX_CAP_BUFFER: *value = MAX_CAP_BUFFER; break; // Start of variable commands case TPM_PT_PERMANENT: // TPMA_PERMANENT { union { TPMA_PERMANENT attr; UINT32 u32; } flags = { TPMA_ZERO_INITIALIZER() }; if(gp.ownerAuth.t.size != 0) SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, ownerAuthSet); if(gp.endorsementAuth.t.size != 0) SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, endorsementAuthSet); if(gp.lockoutAuth.t.size != 0) SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, lockoutAuthSet); if(gp.disableClear) SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, disableClear); if(gp.failedTries >= gp.maxTries) SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, inLockout); // In this implementation, EPS is always generated by TPM SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, tpmGeneratedEPS); // Note: For a LSb0 machine, the bits in a bit field are in the correct // order even if the machine is MSB0. For a MSb0 machine, a TPMA will // be an integer manipulated by masking (USE_BIT_FIELD_STRUCTURES will // be NO) so the bits are manipulate correctly. *value = flags.u32; break; } case TPM_PT_STARTUP_CLEAR: // TPMA_STARTUP_CLEAR { union { TPMA_STARTUP_CLEAR attr; UINT32 u32; } flags = { TPMA_ZERO_INITIALIZER() }; // if(g_phEnable) SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, phEnable); if(gc.shEnable) SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, shEnable); if(gc.ehEnable) SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, ehEnable); if(gc.phEnableNV) SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, phEnableNV); if(g_prevOrderlyState != SU_NONE_VALUE) SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, orderly); // Note: For a LSb0 machine, the bits in a bit field are in the correct // order even if the machine is MSB0. For a MSb0 machine, a TPMA will // be an integer manipulated by masking (USE_BIT_FIELD_STRUCTURES will // be NO) so the bits are manipulate correctly. *value = flags.u32; break; } case TPM_PT_HR_NV_INDEX: // number of NV indexes currently defined *value = NvCapGetIndexNumber(); break; case TPM_PT_HR_LOADED: // number of authorization sessions currently loaded into TPM // RAM *value = SessionCapGetLoadedNumber(); break; case TPM_PT_HR_LOADED_AVAIL: // number of additional authorization sessions, of any type, // that could be loaded into TPM RAM *value = SessionCapGetLoadedAvail(); break; case TPM_PT_HR_ACTIVE: // number of active authorization sessions currently being // tracked by the TPM *value = SessionCapGetActiveNumber(); break; case TPM_PT_HR_ACTIVE_AVAIL: // number of additional authorization sessions, of any type, // that could be created *value = SessionCapGetActiveAvail(); break; case TPM_PT_HR_TRANSIENT_AVAIL: // estimate of the number of additional transient objects that // could be loaded into TPM RAM *value = ObjectCapGetTransientAvail(); break; case TPM_PT_HR_PERSISTENT: // number of persistent objects currently loaded into TPM // NV memory *value = NvCapGetPersistentNumber(); break; case TPM_PT_HR_PERSISTENT_AVAIL: // number of additional persistent objects that could be loaded // into NV memory *value = NvCapGetPersistentAvail(); break; case TPM_PT_NV_COUNTERS: // number of defined NV indexes that have NV TPMA_NV_COUNTER // attribute SET *value = NvCapGetCounterNumber(); break; case TPM_PT_NV_COUNTERS_AVAIL: // number of additional NV indexes that can be defined with their // TPMA_NV_COUNTER attribute SET *value = NvCapGetCounterAvail(); break; case TPM_PT_ALGORITHM_SET: // region code for the TPM *value = gp.algorithmSet; break; case TPM_PT_LOADED_CURVES: #if ALG_ECC // number of loaded ECC curves *value = ECC_CURVE_COUNT; #else // ALG_ECC *value = 0; #endif // ALG_ECC break; case TPM_PT_LOCKOUT_COUNTER: // current value of the lockout counter *value = gp.failedTries; break; case TPM_PT_MAX_AUTH_FAIL: // number of authorization failures before DA lockout is invoked *value = gp.maxTries; break; case TPM_PT_LOCKOUT_INTERVAL: // number of seconds before the value reported by // TPM_PT_LOCKOUT_COUNTER is decremented *value = gp.recoveryTime; break; case TPM_PT_LOCKOUT_RECOVERY: // number of seconds after a lockoutAuth failure before use of // lockoutAuth may be attempted again *value = gp.lockoutRecovery; break; case TPM_PT_NV_WRITE_RECOVERY: // number of milliseconds before the TPM will accept another command // that will modify NV. // This should make a call to the platform code that is doing rate // limiting of NV. Rate limiting is not implemented in the reference // code so no call is made. *value = 0; break; case TPM_PT_AUDIT_COUNTER_0: // high-order 32 bits of the command audit counter *value = (UINT32)(gp.auditCounter >> 32); break; case TPM_PT_AUDIT_COUNTER_1: // low-order 32 bits of the command audit counter *value = (UINT32)(gp.auditCounter); break; default: // property is not defined return FALSE; break; } return TRUE; } //*** TPMCapGetProperties() // This function is used to get the TPM_PT values. The search of properties will // start at 'property' and continue until 'propertyList' has as many values as // will fit, or the last property has been reported, or the list has as many // values as requested in 'count'. // Return Type: TPMI_YES_NO // YES more properties are available // NO no more properties to be reported TPMI_YES_NO TPMCapGetProperties( TPM_PT property, // IN: the starting TPM property UINT32 count, // IN: maximum number of returned // properties TPML_TAGGED_TPM_PROPERTY *propertyList // OUT: property list ) { TPMI_YES_NO more = NO; UINT32 i; UINT32 nextGroup; // initialize output property list propertyList->count = 0; // maximum count of properties we may return is MAX_PCR_PROPERTIES if(count > MAX_TPM_PROPERTIES) count = MAX_TPM_PROPERTIES; // if property is less than PT_FIXED, start from PT_FIXED if(property < PT_FIXED) property = PT_FIXED; // There is only the fixed and variable groups with the variable group coming // last if(property >= (PT_VAR + PT_GROUP)) return more; // Don't read past the end of the selected group nextGroup = ((property / PT_GROUP) * PT_GROUP) + PT_GROUP; // Scan through the TPM properties of the requested group. for(i = property; i < nextGroup; i++) { UINT32 value; // if we have hit the end of the group, quit if(i != property && ((i % PT_GROUP) == 0)) break; if(TPMPropertyIsDefined((TPM_PT)i, &value)) { if(propertyList->count < count) { // If the list is not full, add this property propertyList->tpmProperty[propertyList->count].property = (TPM_PT)i; propertyList->tpmProperty[propertyList->count].value = value; propertyList->count++; } else { // If the return list is full but there are more properties // available, set the indication and exit the loop. more = YES; break; } } } return more; }