// 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; }