blob: 11ea8592c8993fa36418c0b963c6e561b6cc6426 [file] [log] [blame]
/* 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;
}