Enable Fedora UEFI Secure Boot with Custom Keys and Self-Signed Bootloader, Kernel, and Modules

Fedora UEFI Secure Boot with Custom Keys - Featured Image

In this blog, I’ll show you how to safeguard the pre-boot environment by enabling Fedora UEFI Secure Boot with custom keys and self-signing all of the bootloader(s), kernel(s), and module(s) with your private key in order to safely boot the operating system.

The basic concept behind Secure Boot is that UEFI firmware should only pass control to the operating system if it can cryptographically verify boot components against a pre-distributed set of public keys, signatures, and hashes. So when you power on the computer, the firmware checks the signature of each boot component, such as the bootloader, kernel, module, and so on. If the signatures are valid, the computer will be allowed to finish booting, and the firmware will hand over control to the operating system.

To keep this guide easy and secure, I installed a fresh copy of the Fedora 35 Workstation under KVM virtualization with automatic partitioning and secure boot enabled. This virtual machine will be used to test all of the steps I’ll take, such as key creation and enrollment, signing different binaries, and so on. I strongly recommend that you do the same before enrolling your custom keys on your actual computer. Experiment with all of the action on the virtual machine first, and only if you’re satisfied with the results, apply them to your actual computer.

If you haven’t yet installed KVM virtualization on your computer, check out my other blog on how to install KVM virtualization. I have also written a blog on how to install a guest OS in KVM using Virt-Manager. Take a look at both of them.

If you have followed my earlier post ‘Install Fedora 35 with LUKS Full Disk Encryption (FDE)‘ and encrypted your distribution with LUKS, this guide also applies to you.

So let’s get started.

Certain packages are required before you can begin configuring secure boot. So, start the Fedora virtual machine and install the packages listed below.

$ sudo dnf install efitools keyutils mokutil openssl pesign sbsigntools kernel-devel-$(uname -r)

1. Overview of Secure Boot Keys

The UEFI specification provides four types of Secure Boot keys that can be included in your firmware. To list them all, use the following command.

$ efi-readvar

1.1 Platform Key (PK)

This is the top-level key used in Secure Boot. Platform Key (PK) creates a relationship of trust between the system owner and the firmware. UEFI Secure Boot only supports a single PK in a system. If a PK already exists, you will be unable to add another unless the existing one is removed. The PK holder has the ability to replace an existing PK as well as update/replace the Key Encryption Key (KEK). The PK is usually owned by the motherboard manufacturer, who has complete control over the secure boot key chain. So, if you want total control over the Secure Boot process, you must replace the PK with your own.

Find out who is currently in possession of the PK.

$ efi-readvar -v PK
Variable PK, length 976 
PK: List 0, type X509
  Signature 0, size 948, owner 8be4df61-93ca-11d2-aa0d-00e098032b8c
    Subject:
      CN=Red Hat Secure Boot (PK/KEK key 1), emailAddress=secalert@redhat.com
    Issuer:
      CN=Red Hat Secure Boot (PK/KEK key 1), emailAddress=secalert@redhat.com

As you can see, Red Hat owns the PK because KVM is a product of Red Hat Inc. If you check it on your actual system, it will usually be owned by the manufacturer of the motherboard/computer.

To list the public key in the PK, use the following command.

$ mokutil --pk

1.2 Key Exchange Key (KEK)

In the Secure Boot key hierarchy, the KEK comes next. KEKs are used to sign Signatures Database (db) and Forbidden Signatures Database (dbx) updates. On most systems, there will be one or more KEKs. KEKs are commonly used by vendors who need to update the db or dbx. Vendors include system manufacturers such as Acer, Dell, and others, as well as operating system providers such as Microsoft. Microsoft KEK is pre-installed on almost every computer these days. If you have a branded system, such as an Acer, Dell, etc., you’re likely to have their own KEK installed as well.

Take a look at the KEKs that have been installed.

$ efi-readvar -v KEK
Variable KEK, length 2536
KEK: List 0, type X509
  Signature 0, size 948, owner a0baa8a3-041d-48a8-bc87-c36d121b5e3d
    Subject:
      CN=Red Hat Secure Boot (PK/KEK key 1), emailAddress=secalert@redhat.com
    Issuer:
      CN=Red Hat Secure Boot (PK/KEK key 1), emailAddress=secalert@redhat.com
KEK: List 1, 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

You’ve two KEKs installed. One is provided by the hardware manufacturer, in this case, Red Hat Inc, and the other is provided by Microsoft Corporation.

To list public keys in the KEK signature database, use the following command.

$ mokutil --kek

In this tutorial, you will delete both of these KEKs and replace them with your own.

1.3 Signature Database (db)

The UEFI Signature Database is where you store the RSA-2048 public keys and SHA-256 hashes that you plan to use to validate the binaries you execute, such as boot managers, boot loaders, kernels, drivers, hardware, and so on. It essentially serves as a boot executable whitelist.

The majority of computers are shipped with two preinstalled Microsoft keys. Your computer’s manufacturer may also have their own key installed as well.

Take a look at the dbs that have been installed.

$ efi-readvar -v db
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

You have two dbs installed. Both were pre-installed by Microsoft. The first db is used to validate the Microsoft Windows OS, while the second db is used to validate third-party vendors approved by Microsoft Corporation.

