Next: , Previous: , Up: Security   [Contents][Index]


19.8 TPM2 key protector in GRUB

TPM2 key protector extends measured boot to unlock the encrypted partition without user intervention. It uses the TPM Storage Root Key (SRK) to seal the disk key with a given set of PCR values. If the system state matches, i.e. PCR values match the sealed PCR set, TPM2 key protector unseals the disk key for cryptomount (see cryptomount) to unlock the encrypted partition. In case the unsealed key fails to unlock the partition, cryptomount falls back to the passphrase prompt.

Please note that TPM2 key protector uses the SRK in the owner hierarchy without authorization. If the owner hierarchy is password-protected, TPM2 key protector may fail to unseal the key due to the absence of the password. For the systems that already enable the password protection for the owner hierarchy, the following command removes the password protection with the existing password.

# tpm2_changeauth -c owner -p password

There are two supported modes to store the sealed key, SRK and NV index. The details will be addressed in later sections.

TPM2 key protector is currently only supported on EFI and EMU platforms.

19.8.1 TPM PCR usage

Since TPM2 key protector relies on PCRs to check the system state, it is important to decide which PCRs to seal the key with. The following table lists uses of PCRs and the measured objects on EFI platforms.

PCRUsed byMeasured Objects
0FirmwareCore system firmware executable code
1FirmwareCore system firmware data/host platform configuration; typically contains serial and model numbers
2FirmwareExtended or pluggable executable code; includes option ROMs on pluggable hardware
3FirmwareExtended or pluggable firmware data; includes information about pluggable hardware
4FirmwareBoot loader and additional drivers; binaries and extensions loaded by the boot loader
5FirmwareGPT/Partition table
7FirmwareSecureBoot state
8GRUBCommands and kernel command line
9GRUBAll files read (including kernel image)
9Linux KernelAll passed initrds (when the new LOAD_FILE2 initrd protocol is used)
10Linux KernelProtection of the IMA measurement log
14shim“MOK” certificates and hashes

PCR 0, 2, 4, and 7 can be used to check the integrity of the firmware code and bootloaders. PCR 8 and 9 are useful to check the file and data processed by GRUB. PCRs 10, 11, 12, 13, and 15 are controlled by the operating system, so those PCRs are usually still in the initial state when GRUB is running.

In general, it is nice to include PCR 0, 2, 4, and 7 to ensure the integrity of the firmware and bootloaders. For PCR 8 and 9, a sophisticated tool is required to examine the GRUB configuration files and the files to be loaded to calculate the correct PCR values.

Please note that PCRs are sensitive to any change, so an update of a component could invalidate the sealed key, due to the so-called PCR brittleness. For the bootloader update, PCR 4 may be affected. This can be mitigated by extracting the events from the TPM event log and predict the value with the updated bootloader binary. On the other hand, it is difficult to predict PCR 0~7 after a firmware update since the content of the code and the order of drivers may not follow the TPM event log from the previous firmware version, so it is necessary to reboot the system to update the measurement results of PCR 0~7 and seal or sign the sealed key again.

Reference: Linux TPM PCR Registry

19.8.2 Setting up the extra disk key

Instead of using the existing password, it is recommended to seal a new random disk key and use the existing password for recovery.

Here are the sample commands to create a 128 random bytes key file and enroll the key into the target partition (sda2).

# dd if=/dev/urandom of=luks.key bs=1 count=128
# cryptsetup luksAddKey /dev/sda2 luks.key --pbkdf=pbkdf2 --hash=sha512

19.8.3 SRK mode

To unlock the partition with SRK mode, assume that the sealed key is in (hd0,gpt1)/efi/grub/sealed.tpm, the following GRUB commands unseal the disk key with SRK mode and supply it to cryptomount.

grub> tpm2_key_protector_init -T (hd0,gpt1)/efi/grub/sealed.tpm
grub> cryptomount -u <UUID> -P tpm2

