A Practical Guide to Trusted Computing: Writing a TPM Device Driver
The Trusted Platform Module (TPM) is in essence a passive storage device that is hard mounted on the motherboard. The TPM is attached to the Low Pin Count (LPC) bus, a low-pin count bus, which is also used for attaching the system BIOS Flash memory. This ensures that the TPM device is available during the early system bootstrap before any other device is initialized.
Communication with the TPM is typically handled by the TCG device driver library (TDDL), and its interface is defined by the TSS (TCG Software Stack) specification. This library typically communicates with a device driver inside the kernel, and this device driver communicates with the actual TPM device.
There are currently two different TPM device programming interfaces. The TPM 1.1b-compliant devices use a device interface that is vendor specific. Because of the lack of a standardized device interface, each vendor is forced to define its own interface. This interface is typically very simple because the TPM 1.1b specification places only modest requirement on the device interface. To curtail the myriad of incompatible device interfaces, TCG decided to standardize the PC client interface as part of its 1.2 TPM specification. This device interface supports dynamic root of trust and consequently requires a more sophisticated interface that supports locality and special LPC bus cycles.
In this chapter, we will examine how to write a TPM device driver. We start with the TDDL interface and illustrate how to program the TPM 1.1b and 1.2 low-level device interfaces to implement part of the TDDL interface. The code examples have been developed on Linux, but in the interest of staying operating system-neutral, we have removed all the Linux-specific device driver boilerplates. Instead we focused on the core device driver functions that are similar for any operating system.
In particular, this chapter covers the following:
- The TCG device driver library
- The 1.1 device driver interface
- The 1.2 device driver interface
- The device programming interface (both 1.1 and 1.2)
TCG Device Driver Library
The TDDL interface is the standard interface that applications use for communicating directly with the TPM. This interface is part of the TSS library and is in fact used by the TSS stack to talk to the TPM. Although this interface is available for use by applications, its direct use is typically best avoided. The TDDL interface is a single-threaded synchronous interface, and it assumes that all TPM commands are serialized by the caller of the interface. If this interface is used together with TSS library calls, then the results may be undefined.
For those applications that do need direct device access, the TDDL interface specification is listed next:
TSS_RESULT Tddli_Open( ); TSS_RESULT Tddli_Close( ); TSS_RESULT Tddli_Cancel( ); TSS_RESULT Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pCapBuf, UINT32* pCapBufLen); TSS_RESULT Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pSetCapBuf, UINT32 SetCapBufLen); TSS_RESULT Tddli_GetStatus(UINT32 ReqStatusType, UINT32* pStatus); TSS_RESULT Tddli_TransmitData(BYTE* pTransmitBuf, UINT32 TransmitBufLen, BYTE *pReceiveBuf, UINT32* pReceiveBufLen);
The TDDL interface is straightforward. It includes calls to open and close access to the TPM device, cancel any outstanding commands, get and set vendor-specific device capabilities, get the device status, and transmit a command blob to the TPM and receive a response. Unlike the actual device interfaces that are discussed later in the chapter, the TDDL interface is the same for TPMs that follow the 1.1b or the 1.2 specification.
In the next sections, we are going to examine how to implement the device driver equivalent of the Tddli_TransmitData function with a TPM 1.1b- and a TPM 1.2-compliant device.