TCG TIS 1.3 compliant TPM driver to use the TPM as hardware crypto library.

/media/uploads/LordOfDorks/wp_20150409_16_47_21_pro.jpg 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:
3:4b9ad18eae02
Parent:
2:526bf792254d
Child:
4:77fecfe49437

File content as of revision 3:4b9ad18eae02:

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