UEFI Secure Boot and the TPM: Implementing Secure Boot with a TPM
KentYoder 270001NFM8 Visits (11204)
Last time I went through a comparison of UEFI Secure Boot and the root of trust you can construct using a TPM. There are various trade-offs in using UEFI Secure Boot versus a TPM-based trusted boot, one of which was this:
"If a signature verify fails during a UEFI secure boot, the boot process stops."
This isn't necessarily the case with a trusted boot -- but what if that's a feature you want? First, a little background:
As a machine executes a TPM-based trusted boot, it creates a cryptographic digest and sends it to the TPM where its appended to a chain. There are actually 24 different chains to choose from in a 1.2 TPM, although not all of them can be used all the time. Some are for debug purposes and others are deliberately made unusable except from code executing at a different privilege level. The TPM term used for the storage space for each of these chains is PCR, or Platform Configuration Register. You can think of a PCR as a single trust chain used for some specific purpose.
So here's how you might implement secure boot using a TPM. The properties of the boot that you'd like to mimic are:
1. Verify a signed BIOS, boot loader and kernel as we boot
2. Halt boot if any signature verification check fails
Since the TPM is never in direct control of the boot process, we'll need a way to "fail" the boot in case a signature fails. One way to do this is to encrypt each piece of the boot code with a key that's only available when your chain of trust is as expected. We can do this with a TPM. If the PCR value doesn't match the trusted state for a segment of the boot, the TPM will deny you the ability to use these keys, and the boot process must stop (since we can't decrypt the next thing we're booting). Notice that the signature check in UEFI secure boot is carried out by the TPM here at the point you request the key from it. And instead of attaching the signature to the image itself as in UEFI secure boot, the signature is bound to the key as its stored in the TPM.
So how would you set this up? The first step for this kind of configuration would be to digest your BIOS, bootloader and kernel, to calculate what your chain of trust would look like at each step (after the BIOS has run, after the boot loader has run, etc). Next, generate 2 symmetric keys and store them in the TPM, bound to the digests of the boot loader and kernel as they appear in the chain. Then encrypt your boot loader with one key and the kernel with the other. The boot process would look something like this:
1. The BIOS would hash itself and send that digest to a TPM PCR.
2. The BIOS retrieves the first key from the TPM. If the TPM PCR doesn't have the expected value, the key retrieval fails and the machine is halted.
3. Decrypt the boot loader using the first key. Digest the bootloader code and send the digest to the same TPM PCR. Transfer execution to the bootloader.
4. Retrieve the second key from the TPM. If the TPM PCR doesn't have the expected value, the key retrieval fails and the machine is halted.
5. Decrypt the kernel using the second key. Transfer execution to the kernel.
I've simplified a few details here, but the overall idea is hopefully clear enough. If you'd like to dig into some real world examples with source code, tpm-luks can be used to store a LUKS key in the TPM, and you can optionally tie that key to TPM PCR values. Anti evil maid accomplishes the same thing, using slightly different methods.