# Own and lock down your laptop: UEFI Secure Boot.

Posted on 23.01.2017

The Unified Extensible Firmware Interface Secure Boot functionality is much maligned by the internet community at large, who have in general not correctly understood its implications and possible uses. If you are looking for a more authoritative source than me, try Matthew Garrett's Some things you may have heard about Secure Boot which aren't entirely true. In this post I am going to walk through how UEFI Secure Boot can actually be to your benefit and how you can secure your own platform. I have followed this procedure on my own laptop, a Dell XPS 9343 from 2015 running Bios Revision A07 and I would encourage anyone with a UEFI platform, particularly a laptop, to consider going through this process for their own security. The guide I followed before writing this post was James Bottomley's Owning your Windows 8 UEFI Platform; there isn't that much new here, but I wanted to assume you were not current with UEFI.

Why might you want this? Well, a while back I was pointed to this article: A reasonably secure travel laptop. "Reasonably" is a bit modest here; the setup includes taking over your SPI flash, running firmware you can actually read the code of and signing just about every part of the boot chain. Unfortunately my laptop is not in the supported coreboot motherboards list and I doubt coreboot would work - I am also not comfortable opening up the chassis of my laptop to SPI flash my firmware in this case. So, I am "stuck" trusting Dell firmware.

Why would you want to do this? Well, obviously blocking unsigned code from booting on your device is desirable from the point of view of protecting against bootkits as well as raising the bar on evil maid attacks. For me, though, the real appeal is actually the less sexy motivation that, should my laptop ever be stolen it will essentially be a brick for the thief.

Some disclaimers and warnings are necessary before we begin though:

• You should be comfortable enough playing around in your firmware and with your boot process before starting. I am not responsible for any undesirable outcomes, including bricking your laptop, that might arise from following my advice. Please seek assistance if you are at all unsure.
• If you do not also employ Full Disk Encryption so far as is possible and with the inherent risks of hibernating and sleeping fully understood here, thieves might still be able to steal your data even if they can't run any code. Power down your laptop.
• Finally, this process protects the boot process. It is not a magic bullet for userspace protection. In particular, your kernel may not be free of bugs and may allow undesirable things to happen. We are also trusting the kernel and everything it does once booted - if it can be subverted so can your boot process. You should be aware that stealing your data does not necessarily require privilege escalation and that persistence is still possible - you should still practice good security hygiene including regularly applying OS patches from trusted, verified sources.

Got it? Good. Let's begin:

## UEFI abbreviated history: what it is, isn't and how it works

EFI began life, according to wikipedia, as the Intel Boot Initiative as far back as 1998 to support booting newer Itanium processors without the restrictions imposed by BIOS firmware. It quickly became the Extensible Firmware Interface and a consortium, the UEFI consortium, was later set up and the standards handed over to them for continued development. This happened as far back as 1995.

When Apple switched from PowerPC to Intel, they also switched firmware, from OpenFirmware to EFI. However, they chose to implement EFI 1.x and are not UEFI compatible.

The really big push came in 2011 and 2012, when manufacturers began pushing UEFI for consumer motherboards and Microsoft mandated for Windows 8 Logo compatibility that firmware support UEFI. UEFI support, however, existed in Windows Vista SP1. What it isn't is a Microsoft-imposed standard.

Next up, we need to look into the UEFI boot process.

We shall quickly break down each stage after SEC:

• PEI provides platform initialization that is not necessary using an exposed EFI interface. In other words, this stage is where the firmware author does their work. Once they are done they are expected to provide:
• The DXE phase, where UEFI driver writers can hook in and add support for their hardware. Once all relevant drivers are loaded:
• BDS finds a boot device and executes a relevant bootloader.
• TSL is the state your user-visible bootloader, such as grub2, operates in, consuming EFI Boot Services. It will load and hand over to a kernel binary, or the kernel binary will be directly loaded, however that happens.
• The kernel will eventually call ExitBootServices(), which instructs the platform the kernel is ready to take over and destroys the EFI Boot Services table and associated functions. All that is left are UEFI runtime services and the kernel itself - this is runtime, as expected.

Of course, we missed the SEC phase. The SEC phase is responsible for making sure everything that comes after, if Secure Boot is on, is appropriately signed.

UEFI firmware images are stored in UEFI Firmware Volume-format, for the most part, as described at the time of writing in the Platform Initialisation (UEFI PI 1.5) specifications, in Shared Architecture section 2.2.2. An in-depth discussion of this format is out of scope, but it is simple for the SEC, PEI and DXE phaes to read this filesystem.

