rolling your own secure boot keys

ever wanted to have to manage an entire certificate chain to boot your computer? yeah, me too… here's how i did it

written
2025-10-02T20:46:00Z
last modified
2025-10-03T13:44:46Z
tags
link
back to home

rolling your own secure boot keys

we're going to be rolling our own, homemade, gluten free, blazingly secure boot keys with the goal of having a PCR 7 value that's not absolutely meaningless.

structure of secure boot keys

at the root of all, you have a Platform Key (PK). this is typically enrolled by the manufacturer (not OEM) themselves, and signs the Key Exchange Keys (KEKs) that are present on the machine.

KEKs are the keys that are allowed to add authorized or unauthorized signature lists (DBs and DBXes).

DBs are lists of certificate signatures that sign PE32(+) files to allow them to be executed.

i have not done enough research on DBXes but I assume they're there to prevent rollback attacks. SBAT and allat.

the first part of this post assumes you know basic bash and secure boot terminology, and the second part assumes that you know TPM terminology and use dracut. the distro doesn't matter (dracut works on most distros), but you do need dracut.

keep in mind that implementations often suck all this might be completely fucking useless for your specific usecase or hardware. secure boot does NOT prevent malicious images from being booted, but paired with a TPM module, allows you to hide secrets if that is the case. if you want to avoid rogue USB boot attacks, you'll need a BIOS password on a non–backdoored motherboard. well, at least one where the backdoor isn't public yet…

prequisites

generating the keys

we generate 4096–bit RSA keypairs here, which your bios might not support. consider replacing rsa:4096 with rsa:2048. additionally, efitools itself does not support ed25519. whatever you pick, your certificate must be in X.509 PEM format.

# generate the PK keypair
openssl req -nodes -new -x509 -sha256 -newkey rsa:4096 -keyout PK.key -outform DER -out PK.cer -subj "/CN=slonk PK/" -days 3650
# generate a KEK keypair
openssl req -nodes -new -x509 -sha256 -newkey rsa:4096 -keyout KEK.key -outform PEM -out KEK.crt -subj "/CN=slonk KEK/" -days 3650
# generate a secure boot signing key to be included in DB
openssl req -nodes -new -x509 -sha256 -newkey rsa:4096 -keyout db1.key -outform PEM -out db1.crt -subj "/CN=slonk SB signing key 1/" -days 3650
# generate a second secure boot signing key, just as an example
openssl req -nodes -new -x509 -sha256 -newkey rsa:4096 -keyout db2.key -outform PEM -out db2.crt -subj "/CN=slonk SB signing key 2/" -days 3650

make sure the Common Name (CN) field isn't too long. it errored out in a weird and freaky way when i tried to enroll it on my lenovo thinkpad e14 gen 6. help

we must then generate EFI Signature List (ESL) files for these keypairs

# generate a uuid to identify our ESLs
uuidgen -r >uuid # any other tool works
for crt in *.crt; do # for every .crt file,
  # generate a corresponding ESL
  cert-to-efi-sig-list -g "$(<uuid)" "$crt" "$(basename "$crt" .crt)".esl
done
# combine the DBs into one list
cat db*.esl > db.esl
# create an empty DBX
touch dbx.esl
# sign the ESLs
sign-efi-sig-list -k PK.key -c PK.crt PK PK.{esl,auth} # PK signs itself
sign-efi-sig-list -k PK.key -c PK.crt KEK KEK.{esl,auth} # …and the KEK
sign-efi-sig-list -k KEK.key -c KEK.crt db db.{esl,auth} # the KEK signs DBs
sign-efi-sig-list -k KEK.key -c KEK.crt dbx dbx.{esl,auth} # and DBXes

enrolling

ensure that Secure Boot is in Setup Mode. you will not be able to enroll platform keys otherwise. enrolling a PK exits Setup Mode, and all other ESLs must be signed to be enrolled once you're out of Setup Mode, except on Lenovo because fuck you i guess.

from the os

you can allegedly enroll unsigned ESLs as long as you do it before enrolling the PK. use -ef instead of -f for that.

# you won't believe what these commands do
sudo efi-updatevar -f KEK.auth KEK
sudo efi-updatevar -f db.auth db
sudo efi-updatevar -f dbx.auth dbx
sudo efi-updatevar -f PK.auth PK

from the bios

save the .auth files into an accessible, FAT-32 formatted partition somewhere. reboot into firmware setup, locate secure boot options, and read what's on the screen. actually, save every file except the private keys because some bioses are that dumb.

signing the boot chain (part 2)

you are responsible with signing the following parts of the boot chain

  1. bootloader (if you have one)
  2. UKI
  3. any out–of–tree kernel modules

yes, we will not be using shim for this. if you want to use shim anyways, go build it yourself.

bootloader

you'd want a setup like https://wiki.archlinux.org/title/Systemd-boot#Signing_for_Secure_Boot. here's a similar snippet for dnf4 using dnf-plugins-core:

/etc/dnf/plugins/post-transaction-actions.d/sign-sd-boot.action:

systemd-boot-unsigned:in:/usr/lib/systemd/systemd-sbsign sign --private-key /root/sb/my_db.key --certificate /root/sb/my_db.crt --output /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed /usr/lib/systemd/boot/efi/systemd-bootx64.efi

there seems to be no easy way to do it on dnf5. lmk if you find one. you can manually sign it with that command, and re–run bootctl install to install the signed version.

UKI

you'd want to configure dracut like this:

/etc/dracut.conf.d/uefi.conf

uefi=yes
uefi_secureboot_cert=/root/sb/my_db.crt
uefi_secureboot_key=/root/sb/my_db.key
# extra hardening to not make this all useless. consider `man 7 kernel_lockdown` as well
kernel_cmdline+=" ro rd.shell=0 rd.emergency=halt "

beware that on Fedora, the default kernel-install configuration sidesteps your dracut UKI configuration. to fix that, write an install.conf like so:

/etc/kernel/install.conf:

layout=uki
uki_generator=dracut

if you use kernel-install, the rd.luks.uuid, root, rootflags, ro, rhgb and quiet cmdline arguments get automatically appended to the bootloader configuration. if you do not fw this behavior, make sure to configure those cmdline arguments in dracut, and disable the automatic entry generation:

# install an empty override file for 90-loaderentry.install
sudo ln -sf /dev/null /etc/kernel/install.d/90-loaderentry.install

this has the upside of making kernel-install add-all and dracut -f --regenerate-all effectively do the same thing when using systemd-boot.

modules

only out-of-tree modules (proprietary drivers, stuff built with akmods/dkms, etc.) need to be signed for Secure Boot. unless you have an nvidia graphics card or use virtualbox, you probably won't need to do any of this.

akmods

sudo openssl x509 -in /root/sb/my_db.crt -outform DER -out /root/sb/my_db.der
sudo ln -sf /root/sb/my_db.der /etc/pki/akmods/certs/public_key.der
sudo ln -sf /root/sb/my_db.key /etc/pki/akmods/private/private_key.pem

dkms

https://wiki.archlinux.org/title/Signed_kernel_modules#Native_DKMS_method

sources