There are two programs to create the sealed key for SRK mode: grub-protect and pcr-oracle (https://github.com/okirch/pcr-oracle).

The following sample command uses grub-protect to seal the random key, luks.key, with PCR 0, 2, 4 and 7 in TPM 2.0 Key File format.

# grub-protect --action=add \
               --protector=tpm2 \
               --tpm2-pcrs=0,2,4,7 \
               --tpm2key \
               --tpm2-keyfile=luks.key \
               --tpm2-outfile=/boot/efi/efi/grub/sealed.tpm

grub-protect only seals the key with the current PCR values. Therefore, when a boot component, such as shim or GRUB, is updated, it is necessary to reboot the system to update the measurement results and seal the key again. That means the random disk key has to be stored in cleartext for the next key sealing. Besides this, the measurement result of some PCRs may differ between boot time and OS runtime. For example, PCR 9 measures the files loaded by GRUB including the Linux kernel and initrd. To unlock the disk containing the kernel and initrd, the key has to be sealed with PCR 9 value before loading the kernel and initrd. However, PCR 9 changes after GRUB loading the kernel and initrd, so PCR 9 at OS runtime cannot be used directly for key sealing.

To solve these problems, pcr-oracle takes a different approach. It reads the TPM eventlog and predicts the PCR values. Besides, pcr-oracle also supports “authorized policy” which allows the PCR policy to be updated with a valid signature, so that the user only seals the random disk key once. If at some later time the PCR values change due to an update of the system firmware, bootloader, or config file, the user just needs to update the signature of the PCR policy.

To seal the key with the authorized policy, the first thing is to generate the RSA policy key, policy-key.pem, and the authorized policy file, authorized.policy. In this example, PCR 0, 2, 4, 7 and 9 are chosen for key sealing.

# pcr-oracle --rsa-generate-key \
             --private-key policy-key.pem \
             --auth authorized.policy \
             create-authorized-policy 0,2,4,7,9

Then, we seal the random disk key, luks.key, with the authorized policy file and save the sealed key in sealed.key.

# pcr-oracle --key-format tpm2.0 \
             --auth authorized.policy \
             --input luks.key \
             --output sealed.key \
             seal-secret

Since we now have the sealed key, we can remove the random disk key file luks.key.

The last step is to sign the predicted PCR policy and save the final key file, sealed.tpm.

# pcr-oracle --key-format tpm2.0 \
             --private-key policy-key.pem \
             --from eventlog \
             --stop-event "grub-file=grub.cfg" \
             --after \
             --input sealed.key \
             --output /boot/efi/efi/grub/sealed.tpm \
             sign 0,2,4,7,9

Here we also set a stop event for the prediction. With --stop-event grub-file=grub.cfg --after, pcr-oracle stops the calculation of PCR values right after GRUB loads grub.cfg.

When/After the shim or GRUB are updated, it only requires to run the last pcr-oracle command to update the predicted PCR policy.

19.8.4 NV index mode

Instead of storing the sealed key in a file, NV index mode uses the TPM non-volatile memory to store the sealed key and could be useful when accessing the file is not possible.

However, the Linux root user must be careful who she/he gives access to the TPM (tss group) since those users will also be able to modify the NV index that’s holding the key.

There are two types of TPM handles supported by NV index mode: persistent handle and NV index handle.

19.8.4.1 Persistent handle

The range of persistent handles is from 0x81000000 to 0x81FFFFFF. The persistent handle is designed to make TPM objects persistent through power cycles, and only TPM objects, such as RSA or EC keys, are accepted. Thus, only the raw format is supported by persistent handles. The following shows the grub-protect command to seal the disk key luks.key into the persistent handle 0x81000000 with the PCRs 0,2,4,7.

# grub-protect \
             --protector=tpm2 \
             --action=add \
             --tpm2-bank=sha256 \
             --tpm2-pcrs=0,2,4,7 \
             --tpm2-keyfile=luks.key \
             --tpm2-nvindex=0x81000000

To unseal the key, we have to specify the mode nv, the persistent handle 0x81000000, and the PCRs 0,2,4,7 for the tpm2_key_protector_init command.

grub> tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=0,2,4,7
grub> cryptomount -u <UUID> --protector tpm2

If the key in the persistent handle becomes unwanted, the following grub-protect command removes the specified persistent handle 0x81000000.

# grub-protect \
             --protector=tpm2 \
             --action=remove \
             --tpm2-evict \
             --tpm2-nvindex=0x81000000

19.8.4.2 NV index handle

The range of NV index handles is from 0x1000000 to 0x1FFFFFF. Unlike the persistent handle, the NV index handle allows user-defined data, so it can easily support both the TPM 2.0 Key File format as well as the raw format.

The following grub-protect command seals the disk key luks.key into the NV index handle 0x1000000 with the PCRs 0,2,4,7 while using the TPM 2.0 Key File format.

# grub-protect \
             --protector=tpm2 \
             --action=add \
             --tpm2key \
             --tpm2-bank=sha256 \
             --tpm2-pcrs=0,2,4,7 \
             --tpm2-keyfile=luks.key \
             --tpm2-nvindex=0x1000000

Furthermore, it is also possible to insert an existing key file, sealed.tpm, into a specific NV index handle using the following tpm2-tools (https://github.com/tpm2-software/tpm2-tools) commands.

# tpm2_nvdefine -C o \
             -a "ownerread|ownerwrite" \
             -s $(stat -c %s sealed.tpm) \
             0x1000000
# tpm2_nvwrite -C o -i sealed.tpm 0x1000000

When unsealing the key in TPM 2.0 Key File format, only the mode nv and the NV index handle 0x1000000 have to be specified for the tpm2_key_protector_init command.

grub> tpm2_key_protector_init --mode=nv --nvindex=0x1000000
grub> cryptomount -u <UUID> --protector tpm2

The following grub-protect command allows to remove the specified NV index handle 0x1000000.

# grub-protect \
             --protector=tpm2 \
             --action=remove \
             --tpm2-evict \
             --tpm2-nvindex=0x1000000

19.8.5 Setting up software TPM for EMU platform

In order to test TPM2 key protector and TPM2 Software Stack (TSS2), it is useful to set up a software TPM (swtpm) instance and run the commands on the EMU platform.

Here are the commands to start a swtpm instance which provides a character device interface. To store the TPM states, the directory, swtpm-state, is created before the swtpm command. All the messages are stored in swtpm.log including the name of the character device.

# mkdir swtpm-state
# swtpm chardev --vtpm-proxy --tpmstate dir=swtpm-state \
        --tpm2 --ctrl type=unixio,path="swtpm-state/ctrl" \
        --flags startup-clear --daemon > swtpm.log

Then, we extract the name of the character device from swtpm.log and save it to the variable, ‘tpm2dev’.

# tpm2dev=$(grep "New TPM device" swtpm.log | cut -d' ' -f 4)

Now we can start grub-emu with --tpm-device $tpm2dev to interact with the swtpm instance.

# grub-emu --tpm-device $tpm2dev

On the host, the tpm2-tools commands can interact with the swtpm instance by setting ‘TPM2TOOLS_TCTI’.

# export TPM2TOOLS_TCTI="device:$tpm2dev"

When the test is done, use swtpm_ioctl to send the shutdown command through the swtpm control channel.

# swtpm_ioctl -s --unix swtpm-state/ctrl

19.8.6 Command line and menuentry editor protection

The TPM key protector provides full disk encryption support on servers or virtual machine images, meanwhile keeping the boot process unattended. This prevents service disruptions by eliminating the need for manual password input during startup, improving system uptime and continuity. It is achieved by TPM, which verifies the integrity of boot components by checking cryptographic hashes against securely stored values, to confirm the disks are unlocked in a trusted state.

However, for users to access the system interactively, some form of authentication is still required, as the disks are not unlocked by an authorized user. This raised concerns about using an unprotected ‘command-line interface’ (see The flexible command-line interface), as anyone could execute commands to access decrypted data. To address this issue, the LUKS password is used to ensure that only authorized users are granted access to the interface. Additionally, the ‘menu entry editor’ (see Editing a menu entry) is also safeguarded by the LUKS password, as modifying a boot entry is effectively the same as altering the grub.cfg file read from encrypted files.

It is worth mentioning that the built-in password support, as described in ‘Authentication and Authorization in GRUB’ (see Authentication and authorisation in GRUB), can also be used to protect the command-line interface from unauthorized access. However, it is not recommended to rely on this approach as it is an optional step. Setting it up requires additional manual intervention, which increases the risk of password leakage during the process. Moreover, the superuser list must be well maintained, and the password used cannot be synchronized with LUKS key rotation.


Next: Signing certificate and hash files, Previous: Lockdown when booting on a secure setup, Up: Security   [Contents][Index]