UEFI drivers and applications themselves at a later stage are typically PE32+ files (64-bit "EXEs") and for users of the UEFI platform, it is this that matters, as shall be discussed below for Secure Boot.

## UEFI Secure Boot: the theory

For this part, you will need the UEFI Spec, in particular sections 30.2, 30.3, 30.4 and 30.5 are relevant. We shall, however, begin at the beginning.

Keys

Firstly, we have the platform key. The specification describes this as establishing "a trust relationship between the platform owner and the firmware". More specifically, objects signed by the platform key will be accepted as allowed to update the firmware; those that are not will be refused. With the platform key enrolled, the system will refuse changes to important databases. For example, a new Key Exchange Key cannot be enrolled.

Secondly, we have the Key Exchange Keys. These are described as establishing trust between the Operating System and firmware, but perhaps more accurately is that they establish trust between the Operating System Vendor and the firmware. It's purpose is to allow an operating system vendor's signature lists to be loaded into the firmware and trusted.

There isn't a name for the last type of key officially, so I am going to call it an Image Key. The image key is what signs the binary that will be trusted - you are likely already familiar with this key as your key for code-signing a binary, for example.

Databases and Variables

The next question is, where are all these keys kept? Well, that's straightfoward. UEFI defines the concept of a signature database, a store for signatures and public keys and the type EFI_CERT_X509_GUID for signatures based on x509 certificates. It also supports certificates based on RSA-2048 public keys and "signatures" in the form of approved hashes (not to be confused with hash-based signatures). The EFI_CERT_X509_GUID type indicates that a signature will validate in an PKIX certificate chain up to the provided certificate as a root.

UEFI provides special-purpose global variables for the PK and KEK databases, named appropriately PK and KEK. The PK database contains a maximum of one entry, whereas the KEK database may contain multiple entries. Firmware can also provide PKDefault and KEKDefault variables as backups.

Other databases do exist, however. Let's go through them quickly:

• db, or authorized signature database, contains all signatures that may be allowed to boot. This might, for example, contain the public x509 certificate of what I called an image key, or the sha256 of an authorised binary.
• dbx, or the forbidden signature database. Fulfils the opposite role of the authorised signature database.
• dbt, the authorised timestamp signature database, for authorising timestamps.
• dbr, the authorised recovery signature database.

For our purposes, we will likely only encounter db and dbx.

Secure boot modes

Secure boot can operate in a couple of modes, which are also worth discussing because they are important from a security perspective. They are:

• Disabled - this should be obvious. Whatever the state of the system, in this mode no enforcement is performed.
• User mode - this is the "normal" Secure Boot state of being. A platform key is enrolled and secure boot is enforcing security by enforcing the relevant signature checks.
• Setup mode - the system has no enrolled platform key and is waiting for one to be enrolled. In this mode, any change can be made to the relevant signature databases. As soon as a platform key is enrolled, the system returns to user mode.

Verifying a binary

As described in about UEFI, UEFI binaries are nothing more than PE binaries of Microsoft fame. UEFI also reuses Microsoft Authenticode for binary signing.

Whenever the firmware sees a call to LoadImage, either from the UEFI Shell, when it tries to load a bootloader or from third party code, i.e. anywhere from the Boot Services mode, it will take the signature and check it against the db and dbx databases. If it finds a match in the db database, the binary is loaded, otherwise, not.

Putting it all together

OK, so let's follow the chain up. We have a binary with a signature. Let's assume there's a certificate in the platform key database. Firstly, the signature on the binary is checked against db and dbx - let's assume there's no matching signature and we want to add our signature to db. To do this, the platform either needs to be in setup mode, or we need an update signed with a key in the KEK database. Assume we have such an update, but the KEK isn't available in the KEK database. Well, KEK entries are set either during setup mode, or by updates signed with the platform key. So, we need to be the platform owner.

In this way, the platform owner is the root of all trust on the system. They can delegate to third parties, but, changes to the setup once installed are their perogative alone. This setup is complex, but allows separation between platform owners and OS vendors quite nicely.

So, that's the terminology and workings of secure boot. Let's get practical!

## The Dell XPS Firmware

The Dell XPS firmware can be accessed in two ways during bootup: you can press F2 to go directly to the setup program, or F12 from the boot menu, which takes you to the boot menu and offers the choice to enter setup.

The setup utility has two main options we are concerned with. Firstly, of course, you can turn UEFI secure boot on and off. The following screen explains it and there is very little complexity to the process. This is available in Secure Boot > Secure Boot Enable.

The second dialog, available in Secure Boot > Expert Key Management, allows unsurprisingly for the management of keys. Here it is:

We could, but won't, do all our key management from here. However, I want to point out two very useful features here - we can back up the keys available on the platform and we can equally restore them from disk, or from the firmware itself, totally undoing anything we might later do. Simply turn off custom mode.

With these options in mind, I booted up the system in secure boot mode on my fedora system. You can, having done this, begin to explore your system. For example, you can examine the certificate database using the following command as root:

# efi-readvar
Variable PK, length 1395
PK: List 0, type X509
Signature 0, size 1367, owner 70564dce-9afc-4ee3-85fc-949649d7e45c
Subject:
DC=com, DC=dell, OU=1, OU=Signing, CN=Dell Inc. UEFI Platform Key
Issuer:
DC=com, DC=dell, CN=Configuration, CN=Services, CN=Public Key Services, CN=AIA, CN=Dell Inc. Issuing CA 1
Variable KEK, length 1560
KEK: List 0, type X509
Signature 0, size 1532, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation KEK CA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation Third Party Marketplace Root
Variable db, length 3143
db: List 0, type X509
Signature 0, size 1515, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Windows Production PCA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010
db: List 1, type X509
Signature 0, size 1572, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation UEFI CA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation Third Party Marketplace Root
Variable dbx, length 2343
dbx: List 0, type X509
Signature 0, size 1663, owner 00000000-0000-0000-0000-000000000000
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Windows PCA 2010
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010
dbx: List 1, type SHA256
Signature 0, size 48, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
Hash:80b4d96931bf0d02fd91a61e19d14f1da452e66db2408ca8604d411f92659f0a
< snip >
Variable MokList has no entries


Hopefully my earlier talk of signature databases now makes more sense. You can also grep dmesg to see what the kernel believes has loaded:

# dmesg | grep "Loaded cert"
[    0.754704] EFI: Loaded cert 'Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53' linked to '.builtin_trusted_keys'
[    0.761671] EFI: Loaded cert 'Fedora Secure Boot CA: fde32599c2d61db1bf5807335d7b20e4cd963b42' linked to '.builtin_trusted_keys'
[    0.763101] EFI: Loaded cert 'Microsoft Windows PCA 2010: d14fa98a0708cef4241898e500fff3d6791d37bc' linked to '.system_blacklist_keyring'


These are what the kernel will later use to sign drivers, as the linux kernel on Fedora also enforces signatures.

Now we've explored the platform a little bit, let's get to the actual securing part.

## Locking down your boot process

Install tools

Finally the fun begins. Firstly, I needed sbsign from Ubuntu. I could optionally have used pesign, but I prefer utilities that work directly with the files I want rather than the NSS key databases, which I find awkward to use. I also needed efitools for the efivars command added above. You can find both of these in Fedora's Copr:

Import these into your /etc/yum.repos.d/ then dnf install efitools sbsign.

Generate Keys

Secondly we need to generate some keys. The UEFI specification contains definitions for EFI_CERT_RSA2048_GUID and EFI_CERT_RSA2048_SHA256_GUID - although it does not specify what firmware might support for EFI PKIX chains, we can safely assume RSA-2048 keys are likely to be supported.

If you feel this key-size is insufficient, unfortunately unless your hardware supports something else you are likely to be stuck. If it helps, I would highlight the following quote from Thomas Pornin on key-size lengths (admittedly with regard to Elliptic Curves) (source).

Use P-256 to minimize trouble. If you feel that your manhood is threatened by using a 256-bit curve where a 384-bit curve is available, then use P-384

RSA-2048 should be sufficient for now. Also remember that any attack requires signature forgery for keys in your hardware and so physical access to your system - this is likely a safer scenario than RSA-2048 for https.

Anyway, enough, RSA-2048 is our only choice. So we are going to generate three key; a platform key, key-exchange-key and image signing key. Change the names as per your tastes.

cd ~/efi-secure-boot
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Platform Key 2017/" -keyout platform_key.pri -out platform_key.crt -days 9125 -nodes -sha256
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=KEK 2017/" -keyout kek.pri -out kek.crt -days 9125 -nodes -sha256
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Secure Boot Key 2017/" -keyout secureboot.pri -out secureboot.crt -days 9125 -nodes -sha256


We need the certificates in DER format in firmware (EFI signature lists), this being slightly more efficient than BER. So, we will convert:

openssl x509 -outform DER -in platform_key.crt -out platform_key.cer
openssl x509 -outform DER -in kek.crt -out kek.cer
openssl x509 -outform DER -in secureboot.crt -out secureboot.cer


At this stage there is an optional further step, which is to secure these keys. I recommend you take this step, but it isn't required. If you want to do this, jump to secure keys.

