Protecting systems with the TPM
This article brought to you by LWN subscribers"TPM," said Matthew Garrett in his linux.conf.au 2016 talk, stands for "trusted platform module"; it is a tool that is meant to allow a system's owner to decide which software to trust. Some years ago, there was a lot of fear that the TPM would be used, instead, to take that decision away, to allow others to decide which software would be trusted to run on our systems; for that reason, some called "trusted computing" by the rather less complimentary name "treacherous computing." That scenario didn't come about, though, for a number of reasons, both technical and social. But we can still use the TPM for its original purpose; Matthew was there to talk about his work to bring about computing that we can trust.Subscribers to LWN.net made this article — and everything that surrounds it — possible. If you appreciate our content, please buy a subscription and make the next set of articles possible.
Verifying software integrity at boot time
The TPM is a 28-pin chip found in most desktop and server-class systems; it is offered by a number of manufacturers, and those offerings are all interchangeable. Most deployed TPMs adhere to the 1.2 standard, but 2.0 is out now and is quite different. Some TPMs are minimal in functionality and slow, while others are essentially ARM cores running at several hundred MHz. They feature a small amount of nonvolatile RAM storage; "small amount" meaning hundreds of bytes in this case. They can do some cryptographic operations, such as signing or encrypting data, but they do it quite slowly. Some operations can take multiple seconds; it would be almost as fast to do things by hand, Matthew said. In other words, the TPM is worse than the CPU in every single way, so why do manufacturers bother installing them in so many machines? Answering that question was the focus of much of the rest of the talk.
A core feature of a TPM is the platform configuration registers, or PCRs.
These are used to perform measurement of the bootstrap process, where
"measurement" means verification of the software that is run. The TPM
cannot do this work on its own, though, since it is unable to perform DMA
or to ask the operating system to perform actions on its behalf. So the
bootstrap code must feed
data to the TPM by way of explicit "extend" operations on the PCRs.
An interesting feature of the PCRs is that their value cannot be set directly (other than initializing them to zero when the system resets). Instead, they support an "extend" operation that calculates a cryptographic hash of a PCR's current state combined with the new data and uses the result as the new value. More precisely, the extend operation appends the new data to the 20-byte value already stored in the PCR, performs a hash of the 40-byte result, and stores the output of the hash back into the PCR. TPM 1.2 uses SHA1; version 2.0 moves on to more secure hashing algorithms.
In a typical trusted boot, things start at power-on time, when the special "management engine" starts running within the CPU. It measures the first-stage firmware by reading and hashing the binary code, using the result to extend the first PCR. Each subsequent stage of the process (second-stage firmware, option-card firmware, the bootloader) measures the stage to follow before executing it; by the time the kernel is measured and booted, the TPM will have a set of PCRs describing the software that has run so far. If those PCRs do not contain the expected values, then somebody has tampered with something somewhere in the process and the system cannot be trusted.
Quotes, sealing, and more
The TPM is not able to block the bootstrap process if the PCRs do not end up with the expected values; somebody must ask it whether all is well or not. The TPM is a device, accessed via a device driver, so any process wanting to query the TPM must do so by way of the kernel. There is an obvious potential problem here: if the kernel has been corrupted, it can lie about the values stored in the PCRs, thus defeating the entire measurement process.
The designers of the TPM specification have thought about this particular problem, though; the result is the remote attestation mechanism. The TPM supports a "quote" operation, which provides a list of current PCR values signed by a private key hidden within the device. This operation also includes a nonce value provided with the request, preventing quotes from being reused by hostile software. A system wanting to verify a quote can verify the signature using a well-known public key and ensure that the nonce matches what it provided; if things check out, then the PCR values can be trusted as having been provided by the TPM.
This quote can be passed back to a remote attestation server, which can check the PCR values and be sure that your machine is running trusted software. This works well for granting (or denying) access to the network or some other resource, but it is rather less helpful for a user trying to decide whether they can trust their own system. That's because answering that question requires asking the remote-attestation server — by sending it packets through the kernel. Once again, a malicious kernel is in a position to lie to the user.
There is some help for this problem as well, based on the TPM's ability to encrypt data. In particular, it can "seal" data, which cannot subsequently be decrypted unless the PCRs contain the expected values. So the solution is to encrypt the disk and seal the key with the TPM. If the system has been tampered with, the PCR values will not match, the disk cannot be decrypted, and the system will fail to boot. If it boots successfully, the software has not been messed with.
This kind of encryption will protect the contents of the disk if somebody removes it from the laptop, but is not helpful if somebody steals the whole box. The obvious answer is to add a passphrase to the bootstrap process, but that just leads to another question: how does the user know that the passphrase prompt is legitimate? An attacker (of the evil maid variety, perhaps) could install malware that would put up a fake password prompt, then fake a crash and reboot. Matthew noted that few of us would be seriously surprised by a crash-and-reboot cycle; we are, he said, not very good at doing computers in general.
One possible anti-evil-maid tactic would be to have the TPM encrypt a secret (a phrase, perhaps) and display it at boot time; if the phrase shows up, the user knows that the software running up to that point has not been modified. But an attacker could simply observe the phrase and replicate it. That problem could be addressed by putting the encrypted phrase onto a USB stick and booting from it anytime the system has been out of the user's control. This tactic requires discipline, though; the user has to remember to use it whenever there might be trouble.
A promising alternative (also described here) is to encrypt a time-based one-time password (TOTP) seed and seal that; the seed would also be put onto a second device (a smartphone, for example). When the system boots, it decrypts the seed, calculates the current one-time password, and displays it on the screen. That value should match what is shown on the second device. If the two numbers match, the system has not been changed. Either that, Matthew said, or both devices have been tampered with; it would be a good idea to not leave them both unattended in the same place.
Other issues
All of this seems like a reasonable solution, but there are still a few potential issues worth pointing out. The point of this whole exercise is that, if somebody has modified the system, it will fail to boot. But there can be legitimate reasons to modify the system, including installing a new bootloader or kernel, firmware upgrades, and more. Supporting upgrades is "awkward." Beyond that, once the TPM has decrypted the disk-encryption key, that key will be sitting in RAM where a hostile device could copy it via a DMA operation. An I/O memory management unit (IOMMU) can address that threat, but it must be enabled to do so; most distributions leave the IOMMU turned off, since it has an unpleasant habit of breaking Intel graphics.
Then there is the issue of the management engine. It runs before the CPU starts and performs the initial firmware verification. If the management engine can be made to run arbitrary code, the whole chain of trust fails before it even starts. This processor runs encrypted code that cannot be audited, so, Matthew said, he has no idea how secure it really is.
What about after the kernel boots? Modified user-space software can be just as bad. That's where the kernel's integrity measurement architecture comes into play. Every binary run by the system can be measured, with the resulting value used to extend a PCR; that PCR can then be used to verify that the binaries have not been modified. The only problem is that getting to a specific PCR value not only requires that a specific set of binaries is run; it also requires that they are run in a specific order. Guaranteeing that order during the bootstrap process is not easy. Working around that problem is a matter of obtaining the "event log" from the TPM; this log contains a record of each individual measurement event. Interested code can examine the log, verifying the trustworthiness of each individual binary that has been run.
Going one step further and measuring containers is really just a matter of measuring their disk images. This, too, can produce an event log, yielding a list of every container that has been launched. If a specific container turns out to be hostile (or to contain a bad vulnerability), it is possible to determine which systems it has run on. The just-announced Rkt 1.0 release has the ability to do this kind of measurement.
For those interested in the code: Rkt is available on this page. Matthew has put up code for shim (for the bootstrap process) and for GRUB. His tpmtotp repository has code to make the one-time password checks work. Much of this code will eventually go upstream to the relevant projects but, for now, it must be obtained separately.
An audience member asked about what pieces are missing still; Matthew replied that there is currently no way to measure the firmware running in the disk drive (or other peripherals). A hostile drive could provide correct code for a critical binary once to pass the IMA test, then provide corrupt code thereafter. We need, he said, a way for users to verify that the rest of the platform is also trustworthy.
When asked about the trustworthiness of the TPM himself, Matthew said that he hasn't really looked into it; he is afraid of what might happen. He knows of nobody who has tried to do any sort of serious fuzz-testing of TPM chips. There is, he said, a push to move TPM functionality into the firmware, running it on the management engine; that would allow manufacturers to remove the separate TPM chip from the board. If that were done, though, any flaws in the TPM implementation might enable code to be executed on the management engine itself — not a pleasing prospect.
The video for this talk is available on the LCA site.
[Your editor thanks LCA for assisting with his travel expenses.]
| Index entries for this article | |
|---|---|
| Conference | linux.conf.au/2016 |
