The Funtoo Linux project has transitioned to "Hobby Mode" and this wiki is now read-only.
Secure Boot
Introduction
This page describes how to set up secure boot on Funtoo Linux with and without GRUB 2, using genkernel and boot-update. The resulting secure boot chain is:
- The firmware (BIOS) setup is password protected
- The firmware has UEFI secure boot certificates installed, and you hold the corresponding private keys
- GRUB is signed by a key registered in the UEFI secure boot signature database
- The GRUB image has a public PGP key, for which you hold the private key
- GRUB config file, kernels and initramfs images are signed with the GRUB PGP key
- GRUB requires a password to do anything besides booting, e.g., to edit boot parameters or to use the command line
Many Linux secure boot guides on the Net recommend using Fedora's "shim" boot loader. I would not recommend it, for the following reasons:
- Shim only checks signatures of the boot loader and kernel, but not the GRUB config file or initramfs, which opens your machine to attacks
- At the time of writing (early 2019), GRUB's shim support (needed to check kernels) has been committed to the GRUB repository but is not yet in any released version
- I don't understand the point of MOKs and am not certain about their security model
That said, shim may be useful if your machine doesn't allow you to install your own secure boot certificates.
Prerequisites
This guide assumes that:
- your machine's firmware allows you to install your own secure boot certificates
- you have a working Funtoo installation
- you are using the GRUB 2 bootloader installed on the EFI boot partition
- the boot partition is mounted on
/boot
- the EFI boot partition is separate and is mounted on
/boot/efi
It is highly recommended that you use full disk encryption.
Generating and Installing Secure Boot Certificates
Enter the firmware setup utility and put secure boot in setup mode.
Install efitools
and sbsigntools
:
root # emerge -av app-crypt/efitools app-crypt/sbsigntools
Decide where you want to keep your keys. If you want to keep them on an eternal drive, be aware that gpg creates a socket for gpg-agent in its config directory, so it should reside on a filesystem that supports sockets (i.e., not FAT) and be mounted read-write for signing.
Save old secure boot certificates:
root # efi-readvar -v PK -o old_PK.esl root # efi-readvar -v KEK -o old_KEK.esl root # efi-readvar -v db -o old_db.esl root # efi-readvar -v dbx -o old_dbx.esl
Generate new certificates valid for 27 years:
root # openssl req -new -x509 -newkey rsa:2048 -subj "/CN=PK/" -keyout PK.key -out PK.crt -days 10000 -nodes -sha256 root # openssl req -new -x509 -newkey rsa:2048 -subj "/CN=KEK/" -keyout KEK.key -out KEK.crt -days 10000 -nodes -sha256 root # openssl req -new -x509 -newkey rsa:2048 -subj "/CN=db/" -keyout db.key -out db.crt -days 10000 -nodes -sha256
Prepare certificate lists:
root # cert-to-efi-sig-list PK.crt PK.esl root # cert-to-efi-sig-list KEK.crt KEK.esl root # cert-to-efi-sig-list db.crt db.esl
If you want to dual boot preinstalled OSes, add old KEK and db certificates to the new lists:
root # cat old_KEK.esl >>KEK.esl root # cat old_db.esl >>db.esl
Sign the certificate lists:
root # sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl PK.auth root # sign-efi-sig-list -k PK.key -c PK.crt KEK KEK.esl KEK.auth root # sign-efi-sig-list -k KEK.key -c KEK.crt db db.esl db.auth root # sign-efi-sig-list -k KEK.key -c KEK.crt dbx old_dbx.esl old_dbx.auth
Remount the efivars
partition read-write:
root # mount -o remount,rw /sys/firmware/efi/efivars
Install the certificates into EFI:
root # efi-updatevar -f old_dbx.esl dbx root # efi-updatevar -f db.auth db root # efi-updatevar -f KEK.auth KEK root # efi-updatevar -f PK.auth PK
Create a Rescue Kernel (Optional)
Before you start playing with GRUB, it's a good idea to prepare a kernel that is bootable directly from EFI.
Enable the following kernel configuration variables:
CONFIG_EFI_STUB=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="..."
CONFIG_CMDLINE_OVERRIDE=y
CONFIG_FB_SIMPLE=y
Under Processor type and features:
[*] EFI runtime service support [*] EFI stub support [*] Built-in kernel command line (...) Built-in kernel command string [*] Built-in command line overrides boot loader arguments
Set the value of Built-in kernel command string
to the current kernel command line (from /proc/cmdline
), but delete the rand_id
parameter. (After you run boot-update
, the random id for the new kernel will appear in /etc/boot.d/config/kernel/random.map
.)
Under Device Drivers-->Graphics support-->Frame buffer Devices-->Support for frame buffer devices:
[*] Simple framebuffer support
If you have early microcode, extract it to a temporary location:
root # mount /boot root # mkdir /tmp/early root # cd /tmp/early root # cpio -i </boot/early_ucode.cpio
Compile and install the kernel with integrated initramfs. This command will further modify the kernel config file.
root # genkernel --no-clean --no-save-config --integrated-initramfs --initramfs-overlay=/tmp/early --fullname=rescue all
Sign the kernel with the secure boot key and copy it to the EFI partition:
root # sbsign --key /path/to/db.key --cert /path/to/db.crt -o /boot/kernel-rescue /boot/kernel-rescue root # mount /boot/efi root # cp /boot/kernel-rescue /boot/efi/EFI/Funtoo\ Linux\ \[GRUB\]/rescue.efi
Add the kernel to the EFI boot order. Replace EFIBOOTDEVICE
below with the device mounted on /boot/efi
.
root # efibootmgr -c -l '\EFI\Funtoo Linux [GRUB]\rescue.efi' -L 'Funtoo Linux [Rescue Kernel]' -d /dev/EFIBOOTDEVICE
Shutdown, enter the firmware setup, enable secure boot and boot using the rescue kernel to make sure that it works.
In fact, you can use the scheme above to install new kernels and forego GRUB entirely. The downside is that you won't be able to use the command line, e.g., to enter the single user mode, in case anything goes wrong.
Installing GRUB
Work in progress
Generate a PGP key pair:
root # TODO
Create the initial GRUB config file which will be embedded into the GRUB image:
grub-initial.cfg
- Initial GRUB configif loadfont /grub/fonts/unicode.pf2; then
set gfxmode=800x600
terminal_output gfxterm
fi
set superusers="root"
export superusers
password_pbkdf2 root grub.pbkdf2.sha512.10000.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
set root=ROOTDISK
search --no-floppy --fs-uuid --set FSUUID
configfile /grub/grub.cfg
echo grub.cfg did not boot the system but returned to initial.cfg.
echo Exiting in 10 seconds.
sleep 10
exit
You will have to edit the config file in three places:
- Use
grub-mkpasswd-pbkdf2
to generate a password hash to replace the zeroes. - Replace
ROOTDISK
with the value of theroot
variable from/boot/grub/grub.cfg
. - Replace
FSUUID
with the filesystem UUID from asearch
line in/boot/grub/grub.cfg
.
Mount /boot
and /boot/efi
:
root # mount /boot root # mount /boot/efi
Make a standalone GRUB image:
root # grub-mkimage -O x86_64-efi -p "ROOTDISK/grub" -c /path/to/grub-initial.cfg -k /path/to/grub.pub -o "/boot/efi/EFI/Funtoo Linux [GRUB]/grubx64.efi" configfile loadenv part_gpt ext2 linux gcry_rsa gcry_sha256 password_pbkdf2 all_video gfxterm videoinfo search minicmd test echo reboot sleep root ## sbsign --key /path/to/db.key --cert /path/to/db.crt -o "/boot/efi/EFI/Funtoo Linux [GRUB]/grubx64.efi" "/boot/efi/EFI/Funtoo Linux [GRUB]/grubx64.efi"