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