List public keys in the db:

$ mokutil --db

You will delete both of this dbs and replace them with your own. There are benefits and drawbacks to this approach.

The benefits include total control over which binaries are allowed to load. Because each binary should be signed with your own private key, your Secure Boot is completely secure. Nothing can sneak up on you until you give it permission to do so.

The drawback is that you must sign everything that will be loaded during the booting process, which might be frustrating if you are not a tech-savvy person. Also, the majority of vendors are Microsoft-certified, and if such a vendor’s hardware/software is involved in the boot process and you do not have their keys installed, the system will not boot. You must sign each of them with your own private key in order for it to boot again.

My advice is to start with your own keys, self-sign whatever blocks the secure boot process with your private key, and you should be okay. And if you feel it’s too much, you can always add Microsoft db/dbx and your hardware manufacturer (OEM) db/dbx, which I’m going to show later in this article.

1.4 Forbidden Signature Database (dbx)

The Forbidden Signature Database (dbx) is a kind of anti-db. It includes keys and hashes that belong to the undesired binary that you do not wish to execute when the computer boots.

Take a look at the dbx that has been installed.

$ efi-readvar -v dbx
Variable dbx, length 76
dbx: List 0, type SHA256
  Signature 0, size 48, owner a0baa8a3-041d-48a8-bc87-c36d121b5e3d
    Hash:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

It currently just includes a single SHA-256 hash. And by looking at the owner GUID, you can say that it was added by Red Hat. Unfortunately, there is no way to tell which binary the hash belongs to. You should look it up on Google to learn more about it. If a binary matches a key or hash in both the db and the dbx, the dbx takes precedence.

To list hashes in the dbx database, use the command:

$ mokutil --dbx

You will not be creating a separate dbx in this tutorial because you are already maintaining your own custom db list. If you don’t want a binary to execute at boot time, just don’t add it to the db list in the first place. This is not the case with vendors like Microsoft or Red Hat, because they will have already signed a large number of binaries with the same private key, only to discover later that some of them have been compromised or are out of date. As a result, such binaries are added to the blacklist (dbx).

2. Backup the Original Secure Boot Keys

Before you can generate your own keys and add them to UEFI Secure Boot, make a backup of the original keys somewhere secure in case you need to use them later.

# mkdir /backup && cd /backup
# efi-readvar > efi-original-keys.txt
# efi-readvar -v PK -o PK.original.esl
# efi-readvar -v KEK -o KEK.original.esl
# efi-readvar -v db -o db.original.esl
# efi-readvar -v dbx -o dbx.original.esl

3. Remove the Original Secure Boot Keys

Now that we’ve saved the original UEFI Secure Boot keys that came with the computer, we can now safely delete them.

Boot into your computer’s firmware.

# systemctl reboot --firmware-setup

Because various firmwares have different methods for deleting keys, I’ll only describe how to delete them in the KVM machine’s firmware.

In the firmware main screen, select the ‘Device Manager‘ option.

Fedora UEFI Secure Boot with Custom Keys - Firmware

Next, select the ‘Secure Boot Configuration‘ option. Scroll down to ‘Reset Secure Boot Keys‘, then hit the <Enter> key.

Fedora UEFI Secure Boot with Custom Keys - Reset Keys

Press [Yes] to remove all the keys and reboot the system to return to the operating system.

Fedora UEFI Secure Boot with Custom Keys - Reboot

Now check the status of Secure Boot from the terminal.

$ sudo bootctl status 2>&1 | grep -E 'Secure|Setup'
  Secure Boot: disabled
   Setup Mode: setup

As you can see, Secure Boot has been disabled, and the platform is in setup mode, which means you need to provide a Platform Key (PK).

As for the entries in the Secure Boot chain, they are all successfully removed.

$ efi-readvar
Variable PK has no entries
Variable KEK has no entries
Variable db has no entries
Variable dbx has no entries
Variable MokList has no entries

4. Generate Your Own Secure Boot Keys

The first step in changing your computer’s default set of keys is to generate your own. Although RSA-2048 bits are the industry standard for Secure Boot keys, I’ll be generating much stronger RSA-4096 bits Secure Boot keys, which are supported by the majority of recent computers. If your machine does not support 4096 bits, make keys using 2048 bits instead.

To use Secure Boot you need at least PK, KEK, and db keys. The following instructions create three key pairs (private/public) with self-signed X509 certificates in PEM format. These three keys will be assigned to PK, KEK, and db, respectively.

Make a directory to hold your key pairs. I’ll make a directory called /keys, but it could be anything and anywhere.

# mkdir /keys && cd /keys

4.1 X509 Certificate for Platform Key

Create a new file called PK.config and add the following lines. Make the necessary modifications to suit your preferences. Changes that can be made are highlighted in orange color. The flag ‘CA:FALSE‘ indicates that the certificate was not issued by a Certificate Authority and is instead a self-signed certificate.

[ req ]
default_bits           = 4096
prompt                 = no
string_mask            = utf8only
distinguished_name     = req_distinguished_name
x509_extensions        = my_exts

[ req_distinguished_name ]
countryName            = IN
stateOrProvinceName    = Karnataka
localityName           = Bengaluru
organizationName       = SysGuides
commonName             = SysGuides Platform Key
emailAddress           = info@sysguides.com

