Programming the Trusted Platform Module (TPM)


The Trusted Platform Module (TPM) is the product of a specification from the Trusted Computing Group (TCG 2006a), designed to enhance system security by moving many sensitive cryptographic operations into hardware. Windows Vista supports TPM 1.2. The most wellknown feature that uses the TPM, if one is available, is BitLocker Drive Encryption and its secure start-up capability (Microsoft 2006e).

Tip 

BitLocker can be used without a TPM, but it only offers drive encryption, not secure start-up.

image from book
What Is a Trusted Platform Module?

There are numerous security technologies–in the form of software and internal and external hardware–that provide some form of “trust” for the applications. There is, however, general consensus that software-based roots of trust are significantly less resilient than hardware-based solutions. For widespread industry adoption that balances reasonable cost and a quality user experience an integrated hardware solution that is a part of the motherboard and that has antitampering characteristics is ideal. A standardized implementation is, clearly, very important.

There are significant software product and service opportunities that require such hardware-based security, but without being able to depend on either general presence or an adoptable standard, these features will either not be created at all or insecure software alternatives will be used with limited acceptance.

The Trusted Computing Group is a non-profit organization that was formed to develop, define, and help promote an open standard for a hardware-based root of trust that allowed for innovation, and it has met most if not all of the needs detailed earlier. Their most well-known result is the specification describing the TPM 1.2 chip.

At the highest level, the TPM is a microcontroller that stores keys, cryptographic hashes, and digital certificates. It can provide a unique public and private key pair, verify data integrity, and release keys dependent on an unchanged environmental state as well as offering other cryptographic services. Strong keys and secure decision making are fundamental to all security features. The TPM is the only standard hardware of its kind that is attachable to the motherboard.

image from book

As it stands in Windows Vista, the TPM is not exposed in a general-purpose fashion that can be used to take full advantage of the capabilities the TPM provides. Using the TPM’s ability to create and store cryptographic keys or perform cryptographic operations requires additional development effort.

Tip 

You can only successfully call TPM functionality from elevated processes.

What is exposed today in Windows Vista are WMI interfaces (Microsoft 2006f) to build TPM and BitLocker management tools. The following C# code shows how to query a TPM using WMI:

 using System.Management; static private ManagementObject m_wmiObject = null; static Boolean BooleanMethod(String method) {    ManagementBaseObject outParams = m_wmiObject.InvokeMethod(method, null, null);    return (0 == (UInt32)outParams["ReturnValue"]) ? false : true; } static void Main(string[] args) {    try    {        string tpm = "root\\cimv2\\security\\microsofttpm:Win32_Tpm=@";        m_wmiObject = new ManagementObject(tpm);        String version = m_wmiObject.GetPropertyValue("SpecVersion").ToString();        Boolean fEnabled = BooleanMethod("IsEnabled");        UInt32 id = (UInt32)m_wmiObject.GetPropertyValue("ManufacturerId");    }    catch (ManagementException me)    {        Console.WriteLine(me.Message);    } }

Here is something similar, but using VBScript:

 Set objWMIServices = GetObject("winmgmts:\\.\root\cimv2\Security\MicrosoftTpm") Set objWMIInstance = objWMIServices.Get("Win32_Tpm=@") If Err.Number<>0 Then   WScript.Echo "Cannot find a TPM in this PC."   Wscript.Quit End If WScript.Echo "TPM Found" WScript.Echo "TPM Enabled: " + CStr(objWMIInstance.IsEnabled) WScript.Echo "TPM Owned : " + CStr(objWMIInstance.IsOwned)

These WMI providers sit atop the Windows Vista TPM Base Services (TBS), which runs as a system service and exposes a small number of APIs (Microsoft 2006g) to software developers wanting to build TPM-aware applications.

Low-Level Access to the TPM

You can program directly to the TPM using the TBS APIs, or you can use a vendor-provided TCG Software Stack (TSS) (TCG 2006b) to make development easier. The TSS is an abstraction layer that makes writing to the TPM much simpler. The TBS in Windows Vista behaves like an “old-school” driver, and code written this way can be complicated and very time-consuming, as you will see in the next code sample. A TSS package helps by reducing the complexity of TPM commands and provides a much simpler API for a TPM application developer to use.

