| // 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 |
| ) |
| { |
| return UINT16_Marshal(&integer, buffer, NULL); |
| } |
| // |
| // |
| // MarshalUint32() |
| // |
| // Function to marshal a 32 bit value to the output buffer. |
| static INT32 |
| MarshalUint32( |
| UINT32 integer, |
| BYTE **buffer |
| ) |
| { |
| return UINT32_Marshal(&integer, buffer, NULL); |
| } |
| // |
| // |
| // 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. |
| s_failFunction = *(UINT32*)&function; |
| 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 |
| longjmp(&g_jumpBuffer[0], 1); |
| } |
| // |
| // |
| // 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; |
| 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]; |
| 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 |
| || (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]; |
| // 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; |
| } |