[ my_exts ]
basicConstraints       = critical,CA:FALSE
keyUsage               = digitalSignature
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid
subjectAltName         = URI:https://sysguides.com, email:copy
issuerAltName          = issuer:copy

Using this configuration file, generate an X509 certificate key pair for Platform Key (PK).

# openssl req -x509 -new -nodes -utf8 \
    -sha256 -days 3650 -batch -config PK.config \
    -outform PEM -keyout PK.key -out PK.crt

Now, take a look at the PK public key.

# openssl x509 -inform PEM -in PK.crt -text -noout
Certificate:
  Data:
    Version: 3 (0x2)
    Serial Number:
      30:7a:70:5a:d8:a1:1f:37:79:a6:e1:7b:30:09:8c:7a:24:45:e9:08
    Signature Algorithm: sha256WithRSAEncryption
    Issuer: C = IN, ST = Karnataka, L = Bengaluru, O = SysGuides, CN = SysGuides Platform Key, emailAddress = info@sysguides.com
    Validity
      Not Before: Feb 24 05:13:59 2022 GMT 
      Not After : Feb 22 05:13:59 2032 GMT 
    Subject: C = IN, ST = Karnataka, L = Bengaluru, O = SysGuides, CN = SysGuides Platform Key, emailAddress = info@sysguides.com
    Subject Public Key Info:
      Public Key Algorithm: rsaEncryption
        RSA Public-Key: (4096 bit)
        Modulus:
          00:c9:75:92:14:e1:00:1a:d2:92:7d:be:d0:25:f1:
          2f:73:40:66:08:93:68:de:2f:7d:42:90:e2:9b:3e:
          ....
          1b:34:19:72:59:a3:41:80:33:13:76:cc:79:10:3a:
          f4:f7:f3
        Exponent: 65537 (0x10001)
    X509v3 extensions:
      X509v3 Basic Constraints: critical
        CA:FALSE
      X509v3 Key Usage: 
        Digital Signature
      X509v3 Subject Key Identifier: 
        35:9B:F3:FF:91:2B:69:FA:99:0D:FD:A6:87:27:AB:B9:94:50:08:9B
      X509v3 Authority Key Identifier: 
        keyid:35:9B:F3:FF:91:2B:69:FA:99:0D:FD:A6:87:27:AB:B9:94:50:08:9B

      X509v3 Subject Alternative Name: 
        URI:https://sysguides.com, email:info@sysguides.com
      X509v3 Issuer Alternative Name: 
        URI:https://sysguides.com, email:info@sysguides.com
  Signature Algorithm: sha256WithRSAEncryption
     31:bc:39:7c:11:f2:0e:72:8f:27:a7:00:45:56:9b:3d:a6:97:
     8b:4b:c2:74:66:5e:03:32:af:e9:cd:cd:03:f4:81:f2:74:33:
     ....
     f7:23:3f:26:16:ea:31:66:df:e9:05:97:60:b4:2c:94:95:d0:
     41:1f:1a:3a:44:34:8d:89

4.2 X509 Certificate for Key Exchange Key

Copy and save the previously created PK.config file as KEK.config, then modify the commonName line in KEK.config.

# cp PK.config KEK.config
# sed -i 's/Platform Key/Key Exchange Key/g' KEK.config

And using KEK.config file, generate an X509 certificate key pair for Key Exchange Key (KEK).

# openssl req -x509 -new -nodes -utf8 \
    -sha256 -days 3650 -batch -config KEK.config \
    -outform PEM -keyout KEK.key -out KEK.crt

View the KEK public key.

# openssl x509 -inform PEM -in KEK.crt -text -noout

4.3 X509 Certificate for Signature Database

Repeat the same process for Signature Database (db) as well.

# cp PK.config db.config

# sed -i 's/Platform Key/Signature Database/g' db.config

# openssl req -x509 -new -nodes -utf8 \
    -sha256 -days 3650 -batch -config db.config \
    -outform PEM -keyout db.key -out db.crt

And view the db public key.

# openssl x509 -inform PEM -in db.crt -text -noout

All three key pairs required have now been generated.

Generally, you should keep your private keys in a secure location, such as an external drive. However, because you must continue signing binaries with your private key, be sure that only the root user has access to the directory and private keys.

# chmod 0700 /keys
# chmod 0400 /keys/*

5. Enroll Keys in UEFI Secure Boot Chain

Now that you have created your own custom secure boot keys, you need to enroll them into the UEFI Secure Boot chain.

To enroll keys using the efi-updatevar tool, the keys must be in the AUTH format. Convert your public keys (crt) to EFI Signature List (esl) format first, then to EFI Signature List with an authentication header (auth) format by signing with your private key.

You must provide a unique ID in the 8-4-4-4-12 format when converting to ESL format. So generate the unique Id.

# GUID="$(uuidgen)"
# echo $GUID
124537e6-5a4f-406e-8830-dd7c0a0f0f6e

Now, let’s create a PK AUTH file. You must sign using the PK private key for this (PK.key).

# cert-to-efi-sig-list -g "$GUID" /keys/PK.crt /keys/PK.esl