The following C++ example shows how to write to the TBS directly. This sample code gets the TPM version information and 32 random bytes.

 // returned data starts at byte 10 #define TPM_DATA_OFFSET 10 #ifdef _DEBUG // Display TPM data hex dump void TpmDisplayRawResult(      __in_bcount(cbResult) BYTE *pbResult,      UINT32 cbResult) {            if (!cbResult || !pbResult)       return;           if (cbResult >= TPM_DATA_OFFSET) {       wprintf(L"Tag : %02X %02X\n",         pbResult[0], pbResult[1]);       wprintf(L"Len : %02X %02X %02X %02X\n",         pbResult[2], pbResult[3], pbResult[4], pbResult[5]);       wprintf(L"Err : %02X %02X %02X %02X\n",         pbResult[6], pbResult[7], pbResult[8], pbResult[9]);       if (cbResult > TPM_DATA_OFFSET) {         wprintf(L"Data: ");         for (UINT32 i=TPM_DATA_OFFSET; i < cbResult-TPM_DATA_OFFSET; i++)          wprintf(L"%02X ",pbResult[i]);       wprintf(L"\n");       }    } } #endif #define MAX_RNG_BUFF 64 #define TPM_RNG_OFFSET 14 HRESULT TpmGetRandomData(        TBS_HCONTEXT hContext,        __inout_bcount(cData) BYTE *pData,        UINT32 cData) {            if (!hContext || !pData || !cData || cData > MAX_RNG_BUFF)            return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);    BYTE bCmd[] = {0x00, 0xc1,            // TPM_TAG_RQU_COMMAND                   0x00, 0x00, 0x00, 0x0e,        // blob length in bytes                   0x00, 0x00, 0x00, 0x46,        // TPM API code (TPM_ORD_GetRandom)                   0x00, 0x00, 0x00, (BYTE)cData};// # bytes    UINT32 cbCmd = sizeof bCmd;    BYTE bResult[128] = {0};    UINT32 cbResult = sizeof bResult;    HRESULT hr = Tbsip_Submit_Command(hContext,                 TBS_COMMAND_LOCALITY_ZERO,                 TBS_COMMAND_PRIORITY_NORMAL,                 bCmd,                 cbCmd,                 bResult,                 &cbResult);                     #ifdef _DEBUG       if (FAILED(hr))          wprintf(L"Tbsip_Submit_Command failed %X",hr);       else          TpmDisplayRawResult(bResult,cbResult);    #endif           if (SUCCEEDED(hr))           memcpy(pData,TPM_RNG_OFFSET+bResult,cData);       return hr;   } HRESULT TpmGetVersion(     TBS_HCONTEXT hContext,     __in_ecount(cVersion) wchar_t *wszVersion,     UINT32 cVersion) {          if (!hContext || !wszVersion || !cVersion)         return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);              BYTE bCmd[] = {0x00, 0xc1, // TPM_TAG_RQU_COMMAND                    0x00, 0x00, 0x00, 0x12, // blob length in bytes                    0x00, 0x00, 0x00, 0x65, // TPM API code (TPM_ORD_GetCapability)                    0x00, 0x00, 0x00, 0x06, // TCPA_CAP_VERSION                    0x00, 0x00, 0x00, 0x00};// no sub capability     UINT32 cbCmd = sizeof bCmd;     BYTE bResult[128] = {0};     UINT32 cbResult = sizeof bResult;     HRESULT hr = Tbsip_Submit_Command(hContext               TBS_COMMAND_LOCALITY_ZERO,               TBS_COMMAND_PRIORITY_NORMAL,               bCmd,               cbCmd,               bResult,               &cbResult);                #ifdef _DEBUG    if (FAILED(hr))       wprintf(L"Tbsip_Submit_Command failed %X",hr);    else       TpmDisplayRawResult(bResult,cbResult);    #endif     if (SUCCEEDED(hr))    swprintf_s(wszVersion,cVersion,L"TCG v%d.%d, Firmware v%d.%d",      (UINT32)bResult[14],      (UINT32)bResult[15],      (UINT32)bResult[16],      (UINT32)bResult[17]);    return hr; } int main(int argc, char* argv[]) {    argv;    argc;        // Create a TBS context    TBS_HCONTEXT hContext = 0;    TBS_CONTEXT_PARAMS contextParams = {0};    contextParams.version = TBS_CONTEXT_VERSION_ONE;    HRESULT hr = Tbsi_Context_Create(&contextParams, &hContext);    if (FAILED(hr))      return hr;    wchar_t wszVersion[32];    if (SUCCEEDED(TpmGetVersion(hContext,wszVersion,_countof(wszVersion))))      wprintf(L"%s\n",wszVersion);    BYTE buff[64];    UINT32 cBuff = sizeof buff;    if (SUCCEEDED(TpmGetRandomData(hContext,buff,cBuff)))       for (UINT32 i=0; i < cBuff; i++)          wprintf(L"%02X ",buff[i]);    if (hContext)       Tbsip_Context_Close(hContext);    return 0; }

When calling into the TBS, you must set up an input buffer that contains function arguments, pass that to the Tbsip_Submit_Command function, and then query the response buffer for status and results.

Note 

TBS functions that start with Tbsip result in a direct TPM call, and functions that start with Tbsi do not directly call the TPM.

The format of the input buffer is shown in Table 9-1.

Table 9-1: The TPM Input Buffer Format
Open table as spreadsheet

Data Size (bytes)

TPM Type

Comment

2

TPM_TAG

Packet type (e.g., a request, TPM_TAG_RQU_COMMAND, 0xC1)

4

UINT32

Total packet length in bytes

4

TPM_CMD_CODE

TPM command code (e.g., TPM_ORD_GetCapability, 0x65 or TPM_ORD_GetRandom, 0x46)

Variable

Often BYTE[] or UINT32

Arguments for the command

The format of the output buffer is shown in Table 9-2.

Table 9-2: The TPM Output Buffer Format
Open table as spreadsheet

Data Size (bytes)

TPM Type

Comment

2

TPM_TAG

Packet type (e.g., a response, TPM_TAG_RSP_COMMAND, 0xC4)

4

UINT32

Total packet length in bytes

4

TPM_RESULT

Error value.

Variable

Often BYTE[] or UINT32

Returned data from command.

The sample code shown earlier issues a TPM command to get TPM chip version information. To learn more about the different TPM commands and the in and out buffers, you should refer to the TCG documentation (TCG 2006c).

To summarize this TPM material, most software developers will not need to write any TPM-aware software because it’s very specialized; for those who need to create TPM-aware applications, though, you can use high-level WMI interfaces, a TCG Software Stack (TSS) ported to work with the TBS, or the low-level TPM Base Service function calls in Windows Vista.



Writing Secure Code for Windows Vista
Writing Secure Code for Windows Vista (Best Practices (Microsoft))
ISBN: 0735623937
EAN: 2147483647
Year: 2004
Pages: 122

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net