/* 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. | |
*/ | |
//** Includes, Defines, and Types | |
#define TPM_FAIL_C | |
#include "Tpm.h" | |
#include <assert.h> | |
// On MS C compiler, can save the alignment state and set the alignment to 1 for | |
// the duration of the TpmTypes.h include. This will avoid a lot of alignment | |
// warnings from the compiler for the unaligned structures. The alignment of the | |
// structures is not important as this function does not use any of the structures | |
// in TpmTypes.h and only include it for the #defines of the capabilities, | |
// properties, and command code values. | |
#include "TpmTypes.h" | |
//** Typedefs | |
// These defines are used primarily for sizing of the local response buffer. | |
typedef struct | |
{ | |
TPM_ST tag; | |
UINT32 size; | |
TPM_RC code; | |
} HEADER; | |
typedef struct | |
{ | |
BYTE tag[sizeof(TPM_ST)]; | |
BYTE size[sizeof(UINT32)]; | |
BYTE code[sizeof(TPM_RC)]; | |
} PACKED_HEADER; | |
typedef struct | |
{ | |
BYTE size[sizeof(UINT16)]; | |
struct | |
{ | |
BYTE function[sizeof(UINT32)]; | |
BYTE line[sizeof(UINT32)]; | |
BYTE code[sizeof(UINT32)]; | |
} values; | |
BYTE returnCode[sizeof(TPM_RC)]; | |
} GET_TEST_RESULT_PARAMETERS; | |
typedef struct | |
{ | |
BYTE moreData[sizeof(TPMI_YES_NO)]; | |
BYTE capability[sizeof(TPM_CAP)]; // Always TPM_CAP_TPM_PROPERTIES | |
BYTE tpmProperty[sizeof(TPML_TAGGED_TPM_PROPERTY)]; | |
} GET_CAPABILITY_PARAMETERS; | |
typedef struct | |
{ | |
BYTE header[sizeof(PACKED_HEADER)]; | |
BYTE getTestResult[sizeof(GET_TEST_RESULT_PARAMETERS)]; | |
} TEST_RESPONSE; | |
typedef struct | |
{ | |
BYTE header[sizeof(PACKED_HEADER)]; | |
BYTE getCap[sizeof(GET_CAPABILITY_PARAMETERS)]; | |
} CAPABILITY_RESPONSE; | |
typedef union | |
{ | |
BYTE test[sizeof(TEST_RESPONSE)]; | |
BYTE cap[sizeof(CAPABILITY_RESPONSE)]; | |
} RESPONSES; | |
// Buffer to hold the responses. This may be a little larger than | |
// required due to padding that a compiler might add. | |
// Note: This is not in Global.c because of the specialized data definitions above. | |
// Since the data contained in this structure is not relevant outside of the | |
// execution of a single command (when the TPM is in failure mode. There is no | |
// compelling reason to move all the typedefs to Global.h and this structure | |
// to Global.c. | |
#ifndef __IGNORE_STATE__ // Don't define this value | |
static BYTE response[sizeof(RESPONSES)]; | |
#endif | |
//** Local Functions | |
//*** MarshalUint16() | |
// Function to marshal a 16 bit value to the output buffer. | |
static INT32 | |
MarshalUint16( | |
UINT16 integer, | |
BYTE **buffer | |
) | |
{ | |
UINT16_TO_BYTE_ARRAY(integer, *buffer); | |
*buffer += 2; | |
return 2; | |
} | |
//*** MarshalUint32() | |
// Function to marshal a 32 bit value to the output buffer. | |
static INT32 | |
MarshalUint32( | |
UINT32 integer, | |
BYTE **buffer | |
) | |
{ | |
UINT32_TO_BYTE_ARRAY(integer, *buffer); | |
*buffer += 4; | |
return 4; | |
} | |
//***Unmarshal32() | |
static BOOL Unmarshal32( | |
UINT32 *target, | |
BYTE **buffer, | |
INT32 *size | |
) | |
{ | |
if((*size -= 4) < 0) | |
return FALSE; | |
*target = BYTE_ARRAY_TO_UINT32(*buffer); | |
*buffer += 4; | |
return TRUE; | |
} | |
//***Unmarshal16() | |
static BOOL Unmarshal16( | |
UINT16 *target, | |
BYTE **buffer, | |
INT32 *size | |
) | |
{ | |
if((*size -= 2) < 0) | |
return FALSE; | |
*target = BYTE_ARRAY_TO_UINT16(*buffer); | |
*buffer += 2; | |
return TRUE; | |
} | |
//** Public Functions | |
//*** SetForceFailureMode() | |
// This function is called by the simulator to enable failure mode testing. | |
#if SIMULATION | |
LIB_EXPORT void | |
SetForceFailureMode( | |
void | |
) | |
{ | |
g_forceFailureMode = TRUE; | |
return; | |
} | |
#endif | |
//*** TpmLogFailure() | |
// This function saves the failure values when the code will continue to operate. It | |
// if similar to TpmFail() but returns to the caller. The assumption is that the | |
// caller will propagate a failure back up the stack. | |
void | |
TpmLogFailure( | |
#if FAIL_TRACE | |
const char *function, | |
int line, | |
#endif | |
int code | |
) | |
{ | |
// Save the values that indicate where the error occurred. | |
// On a 64-bit machine, this may truncate the address of the string | |
// of the function name where the error occurred. | |
#if FAIL_TRACE | |
s_failFunction = (UINT32)(ptrdiff_t)function; | |
s_failLine = line; | |
#else | |
s_failFunction = 0; | |
s_failLine = 0; | |
#endif | |
s_failCode = code; | |
// We are in failure mode | |
g_inFailureMode = TRUE; | |
return; | |
} | |
//*** TpmFail() | |
// This function is called by TPM.lib when a failure occurs. It will set up the | |
// failure values to be returned on TPM2_GetTestResult(). | |
NORETURN void | |
TpmFail( | |
#if FAIL_TRACE | |
const char *function, | |
int line, | |
#endif | |
int code | |
) | |
{ | |
// Save the values that indicate where the error occurred. | |
// On a 64-bit machine, this may truncate the address of the string | |
// of the function name where the error occurred. | |
#if FAIL_TRACE | |
s_failFunction = (UINT32)(ptrdiff_t)function; | |
s_failLine = line; | |
#else | |
s_failFunction = (UINT32)(ptrdiff_t)NULL; | |
s_failLine = 0; | |
#endif | |
s_failCode = code; | |
// We are in failure mode | |
g_inFailureMode = TRUE; | |
// if asserts are enabled, then do an assert unless the failure mode code | |
// is being tested. | |
#if SIMULATION | |
# ifndef NDEBUG | |
assert(g_forceFailureMode); | |
# endif | |
// Clear this flag | |
g_forceFailureMode = FALSE; | |
#endif | |
// Jump to the failure mode code. | |
// Note: only get here if asserts are off or if we are testing failure mode | |
_plat__Fail(); | |
} | |
//*** TpmFailureMode( | |
// This function is called by the interface code when the platform is in failure | |
// mode. | |
void | |
TpmFailureMode( | |
unsigned int inRequestSize, // IN: command buffer size | |
unsigned char *inRequest, // IN: command buffer | |
unsigned int *outResponseSize, // OUT: response buffer size | |
unsigned char **outResponse // OUT: response buffer | |
) | |
{ | |
UINT32 marshalSize; | |
UINT32 capability; | |
HEADER header; // unmarshaled command header | |
UINT32 pt; // unmarshaled property type | |
UINT32 count; // unmarshaled property count | |
UINT8 *buffer = inRequest; | |
INT32 size = inRequestSize; | |
// If there is no command buffer, then just return TPM_RC_FAILURE | |
if(inRequestSize == 0 || inRequest == NULL) | |
goto FailureModeReturn; | |
// If the header is not correct for TPM2_GetCapability() or | |
// TPM2_GetTestResult() then just return the in failure mode response; | |
if(! (Unmarshal16(&header.tag, &buffer, &size) | |
&& Unmarshal32(&header.size, &buffer, &size) | |
&& Unmarshal32(&header.code, &buffer, &size))) | |
goto FailureModeReturn; | |
if(header.tag != TPM_ST_NO_SESSIONS | |
|| header.size < 10) | |
goto FailureModeReturn; | |
switch(header.code) | |
{ | |
case TPM_CC_GetTestResult: | |
// make sure that the command size is correct | |
if(header.size != 10) | |
goto FailureModeReturn; | |
buffer = &response[10]; | |
marshalSize = MarshalUint16(3 * sizeof(UINT32), &buffer); | |
marshalSize += MarshalUint32(s_failFunction, &buffer); | |
marshalSize += MarshalUint32(s_failLine, &buffer); | |
marshalSize += MarshalUint32(s_failCode, &buffer); | |
if(s_failCode == FATAL_ERROR_NV_UNRECOVERABLE) | |
marshalSize += MarshalUint32(TPM_RC_NV_UNINITIALIZED, &buffer); | |
else | |
marshalSize += MarshalUint32(TPM_RC_FAILURE, &buffer); | |
break; | |
case TPM_CC_GetCapability: | |
// make sure that the size of the command is exactly the size | |
// returned for the capability, property, and count | |
if(header.size != (10 + (3 * sizeof(UINT32))) | |
// also verify that this is requesting TPM properties | |
|| !Unmarshal32(&capability, &buffer, &size) | |
|| capability != TPM_CAP_TPM_PROPERTIES | |
|| !Unmarshal32(&pt, &buffer, &size) | |
|| !Unmarshal32(&count, &buffer, &size)) | |
goto FailureModeReturn; | |
// If in failure mode because of an unrecoverable read error, and the | |
// property is 0 and the count is 0, then this is an indication to | |
// re-manufacture the TPM. Do the re-manufacture but stay in failure | |
// mode until the TPM is reset. | |
// Note: this behavior is not required by the specification and it is | |
// OK to leave the TPM permanently bricked due to an unrecoverable NV | |
// error. | |
if(count == 0 && pt == 0 && s_failCode == FATAL_ERROR_NV_UNRECOVERABLE) | |
{ | |
g_manufactured = FALSE; | |
TPM_Manufacture(0); | |
} | |
if(count > 0) | |
count = 1; | |
else if(pt > TPM_PT_FIRMWARE_VERSION_2) | |
count = 0; | |
if(pt < TPM_PT_MANUFACTURER) | |
pt = TPM_PT_MANUFACTURER; | |
// set up for return | |
buffer = &response[10]; | |
// if the request was for a PT less than the last one | |
// then we indicate more, otherwise, not. | |
if(pt < TPM_PT_FIRMWARE_VERSION_2) | |
*buffer++ = YES; | |
else | |
*buffer++ = NO; | |
marshalSize = 1; | |
// indicate the capability type | |
marshalSize += MarshalUint32(capability, &buffer); | |
// indicate the number of values that are being returned (0 or 1) | |
marshalSize += MarshalUint32(count, &buffer); | |
// indicate the property | |
marshalSize += MarshalUint32(pt, &buffer); | |
if(count > 0) | |
switch(pt) | |
{ | |
case TPM_PT_MANUFACTURER: | |
// the vendor ID unique to each TPM manufacturer | |
#ifdef MANUFACTURER | |
pt = *(UINT32*)MANUFACTURER; | |
#else | |
pt = 0; | |
#endif | |
break; | |
case TPM_PT_VENDOR_STRING_1: | |
// the first four characters of the vendor ID string | |
#ifdef VENDOR_STRING_1 | |
pt = *(UINT32*)VENDOR_STRING_1; | |
#else | |
pt = 0; | |
#endif | |
break; | |
case TPM_PT_VENDOR_STRING_2: | |
// the second four characters of the vendor ID string | |
#ifdef VENDOR_STRING_2 | |
pt = *(UINT32*)VENDOR_STRING_2; | |
#else | |
pt = 0; | |
#endif | |
break; | |
case TPM_PT_VENDOR_STRING_3: | |
// the third four characters of the vendor ID string | |
#ifdef VENDOR_STRING_3 | |
pt = *(UINT32*)VENDOR_STRING_3; | |
#else | |
pt = 0; | |
#endif | |
break; | |
case TPM_PT_VENDOR_STRING_4: | |
// the fourth four characters of the vendor ID string | |
#ifdef VENDOR_STRING_4 | |
pt = *(UINT32*)VENDOR_STRING_4; | |
#else | |
pt = 0; | |
#endif | |
break; | |
case TPM_PT_VENDOR_TPM_TYPE: | |
// vendor-defined value indicating the TPM model | |
// We just make up a number here | |
pt = 1; | |
break; | |
case TPM_PT_FIRMWARE_VERSION_1: | |
// the more significant 32-bits of a vendor-specific value | |
// indicating the version of the firmware | |
#ifdef FIRMWARE_V1 | |
pt = FIRMWARE_V1; | |
#else | |
pt = 0; | |
#endif | |
break; | |
default: // TPM_PT_FIRMWARE_VERSION_2: | |
// the less significant 32-bits of a vendor-specific value | |
// indicating the version of the firmware | |
#ifdef FIRMWARE_V2 | |
pt = FIRMWARE_V2; | |
#else | |
pt = 0; | |
#endif | |
break; | |
} | |
marshalSize += MarshalUint32(pt, &buffer); | |
break; | |
default: // default for switch (cc) | |
goto FailureModeReturn; | |
} | |
// Now do the header | |
buffer = response; | |
marshalSize = marshalSize + 10; // Add the header size to the | |
// stuff already marshaled | |
MarshalUint16(TPM_ST_NO_SESSIONS, &buffer); // structure tag | |
MarshalUint32(marshalSize, &buffer); // responseSize | |
MarshalUint32(TPM_RC_SUCCESS, &buffer); // response code | |
*outResponseSize = marshalSize; | |
*outResponse = (unsigned char *)&response; | |
return; | |
FailureModeReturn: | |
buffer = response; | |
marshalSize = MarshalUint16(TPM_ST_NO_SESSIONS, &buffer); | |
marshalSize += MarshalUint32(10, &buffer); | |
marshalSize += MarshalUint32(TPM_RC_FAILURE, &buffer); | |
*outResponseSize = marshalSize; | |
*outResponse = (unsigned char *)response; | |
return; | |
} | |
//*** UnmarshalFail() | |
// This is a stub that is used to catch an attempt to unmarshal an entry | |
// that is not defined. Don't ever expect this to be called but... | |
void | |
UnmarshalFail( | |
void *type, | |
BYTE **buffer, | |
INT32 *size | |
) | |
{ | |
NOT_REFERENCED(type); | |
NOT_REFERENCED(buffer); | |
NOT_REFERENCED(size); | |
FAIL(FATAL_ERROR_INTERNAL); | |
} |