# sign-efi-sig-list \
    -g "$GUID" \
    -t "$(date +'%F %T')" \
    -k /keys/PK.key \
    -c /keys/PK.crt \
    PK \
    /keys/PK.esl \
    /keys/PK.auth

Create a KEK AUTH file. You must also sign using the PK private key for this (PK.key).

# cert-to-efi-sig-list -g "$GUID" /keys/KEK.crt /keys/KEK.esl

# sign-efi-sig-list \
    -g "$GUID" \
    -t "$(date +'%F %T')" \
    -k /keys/PK.key \
    -c /keys/PK.crt \
    KEK \
    /keys/KEK.esl \
    /keys/KEK.auth

Finally, create a db AUTH file. For this, however, you need to sign using the KEK private key (KEK.key).

# cert-to-efi-sig-list -g "$GUID" /keys/db.crt /keys/db.esl

# sign-efi-sig-list \
    -g "$GUID" \
    -t "$(date +'%F %T')" \
    -k /keys/KEK.key \
    -c /keys/KEK.crt \
    db \
    /keys/db.esl \
    /keys/db.auth

Change the file mode bits for newly created public key variants so that only root has access to them.

# chmod 0400 /keys/*

Now enroll the AUTH files in the firmware. You must first enroll db.auth, then KEK.auth, and finally PK.auth.

# efi-updatevar -f /keys/db.auth db
# efi-updatevar -f /keys/KEK.auth KEK
# efi-updatevar -f /keys/PK.auth PK

Check the state of the UEFI Secure Boot now.

# bootctl status 2>&1 | grep -E 'Secure|Setup'
  Secure Boot: disabled
   Setup Mode: user

As you can see, Secure Boot has now entered user mode. When this item is in user mode, the system will do secure boot authentication.

Regarding the keys, they have all been successfully enrolled.

# efi-readvar
Variable PK, length 1701
PK: List 0, type X509
  Signature 0, size 1673, owner 124537e6-5a4f-406e-8830-dd7c0a0f0f6e
    Subject:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Platform Key, emailAddress=info@sysguides.com
    Issuer:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Platform Key, emailAddress=info@sysguides.com
Variable KEK, length 1709
KEK: List 0, type X509
  Signature 0, size 1681, owner 124537e6-5a4f-406e-8830-dd7c0a0f0f6e
    Subject:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Key Exchange Key, emailAddress=info@sysguides.com
    Issuer:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Key Exchange Key, emailAddress=info@sysguides.com
Variable db, length 1713
db: List 0, type X509
  Signature 0, size 1685, owner 124537e6-5a4f-406e-8830-dd7c0a0f0f6e
    Subject:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Signature Database, emailAddress=info@sysguides.com
    Issuer:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Signature Database, emailAddress=info@sysguides.com
Variable dbx has no entries
Variable MokList has no entries

You have now completed enrolling your keys.

6. Sign Binaries

Before you can enable Secure Boot and boot into the operating system, you must first sign the bootloader (shimx64.efi).

To know which bootloader(s) are active on your computer, use the following command and scroll down to the bottom.

# bootctl status --no-pager
...
...
Boot Loaders Listed in EFI Variables:
        Title: Fedora
           ID: 0x0002
       Status: active, boot-order
    Partition: /dev/disk/by-partuuid/67449927-c6d5-4de1-8d9b-94b069361460
         File: └─/EFI/fedora/shimx64.efi
...

6.1 Sign Bootloader

Let’s begin by signing the shimx64.efi. Find out who’s already signed the shimx64.efi bootloader.

# pesign --show-signature \
    --in=/boot/efi/EFI/fedora/shimx64.efi
---------------------------------------------
certificate address is 0x7f5a1cfaca18
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is Microsoft Windows UEFI Driver Publisher
No signer email address.
No signing time included.
There were certs or crls included.
---------------------------------------------

Microsoft has already signed the shimx64.efi bootloader. If you would like to keep the Microsoft signature, this’s fine. However, I’d like to keep the signatures that I signed or those that Fedora signed. So I will remove all the third-party signatures.

Use the pesign tool to remove the signatures. The pesign tool does not yet support in-place writing, so you must first output to a different file. I’ll name the output file shimx64.efi.empty.

# pesign --remove-signature --signature-number=0 \
    --in=/boot/efi/EFI/fedora/shimx64.efi \
    --out=/boot/efi/EFI/fedora/shimx64.efi.empty

Review the shimx64.efi.empty file to ensure all signatures are removed.

# pesign --show-signature \
    --in=/boot/efi/EFI/fedora/shimx64.efi.empty
No signatures found.

Make a backup of the original shimx64.efi bootloader in case you need it later.

# cp /boot/efi/EFI/fedora/shimx64.efi /backup

Now, using the sbsign tool, sign the shimx64.efi bootloader using your db keys.

# sbsign --key /keys/db.key --cert /keys/db.crt \
    --output /boot/efi/EFI/fedora/shimx64.efi \
    /boot/efi/EFI/fedora/shimx64.efi.empty

Verify that the shimx64.efi bootloader now has your signature.

# pesign --show-signature \
    --in=/boot/efi/EFI/fedora/shimx64.efi
---------------------------------------------
certificate address is 0x7f3ab2bcaa18
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is SysGuides Signature Database
The signer's email address is info@sysguides.com
Signing time: Thu Feb 24, 2022
There were certs or crls included.
---------------------------------------------

