Skip to content

Kernel Module Signing

Jason Gerecke edited this page Jun 13, 2019 · 4 revisions

NOTE: This article provides a general overview of the module signing framework. A tutorial with instructions specific to input-wacom can be found on our Secure Boot page.

The Linux kernel can be configured to cryptographically verify its trust in modules before loading them. When enabled, the kernel may refuse to load a module which has been tampered with or which hasn't been signed with a trusted key. This feature provides a degree of resistance against rootkit-style attacks and is often conditionally enabled by distributions.

Although often associated with the "secure boot" process, it is not necessarily dependent on or integrated with it. Many distributions (Fedora, Ubuntu, SUSE) add "Lockdown" and UEFI/MOK trust patches that augment the upstream kernel. Distributions which ship kernels closer to upstream (Arch Linux, Gentoo) may not have the same degree of integration, however.

While module signing can provide valuable security benefits, it often impacts users who want to install out-of-tree modules. Additional steps must be taken to make a freshly-compiled module usable. The first symptom that most users experience is a lack of expected functionality since the desired module is not being loaded. The issue can be confirmed by examining dmesg and finding any of the following error messages:

  • Lockdown: Loading of unsigned modules is restricted; see man kernel_lockdown.7

  • module verification failed: signature and/or required key missing

  • PKCS#7 signature not signed with a trusted key

Workarounds

We recommend following the Module Signing instructions below if possible. However, the module signing framework can be bypassed or disabled in the following ways:

  • Lockdown mode can be disabled until the next reboot with a "Magic SysRq" keypress. You will need to run sudo sysctl kernel.sysrq=1 and then press ALT+SysRq+x. Afterwards, these two messages should be appended to the dmesg log: sysrq : SysRq : Disabling Secure Boot restrictions and Lifting lockdown.

  • Lockdown mode can be permanantly disabled by disabling secure boot in your systems UEFI setup ("BIOS"). Run systemctl reboot --firmware-setup to enter setup, or press the appropriate key while the system is POSTing.

  • Lockdown mode can be permanantly disabled by installing a kernel without the lockdown patches present.

  • Non-lockdown module verification can be disabled by removing the module.sig_enforce parameter from the kernel command-line, if present.

  • Non-lockdown module verification can be disabled by installing a kernel with the CONFIG_MODULE_SIG_FORCE option ("Require all modules to be validly signed") disabled.

Module Signing

The module signing process consists of three parts: generating a key, getting the kernel to trust the key, and finally using the key to sign your module.

Generating a Key

When compiling a kernel for yourself with module verification enabled, the kernel will automatically generate a key for you as part of the build process. The resulting private and public keys will be stored at /certs/signing_key.pem and signing_key.x509. This key will be implicitly trusted as outlined in the Trusting a Key section below.

Keys can also be manually generated. This is primarily useful for users of distribution-provided kernels, but can also be helpful if you want to perform the key generation on a seperate machine or rely on cryptographic hardware. Unless you can point the kernel at the generated key before compiling (or make use of the CONFIG_SYSTEM_EXTRA_CERTIFICATE option), you must take steps to add the key to the kernel's list of trusted keys as described in the Trusting a Key section below.

openssl method

Most distributions do not come with tools to generate a key automatically. In these cases, the openssl tool can be used with. First, an openssl configuration file with the following contents should first be created. The CN = Modules line defines the name of the certificate and can be changed to something else if desired (e.g. CN = Kernel module signing key).

x509.genkey

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

[ req_distinguished_name ]
CN = Modules

[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid

Once the configuration file has been created, it can be provided to openssl to create the actual keypair:

$openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config x509.genkey -outform DER -out signing_key.x509 -keyout signing_key.priv

Ubuntu method

Users of Ubuntu and its forks can more easily generate a key by running sudo update-secureboot-policy --new-key. This command generates a new key for DKMS and out-of-tree modules, or does nothing if a key has already been generated.

rEFInd method

The rEFInd bootloader can generate keys as part of its installation process if run properly. Adding the --locakeys option to refind-install will have it generate keys and store them inside the /etc/refind.d/keys directory.

Trusting a Key

The Linux kernel recognizes keys in one of its two trusted keyrings as valid for module signing. These are the .builtin_trusted_keys (formerly: .system_keyring) and .secondary_trusted_keys keyrings. All of the keys and keyrings curerntly registered can be explored by running sudo cat /proc/keys or sudo keyctl show '%:$NAME'

The .builtin_trusted_keys keyring is a read-only list of keys that were compiled into the kernel. This includes the autogenerated key described in Generating a Key, as well as any other keys added to CONFIG_SYSTEM_TRUSTED_KEYS. The .secondary_trusted_keys keyring is a store of additional keys which have been added at runtime. Normally only keys that have been signed by a key in .builtin_trusted_keys may be added to this keyring, but many distributions patch the kernel to also import keys from the UEFI and MOK databases on boot.

If you are using a self-compiled kernel there is nothing you need to do to have the kernel trust your key since it should already be included in the .builtin_trusted_keys keyring. Users of distribution-provided kernels, on the other can, may be able to add their key to the UEFI or MOK databases (this will, of course, only work if /proc/keys shows that your distro imports those keys). Once added, you should check that /proc/keys contains your key, at which point it should be usable for module signing.

NOTE: Linux 5.0 added a new .platform keyring that, if enabled, will contain UEFI (and MOK?) entries. This keyring is not trusted for module signing. A future kernel release may introduce a .platform_trusted_keys keyring which stores UEFI and MOK keys that are valid for module signing.

Adding Keys to UEFI

The UEFI secure boot key database is a list of keys contained within the system firmware. It is normally populated with keys supplied by Microsoft and your system vendor (e.g. Dell or HP). Many x86 systems allow additional user-defined keys to be added to the database. Specific instructions are outside of the scope of this article.

Adding Keys to MOK

The MOK (Machine Owner Key) database is a list of keys under your own control. It is a more cross-platform solution than the UEFI database. Keys are generally enrolled by running sudo mokutil --import <der cert>. Ubuntu users can alternatively run sudo update-secureboot-policy --enroll-key to enroll the DKMS key.

Signing a Module

Once you have access to a trusted private key, actually signing modules is rather straightforward. The kernel source includes a tool that takes care of generating and appending the signature for you. If the CONFIG_MODULE_SIG_ALL option is enabled, the tool is even automatically run as part of the make modules_install step. This can result in a seamless signing expereince if the kernel was configured with a built-in signing key that you have access to.

If, however, your trusted key is not the built-in key, you will need to run the tool manually. The command is simply:

scripts/sign-file sha512 kernel-signkey.priv kernel-signkey.x509 module.ko

Resources

Clone this wiki locally