This post explains how to build a kernel and corresponding modules with the following criteria:

  • CONFIG_MODULE_SIG_KEY is set to default and we destroy the private part of the signing key after the initial build

  • CONFIG_SYSTEM_TRUSTED_KEYS contains an additional certificate we can use to sign modules built afterwards or out of tree

  • Module signing enforcement is turned on

By having a separate key for signing modules, one could potentially revoke the ‘out of tree’ module signing key; but keep the built-in key for modules built during the initial build time.

The kernel documentation provides a more complete reference.

Generate your keys

First make an x509 key configuration file:

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

[ req_distinguished_name ]
CN = Out of tree build key

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

Save this as x509.genkey.

Now generate the private/public key x509 keypairs:

openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \
	-config x509.genkey -outform PEM -out kernel_key.pem \
	-keyout kernel_key.pem

Build and Install your Kernel

Assuming you have kernel sources and know how to build it, ensure your configuration has the following:

CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_SYSTEM_TRUSTED_KEYS="/path/to/kernel_key.pem"
CONFIG_MODULE_SIG_ALL=y
CONFIG_MODULE_SIG_FORCE=y
CONFIG_MODULE_SIG_SHA512=y
CONFIG_MODULE_SIG_HASH="sha512"

Do the actual build:

make -j56 deb-pkg

Next install it and any headers onto your target machine.

Check the Keyring

After boot check your keyring:

$ sudo cat /proc/keys
0206fe7e I--Q---     1 perm 1f3f0000  1000 65534 keyring   _uid.1000: empty
14fa22e7 I------     1 perm 1f0b0000     0     0 keyring   .system_keyring: 2
1d3e0f7d I--Q---    35 perm 3f030000  1000  1000 keyring   _ses: 1
20a381a5 I------     1 perm 1f030000     0     0 asymmetri Out of tree build key: be477ba1a33ecc6676673ad18c237554ad95c7ec: X509.rsa ad95c7ec []
216ffa7a I------     1 perm 1f030000     0     0 asymmetri Build time autogenerated kernel key: 54c5a144b369821a007b666ac1c57b8c73df6e37: X509.rsa 73df6e37 []
2520d96e I------     1 perm 1f0f0000     0     0 keyring   .evm: empty
268f53e6 I------     1 perm 1f030000     0     0 keyring   .dns_resolver: empty
2ee865ad I------     1 perm 1f0f0000     0     0 keyring   .ima: empty
36604247 I--Q---     2 perm 1f3f0000     0 65534 keyring   _uid.0: empty
36d30925 I--Q---     1 perm 1f3f0000     0 65534 keyring   _uid_ses.0: 1

Build an Out of Tree Module

Using some simple hello world module try to build and insert it. Without signing it and with module signing enforcement you’ll get:

$ sudo insmod example.ko
insmod: ERROR: could not insert module example.ko: Required key not available

Sign the Module

First split the .pem file into its constitutent parts:

chmod 0600 kernel_key.pem
openssl pkey -in kernel_key.pem -out kernel_key.key
openssl x509 -outform der -in kernel_key.pem -out kernel_key.crt

Now we need to sign the module. First co-locate the kernel module and key onto the same machine. I’m going to scp the module out of the target machine and into my build machine.

./scripts/sign-file sha512 ./kernel_key.key ./kernel_key.crt example.ko

Move this to the target machine and try to insert the module.

$ sudo insmod example.ko
$ lsmod | grep example
example                16384  0

It worked.