You can now remove the shimx64.efi.empty file.

# rm /boot/efi/EFI/fedora/shimx64.efi.empty

Reboot the computer.

# reboot

6.2 Sign Kernel

As for the kernel, it is already pre-signed by Fedora and when a kernel is loaded, its signature is validated against the public X509 keys in the kernel system keyring (.builtin_trusted_keys) and the kernel platform keyring (.platform).

Let’s see then what keys are stored in the .builtin_trusted_keys and .platform Keyring.

# keyctl list %:.builtin_trusted_keys
1 key in keyring:
927555564: ---lswrv 0 0 asymmetric: Fedora kernel signing key: f1d9054ec4ff0f353ff9c215c97ed0148cbcb63c

# keyctl list %:.platform
2 keys in keyring:
939933397: ---lswrv 0 0 asymmetric: SysGuides Signature Database: 39c23ad9bdace8e46a844147043e45122b42ed8d
 63525553: ---lswrv 0 0 asymmetric: Fedora Secure Boot CA: fde32599c2d61db1bf5807335d7b20e4cd963b42

When you enroll your custom public key, it gets automatically added to the .platform keyring as well.

Now, find out who already has signed the kernel.

# pesign --show-signature \
    --in=/boot/vmlinuz-$(uname -r)
---------------------------------------------
certificate address is 0x7fb91f98a7a8
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is Fedora Secure Boot Signer
No signer email address.
Signing time: Fri Feb 11, 2022
There were certs or crls included.
---------------------------------------------
certificate address is 0x7fb91f98b0f0
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is kernel-signer
No signer email address.
Signing time: Fri Feb 11, 2022
There were certs or crls included.
---------------------------------------------

As you can see, the kernel is signed by Fedora and kernel-signer, both of which are issued by the Fedora Secure Boot CA. You may find out more about the issuer by using the following command.

# sbverify --list /boot/vmlinuz-$(uname -r)
signature 1
image signature issuers:
 - /CN=Fedora Secure Boot CA
image signature certificates:
 - subject: /CN=Fedora Secure Boot Signer
   issuer:  /CN=Fedora Secure Boot CA
 - subject: /CN=Fedora Secure Boot CA
   issuer:  /CN=Fedora Secure Boot CA
signature 2
image signature issuers:
 - /C=US/ST=Massachusetts/L=Cambridge/O=Red Hat, Inc./OU=Fedora Secure Boot CA 20200709/CN=fedoraca
image signature certificates:
 - subject: /C=US/ST=Massachusetts/L=Cambridge/O=Red Hat, Inc./OU=Fedora Secure Boot Signer/OU=bkernel01 kernel/CN=kernel-signer
   issuer:  /C=US/ST=Massachusetts/L=Cambridge/O=Red Hat, Inc./OU=Fedora Secure Boot CA 20200709/CN=fedoraca
 - subject: /C=US/ST=Massachusetts/L=Cambridge/O=Red Hat, Inc./OU=Fedora Secure Boot CA 20200709/CN=fedoraca
   issuer:  /C=US/ST=Massachusetts/L=Cambridge/O=Red Hat, Inc./OU=Fedora Secure Boot CA 20200709/CN=fedoraca

As the kernel is signed by Fedora itself, and not by any other third-party, there is no reason to add your signature as well. If you turn on Secure Boot right now and reboot, everything should work flawlessly.

But, if you still want to sign this kernel, or any other custom kernel, use the command below.

# sbsign --key /keys/db.key --cert /keys/db.crt \
    --output /boot/vmlinuz-$(uname -r) \
    /boot/vmlinuz-$(uname -r)

# pesign --show-signature \
    --in=/boot/vmlinuz-$(uname -r)
---------------------------------------------
certificate address is 0x7f9507a347a8
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is Fedora Secure Boot Signer
No signer email address.
Signing time: Fri Feb 11, 2022
There were certs or crls included.
---------------------------------------------
certificate address is 0x7f9507a350f0
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is kernel-signer
No signer email address.
Signing time: Fri Feb 11, 2022
There were certs or crls included.
---------------------------------------------
certificate address is 0x7f9507a35cb8
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is SysGuides Signature Database
The signer's email address is info@sysguides.com
Signing time: Thu Feb 24, 2022
There were certs or crls included.
---------------------------------------------

Now that the bootloader and kernel have been signed, go ahead and enable the Secure Boot.

Reboot to the firmware setup.

# systemctl reboot --firmware-setup

Navigate to “Device Manager” -> “Secure Boot Configuration“, then tick the “Attempt Secure Boot” check box to enable Secure Boot. Then, restart the system to the operating system.

# bootctl status 2>&1 | grep -E 'Secure|Setup'
  Secure Boot: enabled
   Setup Mode: user

You now have a computer with a pre-boot environment secured with your own custom keys.

7. Sign Kernel Modules

Like the kernel, Fedora has already pre-signed most of the kernel modules that come with it.

7.1 Check If the Kernel Module Is Already Signed

To find out if the module has already been signed, follow the steps below. I will use the kvm_intel module as an example, which has already been signed by Fedora.

# lsmod | grep kvm_intel
kvm_intel             356352  0
kvm                  1028096  1 kvm_intel

