Secure(ish) boot with QEMU
(Edit 9/21: I’ve gotten some feedback and clarifications about a few steps and also updated the wiki. Thanks to the OVMF developers!)
Despite having too many machines in my possession, none of the x86 machines I have are currently set up to boot with UEFI. This put a real damper on my plans to poke at secure boot. Fortunately, there is virtualization technology to solve this problem. I really like being able to boot kernels directly without a full VM image. There are some instructions for getting started but they are a bit incomplete for what I wanted to do. This is what I used to get secure boot working (or at least detected) in QEMU. I make no guarantees about it actually being secure or signed correctly but it’s a starting point for experiments.
The secure boot firmware is available as part of the standard Fedora package.
$ sudo dnf install edk2-ovmf
You need to tell QEMU to pick up the firmware and emulate a file for storing
EFI variables. The firmware used here is going to be OVMF_CODE.secboot.fd
.
$ cp /usr/share/edk2/ovmf/OVMF_VARS.fd my_vars.fd
This creates a copy of the base variables file for modification and use. The options you need to append to QEMU are (with some comments in #)
# required machine type
-machine q35,smm=on,accel=kvm
# Due to the way some of the models work in edk2, we need to disable
# s3 resume. Without this option, qemu will appear to silently hang
# althouh it emits an error message on the ovmf_log
-global ICH9-LPC.disable_s3=1
# Secure!
-global driver=cfi.pflash01,property=secure,value=on
# Point to the firmware
-drive if=pflash,format=raw,unit=0,file=/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd,readonly=on
# Point to your copy of the variables
- drive if=pflash,format=raw,file=/home/labbott/my\_vars.fd
I added these to the existing command
I had for QEMU. I bumped the memory on the KVM command line to 500 as well
(-m 500
). If all goes well, you should be able to boot a kernel and have it
detect EFI (dmesg | grep EFI
) with this setup.
To actually enable secure boot, we need to run an EFI program to load a set
of certificates. The default Fedora build provides a nice .iso with the UEFI
shell and EFI application built in, /usr/share/edk2/ovmf/UefiShell.iso
.
Add -hda /usr/share/edk2/ovmf/UefiShell.iso
to your QEMU command and remove
the -kernel
and -initrd
options. If all goes well, you should be dropped
into the UEFI shell. You can now run the command to add keys
Shell> FS0:
FS0:\> EnrollDefaultKeys.efi
Your vars file should now be all set up for secure boot. If you boot with a
-kernel
and -initrd
option, you should be able to boot a kernel
and have it detect secure boot (dmesg | grep Secure
).
Booting your own kernels isn’t too difficult. If you take a tree that has secure boot patches in it, make sure the following set of options is enabled
CONFIG_SYSTEM_DATA_VERIFICATION=y
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_ALL=y
CONFIG_MODULE_SIG_UEFI=y
CONFIG_MODULE_SIG_SHA256=y
CONFIG_MODULE_SIG_HASH="sha256"
CONFIG_ASN1=y
CONFIG_EFI_STUB=y
CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=y
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y
CONFIG_PKCS7_MESSAGE_PARSER=y
CONFIG_SIGNED_PE_FILE_VERIFICATION=y
CONFIG_EFI_SIGNATURE_LIST_PARSER=y
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
This will be enough for the kernel to detect that secure boot is enabled and let you experiment with things. You can even issue your own pesign command
$ pesign -c 'Red Hat Test Certificate' --certdir /etc/pki/pesign-rh-test -i arch/x86/boot/bzImage -o vmlinuz.signed -s