In the previous posts, UEFI Secure Boot and Our Planned Approach to Secure Boot, Olaf Kirch has introduced you into the topic of UEFI Secure Boot and the basics of our approach to implementing it in SUSE. In this post, I’ll lead you through the technical details of our Secure Boot plan. So be prepared for this post to be rather detailed. And technical.
The goal of Secure Boot is to prevent malware from hiding embedded in the boot chain by performing a verification of every executed component starting with a fresh reboot of the whole platform. To achieve its goal, Secure Boot must prevent any modification of the verification process, the keys, or any other variables by untrusted code or untrusted entities. An example of an untrusted entity is a hacker who has penetrated the system through an unpatched security hole in the operating system.
There are two types of trusted users:
First, those who hold the keys. The Platform Key (PK) allows almost everything. The Key Exchange Key (KEK) allows all a PK can except changing the PK.
Second, anyone with physical access to the machine. A user with physical access can reboot the machine, and configure UEFI.
UEFI offers two types of variables to cater to the needs of those users:
The first is the so called “Authenticated Variables,” which can be updated from both within the boot process (the so called Boot Services Environment) and the running OS, but only when the new value of the variable is signed with the same key that the old value of the variable was signed. And they can either only be appended to or changed to a value with a higher serial number.
The second is the so called “Boot Services Only Variables.” These variables are accessible to any code that runs during the boot process. After the boot process ends and before the OS starts, the bootloader must call the ExitBootServices() call. After that, these variables are no longer accessible, the OS can’t touch them.
The various UEFI key lists are of the first type, as this allows on-line updating, adding and blacklisting of keys, drivers and firmware fingerprints. It’s the second type of variable, the “Boot Services Only Variable” that will help us in our quest for an implementation of Secure Boot that is both secure and open source friendly. And compatible with GPLv3.
As Olaf explained in the last post, we start with a shim, based on the Fedora shim, signed by either a certificate signed by the SUSE KEK or a Microsoft-issued certificate, based on what KEKs are available in the UEFI key database on the system.
This allows the shim to load and execute.
The shim then goes on to verify that the GRUB2 bootloader it wants to load is trusted. It will not use the SUSE KEK nor the Microsoft cert for this. In a default situation the shim will use an independent SUSE certificate embedded in its body. In addition, the shim will allow to “Enroll” additional keys, overriding the default SUSE key. Let’s call them “Machine Owner Keys” or MOKs for short.
The enrollment process begins by rebooting the machine and interrupting the boot process (e.g., pressing a key) when the shim loads. The shim will then go into enrollment mode, allowing the user to replace the default SUSE key with keys from a file on the boot partition. If the user chooses to do so, the shim will then calculate a hash of that file and put the result in a “Boot Services Only” variable. This allows the shim to detect any change of the file made outside of Boot Services and thus avoid the tampering with the list of user approved MOKs.
An important aspect to remember is that all of this happens during boot time, only verified code is executing now. Therefore, only a user present at the console can say, “I want to use my own set of keys.” It can’t be malware or a hacker with remote access to the OS because hackers or malware can only change the file, but not the hash stored in the “Boot Services Only” variable.
GRUB2, once loaded and verified by the shim, will call back to the shim when it wants to verify the kernel – to avoid duplication of the verification code. The shim will use the same list of MOKs for this and tell GRUB2 whether it can load the kernel.
And that’s it.
This is all you need to be able to work on improving the kernel or the bootloader. Install a new set of keys and authorize them by being physically present during the first reboot.
Also, thanks to MOKs being a list and not just a single MOK, you can make the shim trust keys from several different vendors, allowing dual- and multi-boot from the GRUB2 bootloader.
In the end the real implementation may be a little bit more complicated – for example password-protecting the MOK authorization feature to allow secure authenticated updating of the MOK list from within the OS – but this is the gist of it. And since you can freely modify GRUB2 and your kernel as an owner of a machine, you are happy and so is GPLv3 that the machine didn’t get tivoized.
You may be wondering whether this goes against the UEFI specification or Microsoft Win8 Logo requirements or any of the associated contracts.
I don’t think so – even the UEFI specification allows, but doesn’t mandate, that a UEFI implementation allow a user authorize EFI code with an invalid signature by adding a hash to a special variable.
And the Linux Foundation has asked vendors to make sure to include a way of clearing the PK to allow the user to enroll their own set of keys.
Our approach is just making sure that a feature like this is available everywhere.
To keep the “PC” a free platform.