# modinfo -F signer kvm_intel
Fedora kernel signing key

As shown, the Fedora kernel signing key is used to sign the module. If you don’t get an output, it’s not signed. The signature is validated using the kernel system keyring (.builtin_trusted_keys).

# keyctl list %:.builtin_trusted_keys
1 key in keyring:
891608527: ---lswrv 0 0 asymmetric: Fedora kernel signing key: f1d9054ec4ff0f353ff9c215c97ed0148cbcb63c

7.2 Example 1: Sign VirtulBox Kernel Modules

If UEFI Secure Boot is enabled and you try to run the VirtualBox guest, you will encounter the following error.

Fedora UEFI Secure Boot with Custom Keys - VirtualBox Error

Based on the error description, you must sign the vboxdrv, vboxnetflt, vboxnetadp, and vboxpci kernel modules.

So, first, see if the vboxdrv kernel module is loaded.

$ lsmod | grep vboxdrv

There is no output. This indicates that the vboxdrv kernel module is not loaded.

Then check if you have the VirtualBox kernel modules installed.

# find /lib/modules/$(uname -r) -type f \
    \( -name 'vboxdrv*' -o -name 'vboxnetflt*' \
    -o -name 'vboxnetadp*' -o -name 'vboxpci*' \)
/lib/modules/5.16.9-200.fc35.x86_64/misc/vboxdrv.ko
/lib/modules/5.16.9-200.fc35.x86_64/misc/vboxnetflt.ko
/lib/modules/5.16.9-200.fc35.x86_64/misc/vboxnetadp.ko

Except for vboxpci, I have all other modules installed on my computer. My computer probably doesn’t need it, but yours might be different.

So go ahead and sign all the kernel modules. The syntax is…

/usr/src/kernels/$(uname -r)/scripts/sign-file \
  sha256 \
  your_db_private_key.key \
  your_db_public_key.crt \
  your_kernel_module.ko
# for MOD in /lib/modules/$(uname -r)/misc/vbox*.ko ; \
    do /usr/src/kernels/$(uname -r)/scripts/sign-file \
    sha256 \
    /keys/db.key \
    /keys/db.crt \
    $MOD ; \
    done

Verify the modules have been signed.

# for MOD in /lib/modules/$(uname -r)/misc/vbox*.ko ; \
    do modinfo -F signer $MOD ; \
    done
SysGuides Signature Database
SysGuides Signature Database
SysGuides Signature Database

Reboot or manually load the kernel modules.

# modprobe vboxdrv
# modprobe vboxnetadp
# modprobe vboxnetflt

Check if modules have been loaded correctly.

# lsmod | grep vbox
vboxnetflt             32768  0
vboxnetadp             28672  0
vboxdrv               528384  2 vboxnetadp,vboxnetflt

You can now run the VirtualBox guests without any problems.

7.3 Example 2: Sign Nvidia Kernel Modules

If you have Nvidia drivers installed, you will most likely be unable to boot into the graphical user interface. If this occurs, switch to text-based TTY by pressing <Ctrl>+<Alt>+<F3>. Once the Nvidia Kernel modules have been properly signed, you can boot to the GUI.

Signing the Nvidia kernel modules is similar to signing the VirtualBox kernel modules. The only difference between the two is that Nvidia modules are compressed. You must first uncompress them, sign the modules, and then compress them back.

So, first, find the location of the kernel modules.

# find /lib/modules/$(uname -r) -type f -name 'nvidia*'
/lib/modules/5.16.9-200.fc35.x86_64/extra/nvidia-uvm.ko.xz
/lib/modules/5.16.9-200.fc35.x86_64/extra/nvidia.ko.xz

I’m running commands on a computer that has an old Nvidia card. If you are using a new Nvidia card, you may get the results differently. Notice that Nvidia kernel modules, unlike VirtualBox kernel modules, are compressed. The modules cannot be signed when they are compressed.

So, first, uncompress them.

# cd /lib/modules/$(uname -r)/extra

# unxz nvidia.ko.xz nvidia-uvm.ko.xz

# ls
nvidia.ko  nvidia-uvm.ko

Check if they have already been signed.

# modinfo -F signer nvidia.ko
# modinfo -F signer nvidia-uvm.ko

No output. So they have not been signed. Now go ahead and sign them with your keys.

# /usr/src/kernels/$(uname -r)/scripts/sign-file \
    sha256 \
    /keys/db.key \
    /keys/db.crt \
    nvidia.ko

# /usr/src/kernels/$(uname -r)/scripts/sign-file \
    sha256 \
    /keys/db.key \
    /keys/db.crt \
    nvidia-uvm.ko

Verify the modules have been signed.

# modinfo -F signer nvidia.ko nvidia-uvm.ko
SysGuides Signature Database
SysGuides Signature Database

And compress them back.

# xz nvidia.ko nvidia-uvm.ko

# ls
nvidia.ko.xz  nvidia-uvm.ko.xz

You may now reboot the computer to the GUI without any issues. After restarting, check the status of the modules.

# lsmod | grep nvidia
nvidia              10612736  55
drm                   630784  4 nvidia

7.4 Remove the Signature from the Kernel Module