Generate and authenticate EFI signature lists

Next we need to generate EFI signature lists and create authenticated versions of these lists. Here are the steps you need to take for each set of keys.

First, we need a UUID to identify these objects. I used uuidgen like so:

uuidgen > uuid


to keep the uuid file. However, you could equally have set a session variable.

Then you can create a signature list:

cert-to-efi-sig-list -g cat uuid platformkey.crt platformkey.esl


and now sign it in three steps. I've separated this out into three steps so that users using hardware tokens can correctly use openssl smime -engine ... - for example, to use my smartcard setup detailed later I need to set

alias smime_token_pk="openssl smime -engine pkcs11 -keyform engine -inkey 'pkcs11:object=Antony%20Vennard%20Whiteprophet%20Platform%20Key%202016'"
alias smime_token_kek="openssl smime -engine pkcs11 -keyform engine -inkey 'pkcs11:object=Antony%20Vennard%20Whiteprophet%20KEK%202016'"
alias smime_token_sb="openssl smime -engine pkcs11 -keyform engine -inkey 'pkcs11:object=Antony%20Vennard%20Whiteprophet%20Secureboot%20Signing%20Key%202016'"


with the appropriate p11-kit setup described later on. We can now use our token to sign things (help for using rfc7512 appears later)!

sign-efi-sig-list -t ‘2017-01-01 00:00:00’ -o PK platformkey.esl platformkey.forsig
smime_token_pk -noattr -sign -binary -in platformkey.forsig -text -out platformkey.signed -signer platformkey.crt -outform DER -md sha256
sign-efi-sig-list -i platformkey.signed -t ‘2017-01-01 00:00:00’ PK platformkey.esl platformkey.auth


This creates an auth file with our platform key that can be loaded into firmware. The smime separation steps came from someone I only known as Trevor commenting on James Bottomley's blog.

It is also additionally possible to simply skip the timestamping phase and sign directly with smime. Those wanting to sign in one line without hardware should run:

sign-efi-sig-list -g cat uuid -a -t ‘2017-01-01 00:00:00’ -c platformkey.crt -k platformkey.pri PK pk.esl platformkey.auth


Next we create an empty signature list signed by our platform key. This allows us to remove the platform key. On my laptop this is an optional nicety, since the firmware can do it. However, if your platform cannot do this then you need this option:

> empty_pk.esl
sign-efi-sig-list -t ‘2017-01-01 00:00:00’ -k platformkey.pri -c platformkey.crt PK empty_pk.esl empty_pk.auth


Ironically, if you actually need this option your hardware isn't Windows logo compatible!

Next step, we create an ESL and AUTH pair for our KEK and image key:

cert-to-efi-sig-list -g cat uuid kek.crt kek.esl
cert-to-efi-sig-list -g cat uuid secureboot.crt secureboot.esl


and now you sign the KEK list with your platform key as follows:

sign-efi-sig-list -t ‘2017-01-01 00:00:00’ -o KEK kek.esl kek.forsig
smime_token_pk -noattr -sign -binary -in kek.forsig -text -out kek.signed -signer platformkey.crt -outform DER -md sha256
sign-efi-sig-list -i kek.signed -t ‘2017-01-01 00:00:00’ KEK kek.esl kek.auth


It is vitally important you sign this with your platform key - you should see my earlier explanation in action right here!

Finally we do the same thing, but with the image key. Here goes:

sign-efi-sig-list -t ‘2017-01-01 00:00:00’ -o DB secureboot.esl secureboot.forsig
smime_token_kek -noattr -sign -binary -in secureboot.forsig -text -out secureboot.signed -signer kek.crt -outform DER -md sha256
sign-efi-sig-list -i secureboot.signed -t ‘2017-01-01 00:00:00’ DB secureboot.esl secureboot.auth


Again, this is signed with your KEK, which is allowed to update the DB and DBX signature lists / databases.

How (and whether this is even necessary) you do this depends on the outcome you want to achieve. If you intend to remove the Microsoft UEFI CAs from your KEK and DB, then you will need to replace the signatures on your bootloader as only things signed with your image key will be allowed to boot.

I have placed KeyTool.efi in my working directory ~/efi-secure-boot. For the Fedora boot process, the shim requires signing. This in turn holds its own key database, which signs the kernel and modules built as part of Fedora. I haven't, but if you intend to replace these you will need to compile the kernel yourself for each update.

The easy way, using files on disk, is to sign the relevant files like so:

sudo cp /boot/efi/EFI/BOOT/BOOTX64.EFI ./BOOTX64.EFI
sudo cp /boot/efi/EFI/fedora/shim.efi ./shim.efi
sbsign --key /home/antony/efi-secure-boot/secureboot.pri --cert /home/antony/efi-secure-boot/secureboot.crt --output SHELL-signed.efi SHELL.EFI
sbsign --key /home/antony/efi-secure-boot/secureboot.pri --cert /home/antony/efi-secure-boot/secureboot.crt --output shim-signed.efi shim.efi
sbsign --key /home/antony/efi-secure-boot/secureboot.pri --cert /home/antony/efi-secure-boot/secureboot.crt --output BOOTX64-signed.efi BOOTX64.EFI
sbsign --key /home/antony/efi-secure-boot/secureboot.pri --cert /home/antony/efi-secure-boot/secureboot.crt --output KeyTool-signed.efi KeyTool.efi


The install steps for these are part of "copy to efi sp".

Sbsign has no options for the use of hardware tokens, so we need to fall back to pesign if you wish to install to a token. Refer to Protecting your Keys for NSS-specific stuff here.

Assuming our keys are stored in a module named "CardOS" on a token named "UEFI" and our certificate has the common name "Secureboot Signing Key 2017" then the following command should be run to sign a binary:

pesign --certdir ~/efi-secure-boot/nss -t UEFI -i SHELL.EFI -s -c "Secureboot Signing Key 2017" -o SHELL-signed.EFI


Repeat this for all binaries that need signing.

Sign modules

This step is optional. Any custom modules you have will need signing each time the kernel is updated. I wrote the following script to do this:

#!/bin/sh

KEYDIR=/home/antony/efisb-keys
PRIVKEY="pkcs11:object=Antony%20Vennard%20Whiteprophet%20Secureboot%20Signing%20Key%202016"
PUBKEY=$KEYDIR/whiteprophet_db.cer # SIGN_CMD=/usr/src/kernels/$(uname -r)/scripts/sign-file
SIGN_CMD=/root/sign-file

rm -rf /root/signmodules
mkdir /root/signmodules
pushd /root/signmodules

cp /lib/modules/$(uname -r)/extra/wl/wl.ko . cp /lib/modules/$(uname -r)/misc/vmmon.ko .
cp /lib/modules/$(uname -r)/misc/vmnet.ko .$SIGN_CMD sha256 $PRIVKEY$PUBKEY wl.ko
$SIGN_CMD sha256$PRIVKEY $PUBKEY vmmon.ko$SIGN_CMD sha256 $PRIVKEY$PUBKEY vmnet.ko

cp -f wl.ko /lib/modules/$(uname -r)/extra/wl/wl.ko cp -f vmmon.ko /lib/modules/$(uname -r)/misc/vmmon.ko
cp -f vmnet.ko /lib/modules/$(uname -r)/misc/vmnet.ko popd  This should be run as the root user and is very straightforward - it copies the unsigned modules from their place in /lib, signs them and reinserts them into /lib. Update March 2017: If you follow the updated instructions on preparing your smart card, you can use p11-kit instead. OpenSC's engine-pkcs11 will load modules directly from p11-kit, meaning you do not need to modify sign-file and it will work straight out of the box. Deprecated instructions: Unfortunately, the linux kernel sign-file has a bug where it does not correctly use SSL engines. I have patched sign-file in this repository on github. Copy to EFI SP We are now ready to begin modifying our EFI System Partition, by installing our signed bootloaders and loading our keys. To do this: sudo mkdir /boot/efi/secureboot sudo cp ./KeyTool-signed.efi /boot/efi/secureboot/KeyTool.efi sudo cp ./shim-signed.efi /boot/efi/EFI/fedora/shim.efi sudo cp ./BOOTX64-signed.efi /boot/efi/EFI/BOOT/BOOTX64.EFI sudo cp ./SHELL-signed.efi /boot/efi/EFI/BOOT/SHELL.EFI  This copies the files to the relevant places on the UEFI system partition. Note that if the shim is updated, you will need to repeat this process. If you want to prevent that (not recommended), do this: sudo dnf lock shim  This will force DNF to prevent modifications to the shim package when you run dnf upgrade. We are going to use the UEFI shell to launch KeyTool.efi. Not specifically necessary, but I wanted the shell around for other testing. So, first up reate the shell entry: sudo efibootmgr --create --disk /dev/sda --part 1 --loader /EFI/BOOT/SHELL.EFI --label "UEFI SHELL"  Now if you run the tool with no arguments as root you should have something like this: $ sudo efibootmgr
BootCurrent: 0001
Timeout: 0 seconds
BootOrder: 0001,0000,0002
Boot0000  Windows Boot Manager
Boot0001* Fedora
Boot0002* UEFI SHELL


