UEFI Secure Boot provides a security feature that ensures only trusted digitially signed binaries are executed in the boot chain. Secure Boot validates each digital signature before allowing anything to load during boot. Linux kernel modules are one of the final components of the boot chain. To maintain the signing validation requirement, all kernel modules must be signed and validated. Linux distributions enforce integrity lockdown mode when booting with Secure Boot enabled. Within lockdown mode, kernel module signature validation is enforced. With the mainline kernel, users who wanted the extra flexibility to load their own kernel modules had to go through a complex process to enroll their own keys. This is a thing of the past, as there is now a much simpler process which this blog will explain.
Back in 2013, Linus requested a feature to allow end-users to have the ability “to add their own keys and sign modules they trust” [1]. Many attempts over the years were proposed to solve this problem; all were rejected. The most popular one that many distributions picked up (but was outright rejected upstream) was to load pre-boot firmware keys into the kernel, including the Secure Boot keys.
Linux keyrings are an in-kernel key management and retention facility. Prior to Linux mainline version 5.18, there were two restricted system kernel keyrings (builtin_trusted_keys and secondary_trusted_keys). Only these two keyrings could be used as a trust source for validating and loading sensitive code into the kernel. The keys contained in the builtin_trusted_keys keyring are compiled into the kernel (so vendor specific) and as such, it is not possible to add keys to this keyring during runtime. The secondary_trusted_keys keyring may have new keys loaded into it at anytime; however, the key being added to this keyring must be signed by a key already in the builtin_trusted_keys keyring. In effect, this meant that the key would need to be signed by the distro. There is no established mechanism for the users of a distro to get their keys signed to be included in this keyring.
On UEFI platforms, Linux is traditionally booted from shim, a light weight bootable signed executable. Shim owns many Boot Services (BS) UEFI variables. One such shim variable is Machine Owner Keys (MOK). These are keys the system owner has declared they trust. These keys can be used to validate things further down in the boot chain. For instance, a MOK key could be used to validate a custom kernel with Secure Boot enabled.
Linux 5.18 has introduced a new restricted system kernel keyring, “machine keyring”. The keys within the machine keyring are trusted for use within the Linux kernel. With the introduction of the machine keyring, MOK keys may now be used within Linux. For example: to validate a kernel module allowing the system owner to include their own keys as a trust source for use within the Linux kernel [2]. Just like the builtin_trusted_keys keyring is linked to the secondary_trusted_keys keyring, the new machine keyring is linked to it as well. With this new link in place, the machine keyring will be referenced when the kernel uses the secondary_trusted_keys keyring to vouch for something.
A new UEFI variable has been introduced to enable the machine keyring in Linux. This variable allows the system owner the ability to decide if they want to trust the MOK keys [3]. Within the Oracle Linux shim, this variable is on by default. The system owner may decide to turn this off with mokutil [4]. Again, just like enrolling MOK keys, changing this behavior happens after the reboot.
By default, the machine keyring will contain three MOK keys that are embedded into shim. These three keys are necessary for booting GRUB2 and Linux. As root on a machine, the keys can be displayed using the keyctl utility:
$ keyctl show %:.secondary_trusted_keys Keyring 772746105 ---lswrv 0 0 keyring: .secondary_trusted_keys 252396885 ---lswrv 0 0 \_ keyring: .builtin_trusted_keys 660166481 ---lswrv 0 0 | \_ asymmetric: Oracle CA Server: 702a35b0d12005e5010c0614f7b8abf7c5bd5f73 86702374 ---lswrv 0 0 | \_ asymmetric: Oracle IMA signing CA: a2f28976a05984028f7d1a4904ae14e8e468e551 247354640 ---lswrv 0 0 | \_ asymmetric: Oracle America, Inc.: Ksplice Kernel Module Signing Key: 09010ebef5545fa7c54b626ef518e077b5b1ee4c 264616160 ---lswrv 0 0 | \_ asymmetric: Oracle Linux Kernel Module Signing Key: 2bb352412969a3653f0eb6021763408ebb9bb5ab 772320403 ---lswrv 0 0 \_ keyring: .machine 450491670 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 7c552922286d66bcb33c53d7ee0f1cd716ecdc63 100307441 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 39bff3f0f578f26e527321cafda2a9cdbd71143c 688922247 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 4ff35c3e09ce586fa776d56468d86b022af272f1
The examples presented in this section will illustrate two different approaches that can be used to enroll MOK keys to the machine keyring using Oracle Linux UEK7. There are various tools, methods and hardware for generating and storing private keys. The examples below use the most insecure method for demonstration purposes only. These examples also assume you have root access.
$ efikeygen -d /etc/pki/pesign --ca --self-sign --nickname="mokcert" --common-name='CN=FooBar' --serial=00 --kernel
$ certutil -L -d /etc/pki/pesign -n "mokcert" -o mokcert.der -r
At the password prompt, create a temporary password and enter. This password will need to be entered again when shim loads MokManager to complete the MOK enrollment:
$ mokutil --import ./mokcert.der input password: input password again:
Follow the onscreen prompts from MokManager for enrolling the new MOK key. MokManager will prompt you to enter the password created in the previous step. After the MOK key is enrolled, reboot the machine again. Afterwards, the new FooBar key will be included in the machine keyring.
$ keyctl show %:.secondary_trusted_keys Keyring 312971308 ---lswrv 0 0 keyring: .secondary_trusted_keys 1037502130 ---lswrv 0 0 \_ keyring: .builtin_trusted_keys 330709123 ---lswrv 0 0 | \_ asymmetric: Oracle CA Server: 702a35b0d12005e5010c0614f7b8abf7c5bd5f73 1015945864 ---lswrv 0 0 | \_ asymmetric: Oracle IMA signing CA: a2f28976a05984028f7d1a4904ae14e8e468e551 995965637 ---lswrv 0 0 | \_ asymmetric: Oracle America, Inc.: Ksplice Kernel Module Signing Key: 09010ebef5545fa7c54b626ef518e077b5b1ee4c 568726060 ---lswrv 0 0 | \_ asymmetric: Oracle Linux Kernel Module Signing Key: 2bb352412969a3653f0eb6021763408ebb9bb5ab 245236924 ---lswrv 0 0 \_ keyring: .machine 75753354 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 7c552922286d66bcb33c53d7ee0f1cd716ecdc63 423569441 ---lswrv 0 0 \_ asymmetric: FooBar: d542d5b607e29fbe3fc38373bfd8511078e0dbcb 610218071 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 39bff3f0f578f26e527321cafda2a9cdbd71143c 865719351 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 4ff35c3e09ce586fa776d56468d86b022af272f1
If the system owner has a key in the UEFI Secure Boot DB, they can enroll keys into the MOK without showing physical presence [5]. This simplifies the MOK key enrollment process for large fleets where the key is deployed through the machine’s firmware. The binary, “certmule,” contains the key to be enrolled in the MOK and is signed by the DB key. As shim boots, upon seeing and validating a certmule, it will load the key into the MOK. Later, if the the key used to sign the certmule is revoked, the key will not be loaded into the MOK on subsequent boots.
$ efikeygen -d /etc/pki/pesign --ca --self-sign --nickname='certmule' --common-name="CN=Test" --serial=00 --kernel
$ git clone https://github.com/rhboot/certmule.git $ cd certmule
$ certutil -L -d /etc/pki/pesign -n certmule -o certmule.der -r
With OL9 use efisecdb
$ efisecdb -a -g $(uuidgen) -c certmule.der -o db.esl
With OL8 use efisiglist
$ efisiglist -a -c certmule.der -o db.esl
$ make update all
The certmule binary may be signed by any key contained within the UEFI Secure Boot DB. In this example, we are assuming the key embedded into the certmule is also already contained within the UEFI Secure Boot DB.
$ pesign -i certmule.efi -o /boot/efi/EFI/redhat/shim_certificate.efi -c certmule -s
After the reboot, the new Test certificate will be contained within the machine keyring.
$ keyctl show %:.secondary_trusted_keys Keyring 584848485 ---lswrv 0 0 keyring: .secondary_trusted_keys 710271780 ---lswrv 0 0 \_ keyring: .builtin_trusted_keys 694162499 ---lswrv 0 0 | \_ asymmetric: Oracle CA Server: 702a35b0d12005e5010c0614f7b8abf7c5bd5f73 23095449 ---lswrv 0 0 | \_ asymmetric: Oracle IMA signing CA: a2f28976a05984028f7d1a4904ae14e8e468e551 248749911 ---lswrv 0 0 | \_ asymmetric: Oracle America, Inc.: Ksplice Kernel Module Signing Key: 09010ebef5545fa7c54b626ef518e077b5b1ee4c 563122648 ---lswrv 0 0 | \_ asymmetric: Oracle Linux Kernel Module Signing Key: 2bb352412969a3653f0eb6021763408ebb9bb5ab 624487900 ---lswrv 0 0 \_ keyring: .machine 848354545 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 7c552922286d66bcb33c53d7ee0f1cd716ecdc63 959810021 ---lswrv 0 0 \_ asymmetric: Test: 8c7c76bb0d7cec080a9d3b5707d6ca9656676c96 1016027627 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 39bff3f0f578f26e527321cafda2a9cdbd71143c 965116557 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 4ff35c3e09ce586fa776d56468d86b022af272f1
By default, MOK keys are trusted and loaded into the machine keyring. If no additional MOK keys are loaded, the secondary_trusted_keys keyring will look similar to this:
$ keyctl show %:.secondary_trusted_keys Keyring 881532104 ---lswrv 0 0 keyring: .secondary_trusted_keys 916562914 ---lswrv 0 0 \_ keyring: .builtin_trusted_keys 957550911 ---lswrv 0 0 | \_ asymmetric: Oracle CA Server: 702a35b0d12005e5010c0614f7b8abf7c5bd5f73 201362191 ---lswrv 0 0 | \_ asymmetric: Oracle IMA signing CA: a2f28976a05984028f7d1a4904ae14e8e468e551 955284467 ---lswrv 0 0 | \_ asymmetric: Oracle America, Inc.: Ksplice Kernel Module Signing Key: 09010ebef5545fa7c54b626ef518e077b5b1ee4c 120852846 ---lswrv 0 0 | \_ asymmetric: Oracle Linux Kernel Module Signing Key: 2bb352412969a3653f0eb6021763408ebb9bb5ab 65129500 ---lswrv 0 0 \_ keyring: .machine 796703122 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 7c552922286d66bcb33c53d7ee0f1cd716ecdc63 536326034 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 39bff3f0f578f26e527321cafda2a9cdbd71143c 1019822789 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 4ff35c3e09ce586fa776d56468d86b022af272f1
There will be a password prompt. This is a password you are creating. This password will need to be entered again when shim loads MokManager to untrust the MOK keys.
$ mokutil --untrust-mok password length: 8~16 input password: input password again:
Follow the onscreen prompts from MokManager for untrusting the MOK keys. MokManager will prompt you to enter the password created in the previous step. Reboot the machine again. Afterwards, the machine keyring will not be used.
$ keyctl show %:.secondary_trusted_keys Keyring 914631770 ---lswrv 0 0 keyring: .secondary_trusted_keys 181249890 ---lswrv 0 0 \_ keyring: .builtin_trusted_keys 628701142 ---lswrv 0 0 \_ asymmetric: Oracle CA Server: 702a35b0d12005e5010c0614f7b8abf7c5bd5f73 306795764 ---lswrv 0 0 \_ asymmetric: Oracle IMA signing CA: a2f28976a05984028f7d1a4904ae14e8e468e551 300928728 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: Ksplice Kernel Module Signing Key: 09010ebef5545fa7c54b626ef518e077b5b1ee4c 805419922 ---lswrv 0 0 \_ asymmetric: Oracle Linux Kernel Module Signing Key: 2bb352412969a3653f0eb6021763408ebb9bb5ab
All MOK keys will show up in the platform keyring, along with the UEFI Secure Boot DB keys.
$ keyctl show %:.platform Keyring 797568476 ---lswrv 0 0 keyring: .platform 718847600 ---lswrv 0 0 \_ asymmetric: Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53 540371605 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 39bff3f0f578f26e527321cafda2a9cdbd71143c 936540732 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 4ff35c3e09ce586fa776d56468d86b022af272f1 416352496 ---lswrv 0 0 \_ asymmetric: Oracle America, Inc.: 7c552922286d66bcb33c53d7ee0f1cd716ecdc63 633944648 ---lswrv 0 0 \_ asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed522988a1bd4