How to interact with a TPM?
Introduction
It’s important to keep in mind that a TPM is primarily a passive device. By “passive”, I mean that a TPM will never act on its own—it always responds to a request. This behavior could be compared to a REST API, for example. The specification1 defines a set of commands (a little over a hundred) that a TPM must support, along with the associated interface contract.
In the previous pill, we used the TPM2_GetCapability
command to display the TPM version. This command is very useful because it provides a set of information about a TPM (static data) and its current state (dynamic data). The two libraries (tpm2-tools and go-tpm) that we used did more or less the same thing:
- The library created the
TPM2_GetCapability
command in accordance with the specification - The command was sent to the TPM2
- The command was received and interpreted by the TPM
- The TPM produced a response in accordance with the specification
- The response was sent back to the client2
Local Access
The content below focuses on Linux.
Let’s take a closer look at the transmission part (steps 2 and 5), as this is a topic that’s often overlooked. The diagram above describes a somewhat simplistic interaction. In reality, a TPM client never has a direct connection to a TPM, which, let’s remember, is a physical device. It's the operating system that provides an interface to bridge the userspace and the hardware.
The device is usually named /dev/tpm0
.
As we saw in pill #1, a TPM is characterized by being resource-efficient, which is why it does not natively manage multi-tenancy when several applications need to communicate concurrently with it. To address this issue, the TCG produced a specification (TCG TSS 2.0 TAB and Resource Manager) describing how to implement this logic.
tpm2-abrmd
is an implementation of that spec.
Adding this functionality unfortunately requires installing an additional tool on your machine and maintaining it in an operational state. Fortunately for us, starting from kernel version 4.123, the Resource Manager is a service directly integrated into the OS—which greatly simplifies integration. In summary, if your application communicates with a TPM, it will generally follow the pattern below:
As you’ve noticed, the OS provides a new device named /dev/tpmrm0
. It is preferable to use it to take advantage of the features offered by the Resource Manager.
By default, the data flow is unencrypted; however, we’ll see in a dedicated pill how it is possible to encrypt it.
Limitations
In most distributions, the devices dedicated to the TPM are owned by the root
user.
Screenshot from a NixOS Laptop
This has significant implications, as it requires your application to be run with root privileges—an unacceptable situation in many contexts (e.g., general public usage). By comparison, a Yubikey will ask the user to enter a PIN or press the device to unlock access to keys, without the underlying driver requiring root
privileges. The concept of authorization exists on a TPM, so there’s fundamentally nothing preventing a rootless approach.
Unfortunately, there is no consensus on the subject that would allow all applications to communicate with a TPM in a rootless manner. As of now, the hack consists of requiring the user to install tpm2-tss
in order to benefit from its udev rules, which have become a sort of unofficial standard. Admittedly, this method is not ideal, for two reasons:
- It installs a binary that might not even be used
tpm2-tss
is not necessarily packaged on all distributions
Nevertheless, it allows you to achieve the following result:
Screenshot from a NixOS Laptop
Note: in the different labs, we won’t be affected by this issue, as we’ll be using a Software TPM.
What about Windows?
Since Windows 8 and Windows Server 2012, the operating system includes TBS (TPM Base Services), which is an interface that centralizes access to the TPM through RPC calls4. The following illustration shows the relationship between TBS and the TPM:
source: https://learn.microsoft.com/en-us/windows/win32/devio/tpm-base-services
For security reasons, TBS only accepts calls originating from the host machine.
Remote Access
We’ve seen how to interact with a TPM locally, but is it possible to do so remotely? The answer is yes. tpm2-tss
implements a number of drivers5 that enable remote access. There are two approaches—either via SSH access or via a TCP socket.
As an example, the TCP approach is the one used by many simulators such as:
The most important thing is to remember that this type of access exists. If your context requires it, keep in mind that establishing an encrypted channel is a prerequisite to prevent any man-in-the-middle attacks.
Bonus: an exotic TPM
It’s worth knowing that a TPM can also be located outside of a machine, for example... on a USB stick! That’s the rather wild idea proposed by LetsTrust-TPM2Go, offering a portable TPM.
Technically, this is a TPM that responds to SPI (Serial Peripheral Interface) inputs; then, libusb is used to connect the USB device with the host.
source: https://github.com/tpm2-software/tpm2-tss/blob/master/doc/tcti.md#tcti-spi-ltt2go
Conclusion
In this pill, we’ve seen how we can interact with a TPM and, most importantly, the wide range of methods available to us—whether for local or remote access.
Next pill...
...we will create our first key and discover how the TPM manages such resources.
🚧 TPM Pills
is in beta 🚧
- if you encounter problems 🙏 please report them on the tpm-pills issue tracker
- if you think that
TPM Pills
should cover a specific topic which isn't in the roadmap, let's initiate a discussion 💬