To remove the existing signature from the kernel module, use the strip command-line tool. For instance, if you wish to remove the signature from the vboxdrv.ko kernel module that you previously signed, use the following command.

# strip -g /lib/modules/$(uname -r)/misc/vboxdrv.ko

Confirm if the signature has been removed.

# modinfo -F signer /lib/modules/$(uname -r)/misc/vboxdrv.ko

No output, which means the signature is removed from the module.

8. Add Microsoft Keys to UEFI Secure Boot

If you wish to dual boot into Microsoft Windows or just use the products that Microsoft has signed, you may want to add the Microsoft keys to the UEFI Secure Boot Signature Database.

8.1 Microsoft Signature Database (db)

Microsoft provides two X509 certificates for the Signature Database (db). One is required to allow the Windows OS Loader to load, while the other is required to allow UEFI drivers and applications from third-party vendors.

Download Microsoft Windows Production PCA 2011 X509 certificate for Windows.

# curl -L https://www.microsoft.com/pkiops/certs/MicWinProPCA2011_2011-10-19.crt \
    -o /keys/MicWinProPCA2011_2011-10-19.crt

Download Microsoft Corporation UEFI CA 2011 X509 certificate for third-party vendors approved by Microsoft.

# curl -L https://www.microsoft.com/pkiops/certs/MicCorUEFCA2011_2011-06-27.crt \
    -o /keys/MicCorUEFCA2011_2011-06-27.crt

Create EFI Signature List (ESL) from Microsoft’s certificates using Microsoft’s GUID (77fa9abd-0359-4d32-bd60-28f4e78f784b)

# sbsiglist --type x509 \
    --owner "77fa9abd-0359-4d32-bd60-28f4e78f784b" \
    --output /keys/MS_0_Win.esl \
    /keys/MicWinProPCA2011_2011-10-19.crt

# sbsiglist --type x509 \
    --owner "77fa9abd-0359-4d32-bd60-28f4e78f784b" \
    --output /keys/MS_1_UEFI.esl \
    /keys/MicCorUEFCA2011_2011-06-27.crt

Combine the two ESL keys into one.

# cat /keys/{MS_0_Win.esl,MS_1_UEFI.esl} > /keys/MS_db.esl

Create a db AUTH file and sign it using your KEK private key (KEK.key). You must provide the append (-a) option since we are appending db keys rather than replacing them.

# sign-efi-sig-list -a \
    -g "77fa9abd-0359-4d32-bd60-28f4e78f784b" \
    -t "$(date +'%F %T')" \
    -k /keys/KEK.key \
    -c /keys/KEK.crt \
    db \
    /keys/MS_db.esl \
    /keys/MS_db.auth

To prevent unintentional changes, the db efivar attribute will be set as immutable. Before appending the AUTH file, you must first remove this attribute.

# lsattr /sys/firmware/efi/efivars/db-*
----i----------------- /sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f

# chattr -i /sys/firmware/efi/efivars/db-*

Append the AUTH file in the UEFI Secure Boot Signature Database. Please make sure that you have included the append (-a) option, otherwise, the Microsoft keys will overwrite and replace your original keys.

# efi-updatevar -a -f /keys/MS_db.auth db

Now check to see if Microsoft keys were added.

# efi-readvar -v db
Variable db, length 4856
db: List 0, type X509
  Signature 0, size 1685, owner 124537e6-5a4f-406e-8830-dd7c0a0f0f6e
    Subject:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Signature Database, emailAddress=info@sysguides.com
    Issuer:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Signature Database, emailAddress=info@sysguides.com
db: List 1, 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 2, 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

Set the attribute back to immutable.

# chattr +i /sys/firmware/efi/efivars/db-*

8.2 Microsoft Forbidden Signature Database (dbx)

You must also include Microsoft’s Forbidden Signature Database (dbx). The database contains multiple certificates, keys, and hashes in order to identify forbidden images.

Download the UEFI Revocation List File for x64 (64 bit). For other architectures, visit this site.

# curl -L https://uefi.org/sites/default/files/resources/dbxupdate_x64.bin \
    -o /keys/dbxupdate_x64.bin

Before you can add Microsoft revocation list Signature Database (dbx) to Secure Boot, you must temporarily remove the PK key. To do so, first, remove the immutable attribute from the PK efivar.

# chattr -i /sys/firmware/efi/efivars/PK-*

After that, remove the Platform Key (PK).

# efi-updatevar -d 0 -k /keys/PK.key PK

Now, add dbxupdate_x64.bin to the dbx.

# efi-updatevar -f /keys/dbxupdate_x64.bin dbx

Finally, re-enroll Platform Key (PK) in the Secure Boot chain and set the immutable attribute of the PK efivar.

# efi-updatevar -f /keys/PK.auth PK
# chattr +i /sys/firmware/efi/efivars/PK-*

Check the Forbidden Signature Database (dbx)

