Secure Boot Linux Shim (Mokmanager)

Previously, we’ve had a look at secure boot in Fedora 27 / 28. Now we will look at another part of Secure Boot in linux. It is important to know about this aspect in order to have a complete picture of how Secure Boot functions in a typical linux distribution. In part, because having the shim misconfigured, may limit the security that is claimed Secure Boot provides.

The Shim fixing a problem

The idea of Secure Boot is to have every step in the boot process verified before it is executed. The effect is that, unless you allow your bootable executable to be vetted for correctness and malicious content, your executable cannot be installed into the boot process. Thereby, preventing viruses and other malicious content from inserting itself in the boot process before the operating system is even active and able to defend itself.

This process works best for Microsoft, as they own the certificate that is installed by default in all UEFI systems, and in particular works best if there is little variation needed. However, this is contrary to expectations of linux and other open source systems, as well as their users. These expect full freedom. One could argue that you could just turn off Secure Boot, but that would defeat the purpose of the feature. In addition, this way of working will not be acceptable for businesses.

To make Secure Boot work together with the large variation of linux distributions, a shim is introduced. The shim is a very thin, light-weight layer, that allows injecting any executable as the next step in the process. The shim itself is verified and signed as a valid bootable executable. It is, in turn, expected to preserve the safety and security offered by secure boot. It continues the boot process with an executable it can verify to be trusted. Only after having verified trustworthiness, will it relinquish control of the boot process over to the executable.

Security by the shim

The shim introduces some security measures to prevent modifications from happening silently. A user is expected to be present locally and confirm potentially dangerous operations at boot-time to ensure that modifications are intentional and acceptable. This prevents malicious content from installing itself silently. The shim makes evident that changes have been made by deviating from the normal boot process.

Trustworthiness is verified by either:

  1. verifying that the hash of the executable is present in a list of known hashes
  2. verifying that the executable is signed by a trusted certificate

Hashes and certificates must be installed in the shim to be recognized. Installing new hashes and certificates need to be confirmed by a user that is locally present as well.

Consequences of Secure Boot security in linux

Now let’s pull back a little bit and look at the goal of Secure Boot itself. It is expected that every certified step in the process is trustworthy. This security property is intended to be transitive and therefore the shim has to do its part in ensuring system integrity. The linux kernel will be the next step. That is, the shim will load the linux kernel, after having verified by file hash/cryptographic signature that the kernel is unmodified. By transitivity, we now expect the linux kernel to be a good citizen and preserve system integrity. However, the linux kernel needs to load kernel modules to operate and some kernel modules are provided by a third-party.

For this reason, the shim introduces MokManager. MokManager introduces a new security concept to the Secure Boot process which improves flexibility while preserving security properties. It allows the registration of hashes and certificates such that the kernel and its kernel modules can be certified without having to modify the Secure Boot configuration or its key management.

The Shim is a minimal, verified, trusted UEFI application that is loaded by Secure Boot. Secure Boot knows to trust Shim, as it is certified by Microsoft. Now shim is expected to perform validation further down the chain however it sees fit.

Shim allows for:

Various linux distributions rely on the shim to provide them with the initial certified UEFI executable. The linux distributions themselves register their certificate in the shim and this enables further booting.

Some distributions will disable further validation in the shim to enable loading of custom/proprietary kernel modules, without requiring the user to generate its own certificates and do all of its own management. For optimal security, disabling validation is not guaranteed.

Verifying the secure boot state

mokutil is the general tool for interacting with the MokManager.

To verify whether or not Secure Boot is enabled, one can use: mokutil --sb-state

SecureBoot enabled

It should report that Secure Boot is enabled. If this is not the case, you should enable it in order to enable protection of the boot process.

Now, even if Secure Boot is enabled, there is a chance that MokManager is configured to halt further validation. The shim will then report on booting insecurely in a textual message at start-up. It shows right before the linux kernel starts initializing.

To enable validation in the MokManager: sudo mokutil --enable-validation.

Follow the process, as this step requires local access to the hardware. A temporary password is requested such that on next boot, that same password can be used to aid in verifying that the enable/disable request is intentional by the user. Only after input is confirmed, will the shim change the current validation status.

You would typically want to enable validation, unless you need to load unsigned (often proprietary) kernel modules. Alternatively, one can sign the custom kernel modules and register the certificate in MokManager such that we can keep validation enabled.

Preparing the shim / MokManager for your own signed kernel modules

MokManager can work with user’s own certificates, such that custom kernel modules can be signed and thus validated as part of the Secure Boot validation process. To do so, we first generate a new certificate, we register it in MokManager, and then we sign our kernel modules with the generated certificate (private key, to be exact).

  1. Generate a new private key and certificate: openssl req -new -x509 -newkey rsa:2048 -subj "/CN=PK/" -keyout PK.key -out PK.crt -days 3650 -nodes -sha256
  2. Convert to DER certificate format: openssl x509 -in test.crt -out test.der -outform DER
  3. Install the certificate in MokManager: sudo mokutil --import test.der
  4. To verify that the certificate is indeed enlisted to be installed: sudo mokutil --list-new
  5. Now restart the system. You will drop into the MokManager. Verify that the proposed change is indeed your own generated certificate and follow the process to complete enrollment, after which you restart and boot into linux again.
  6. To verify that the certificate is now indeed enrolled: mokutil --list-enrolled.
  7. Sign any kernel image, if needed. In case a stock distribution kernel is used, they are probably already signed with the distribution’s certificate. In that case, signing kernel images is not necessary.
  8. Sign all custom kernel modules that we need to load. Note that with full validation active, the kernel is restricted in some ways. For example, kernel modules will be validated before they are authorized to load.
    /usr/bin/sudo "/usr/src/kernels/$(uname -r)/scripts/sign-file" sha256 "test.key" "test.der" "$(modinfo -n kernelmodulename)", with kernelmodulename the name of the kernel module to be signed.

Note that the kernel sources need to be present to perform signing. This is typically not a problem, as you would also need the kernel sources to compile the various custom kernel modules.