363 lines
12 KiB
C
363 lines
12 KiB
C
// 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;
|
|
}
|