# efi-readvar -v dbx
Variable dbx, length 10156
dbx: List 0, type SHA256
    Signature 0, size 48, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
        Hash:80b4d96931bf0d02fd91a61e19d14f1da452e66db2408ca8604d411f92659f0a
    Signature 1, size 48, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
        Hash:f52f83a3fa9cfbd6920f722824dbe4034534d25b8507246b3b957dac6e1bce7a
    Signature 2, size 48, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
        Hash:c5d9d8a186e2c82d09afaa2a6f7f2e73870d3e64f72c4e08ef67796a840f0fbd
    Signature 3, size 48, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
        Hash:1aec84b84b6c65a51220a9be7181965230210d62d6d33c48999c6b295a2b0a06
    Signature 4, size 48, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
        Hash:c3a99a460da464a057c3586d83cef5f4ae08b7103979ed8932742df0ed530c66
    Signature 5, size 48, owner 77fa9abd-0359-4d32-bd60-28f4e78f784b
        Hash:58fb941aef95a25943b3fb5f2510a0df3fe44c58c95e0ab80487297568ab9771
...
...

The Microsoft revocation list has been added. You may now use any Microsoft product on your computer.

9. Add OEM Key to UEFI Secure Boot (If Any)

If your computer came with an OEM key, you may need to enroll that as well, since it may be required for system restoration or OTA updates. As an example, in this section, I will add the Acer OEM db key which I previously had saved from another Acer laptop. If you have a different make, the technique will remain the same.

The EFI Signature List (ESL) I have saved from the signature database (db) of Acer’s laptop is db.acer.esl. Refer to section ‘2. Backup the Original Secure Boot Keys‘ to know how to save keys.

Extract certificates from the db.acer.esl file.

# sig-list-to-certs db.acer.esl db
X509 Header sls=1543, header=0, sig=1499
file db-0.der: Guid 77fa9abd-0359-4d32-bd60-28f4e78f784b
Written 1499 bytes
X509 Header sls=1600, header=0, sig=1556
file db-1.der: Guid 77fa9abd-0359-4d32-bd60-28f4e78f784b
Written 1556 bytes
X509 Header sls=951, header=0, sig=907
file db-2.der: Guid 92fcafcd-c861-4b8b-aff2-a3d5a3e093f8
Written 907 bytes
X509 Header sls=803, header=0, sig=759
file db-3.der: Guid 73f64a94-c5fc-4e09-9c3b-5104b5e49515
Written 759 bytes
X509 Header sls=785, header=0, sig=741
file db-4.der: Guid 73f64a94-c5fc-4e09-9c3b-5104b5e49515
Written 741 bytes

In total, 5 certificates were extracted in DER format. Looking at the GUID, you can say that db-0.der and db-1.der are from Microsoft. I’m not sure who owns db-3.der and db-4.der. The certificate of interest here is db-2.der, so let’s see who owns it.

# openssl x509 -inform DER -in db-2.der \
    -issuer -subject -dates -noout
issuer=C = Taiwan, ST = TW, L = Taipei, O = Acer, CN = Acer Root CA
subject=C = Taiwan, ST = TW, L = Taipei, O = Acer, CN = Acer Database
notBefore=Jul 10 03:35:15 2013 GMT
notAfter=Jul 10 03:45:15 2033 GMT

The certificate, as shown, belongs to Acer and is valid until July 10, 2033.

So, I’ll add this certificate to my Signature Database (db). Using the GUID 92fcafcd-c861-4b8b-aff2-a3d5a3e093f8, I’ll convert it first into ESL format, then to AUTH format by signing with my KEK keys. Make sure you have included the append (-a) option when signing to AUTH key.

# sbsiglist --type x509 \
    --owner "92fcafcd-c861-4b8b-aff2-a3d5a3e093f8" \
    --output db-2.esl \
    db-2.der

# sign-efi-sig-list -a \
    -g "92fcafcd-c861-4b8b-aff2-a3d5a3e093f8" \
    -t "$(date +'%F %T')" \
    -k /keys/KEK.key \
    -c /keys/KEK.crt \
    db \
    db-2.esl \
    db-2.auth

Append the Acer AUTH key in the Signature Database.

# chattr -i /sys/firmware/efi/efivars/db-*
# efi-updatevar -a -f db-2.auth db
# chattr +i /sys/firmware/efi/efivars/db-*

Now check if the Acer key has been added to the Signature Database.

# efi-readvar -v db
Variable db, length 5807
db: List 0, type X509
  Signature 0, size 1685, owner 124537e6-5a4f-406e-8830-dd7c0a0f0f6e
    Subject:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Signature Database, emailAddress=info@sysguides.com
    Issuer:
      C=IN, ST=Karnataka, L=Bengaluru, O=SysGuides, CN=SysGuides Signature Database, emailAddress=info@sysguides.com
db: List 1, 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 2, 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 3, type X509
  Signature 0, size 923, owner 92fcafcd-c861-4b8b-aff2-a3d5a3e093f8
    Subject:
      C=Taiwan, ST=TW, L=Taipei, O=Acer, CN=Acer Database
    Issuer:
      C=Taiwan, ST=TW, L=Taipei, O=Acer, CN=Acer Root CA

10. Conclusion

Congratulations, you’ve finished securing your pre-boot environment by enabling Fedora UEFI Secure Boot with custom keys. Although the process has been laborious and time-consuming, having full control over the secure boot of your computer is well worth the effort. Don’t forget to password protect your computer’s UEFI firmware. Anybody who gets access to your unprotected firmware can easily reset your custom keys and take control of your computer.

Watch on YouTube

guest
7 Comments
Newest
Oldest
Inline Feedbacks
View all comments