How to enable both secure boot and LUKS with TPM

Secure Boot and LUKS TPM

Prepare

Install all packages we need

1
yay -S sbctl tpm2-tss tpm2-tools

follow this guideline , generate Machine Own Key and enroll it into the EFI variables.

Install bootloader

this section changes bootloader from grub to systemd-boot, because grub has not support to LUKSv2.

Change esp partition mount point from /boot/efi to /efi permanently. If the esp mount point remains unchanged, grub packages should be removed.

1
2
3
4
umount /boot/efi
sudo mkdir -p /efi
sudo sed -i 's/\/boot\/efi/\/efi/g' /etc/fstab
mount -a

Delete old boot entry and install new bootloader

1
2
3
OLD_MANJARO="$(efibootmgr | grep "manjaro" | cut -d' ' -f1 | cut -c 5-8)" # Manjaro is old boot entry name
efibootgmr -b "${OLD_MANJARO}" -B # delete old boot entry
bootctl install && systemctl enable systemd-boot-update.service # install systemd-boot

After installation, it should be a new boot entry "Linux Boot Manager" appeared in the UEFI boot menu.

Open /boot/efi/loader/loader.conf and add there default @saved. This will make systemd-boot select your previously booted kernel by default. Another useful change is setting timeout to 1 or 2, most likely that’s long enough period to see bootloader’s menu and stop countdown if needed.

Configure initramfs

mkinitcpio.conf

Replace HOOKS array in /etc/mkinitcpio.conf and save old ones commented in the end of the file just in case:

1
2
OLD_HOOKS=$(cat /etc/mkinitcpio.conf | grep "^HOOKS=(")
sed -i 's|'"${OLD_HOOKS}"'|HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole sd-encrypt block filesystems fsck)|' /etc/mkinitcpio.conf && echo '#previous_'$OLD_HOOKS |tee -a /etc/mkinitcpio.conf

Also for better (de)compression speed/efficiency ratio consider setting COMPRESSION="zstd" in your /etc/mkinitcpio.conf if not set already. Note though that this works only starting from linux 5.10.

crypttab.initramfs

Do the following to add entry about LUKS partition to crypttab.initramfs

1
2
UUID=$(sudo blkid -s UUID -o value /dev/nvme0n1p5)
sudo echo luks-$UUID UUID=$UUID none tpm2-device=auto > /etc/crypttab.initramfs

cmdline

Create cmdline with the current boot parameters of the system

Optionally, /etc/cmdline.d can be used for more flexible configuration.

1
cat /proc/cmdline > /etc/kernel/cmdline

linux.preset

Open preset file for the current kernel in /etc/mkinitcpio.d, such as linux66.preset.

Make changes following line :

  • uncomment default_uki fallback_uki default_options
  • comment default_image fallback_image
  • make sure the appropriate mount point of the esp in the uki path

build UKI

1
sudo mkinitcpio -P

After building, there should be several UKI images in /boot/efi/EFI/Linux. Optionally, we can remove old images unused under /boot.

1
sudo rm /boot/initramfs*

if warning about consolefont appears during build process, create vconsole.conf and build again.

1
echo "KEYMAP=us\nFONT=tcvn8x16" > /etc/vconsole.conf

Secure Boot

sbctl is a tool that generates signed and thus trusted images used to boot system.

Create a new script sbsign-all.

1
vim ./sbsign-all

Write following code in this script and save

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env bash

efidir="/boot/efi"

# UKI sign
for file in ${efidir}/EFI/Linux/*.efi; do /usr/bin/sbctl sign -s $file; done

# system-boot sign
/usr/bin/sbctl sign -s -o /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed /usr/lib/systemd/boot/efi/systemd-bootx64.efi

# kernel sign
for file in /boot/vmlinuz*; do /usr/bin/sbctl sign -s $file; done

change permission for excutation

1
sudo chmod a+x ./sbsign-all

then run the script.

1
sudo ./sbsign-all

Benefit from mkinitcpio hook and pacman hook, the sign process will run automatically when system upgrade or modified.

After all steps above, reboot and enter UEFI setup menu, set Secure Boot ON, exit saving setting, check if the system can boot normally.

Unlock LUKS via TPM

The manjaro installation use LUKSv1 for the default crypt solution, but our plan only support LUKSv2. So we need convert LUKS before configuring TPM.

Insert the manjaro installation U-disk into the computer, enter live CD environment. if it is prohibited by secure policy, disable secure boot mode temporarily.

Open a terminal, run following command.

1
sudo cryptsetup convert --type luks2 /dev/nvme0n1p5

reboot and enable secure boot mode again.

Before sealing LUKS key into TPM, check command bootctl, following condition should be satisfied:

  • system booted by systemd-boot bootloader

  • system booted in secure boot mode

If the conditions are satisfied, check the cryptsetup status:

1
sudo cryptsetup luksDump /dev/nvme0n1p5

Normally it should have 1 or 2 keyslots already occupied, the first one is passphrase we set, the other is probably /crypto_keyfile.bin, and no tokens in place (yet). we suggest remove slot 1 if it’s occupied by crypto_keyfile at the moment (since it’s not safe to use crypto_keyfile in configuration we’re building).

1
2
sudo cryptsetup luksKillSlot /dev/nvme0n1p5 1
sudo rm /crypto_keyfile.bin

Then seal the LUKS key into TPM with PCR 7

1
sudo systemd-cryptenroll /dev/nvme0n1p5 --tpm2-device=auto --tpm2-pcrs=7

References

  1. https://forum.manjaro.org/t/howto-using-secure-boot-and-tpm2-to-unlock-luks-partition-on-boot/101626
  2. https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#
  3. https://wiki.archlinux.org/title/Unified_kernel_image
  4. https://wiki.archlinux.org/title/Trusted_Platform_Module
  5. https://wiki.archlinux.org/title/Systemd-cryptenroll#Trusted_Platform_Module
  6. https://wiki.archlinux.org/title/Dm-crypt/System_configuration#Using_systemd-cryptsetup-generator
  7. https://wiki.archlinux.org/title/Dm-crypt/System_configuration#Examples
  8. https://wiki.archlinux.org/title/Dm-crypt/System_configuration#Trusted_Platform_Module_and_FIDO2_keys