TCG TIS 1.3 compliant TPM driver to use the TPM as hardware crypto library.
The TPM 2.0 architecture, commands and structures are defined in the set of 4 Trusted Platform Module Library Specification, Family "2.0" specifications that that can be found at http://www.trustedcomputinggroup.org/resources/tpm_library_specification
The "PC Client Specific TPM Interface Specification (TIS), Version 1.3" that was used for this implementation can be found at http://www.trustedcomputinggroup.org/resources/pc_client_work_group_pc_client_specific_tpm_interface_specification_tis
All the information to get going is in SPITIS_TPM20.h!
SPITIS_TPM20.h
- Committer:
- LordOfDorks
- Date:
- 2015-04-11
- Revision:
- 4:77fecfe49437
- Parent:
- 3:4b9ad18eae02
File content as of revision 4:77fecfe49437:
/* mbed TCG SPI TPM 2.0 TIS 1.3 driver, * Copyright (c) 2015, Microsoft Coprporation Inc. * by Stefan Thom (LordOfDorks) StefanTh@Microsoft.com, Stefan@ThomsR.Us * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * This code was developped and tested with a STMicro Nucleo-L152RE with * the STMicro ST33TPMF20MSPI SPI parts (TSSOP28), connected as follows: * * ------------- * NC + 01 28 + NC * NC + 02 S 27 + NC * NC + 03 T 26 + MISO -> D12/PA_6 * GND <- GND + 04 M 25 + NC * NC + 05 i 24 + VPS -> 3V3 * NC + 06 c 23 + MOSI -> D11/PA_7 * NC <- PP + 07 r 22 + #SPI_CS -> D10/PB_6 * NC + 08 o 21 + SPI_CLK -> D13/PA_5 * NC + 09 20 + #SPI_PIRQ -> D7/PA_8 * NC + 10 S 19 + NC * NC + 11 P 18 + NC * NC + 12 I 17 + NC * NC + 13 16 + #SPI_RST -> NRST * NC + 14 15 + NC * ------------- * * TestCode main.cpp: #include "mbed.h" #include "SPITIS_TPM20.h" DigitalIn mybutton(USER_BUTTON); TIS_TPM20 tpm(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS, D7); int main() { uint32_t result = 0; result = tpm.InitializeTis(); printf("TIS.InitializeTis= 0x%08x\n\r", result); if(((result = tpm.StartSession(TIS_TPM20::TIS_LOCALITY_0)) != TIS_TPM20::TIS_SESSION_RESULT_COMPLETE) || ((result = tpm.TPM2_Startup(TPM_SU_CLEAR)) != TIS_TPM20::TIS_SESSION_RESULT_COMPLETE) || ((result = tpm.EndSession()) != TIS_TPM20::TIS_SESSION_RESULT_COMPLETE)) { printf("TPM2_Startup= 0x%08x\n\r", result); } else { printf("TPM2_Startup= OK\n\r"); } while(1) { if(mybutton == 0) { printf("Button!\n\r"); if((result = tpm.StartSession(TIS_TPM20::TIS_LOCALITY_0)) == TIS_TPM20::TIS_SESSION_RESULT_COMPLETE) { TPM2B_AUTH auth = {0}; TPMI_DH_OBJECT hashHandle = 0; TPML_DIGEST_VALUES values = {0}; result = tpm.TPM2_HashSequenceStart(&auth, TPM_ALG_NULL, &hashHandle); printf("TPM2_HashSequenceStart= 0x%08x\n\r", result); for(uint32_t n = 0; n < 0x80000; n += 1024) { if((result = tpm.TPM2_SequenceUpdate(hashHandle, &auth, (uint8_t*)(0x08000000 + n), 1024)) != TIS_TPM20::TIS_SESSION_RESULT_COMPLETE) { printf("TPM2_SequenceUpdate(%d)= 0x%08x\n\r", n, result); } } result = tpm.TPM2_EventSequenceComplete((TPM_HC)(HR_PCR + 0), &auth, hashHandle, &auth, &values); printf("TPM2_EventSequenceComplete= 0x%08x\n\r", result); for(uint32_t n = 0; n < values.count; n++) { printf("Digest(0x%04x)= ", (uint16_t)values.digests[n].hashAlg); switch(values.digests[n].hashAlg) { case TPM_ALG_SHA1: for(uint16_t m = 0; m < sizeof(values.digests[n].digest.sha1); m++) printf("%02x", values.digests[n].digest.sha1[m]); break; case TPM_ALG_SHA256: for(uint16_t m = 0; m < sizeof(values.digests[n].digest.sha256); m++) printf("%02x", values.digests[n].digest.sha256[m]); break; case TPM_ALG_NULL: break; } printf("\n\r"); } tpm.EndSession(); printf("\n\r"); } if((result = tpm.StartSession(TIS_TPM20::TIS_LOCALITY_0)) == TIS_TPM20::TIS_SESSION_RESULT_COMPLETE) { TPML_PCR_SELECTION pcrSelection = {0}; uint32_t pcrUpdateCounter = 0; TPML_DIGEST pcrValues = {0}; pcrSelection.count = 2; pcrSelection.pcrSelections[0].hash = TPM_ALG_SHA1; pcrSelection.pcrSelections[0].sizeofSelect = 3; pcrSelection.pcrSelections[0].pcrSelect[0] = 0x01; pcrSelection.pcrSelections[0].pcrSelect[1] = 0x00; pcrSelection.pcrSelections[0].pcrSelect[2] = 0x00; pcrSelection.pcrSelections[1].hash = TPM_ALG_SHA256; pcrSelection.pcrSelections[1].sizeofSelect = 3; pcrSelection.pcrSelections[1].pcrSelect[0] = 0x01; pcrSelection.pcrSelections[1].pcrSelect[1] = 0x00; pcrSelection.pcrSelections[1].pcrSelect[2] = 0x00; result = tpm.TPM2_PCR_Read(&pcrSelection, &pcrUpdateCounter, &pcrSelection, &pcrValues); printf("TPM2_PCR_Read= 0x%08x\n\r", result); for(uint32_t n = 0; n < pcrValues.count; n++) { printf("PCR[0](0x%04x)= ", (uint16_t)pcrSelection.pcrSelections[n].hash); for(uint16_t m = 0; m < pcrValues.digests[n].t.size; m++) printf("%02x", pcrValues.digests[n].t.buffer[m]); printf("\n\r"); } tpm.EndSession(); printf("\n\r"); } if((result = tpm.StartSession(TIS_TPM20::TIS_LOCALITY_0)) == TIS_TPM20::TIS_SESSION_RESULT_COMPLETE) { TPM2B_AUTH auth = {0}; TPMI_DH_OBJECT hashHandle = 0; TPM2B_DIGEST digest = {0}; TPMT_TK_HASHCHECK validation = {0}; uint8_t testVector[] = "The quick brown fox jumps over the lazy dog"; result = tpm.TPM2_HashSequenceStart(&auth, TPM_ALG_SHA256, &hashHandle); printf("TPM2_HashSequenceStart= 0x%08x\n\r", result); result = tpm.TPM2_SequenceUpdate(hashHandle, &auth, testVector, sizeof(testVector) - 1); printf("TPM2_SequenceUpdate= 0x%08x\n\r", result); result = tpm.TPM2_SequenceComplete(hashHandle, &auth, TPM_RH_NULL, &digest, &validation); printf("TPM2_HashSequenceComplete= 0x%08x\n\r", result); printf("Digest= "); for(uint16_t n = 0; n < digest.t.size; n++) printf("%02x", digest.t.buffer[n]); printf("\n\r"); printf("Ref= d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592\n\r"); tpm.EndSession(); printf("\n\r"); } if((result = tpm.StartSession(TIS_TPM20::TIS_LOCALITY_0)) == TIS_TPM20::TIS_SESSION_RESULT_COMPLETE) { TPM2B_DIGEST random = {0}; random.t.size = 32; result = tpm.TPM2_GetRandom(&random); printf("TPM2_GetRandom = 0x%08x\n\r", result); printf("Random = "); for(uint16_t n = 0; n < random.t.size; n++) printf("%02x", random.t.buffer[n]); printf("\n\r"); result = tpm.TPM2_StirRandom(&random); printf("TPM2_StirRandom = 0x%08x\n\r", result); tpm.EndSession(); printf("\n\r"); } wait(1); } } } * * The TPM 2.0 architecture, commands and structures are defined in the set of 4 * Trusted Platform Module Library Specification, Family "2.0" specifications that * that can be found at * http://www.trustedcomputinggroup.org/resources/tpm_library_specification * * The "PC Client Specific TPM Interface Specification (TIS), Version 1.3" that was * used for this implementationcan be found at * http://www.trustedcomputinggroup.org/resources/pc_client_work_group_pc_client_specific_tpm_interface_specification_tis * */ #include "mbed.h" #include "TPM20.h" #include "GizmosNGadgets.h" #include "Marshal.h" //#define TPM_TIS_DEBUG_OUTPUT 1 //#define TPM_TIS_INTERFACE_DEBUG_OUTPUT 1 // If you do not need command filtering, you can save some space here //#define TPM_TIS_NO_COMMAND_FILTERING 1 class TIS_TPM20 { public: enum TIS_RESULT { TIS_SESSION_RESULT_COMPLETE = 0, TIS_SESSION_RESULT_PENDING, TIS_SESSION_RESULT_FAILED, TIS_SESSION_RESULT_FILTERED, TIS_SESSION_RESULT_PREEMPTED, TIS_SESSION_RESULT_TIMEOUT, TIS_SESSION_RESULT_OCCUPIED }; enum TIS_LOCALITY { TIS_LOCALITY_0 = 0, TIS_LOCALITY_1 = 1, TIS_LOCALITY_2 = 2, TIS_LOCALITY_3 = 3, TIS_LOCALITY_4 = 4, TIS_NOT_IN_USE = -1 }; TIS_TPM20(PinName miso, PinName Mosi, PinName clk, PinName cs, PinName irq) : m_spi(miso, Mosi, clk), m_chipSelect(cs), m_interrupt(irq) { m_spi.format(8, 00); m_spi.frequency(4000000); m_chipSelect = 1; m_interrupt.mode(PullUp); m_locality = TIS_NOT_IN_USE; m_intfCabability = 0; m_fixedBurstCount = true; m_maxBurstCount = 0; #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Init: OK\n\r"); #endif } ~TIS_TPM20() { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Destroy: OK.\n\r"); #endif } TIS_RESULT InitializeTis(); // Session management TIS_RESULT StartSession(TIS_TPM20::TIS_LOCALITY locality = TIS_TPM20::TIS_LOCALITY_0); TIS_RESULT EndSession(); // Submit a command TIS_RESULT SendCommand(uint8_t* pbCmd, uint32_t cbCmd, uint8_t* pbTrailingData = NULL, uint32_t cbTrailingData = 0); // Retrieve the response TIS_RESULT RetrieveResponse(uint8_t* pbRsp, uint32_t cbRsp, uint32_t* pcbRsp); // Attempt to abort the current command TIS_TPM20::TIS_RESULT AbortCommand(); // TPM sample commands TPM_RC TPM2_Startup(uint16_t startupType); TPM_RC TPM2_Shutdown(uint16_t shutdownType); TPM_RC TPM2_GetRandom(TPM2B_DIGEST* random); TPM_RC TPM2_StirRandom(TPM2B_DIGEST* seed); TPM_RC TPM2_HMAC_Start(TPMI_DH_OBJECT handle, TPM2B_AUTH* handleAuth, TPM2B_AUTH* auth, TPMI_ALG_HASH hashAlg, TPMI_DH_OBJECT* sequenceHandle); TPM_RC TPM2_HashSequenceStart(TPM2B_AUTH* auth, TPMI_ALG_HASH hashAlg, TPMI_DH_OBJECT* sequenceHandle); TPM_RC TPM2_SequenceUpdate(TPMI_DH_OBJECT sequenceHandle, TPM2B_AUTH* sequenceHandleAuth, uint8_t* pbData, uint16_t cbData); TPM_RC TPM2_SequenceComplete(TPMI_DH_OBJECT sequenceHandle, TPM2B_AUTH* sequenceHandleAuth, TPMI_RH_HIERARCHY hierarchy, TPM2B_DIGEST* result, TPMT_TK_HASHCHECK* validation); TPM_RC TPM2_EventSequenceComplete(TPMI_DH_PCR pcrHandle, TPM2B_AUTH* pcrAuth, TPMI_DH_OBJECT sequenceHandle, TPM2B_AUTH* handleAuth, TPML_DIGEST_VALUES* results); TPM_RC TPM2_PCR_Read(TPML_PCR_SELECTION* pcrSelectionIn, uint32_t* pcrUpdateCounter, TPML_PCR_SELECTION* pcrSelectionOut, TPML_DIGEST* pcrValues); private: // TIS registers addresses const static uint16_t TIS_ACCESS_REGISTER = 0x0000; const static uint16_t TIS_INT_ENABLE_REGISTER = 0x0008; const static uint16_t TIS_INT_VECTOR_REGISTER = 0x000c; const static uint16_t TIS_INT_STATUS_REGISTER = 0x0010; const static uint16_t TIS_INTF_CAPABILITY_REGISTER = 0x0014; const static uint16_t TIS_STS_REGISTER = 0x0018; const static uint16_t TIS_STS_BURSTCOUNT_REGISTER = 0x0019; // 16bit segment in TIS_STS_REGISTER const static uint16_t TIS_DATA_FIFO = 0x0024; const static uint16_t TIS_XDATA_FIFO = 0x0080; const static uint16_t TIS_DID_VID = 0x0F00; const static uint16_t TIS_RID = 0x0F04; const static uint16_t TIS_VENDORSPECIFIC = 0x0F90; const static uint8_t TIS_MAX_HW_FRAME_SIZE = 64; // TIS Specification Table 14 enum TIS_ACCESS { TIS_ACCESS_VALID = 0x80, TIS_ACCESS_ACTIVE_LOCALITY = 0x20, TIS_ACCESS_BEEING_SEIZED = 0x10, TIS_ACCESS_SEIZE = 0x08, TIS_ACCESS_PENDING_REQUEST = 0x04, TIS_ACCESS_REQUEST_USE = 0x02, TIS_ACCESS_TPM_ESTABLISHMENT = 0x01 }; // TIS Specification Table 15 enum TIS_STS { TIS_STS_VALID = 0x80, TIS_STS_COMMAND_READY = 0x40, TIS_STS_GO = 0x20, TIS_STS_DATA_AVAIL = 0x10, TIS_STS_DATA_EXPECT = 0x08, TIS_STS_RESPONSERETRY = 0x02 }; // TIS Specification Table 17 enum TIS_INTF_CAPPABILITY { TIS_INTF_CAPPABILITY_INTERFACE_VERSION_12 = 0x00000000, TIS_INTF_CAPPABILITY_INTERFACE_VERSION_13 = 0x20000000, TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_MASK = 0x00000600, TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_64B = 0x00000600, TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_32B = 0x00000400, TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_8B = 0x00000200, TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_LEGACY = 0x00000000, TIS_INTF_CAPPABILITY_BURST_COUNT_STATIC = 0x00000100, TIS_INTF_CAPPABILITY_COMMAND_READY_INT_SUPPORT = 0x00000080, TIS_INTF_CAPPABILITY_INTERRUPT_EDGE_FALLING = 0x00000040, TIS_INTF_CAPPABILITY_INTERRUPT_EDGE_RISING = 0x00000020, TIS_INTF_CAPPABILITY_INTERRUPT_LEVEL_LOW = 0x00000010, TIS_INTF_CAPPABILITY_INTERRUPT_LEVEL_HIGH = 0x00000008, TIS_INTF_CAPPABILITY_LOCALITY_CHANGE_INT_SUPPORT = 0x00000004, TIS_INTF_CAPPABILITY_STS_VALID_INT_SUPPORT = 0x00000002, TIS_INTF_CAPPABILITY_DATA_AVAILABLE_INT_SUPPORT = 0x00000001 }; // TIS Spceification Table 19 enum TIS_INT_ENABLE { TIS_INT_ENABLE_DATA_AVAILABLE_INT_ENABLE = 0x00000001, TIS_INT_ENABLE_STS_VALID_INT_ENABLE = 0x00000002, TIS_INT_ENABLE_LOCALITY_CHANGE_INT_ENABLE = 0x00000004, TIS_INT_ENABLE_TYPE_POLARITY_HIGH = 0x00000000, TIS_INT_ENABLE_TYPE_POLARITY_LOW = 0x00000008, TIS_INT_ENABLE_TYPE_POLARITY_RISING = 0x00000010, TIS_INT_ENABLE_TYPE_POLARITY_FALLING = 0x00000018, TIS_INT_ENABLE_COMMAND_READY_INT_ENABLE = 0x00000080, TIS_INT_ENABLE_GLOBAL_INT_ENABLE = -2147483648 //0x80000000 }; enum TIS_INT_STATUS { TIS_INT_STATUS_DATA_AVAILABLE_INT_OCCURED = 0x01, TIS_INT_STATUS_STS_VALID_INT_OCCURED = 0x02, TIS_INT_STATUS_LOCALITY_CHANGE_INT_OCCURED = 0x04, TIS_INT_STATUS_COMMAND_READY_INT_OCCURED = 0x80, TIS_INT_STATUS_RESET_ALL = TIS_INT_STATUS_DATA_AVAILABLE_INT_OCCURED | TIS_INT_STATUS_STS_VALID_INT_OCCURED | TIS_INT_STATUS_LOCALITY_CHANGE_INT_OCCURED | TIS_INT_STATUS_COMMAND_READY_INT_OCCURED }; enum TIS_SESSION_STATUS { TIS_SESSION_STATUS_UNINITIALIZED = 0, TIS_SESSION_STATUS_NEW, TIS_SESSION_STATUS_GET_READY_FOR_COMMAND, TIS_SESSION_STATUS_READY_FOR_COMMAND, TIS_SESSION_STATUS_EXECUTING, TIS_SESSION_STATUS_DATA_AVAILABLE, TIS_SESSION_STATUS_COMPLETE, TIS_SESSION_STATUS_PREEMPTED, TIS_SESSION_STATUS_TIMEOUT }; // Bottom interface to the TPM chip SPI m_spi; DigitalOut m_chipSelect; DigitalIn m_interrupt; uint32_t m_intfCabability; bool m_fixedBurstCount; uint16_t m_maxBurstCount; TIS_LOCALITY m_locality; // Bottom communication functions bool FullDuplex(bool readCycle, uint16_t reg, uint8_t* pbBuffer, uint16_t cbBuffer); bool ReadRegister(uint16_t reg, uint8_t* pbBuffer, uint16_t cbBuffer) { return FullDuplex(true, reg, pbBuffer, cbBuffer); } bool WriteRegister(uint16_t reg, uint8_t* pbBuffer, uint16_t cbBuffer) { return FullDuplex(false, reg, pbBuffer, cbBuffer); } uint16_t GetBurstCount(); bool TpmInteruptOn(uint32_t intEnable); bool RequestLocality(TIS_TPM20::TIS_LOCALITY locality); bool ReleaseLocality(); // Top interface to caller #ifndef TPM_TIS_NO_COMMAND_FILTERING TIS_RESULT ApplyFilter(TIS_TPM20::TIS_LOCALITY locality, uint8_t* pbCmd, uint32_t cbCmd); #endif TPM_RC ParseResponseHeader(TPM_ST* tag, UINT32* rspSize, uint8_t** buffer, int32_t* size); };