You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
12 KiB
363 lines
12 KiB
// This file was extracted from the TCG Published |
|
// Trusted Platform Module Library |
|
// Part 4: Supporting Routines |
|
// Family "2.0" |
|
// Level 00 Revision 01.16 |
|
// October 30, 2014 |
|
|
|
#define TPM_FAIL_C |
|
#include "InternalRoutines.h" |
|
#include <assert.h> |
|
// |
|
// On MS C compiler, can save the alignment state and set the alignment to 1 for the duration of the |
|
// TPM_Types.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 TPM_Types.h and only include it for the #defines of the capabilities, properties, and |
|
// command code values. |
|
// |
|
#pragma pack(push, 1) |
|
#include "TPM_Types.h" |
|
#pragma pack (pop) |
|
#include "swap.h" |
|
// |
|
// |
|
// Typedefs |
|
// |
|
// These defines are used primarily for sizing of the local response buffer. |
|
// |
|
#pragma pack(push,1) |
|
typedef struct { |
|
TPM_ST tag; |
|
UINT32 size; |
|
TPM_RC code; |
|
} HEADER; |
|
typedef struct { |
|
UINT16 size; |
|
struct { |
|
UINT32 function; |
|
UINT32 line; |
|
UINT32 code; |
|
} values; |
|
TPM_RC returnCode; |
|
} GET_TEST_RESULT_PARAMETERS; |
|
typedef struct { |
|
TPMI_YES_NO moreData; |
|
TPM_CAP capability; // Always TPM_CAP_TPM_PROPERTIES |
|
TPML_TAGGED_TPM_PROPERTY tpmProperty; // a single tagged property |
|
} GET_CAPABILITY_PARAMETERS; |
|
typedef struct { |
|
HEADER header; |
|
GET_TEST_RESULT_PARAMETERS getTestResult; |
|
} TEST_RESPONSE; |
|
typedef struct { |
|
HEADER header; |
|
GET_CAPABILITY_PARAMETERS getCap; |
|
} CAPABILITY_RESPONSE; |
|
typedef union { |
|
TEST_RESPONSE test; |
|
CAPABILITY_RESPONSE cap; |
|
} RESPONSES; |
|
#pragma pack(pop) |
|
// |
|
// 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, |
|
INT32 *size |
|
) |
|
{ |
|
return UINT16_Marshal(&integer, buffer, size); |
|
} |
|
// |
|
// |
|
// MarshalUint32() |
|
// |
|
// Function to marshal a 32 bit value to the output buffer. |
|
static INT32 |
|
MarshalUint32( |
|
UINT32 integer, |
|
BYTE **buffer, |
|
INT32 *size |
|
) |
|
{ |
|
return UINT32_Marshal(&integer, buffer, size); |
|
} |
|
// |
|
// |
|
// UnmarshalHeader() |
|
// |
|
// Funtion to unmarshal the 10-byte command header. |
|
// |
|
static BOOL |
|
UnmarshalHeader( |
|
HEADER *header, |
|
BYTE **buffer, |
|
INT32 *size |
|
) |
|
{ |
|
UINT32 usize; |
|
TPM_RC ucode; |
|
if( UINT16_Unmarshal(&header->tag, buffer, size) != TPM_RC_SUCCESS |
|
|| UINT32_Unmarshal(&usize, buffer, size) != TPM_RC_SUCCESS |
|
|| UINT32_Unmarshal(&ucode, buffer, size) != TPM_RC_SUCCESS |
|
) |
|
return FALSE; |
|
header->size = usize; |
|
header->code = ucode; |
|
return TRUE; |
|
} |
|
// |
|
// |
|
// Public Functions |
|
// |
|
// SetForceFailureMode() |
|
// |
|
// This function is called by the simulator to enable failure mode testing. |
|
// |
|
LIB_EXPORT void |
|
SetForceFailureMode( |
|
void |
|
) |
|
{ |
|
g_forceFailureMode = 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(). |
|
// |
|
void |
|
TpmFail( |
|
const char *function, |
|
int line, 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. |
|
memcpy(&s_failFunction, function, sizeof(s_failFunction)); |
|
s_failLine = line; |
|
s_failCode = code; |
|
// if asserts are enabled, then do an assert unless the failure mode code |
|
// is being tested |
|
assert(g_forceFailureMode); |
|
// Clear this flag |
|
g_forceFailureMode = FALSE; |
|
// Jump to the failure mode code. |
|
// Note: only get here if asserts are off or if we are testing failure mode |
|
#ifndef EMBEDDED_MODE |
|
longjmp(&g_jumpBuffer[0], 1); |
|
#endif |
|
} |
|
// |
|
// |
|
// 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 |
|
) |
|
{ |
|
BYTE *buffer; |
|
INT32 bufferSize; |
|
UINT32 marshalSize; |
|
UINT32 capability; |
|
HEADER header; // unmarshaled command header |
|
UINT32 pt; // unmarshaled property type |
|
UINT32 count; // unmarshaled property count |
|
// 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; |
|
buffer = inRequest; |
|
if(!UnmarshalHeader(&header, &inRequest, (INT32 *)&inRequestSize)) |
|
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]; |
|
bufferSize = MAX_RESPONSE_SIZE-10; |
|
marshalSize = MarshalUint16(3 * sizeof(UINT32), &buffer, &bufferSize); |
|
marshalSize += MarshalUint32(s_failFunction, &buffer, &bufferSize); |
|
marshalSize += MarshalUint32(s_failLine, &buffer, &bufferSize); |
|
marshalSize += MarshalUint32(s_failCode, &buffer, &bufferSize); |
|
if(s_failCode == FATAL_ERROR_NV_UNRECOVERABLE) |
|
marshalSize += MarshalUint32(TPM_RC_NV_UNINITIALIZED, &buffer, &bufferSize); |
|
else |
|
marshalSize += MarshalUint32(TPM_RC_FAILURE, &buffer, &bufferSize); |
|
// |
|
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 |
|
|| (UINT32_Unmarshal(&capability, &inRequest, |
|
(INT32 *)&inRequestSize) |
|
!= TPM_RC_SUCCESS) |
|
|| (capability != TPM_CAP_TPM_PROPERTIES) |
|
|| (UINT32_Unmarshal(&pt, &inRequest, (INT32 *)&inRequestSize) |
|
!= TPM_RC_SUCCESS) |
|
|| (UINT32_Unmarshal(&count, &inRequest, (INT32 *)&inRequestSize) |
|
!= TPM_RC_SUCCESS) |
|
) |
|
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]; |
|
bufferSize = MAX_RESPONSE_SIZE-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, &bufferSize); |
|
// indicate the number of values that are being returned (0 or 1) |
|
marshalSize += MarshalUint32(count, &buffer, &bufferSize); |
|
// indicate the property |
|
marshalSize += MarshalUint32(pt, &buffer, &bufferSize); |
|
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, &bufferSize); |
|
break; |
|
default: // default for switch (cc) |
|
goto FailureModeReturn; |
|
} |
|
// Now do the header |
|
buffer = response; |
|
bufferSize = 10; |
|
marshalSize = marshalSize + 10; // Add the header size to the |
|
// stuff already marshaled |
|
MarshalUint16(TPM_ST_NO_SESSIONS, &buffer, &bufferSize); // structure tag |
|
MarshalUint32(marshalSize, &buffer, &bufferSize); // responseSize |
|
MarshalUint32(TPM_RC_SUCCESS, &buffer, &bufferSize); // response code |
|
*outResponseSize = marshalSize; |
|
*outResponse = (unsigned char *)&response; |
|
return; |
|
FailureModeReturn: |
|
buffer = response; |
|
bufferSize = 10; |
|
marshalSize = MarshalUint16(TPM_ST_NO_SESSIONS, &buffer, &bufferSize); |
|
marshalSize += MarshalUint32(10, &buffer, &bufferSize); |
|
marshalSize += MarshalUint32(TPM_RC_FAILURE, &buffer, &bufferSize); |
|
*outResponseSize = marshalSize; |
|
*outResponse = (unsigned char *)response; |
|
return; |
|
}
|
|
|