Introduction
The UEFI specification (2.3.1c) defines several key stores and their formats: The Platform Key (PK), The Key Exchange Key (KEK) The key database (db) and the forbidden signatures database (dbx). This post describes the relationships between them all and how they’re implemented in the Tianocore reference implementation. This means that not everything possible is implemented because Tianocore follows the Windows 8 hardware certification requirements closely.
UEFI Secure Variables
All of the keys are stored in UEFI secure variables (see section 7.2 of the UEFI specification). A secure variable cannot be updated unless the person attempting the update can prove (with a digital signature on a specified payload, called the authentication descriptor) that they possess the private part of the key used to create the variable. The UEFI specifications only allow two types of signing keys: X509 and RSA2048. A secure variable may be cleared by writing an empty update (which must still contain a valid authentication descriptor).
Authentication Descriptor
The specifications allow two types of authentication descriptors: time based and monotonic count based. Once a variable is created, it stores both the key that created it and the initial value for the time or monotonic count and will only accept subsequent updates signed with that key and which have the same update type (time based or monotonic count) that it was created with. The reason for this is to prevent replay of previous updates, so a newer update must have either a later time or a higher monotonic count. Once the update is accepted, the time or count is updated as well to the value in the authentication descriptor.
Setup and User Modes
When a platform is in Setup Mode, the secure variables may be altered without the usual authentication checks (although the secure variable writes must still contain an authentication descriptor for the initial key and update type but the actual authentication information isn’t checked). In this mode, secure boot is turned off.
In user mode, the platform will check that any attempt to write to a secure variable has a validly signed authentication descriptor. In user mode, the platform will also expose a secure boot flag (which is on by default). If secure boot is set, it will only execute efi binaries which
- are unsigned but have a sha-256 hash that is in db and not in dbx or
- are signed and have a signature in db but not in dbx or
- are signed by either a key in KEK or a key in db and neither the key nor the signature appears in dbx.
Platform Key (PK)
The Platform Key is the key to the platform and is stored in the PK variable. Its job is to control access to the PK variable and the KEK variable. In most implementations, only one key at once may be stored in PK and the PK may only be an X509 key.
If the PK variable is cleared (either by an authenticated variable write or by a special user present firmware action), the platform must immediately enter setup mode.
The PK variable may only be updated by an authentication descriptor signed with the platform key.
Note: The platform key may not be used to sign binaries for execution.
Key Exchange Key (KEK)
The Key Exchange Key is used to update the signature database and is stored in the KEK variable. It may be used either to update the current signature databases or to sign binaries for valid execution. In most current implementations, the KEK variable may contain multiple keys which may be of type X509 or RSA2048 any of which may perform the function of the key exchange key.
The KEK variable may only be updated by an authentication descriptor signed with the platform key.
The Forbidden Signatures Database (dbx)
The forbidden signatures database is used to invalidate efi binaries and loadable roms when the platform is operating in secure mode. It is stored in the dbx variable. The dbx variable may contain either keys, signatures or hashes. In secure boot mode, the signature stored in the efi binary (or computed using SHA-256 if the binary is unsigned) is compared against the entries in the database. Execution is refused if either
- The binary is unsigned and the SHA-256 hash of the binary is in dbx or
- The image is signed and the signature matches an entry in dbx or
- The image is signed and the key used to create the signature matches an entry in dbx.
Note: since unsigned binaries are automatically refused execution, the addition of a hash to dbx serves only to prevent that image being authorised by having an entry for its hash in the signature database (see below).
The dbx variable may only be updated by an authentication descriptor signed with the key exchange key.
The Signature Database (db)
The signature database is used to validate signed efi binaries and loadable roms when the platform is operating in secure mode. It is stored in the db variable. The db variable may contain a mixed set of keys, signatures or hashes. In secure boot mode, the signature stored in the efi binary (or the SHA-256 hash if there is no signature) is compared against the entries in the database. The image will be executed if either
- the image is unsigned and a SHA-256 hash of the image is in the database or
- the image is signed and the signature itself is in the database or
- the image is signed and the signing key is in the database (and the signature is valid).
The db variable may only be updated by an authentication descriptor signed with the key exchange key.
How Key Verification Works
Although key verification with either X509 or RSA2048 keys looks to be SSL standard, it isn’t quite: the key chain is only verified back to the key in the databases and no further. This means that none of the keys has to be self signed, and that the usual ssl approach to verify all the way to the root CA isn’t followed.
Some consequences of all of this
As you can see from the above, the holder of the platform key is essentially the owner of the platform. However, simply knowing the platform key (the private part) isn’t enough because in order to change the platform you have to be able to execute binaries and the platform will only execute binaries signed by a key either in KEK or db. If you take control of your platform by installing a platform key, you need to ensure that this key (or another you control) is also added to either KEK or db so you can sign binaries with it and have them execute.
Pingback: Spanish Linux group runs to teacher, complains about Microsoft’s Secure Boot |
Pingback: Take Control of Your PC with UEFI Secure Boot | The Root Shell
Hi,
This was quite helpfull in getting to know more about secure boot.
But I am also looking for a way to boot a live OS (win2go, live linux distro) next to my company laptop.
They have UEFi only secure boot enabled laptop, and since i travel a lot i like to take my own OS along to watch a movie/play a game when i stay in a hotel, instead of carrying my own laptop along.
Is there a way to boot my private OS ? The EUFI options are most locked.
Thank you
It depends on the UEFI of the actual laptop. If it comes with preinstalled Windows 8.1/10, then it accepts only the KEK from Microsoft (I think). So you need a Microsoft signed boot loader. If you want to run Linux, then you can use Shim https://github.com/rhboot/shim which is a Microsoft signed app. It has it’s own db for our custom keys, called MOK (machine owner key), which you can use to sign a boot loader, for example GRUB. If you use a boot loader, which can boot from an encrypted /boot and everything else is encrypted as well, then I think there is no way to modify your system, while you are sleeping on the airplane. If the UEFI of your laptop supports custom secure boot, then you can add your key to the UEFI db and you don’t need Shim.
Thank you for this clear and short explanation of all that UEFI secure boot stuff!
There are guides that explain how to put your own PK into your firmware and have your own KEK.
But, I wonder are all mainboards able to clear the PK?
I have an Asrock AMD system, I can enable and disable secure boot and I can reset the keys to some defaults, and I can see it is in setup mode. But, there seem no GUI in the UEFI to manually put my own PK and KEK…..
Can you put your own PK and KEK into the firmware from the UEFI shell if there is no GUI menu in the UEFI?
My MSI C236M and my Asus Z97-P support it, afaik. my Asus T100TA tablet does not support it. My impression that tablets and notebooks coming with preinstalled Windows don’t support custom PK and KEK, but you can still use Shim + MOK by those. By your mobo I think you should ask the Asrock support. Maybe they have a firmware upgrade or some special UEFI option for it.
I meant to add, look for the tool, doh, what’s it called, it might be keytool.efi. *.efi are binary executables in an EFi environment, like .exe in Windows.
Pingback: VirtualBox Kernel driver not installed – Erawanu Seton
Thanks for the article!
Thanks for the article.
Say I want to put my own PK and KEK. They need to have the right format. As far as I understand, this format is often referred to as EFI Signing List (ESL). Is this format documented somewhere, and are there Tools to read/write these files ?
ESL is documented in the UEFI standard:
http://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_7_A%20Sept%206.pdf
In section 31.4.1 (The Signature Database); look for struct _EFI_SIGNATURE_LIST
Thank you.
I have saved my PK key on a usb stick. I am desperatly trying to read this file (using Certutil on Windows 10) but can’t figure it out. You say the PK is stored in a PK variable. Does that mean that the format of the file I get when I say the PK on a usb stick is the same as the PK variable ? If so, what is the format of this variable ? I thought it would be an DER encoded x509 certificate, but in this case CertUtil.exe should have been able to read it but I get a dump of hex characters instead…!?
I don’t know of anything for windows. For linux efitools
https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git
Has a sig-list-to-certs utility which can break apart the ESL file you get out of the variable into its component X509 certificates. It probably won’t compile on windows because of the gnu-efi dependency, though.
Nice article, thanks for the summary.
There is just one slight contradiction:
“Note: The platform key may not be used to sign binaries for execution.”
vs
“If you take control of your platform by installing a platform key, you need to ensure that this key (or another you control) is also added to either KEK or db so you can sign binaries with it and have them execute.”
Should certificates that are expired be usable for secure boot at UEFI setup/configuration time and/or thereafter upon each boot? I did not find any mention of this in the UEFI specification.
Thank you.
The UEFI specs require that no check is done of the expiry or start dates for a secure boot certificate. The reason is that the BIOS clock might not be reliable and boot and it also blocks a potential DoS vector (tamper with the clock and force a reboot).
Thank you for the explanation.
You mentioned that KEK can be used “to sign binaries for valid execution”. However the UEFI Spec v2.8 makes no mention of this. Section “32.5.3.3 Authorization Process”, step 3, states that binaries are checked against db and dbx only.
You went on to state that “the KEK variable may contain multiple keys which may be of type X509 or RSA2048”. I’m a bit confused by this as it seems to imply X509 and RSA2048 are two types of the same class. X509 is a certificate format, but RSA2048 is a public key cryptosystem. Looking at the Spec, section “32.3.5 Enrolling Key Exchange Keys”, it states ‘Key exchange keys are stored in a signature database as described in “Signature Database” below.’ Proceeding to section “32.4.1 Signature Database”, we see that the signature type can be a simple hash, a RS2048 key, a RS2048 signature of a hash, a X509 certificate, or a hash of a X509 certificate.
You have to take into account that the post is old: it was current as of UEFI 2.3.1
UEFI keeps changing which keys can sign binaries … I think today it’s just keys in db and the PK.
RSA2048 keys proved to be a huge pain and were deprecated in UEFI 2.5 (I think). They were basically a bare public key. X509 is a bare public key wrapped with a signed shell identifiying the issuer, so there’s no functional difference except that X509 certs are harder to create.
Thanks for clarifying.
RSA2048 keys seems to be supported by the current spec (v2.8). In fact it states that “the recommended Platform Key format is RSA-2048”.
It would be great if the post was updated with the latest information. It ranks quite highly when one googles uefi secure boot keys, and it has one of the most concise and clearest explanation of the keys out there. Thus it’s a great resource for anyone wanting to learn about Secure Boot.
MOK appears to be specific to to shim / linux after shim loaded. While MS/UEFI are working on new requirements for signing and updates are now invalidating all existing CA 2001 signed binaries. Pending MS ability to sign, I need a way to have our shim type loader signed using our own key and the user will have to add that to the DB. The plan is to have a custom program that installs our key if not already installed (from a boot disk). The users I would think have to disable safe boot for it to be able to install. Does that sound like the correct procedure? (in other words if safe boot is disabled can we directly update the “db” variable and then users can continue to use our product). ?
that should have been CA2011