This article assumes the reader already has a familiarity with the concepts of secureboot on Linux. If the reader doesn't, there are references at the bottom that should help.
For measurements to be at all meaningful, we first need to implement secureboot. In modern times, the easiest way to do this is via app-crypt/sbctl (Github). Firstly, ensure your system is in setup mode with secureboot off.
Next, generate your secureboot signing keys.
Created Owner UUID a9fbbdb7-a05f-48d5-b63a-08c5df45ee70 Creating secure boot keys...✔ Secure boot keys created!
Then, install them.
Enrolling keys to EFI variables...✔ Enrolled keys to the EFI variables!
In many cases, it's really this easy! In my experience, you will sometimes need to make some efivarfs files related to secureboot writable, but sbctl tends to give you easily understandable error messages for simple errors like this.
If you have option roms that need to be loaded (which is more and more the norm, especially with newer GPUs), you can easily tell sbctl to enroll the option ROM checksums into your secureboot db, too! If you don't and your GPU hardware does indeed require option ROMs to be loaded during boot, you will most likely end up with a computer that turns on but never outputs anything. You'll generally need to short your CMOS pins and try again.
sbctl finds the option ROMs via the TPM eventlog (TODO: find a way to check for option ROMs from TPM eventlog), then adds their checksums to the secureboot db, allowing them to pass verification for the purposes of secureboot.
sbctl enroll-keys --tpm-eventlog --yes-this-might-brick-my-machine
After multiple rounds of "boothole" vulnerabilities in GRUB, many people might not want a bootloader with such a large attack surface. I use systemd-boot, whose wiki page provides a great guide to installation and basic usage.
For the UEFI firmware to allow execution of the bootloader after secureboot is turned on, the systemd-boot .efi will need to be signed. Below I used the .efi exists at on my system, but the exact path may vary from system to system.
sbctl sign /boot/EFI/systemd/systemd-bootx64.efi
I use the Gentoo distribution kernels on my systems, which implicitly use the system's installkernel executable to install kernels. To comfortably install kernels for use with systemd-boot, we will want sys-kernel/installkernel-systemd-boot instead of the default sys-kernel/installkernel-gentoo. This way, kernels will be installed according to the layout that systemd-boot expects. We also need app-crypt/sbsigntools for dracut to automatically sign the UEFI image.
We will also want to provide a dracut configuration to generate a single .efi binary (aka a "unified EFI blob") of the kernel, initramfs, and command line (TODO: why's this important for measured boot?). Adjust the kernel command line and such as necessary.
hostonly=yes hostonly_cmdline=yes compress=lz4 show_modules=yes add_drivers+='lz4 tpm_crb' add_dracutmodules+=' tpm2-tss ' install_items+=" /usr/lib64/cryptsetup/libcryptsetup-token-systemd-tpm2.so " uefi=yes uefi_stub=/usr/lib/systemd/boot/efi/linuxx64.efi.stub uefi_secureboot_cert=/usr/share/secureboot/keys/db/db.pem uefi_secureboot_key=/usr/share/secureboot/keys/db/db.key kernel_cmdline=""
We will also need app-crypt/sbsigntools for dracut to be able to sign the image. Ideally, dracut would understand how to use sbctl to sign images, but it currently doesn't.
With this, and with USE=initramfs on your distribution kernel, we can finally install it. If it's already installed, we can simply reconfigure it.
emerge --config gentoo-kernel
At this point, we should hopefully be able to reboot, turn secureboot on, and successfully get back to our Gentoo installation.
Automatic LUKS root unlocking
First install app-crypt/tpm2-tools.
Add the LUKS Key
My system has one TPM device and the LUKS encrypted root is at /dev/nvme0n1p7. I used PCRS 0, 1, and 7, but adjust as necessary for your given system.
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0,1,7 /dev/nvme0n1p7
🔐 Please enter current passphrase for disk /dev/nvme0n1p7: (no echo)
Tell the initramfs
With the encrypted LUKS device's UUID as $UUID, a kernel command line like the following is necessary for the initramfs to automatically unlock the root partition at boot.