Perfect. Now, for using the shell on my system I needed to make the console font actually usable, due to the HIDPI display. To do that, edit /boot/efi/startup.nsh as root to contain:

mode 100 31


Note this needs to be in a specific text format. This should read:

$file startup.nsh startup.nsh: Little-endian UTF-16 Unicode text, with no line terminators  Working out how to set this up is an exercise left to the reader. Finally, let us copy all our esl and auth files to the SP as well. We technically do not need the ESL files, but you will see later depending on the order you choose, they can be used in place of auth files. So, here we go: sudo cp *.esl /boot/efi/secureboot sudo cp *.auth /boot/efi/secureboot  Key modifications on firmware We are now ready to actually reboot! Let's do that, and enter the firmware utility. We are going to enter the the Secure Boot section and then use the Expert Key Usage to clear the platform key. You additionally have the choice here to clear the KEK and DB keys too. I personally did. The implications are this: • If you remove the Microsoft KEK and Image Keys, no Microsoft products or Microsoft-signed UEFI binaries will run. You will have to sign them yourself in order for them to run, following the pesign steps above. • If you leave the Microsoft KEK and Image Keys in place, Microsoft-Signed EFI binaries and firmware will still be able to run. Remove at least the platform key and your choice regarding the KEK and DB keys, and leave secure boot off for now. While we are here - it is vitally important that you set a firmware password. Not doing so allows anyone with physical access to trivially reset your platform key or just disable secure boot. You want to make them at least get out an SPI flash tool! Next - reboot into the boot menu. You should now have something like this: Select the UEFI Shell entry and allow startup.nsh to run - pressing any key escept esc runs it immediately. Then run the following commands fs0: cd secureboot KeyTool.efi  As shown below (with intermediate ls): This runs KeyTool, which looks like this: Note the words "platform is in setup mode" - since we have deleted the platform key this is required as per the UEFI spec as discussed above. The next step is to perform the enrollment, which is fairly uneventful and mechanical. In the edit keys menu you should be able to go to each of the key categories in turn. To do this, proceed as follows: 1. Go to the Platform Key option and select "replace platform key". Navigate to fs:0\secureboot and select your platformkey.auth. As soon as this is done the platform will switch to user mode. 2. Go to the Key Exchange Key option and select "add key". Navigate to fs0:\secureboot and select kek.auth. 3. Go to the DB signature list option and select "add key". Navigate to fs0:\secureboot and select secureboot.auth. You can actually proceed in a different order. Until the platform key has been loaded, you can load any of the other keys in any order directly from their esl file, as the signature checks will not be enforced. Once the platform key is loaded, you must proceed in this order. Below is an example screenshot with the Microsoft keys left in for the DB entry: and a picture of the platform key replacement dialog: We are now ready to reboot again. Let's do that. Reboot into firmware, enter your firmware password, set uefi boot to enabled and then reboot again. Now, your boot screen should look something like this: Select Fedora. If you did everything correctly, the system will boot. Congratulations, secure boot is enabled. To check this, do the following: $ efi-readvar
Variable PK, length 883
PK: List 0, type X509
Signature 0, size 855, owner 8a4d80e9-1fff-490a-9537-7725ea401f77
Subject:
CN=Antony Vennard Whiteprophet Platform Key 2016
Issuer:
CN=Antony Vennard Whiteprophet Platform Key 2016
Variable KEK, length 865
KEK: List 0, type X509
Signature 0, size 837, owner 8a4d80e9-1fff-490a-9537-7725ea401f77
Subject:
CN=Antony Vennard Whiteprophet KEK 2016
Issuer:
CN=Antony Vennard Whiteprophet KEK 2016
Variable db, length 903
db: List 0, type X509
Signature 0, size 875, owner 8a4d80e9-1fff-490a-9537-7725ea401f77
Subject:
CN=Antony Vennard Whiteprophet Secureboot Signing Key 2016
Issuer:
CN=Antony Vennard Whiteprophet Secureboot Signing Key 2016
Variable dbx, length 2343
dbx: List 0, type X509
Signature 0, size 1663, owner 00000000-0000-0000-0000-000000000000
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Windows PCA 2010
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010
dbx: List 1, type SHA256
< snip >


you can also see what certificates were detected on boot:

