Secure Boot with Debian Testing

I’m running Debian 8 (Jessie). A while ago I came across Greg Kroah-Hartman’s post about getting a self-signed kernel image working. I’ve been trying to get it to work on and off for a while now. Yesterday I finally got it working, so I thought I’d write down the process before I forget.

So first the details of my setup:

Dell XPS 12

Debian 8 (Jessie)

dm-crypt full disk encryption

systemd

I’ll try and explain what the usual proceedure should be, as well as where mine diverged from the extant tutorials and documentation. I’ve decided that I trust Debian’s kernels, so I’m not compiling from source. This will not work if you boot using legacy mode. You have to be using UEFI to boot your install.

Post-install

I selected full disk encryption during Debian’s installation. Once it was all done I installed systemd according to the Debian wiki. It boils down to:

sudo apt-get install systemd systemd-sysv

You may also want to add init=/lib/systemd/systemd to your kernel commandline in grub.

Bootloader

Once you’re done with the OS installation and any init shenanegans you should have a system that boots using GRUB. We’re going to switch to the EFI Stub bootloader that exists within the Linux kernel. That way your computer goes straight from UEFI to the kernel with no intermediaries. This section is based on the EFI Stub page on the Debian Wiki.

Switching to EFI Stub

First we need to move the kernel and initrd to the EFI boot partition which is normally mounted at /boot/efi. To automate this process create a file at /etc/kernel/postinst.d/zz-update-efistub with the following contents (from the Bit Binary wiki):

#!/bin/bash VMLINUZ=false INITRD=false if [ -L /vmlinuz ] ; then VMLINUZ=/vmlinuz elif [ -L /vmlinuz.old ] ; then VMLINUZ=/vmlinuz.old fi if [ -L /initrd.img ] ; then INITRD=/initrd.img elif [ -L /initrd.img.old ] ; then INITRD=/initrd.img.old fi if [ "${VMLINUZ}" == "false" ] ; then echo "Symlink for vmlinuz not found" exit 1 fi if [ "${INITRD}" == "false" ] ; then echo "Symlink for initrd not found" exit 1 fi CPEXIT=0 cp ${VMLINUZ} /boot/efi/EFI/debian/vmlinuz || { echo "Failed to copy ${VMLINUZ} to ESP" ; CPEXIT=1 ; } cp ${INITRD} /boot/efi/EFI/debian/initrd || { echo "Failed to copy ${INITRD} to ESP" ; CPEXIT=1 ; } exit $CPEXIT

Note: The Debian wiki assumes the initrd file is initrd. On my system it was called initrd.img.

Make the file executable, and link the script to initramfs updates as well.

chmod +x /etc/kernel/postinst.d/zz-update-efistub mkdir -p /etc/initramfs/post-update.d sudo ln -s /etc/kernel/postinst.d/zz-update-efistub /etc/initramfs/post-update.d/zz-update-efistub

Then run the script:

sudo /etc/kernel/postinst.d/zz-update-efistub

This should copy both the kernel and initrd into correct places. The script will ensure that after a kernel update the new files are copied over automatically.

Adding a UEFI boot entry

To get EFI Stub booting working we need to add an entry to our UEFI. To do this we use a tool called efibootmgr:

sudo apt-get install efibootmgr

Once efibootmgr is installed, you can check what your current EFI entries are:

sudo efibootmgr

or for a more detailed view:

sudo efibootmgr -v

You should be able to see at least the entry for GRUB, which is best to leave alone until everything is working (I still hold on to grub as a backup). To add a new entry for EFI Stub execute the following:

sudo efibootmgr -c -g -L "Debian (EFIStub)" -l '\EFI\debian\vmlinuz' -u root=UUID=<UUID of root partition> ro quiet rootfstype=ext4 add_efi_memmap initrd=\\EFI\\debian\\initrd

To get the UUID of your disks use blkid:

blkid

Getting the right UUID caused a lot of frustration. If you are using dm-crypt (i.e. you selected disk encryption during installation) as well as LVM, then your UUID is in the line most similar to /dev/mapper/xxxY_crypt. If you are not sure, it might be worth creating several boot entries with different UUIDs. Just remember to change the labels to something more informative than “Debian (EFIStub)”.

It will probably take several attempts to get the command line right, so be prepared for some rebooting and tweaking. You can remove bad boot entries with

efibootmgr -b <Entry number> -B

I got some odd behaviour when I booted with EFI Stub. This was fixed by adding init=/lib/systemd/systemd to kernel command line. So my final command was:

sudo efibootmgr -c -g -L "Debian (EFIStub)" -l '\EFI\debian\vmlinuz' -u 'root=UUID=<UUID of root partition> ro quiet init=/lib/systemd/systemd rootfstype=ext4 add_efi_memmap initrd=\\EFI\\debian\\initrd'

Setting up Secure Boot keys:

For this section you will need the UEFI KeyTool USB image from here. dd the image to a USB stick:

sudo dd if=/path/to/sb-usb.img of=/dev/xxY bs=4M

You will also need the efitools package

sudo apt-get install efitools

Backup Secure Boot keys:

Shutdown and boot from the USB stick you just created. On my Dell XPS 12 you must press F12 during power on. I just hit the key repetitively until the boot menu comes, otherwise the Dell logo comes and goes too fast to hit the keys in time.

Select the USB key from the boot menu.

I got a UEFI shell. To open KeyTool just type:

KeyTool

This should provide you with a menu. Pick Save Keys and choose a place to save them. I just saved them to the UEFI tool USB stick.

Clearing the existing Secure Boot keys:

Once you are sure you have saved and backed up your original Secure Boot keys, reboot into the BIOS setup menu. On my laptop this involves pressing F2 during boot.

It took some digging to find how to delete my UEFI keys. I had to go into “Boot”, enable “Secure Boot”, set the Secure Boot mode to “Custom”, before I could navigate to an option that said something like “Delete all Secure Boot Keys”. I then saved and exited the BIOS with Secure Boot still enabled incase the keys were deleted once I saved rather than when I selected “Delete keys”. Next I booted back in to the BIOS to disable Secure Boot again (otherwise it isn’t possible to boot Debian).

Creating keys:

I followed the steps from Greg Kroah-Hartman’s post. Back in debian I executed the following to create the necessary keys:

openssl req -new -x509 -newkey rsa:2048 -subj "/CN=my PK name/" -keyout PK.key -out PK.crt -days 3650 -nodes -sha256 openssl req -new -x509 -newkey rsa:2048 -subj "/CN=my KEK name/" -keyout KK.key -out KK.crt -days 3650 -nodes -sha256 openssl req -new -x509 -newkey rsa:2048 -subj "/CN=my db name/" -keyout db.key -out db.crt -days 3650 -nodes -sha256

While it won’t affect the keys themselves, it is worth making sure the CN is a descriptive name.

You also need to generate a GUID:

python -c 'import uuid; print str(uuid.uuid1())' > GUID.txt; cat GUID.txt

You then need to create an EFI Signature list file

cert-to-efi-sig-list -g <generated GUID> PK.crt PK.esl

I also had to create esls for my db and KEK keys.

cert-to-efi-sig-list -g < generated GUID > KK.crt KK.esl cert-to-efi-sig-list -g < generated GUID > db.crt db.esl

Now you need to create a signed update file from you PK.esl file:

sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl PK.auth

Its time to copy PK.auth, PK.esl, KK.crt, KK.esl, db.crt, and db.esl onto the UEFI KeyTool USB key. The *.crt files are probably unnecessary, but I hate rebooting.

Make sure your original Secure Boot keys are backed up and safe.

Adding Keys to UEFI:

Boot into UEFI KeyTool USB and open up KeyTool. Add your KK and db files first. After that add your PK files. Reboot and enable secure boot. Now try to boot in to Debian. This should fail. Disable Secure Boot and reboot.

Signing the Kernel

To sign the kernel with your db key use the following command:

sbsign --key db.key --cert db.crt /boot/efi/EFI/debian/vmlinuz --output vmlinuz.signed

Then copy the signed kernel to your /boot/efi partition

s udo cp vmlinuz.signed /boot/efi/EFI/debian/

Finally add a new boot entry for your signed kernel:

sudo efibootmgr -c -g -L "Debian (ES) Secure" -l '\EFI\debian\vmlinuz.signed' -u 'root=UUID=<UUID> ro quiet rootfstype=ext4 add_efi_memmap initrd=\\EFI\\debian\\initrd'

Remeber to add init=/lib/systemd/systemd if you are using systemd.

Reboot and enable Secure Boot. You should now be able to boot your signed Debian kernel with Secure boot. I keep both GRUB and the non-secure EFI entry as safety nets for when I inevitably update my kernel and have to re-sign.

Sources/Further Reading:

http://kroah.com/log/blog/2013/09/02/booting-a-self-signed-linux-kernel/

http://blog.hansenpartnership.com/owning-your-windows-8-uefi-platform/

https://wiki.debian.org/EFIStub

http://wiki.bitbinary.com/index.php/Debian_Wheezy_EFI_Stub