UEFI Secure Boot


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:

  1. Jeremy Kerr’s sbtools available from git://kernel.ubuntu.com/jk/sbsigntool
  2. 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.

31 thoughts on “UEFI Secure Boot

  1. Finnbarr P. Murphy

    A clarification. You state that the PK (The platform key) is “required to be X509”. This is not a UEFI Specification requirement but rather a Microsoft requirement. In fact the UEFI Specification recommends RSA 2048 (see 2.3.1, Errata C, Section 27.5, top of page 1451.)

    1. jejb Post author

      I’m just going by the code in Tianocore as I look at it. The way it’s coded (doubtless according to the MS specs) is that the PK can *only* be X509. The KEK can contain both X509 and RSA2048

  2. Seth

    “CRS” is not an ACPI table type — it’s a METHOD for particular devices in the ACPI DSDT/SSDT tables. Please correct your post.

  3. xsoliman3

    Presumably the ‘OVMF bios’ binary would run on the Windows version of Qemu, if I could extract it from the .rpm

    I already have qemu running the older (duet) efi-bios

    “You must use the CVS version of QEMU to use the BIOS (the version
    0.9.0 won’t work).

    Replace the default QEMU BIOS (usually in /usr/local/share/qemu) by
    the file ‘bios.bin’. “

  4. Pingback: No Boot on UEFI box (Samsung 350V)

  5. Tony

    I have a problem: I’ve tried to boot windows 8 32 bit with tianocore but it gives me the problem related to ACPI and CRS tables, so it results that the (virtual) Machine is not ACPI-capable. Any suggestions to solve this problem?

  6. Darek

    I would like to see such solutions in the future:
    * You have UEFI + Secure Boot turned on – Linux auto repair system like Windows 8 does.
    * You have UEFI + Secure Boot turned off – Linux behave normally, do nothing.
    …instead of just passing by something (UEFI + Secure boot) you can just turn off in BIOS 😉

    The solution should be automatic and simple to work for all “UEFI/Secure Boot” users, even those non-technical.

  7. giggler

    You covered creation of PK with openssl but what about the KEK that signed by PK? sounds like a dumb question I know but I want to make sure I have the process clear.

    1. jejb Post author

      It’s the same process: all keys in the system may be self signed (they don’t have to be, but self signed certificates are just the easiest ones to describe how to create), so you use the PK process but substitute PK< ->KEK

      openssl req -new -x509 -newkey rsa:2048 -keyout KEK.key -out KEK.crt -days < length> -subj “/CN=< my common name>/”

    1. jejb Post author

      I looked into this. The first thing I had to do was unbreak all the builds which had collapsed due to various bitrot effects. All the necessary UEFI pieces should now be building … I’m still testing them, however.

      By “latest” I assume you mean UDK 2014 which is r15322? Once I complete testing of the current openSUSE 13.1 OVMF, I’ll see if I can do that, but it may take some time given the eccentric and finicky way edk2 builds.

      1. Maarten

        Hi James, your efforts are very much appreciated. I’m quite keen on attempting legacy-free device passthrough as per here. The pre-built binaries linked to on that page for Fedora are what I’d be interested in for openSUSE. It would be good to have the following commit in there: link as I’m using the Q35 chipset model in most VMs.

  8. 0ffer

    Your HashTool.efi can browse EFI media in Text USer Interface.
    It seems that many users would be useful Run.efi for browse EFI media and launch EFI applications.

  9. Dave

    Unable to affect keys in user mode

    I downloaded and built the latest version (v1.4.2+2014-05-27); deleted all keys from UEFI; ran LockDown.efi from EFI Shell and reset system.
    Booted off EFI USB stick with signed shell (efi\boot\bootx64.efi) successfully. Secure boot is now enabled and in user mode – only signed executables are allow to run.

    I am unable to append a new key to the db now I am in user mode; I get a Security Violation error (26).

    UpdateVars-signed.efi -a db DB2.auth

    The DB2 key and authentication file was generated as follows:

    openssl req -new -x509 -newkey rsa:2048 -subj “/CN=DB2/” -keyout DB2.key -out DB2.crt -days 3650 -nodes -sha256
    cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc DB2.crt DB2.esl
    sign-efi-sig-list -a -c KEK.crt -k KEK.key db DB2.esl DB2.auth

    I also tried using the KeyTool-signed.efi with same problem.

    I can however append the DB2 key when in setup mode and update the variables manually:

    UpdateVars.efi db DB.auth
    UpdateVars.efi -a db DB2.auth
    UpdateVars.efi KEK KEK.auth
    UpdateVars.efi PK PK.auth

    I have also tried this under Ubuntu 14.04 (signed grubx64.efi) using the following:

    sudo efi-updatevar -a -c DB2.crt -k KEK.key db

    This time I get a Cannot write to db, wrong filesystem permissions

    Also I am unable to switch from user to setup mode using the noPK.auth file either using UpdateVar or KeyTool

    UpdateVars-signed.efi PK noPK.auth

    Do you have any ideas as to why I am having no success?

    1. Dave

      I have had a response from AMI regarding this issue, does this help …

      It looks like the Linux utility is not quite making the signature data per spec. This is listed in section 7.2.1 of the UEFI spec. The following two bolded lines from this section are not compatible:
      4. Construct a DER-encoded PKCS
      Construct a DER-encoded PKCS #7 version 1.5 SignedData (see [RFC2315]) with the signed content as follows:
      a SignedData.version shall be set to 1
      b SignedData.digestAlgorithms shall contain the digest algorithm used when preparing the signature. Only a digest algorithm of SHA-256 is accepted.
      c SignedData.contentInfo.contentType shall be set to id-data
      d SignedData.contentInfo.content shall be absent (the content is provided in the Data parameter to the SetVariable() call)
      e SignedData.certificates shall contain, at a minimum, the signer’s DER-encoded X.509 certificate
      f SignedData.crls is optional.
      g SignedData.signerInfos shall be constructed as:
      — SignerInfo.version shall be set to 1
      — SignerInfo.issuerAndSerial shall be present and as in the signer’s certificate
      — SignerInfo.authenticatedAttributes shall not be present.

      a.: The SignedData sequence from the utility begins with “SignedData” OID 1 2 840 113549 1 7 2. The spec says the first thing must be SignedData.version.
      g.: The utility is including the SignerInfo.authenticatedAttributes field. According to the spec, this should not be present.

      1. jejb Post author

        This might be due either to a difference in openssl versions or the presence of additional terms in the signing certificate. When I look at what I get for authenticated variable updates, I do see version 1, however, I do see some attributes like s/mime types and signature date.

        You can check the signature yourself using asn1parse from openssl (it’s at offset 40 in the bundle)

        openssl asn1parse -inform DER -offset 40 -i -in file

        The starting data should look like:

        0:d=0 hl=4 l=1138 cons: SEQUENCE
        4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
        15:d=1 hl=4 l=1123 cons: cont [ 0 ]
        19:d=2 hl=4 l=1119 cons: SEQUENCE
        23:d=3 hl=2 l= 1 prim: INTEGER :01

        That integer with value :01 is version 1

        It’s possible there’s an extension in your signing certificate that forces the version up (RFC5652 extended RFC2315 and defines versions up to 5 depending on particular signing and signed data characteristics).

        The attributes problem should be fixed by version 1.4.3

  10. Robert

    I am having a similar problem as Dave with trying to get Secure Boot to work. I generate keys using

    openssl req -new -x509 -newkey rsa:2048 -subj “/CN=PK/” -keyout PK.key -out PK.crt -days 3650 -nodes -sha256

    and then I use

    ./efitools/cert-to-efi-sig-list -g `uuidgen` PK.crt PK.esl
    ./efitools/sign-efi-sig-list -k PK.key -c PK.crt KEK KEK.esl KEK.auth
    sudo ./efitools/Cefi-updatevar -f PK.auth PK

    and I get “Cannot write to PK, wrong filesystem permissions.” If I try to use KeyTool, I get the same error 26 security violation. I am using Ubuntu 14.04 and efitools ede47075ba54791245e3bbf20a7e740eb1d91b33. If I use openssl asn1parse, I see a version 1 with no s/mime or other attributes.

    I am definitely sure my system is in setup mode. In case it matters, system is an ASRock Q1900M with BIOS 1.50. Do you have any idea what is wrong?

    1. Tatterdemalian

      It’s possibly something in the ASRock UEFI, because I’m getting the same thing on an ASRock H97M Pro4 mobo with UEFI P2.00 and getting the same error.

      Apparently the ASRock UEFI doesn’t allow append operations in setup mode, at least the way efi-updatevar performs them.

  11. Pingback: Getting by without passwords: disk encryption (part III) | Random Oracle

  12. Trevor

    My PK private key is in an HSM. I can use OpenSSL to access the key. When I try to replicate
    sign-efi-sig-list -t ‘2016-02-25 07:47:47’ -k PK.key -c PK.pem PK PK.esl PK.auth


    sign-efi-sig-list -t ‘2016-02-25 07:47:47’ -o PK PK.esl PK.forsig
    openssl smime -sign -binary -in PK.esl -out PK.signed -signer PK.pem -inkey PK.key -outform DER -md sha256
    sign-efi-sig-list -i PK.signed -t ‘2016-02-25 07:47:47’ PK PK.esl PK.auth

    I do not get the same results

    1. jejb Post author

      openssl will add attributes which the usual secure boot signing process strips. Chances are the differences are just these attributes. To see this, you’ll have to use dd to extract the der format pkcs7 signature and then use openssl to convert it to text

      1. Trevor

        Passing in the noattr flag did the trick. Now I can use my HSM’s openssl engine to access the private key.

        sign-efi-sig-list -t ‘2016-02-25 00:01:00’ -o PK PK.esl PK.forsig
        smime -noattr -sign -binary -in PK.forsig -text -out PK.signed -signer PK.crt -inkey PK.key -outform DER -md sha256
        sign-efi-sig-list -i PK.signed -t ‘2016-02-25 00:01:00’ PK PK.esl PK.auth

  13. Pingback: Main Parts of a Linux Machine – programtweak

  14. Michael Allen

    I am getting some strange behavior trying to manage the secure boot keys from Linux — specifically with the PK/noPK combinations.

    I have an AMI based BIOS.

    If I install PK.esl into PK (from BIOS), secure boot is enabled, and all the signature checking works as expected (grub, and chainloaded vmlinuz signature checks work).

    From Linux, I can remove the PK using the noPK.auth file (good so far). For good measure, I rebooted the system after removing the PK so the new modes get established.

    I can now install PK.auth from within Linux, and secure boot gets enabled again.

    However, I can no longer remove PK using the noPK.auth file.

    If I remove the PK from BIOS, and this time add the PK.auth to the PK database with BIOS, again secure boot gets enabled, but again Linux cannot remove the PK using the noPK.auth file.

    With both PK versions (esl/auth) installed, a complete dump of the PK signature [with a version of efi-readvar that uses “X509_print_ex_fp(stdout, X, 0, 0);” for a verbose output] shows to be identical with ESL or AUTH versions of PK installed.

    What am I missing in the equation so I can freely install PK.auth and noPK.auth back and forth? Even in KeyTool.efi, I get the same error (security violation error 26) trying to remove the PK with the noPK.auth file.

    Any insight is much appreciated.

    1. Michael Allen

      Looks like I had several issues.
      o The efitools published to Ubuntu is pretty old and is missing various issues fixed in the Git repo.
      o I had some issues with the “signature” timestamps in the scripts I created for managing the different signatures. For example, the noPK.auth *must* have a later signature timestamp than the PK.auth or it will not work to disable the PK. My timestamps prior to the fix were identical.


Leave a Reply

Your email address will not be published. Required fields are marked *