$dmesg | grep Loaded cert [ 0.761784] EFI: Loaded cert 'Antony Vennard Whiteprophet Secureboot Signing Key 2016: 2d7ed9070075c9c23ef13f176701e68d84d708e7' linked to '.builtin_trusted_keys' [ 0.763389] EFI: Loaded cert 'Fedora Secure Boot CA: fde32599c2d61db1bf5807335d7b20e4cd963b42' linked to '.builtin_trusted_keys' [ 0.764699] EFI: Loaded cert 'Microsoft Windows PCA 2010: d14fa98a0708cef4241898e500fff3d6791d37bc' linked to '.system_blacklist_keyring'  What if I left the Microsoft Keys in place? I did not (the above are outputs from my system) but assuming you did, you would see: $ efi-readvar
Variable PK, length 883
PK: List 0, type X509
Signature 0, size 855, owner 8a4d80e9-1fff-490a-9537-7725ea401f77
Subject:
CN=Antony Vennard Whiteprophet Platform Key 2016
Issuer:
CN=Antony Vennard Whiteprophet Platform Key 2016
Variable KEK, length 2425
KEK: List 0, type X509
Signature 0, size 1532, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation KEK CA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation Third Party Marketplace Root
KEK: List 1, type X509
Signature 0, size 837, owner 8a4d80e9-1fff-490a-9537-7725ea401f77
Subject:
CN=Antony Vennard Whiteprophet KEK 2016
Issuer:
CN=Antony Vennard Whiteprophet KEK 2016
Variable db, length 4046
db: List 0, type X509
Signature 0, size 1515, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Windows Production PCA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010
db: List 1, type X509
Signature 0, size 1572, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation UEFI CA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation Third Party Marketplace Root
db: List 2, type X509
Signature 0, size 875, owner 8a4d80e9-1fff-490a-9537-7725ea401f77
Subject:
CN=Antony Vennard Whiteprophet Secureboot Signing Key 2016
Issuer:
CN=Antony Vennard Whiteprophet Secureboot Signing Key 2016
Variable dbx, length 2343
dbx: List 0, type X509
Signature 0, size 1663, owner 00000000-0000-0000-0000-000000000000
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Windows PCA 2010
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010
dbx: List 1, type SHA256
< snip >


and

$dmesg | grep Loaded cert [ 0.754704] EFI: Loaded cert 'Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53' linked to '.builtin_trusted_keys' [ 0.756192] EFI: Loaded cert 'Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed522988a1bd4' linked to '.builtin_trusted_keys' [ 0.760148] EFI: Loaded cert 'Antony Vennard Whiteprophet Secureboot Signing Key 2016: 2d7ed9070075c9c23ef13f176701e68d84d708e7' linked to '.builtin_trusted_keys' [ 0.761671] EFI: Loaded cert 'Fedora Secure Boot CA: fde32599c2d61db1bf5807335d7b20e4cd963b42' linked to '.builtin_trusted_keys' [ 0.763101] EFI: Loaded cert 'Microsoft Windows PCA 2010: d14fa98a0708cef4241898e500fff3d6791d37bc' linked to '.system_blacklist_keyring'  Do I have to do any maintenace? As mentioned in the above, I would make specific note of two things: 1. If the shim is ever updated you will need to resign it. 2. You need to sign any custom modules every time you upgrade your kernel (i.e. kernel modules built by dkms or via third party products, such as VMware Workstation). This is not ideal and there is no real (secure) way to automate it, sadly. I am currently undertaking a lot of smartcard research; while not directly relevant to UEFI secure boot, it would be a shame not to further protect the keys being used. The specifics of your smartcard are certainly out of scope. I am going to assume you have PKCS#11-supporting libraries for your smartcard or device and that you have aliased alias p11=pkcs11-tool -M /path/to/your/pkcs11.so  for the following steps: 1. Create an NSS database (you can also use these steps instead of sbsign if you prefer pesign, without needing hardware. Also creating a database isn't strictly necessary): mkdir ~/efi-secure-boot/nss certutil -d ~/efi-secure-boot/nss -N  Note: we are creating a separate database to avoid affecting any configuration you already have in your browser / email client. 2. Prepare and load your token. My token actually only loads successfully from Windows due to a buggy PKCS#11 library. However if you did want to load from Linux because you are using a token that works, then follow the instructions in this section. If you use an alternative method to load your token you can try part 4 to check it has been successful. Initialize your token (options my vary): p11 --init-token --slot 1 -l --login-type so --init-pin  Convert your keys to DER format too: openssl rsa -in platformkey.pri -out form DER -out platformkey.key openssl rsa -in kek.pri -out form DER -out kek.key openssl rsa -in secureboot.pri -out form DER -out secureboot.key  Then load the lot to your token: p11 -l -p <pin> -w key -a <label> --usage-sign --usage-decrypt --private -i platformkey.key p11 -l -p <pin> -w key -a <label> --usage-sign --usage-decrypt --private -i kek.key p11 -l -p <pin> -w key -a <label> --usage-sign --usage-decrypt --private -i secureboot.key p11 -l -p <pin> -w cert -a <label> -i platformkey.cer p11 -l -p <pin> -w cert -a <label> -i kek.cer p11 -l -p <pin> -w cert -a <label> -i secureboot.cer  3. Add your PKCS#11 module to your database: modutil -dbdir ~/efi-secure-boot/nss -add CardOS -libfile /opt/cardos/lib/libcardos11.so  Now when you run $ modutil -dbdir ~/efi-secure-boot/nss -list

