UEFI secure boot is a feature described by the latest UEFI specification (2.3.1c) which is available from the UEFI Forum Site. There have also been numerous blog posts about how UEFI secure boot works (e.g. here or here), so it will not be described here further. The purpose of this site is to keep relevant information for enabling people to play with secure booting systems. The goal is to have a working qemu system with the UEFI secure boot bios as well as various repositories for efi binary signing tools. This should enable people to produce their own boot media for secure boot systems
Intel and TianoCore
Intel has produced a project called TianoCore as an open firmware reference implementation of UEFI. One of the sub projects within TianoCore is OVMF which stands for Open Virtual Machine Firmware. It is OVMF that we are using to produce the virtual machine image for qemu that will run the UEFI secure boot environment. TianoCore secure boot is only really working as of version r13466 of the svn repository. This version has not yet been released as a downloadable zip file.
Since building TianoCore can be a bit of a challenge, a version supporting secure boot has been uploaded to the openSUSE build server here. The particular package you need for the virtual machine firmware is the OVMF rpm (download).
Booting the TianoCore Virtual Machine Image
After installing the rpm, execute
qemu-system-x86_64 -L /usr/share/qemu-ovmf/bios
And the secure boot bios will come up. Unfortunately, there is currently no way to save the EFI nvram with qemu, so the platform will come up in pristine state with each new invocation of qemu.
If your platform is kvm capable, you may also use
qemu-kvm -L /usr/share/qemu-ovmf/bios
Booting Linux with TianoCore
By default, all the standard methods (elilo, grub or even native boot using the linux kernel efi stub) work. However, TianoCore itself has a problem (as of release r13478) in that the ACPI CRS tables seem to be wrong, which causes the booting kernel to remap the EFI framebuffer and consequently be unable to attach (so you basically get no output on the screen once the kernel has booted). The workarounds for this are to specify
on the kernel boot line. This causes the kernel to ignore the ACPI CRS tables and thus attach normally to the EFI framebuffer. Thanks to Peter Jones for this. Or to boot the kernel using the serial console
Playing with Secure Boot in Tianocore
By default, TianoCore boots up into Setup Mode, meaning the platform is not provisioned with any keys and the user can take control. To take control, go to the EFI menu screens (type exit if you’re at the efi boot prompt) select the “Device Manager” entry, then “Secure Boot Configuration”. Here you will see the status of the Secure Boot flag (“Attempt Secure Boot”) and the platform mode. Setting the platform from “Standard Mode” to “Custom Mode” will allow you to edit the keys. Once the platform is in “Custom Mode”, a “Custom Secure Boot Options” menu will appear and you will be able to manipulate the four sets of key databases from here. The format of all key files for openssl generated keys is DER format (by default openssl generates PEM format). Note that the KEK, db and dbx options will ask you for a GUID as well as a key file. The GUID is the platform’s way of identifying the key. It serves no purpose other than for you to tell which key is which when you delete them (it’s not used at all in signature verification). By default, since GUIDs aren’t really human readable, I just ignore this and the GUID is set to all zeros.
Because there’s no way to save the nvram area, these variables get reset on each invocation of qemu as well and entering three sets of keys with each invocation of qemu gets very old, very fast. The repository
contains a set of tools to help with this. Note that there’s a bug in gnu-efi earlier than 3.0q so you must have this installed if you want to build efi binaries that are capable of being signed (there’s a rpm for it in the openSUSE build service UEFI project)
If you type make, it will generate a set of keys and place them into a binary called LockDown.efi. Execution of this efi binary will provision all the keys and place the platform into Secure Boot enabled User Mode (from this point on, it will only execute signed efi binaries)
UEFI Keys and openssl
The UEFI specification has several possible key types, but X509 is the most useful to us, since it’s the easiest to generate with openssl (The platform key is required to be X509 anyway). Note that when the UEFI spec says “key”, it doesn’t mean the same as an openssl key. In UEFI parlance, the “key” or “public key” means the public part (i.e. the X509 certificate); openssl uses the term key to mean the private key used to sign stuff with.
All keys (PK, and X509 keys in KEK and db) should be X509 CA keys (i.e. self signed). The reason for this is that the platform will verify a key back to its root of trust. It is possible to provision a signature chain going back to the root of trust, but it’s not easy, so starting with self signed CA certificates is easiest. Note that from the CA, you can issue signing keys, but those keys cannot themselves then be used to create subordinate signing keys because the intermediate trust certificate will be missing from the signing chain.
For more details on all the keys and how they work, see this post.
Creating UEFI CA keys
The easiest way is to use the x509 CA creation command
openssl req -new -x509 -newkey rsa:2048 -keyout PK.key -out PK.crt -days <length
> -subj “/CN=<my common name>/”
Will create two files, PK.crt (which is the public certificate we’ll use as the UEFI key) and PK.key which is the private signing key (note: the UEFI spec mandates that all X509 keys be 2048 bit rsa keys). Fill in <days> with how long you want the certificate to be valid for and <my common name> with whatever information you want the common name to be (UEFI doesn’t use this, but it’s customary for every X509 certificate to have at least a common name). We’re still not quite done, because the keys must be in DER form. Conversion is done like this
openssl x509 -in PK.crt -out PK.cer -outform DER
Note that the .cer extension is what tells UEFI that the file contains an x509 key, so you must use it.
Signing UEFI binaries
There are two sets of tools available in Linux for this:
- Jeremy Kerr’s sbtools available from git://kernel.ubuntu.com/jk/sbsigntool
- Peter Jones’ pesign available from git://github.com/vathpela/pesign.git
The opensuse build service UEFI project contains both, but I’ve mostly played with sbsigntools which is what’s described below.
Once you have your .crt and .key files, you can sign efi binaries like this
sbsign –key KEK.key –cert KEK.crt –output HelloWorld-signed.efi HelloWorld.efi
If you’re building this yourself, you must have version 0.3 or later of the sbsigntools because earlier versions wouldn’t correctly sign efi binaries generated by gnu-efi.