Listing of PKCS #11 Modules
-----------------------------------------------------------
1. NSS Internal PKCS #11 Module
slots: 2 slots attached

slot: NSS Internal Cryptographic Services
token: NSS Generic Crypto Services

slot: NSS User Private Key and Certificate Services
token: NSS Certificate DB

2. CardOS
library name: /opt/cardos/lib/libcardos11.so
slots: 1 slot attached

token: UEFI
-----------------------------------------------------------

4. You are now ready to use pesign. You can check your certificates are detected with:

$certutil -d ~/efi-secure-boot/nss -h UEFI -L Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI Enter Password or Pin for "UEFI": UEFI:Antony Vennard Whiteprophet Platform Key 2016 u,u,u UEFI:Antony Vennard Whiteprophet KEK 2016 u,u,u UEFI:Antony Vennard Whiteprophet Secureboot Signing Key 2016 u,u,u  which you could also check with: $ p11 --login -p <pin> -O
Using slot 0 with a present token (0x1)
Private Key Object; RSA
label:      Antony Vennard Whiteprophet Platform Key 2016
Usage:      decrypt, sign, unwrap, derive

Private Key Object; RSA
label:      Antony Vennard Whiteprophet KEK 2016
ID:         bbd6608d6fb11e29109637028e29d610
Usage:      decrypt, sign, unwrap, derive

Private Key Object; RSA
label:      Antony Vennard Whiteprophet Secureboot Signing Key 2016
Usage:      decrypt, sign, unwrap, derive

Certificate Object, type = X.509 cert
label:      Antony Vennard Whiteprophet Platform Key 2016
Certificate Object, type = X.509 cert
label:      Antony Vennard Whiteprophet KEK 2016
ID:         bbd6608d6fb11e29109637028e29d610
Certificate Object, type = X.509 cert
label:      Antony Vennard Whiteprophet Secureboot Signing Key 2016

5. Set up OpenSSL to use your token's engine, both for openssl smime commands and for sign-file.

Updated March 2017: the best way to achieve this is to plug your PKCS#11 module into p11-kit. To do this, you need the configuration instructions, which boils down to creating either /etc/pkcs11/modules/yourlib.module or ~/.pkcs11/modules/yourlib.module. For my use case, I created /etc/pkcs11/modules/cardos.module with the contents:

module: /opt/cardos/lib/libcardos11.so
managed: yes


This will then load the PKCS#11 library into all applications that use p11-kit.

Many thanks to David Woodhouse for his advice and feedback regarding using p11-kit.

Deprecated instructions: I created /root/uefisb/openssl.cnf for sign-file to use and ~/efi-secure-boot/openssl.cnf for openssl smime. These both contain:

openssl_conf = openssl_init
engines = engine_section

[openssl_init]
engines = engine_section

[engine_section]
pkcs11 = pkcs11_cardos

[pkcs11_cardos]
engine_id = pkcs11
dynamic_path = /usr/lib64/openssl/engines/libpkcs11.so
MODULE_PATH = /opt/cardos/lib/libcardos11.so
init = 0


The remaining instructions are still valid:

You can then use this for signatures as detailed above using for example:

alias smime_token="openssl smime -engine pkcs11 -keyform engine -inkey 'pkcs11:object=Antony%20Vennard%20Whiteprophet%20Secureboot%20Signing%20Key%202016'"


The -inkey option is defined in rfc7512. If you want to find yours without too much thought, you can also try:

p11tool --provider=... --list-all --login


Since I am using Atos Cards for this particular use, I checked with the Windows viewer just to make sure everything was there.

## End

That is it. You should now have a secure boot system with optionally protected keys that only you can use.

## Revisions

1. 2017-03-09 - updated to incorporate the advice of David Woodhouse on using p11-kit instead of the horribleness of OpenSSL module configuration.
2. 2017-01-23 - initial post.