-
Notifications
You must be signed in to change notification settings - Fork 0
Using Pkcs11 Device (SoftHSM) for Signing Linux Kernel Modules
The following example shows how to sign Linux kernel modules using an ECC key provided by a Pkcs11 device. We use softhsm2 as an example Pkcs11 device since it is commonly available. The p11tool and certtool we are using is part of the GnuTLS package.
First we install softhsm2 and gnutls and setup softhsm2:
#> sudo apt-get install -y softhsm gnutls-bin p11-kit # Debian/Ubuntu
#> sudo dnf install -y softhsm gnutls-utils p11-kit pcsc-lite # Fedora/RedHat
#> mkdir -p ~/.config/softhsm2/tokens
#> cat <<_EOF_ > ~/.config/softhsm2/softhsm2.conf
directories.tokendir = ${HOME}/.config/softhsm2/tokens
objectstore.backend = file
log.level = DEBUG
slots.removable = false
_EOF_
#> export SOFTHSM2_CONF=${HOME}/.config/softhsm2/softhsm2.conf
#> softhsm2-util --init-token --label mytoken --free --so-pin my-so-pin --pin my-pin
Slot 0 has a free/uninitialized token.
The token has been initialized and is reassigned to slot 1501407254
At this point you may want to put the export SOFTHSM2_CONF=...
line into your .bashrc
so you have access to your key the next time you log in. This environment variable is important.
Now we use p11tool to create the ECC key for signing the kernel modules. Using ECC keys for it is/will be possible with Linux 5.13. We can also create an RSA key for older kernels by simply replacing the ecc
argument below with rsa
.
In every step involving Pkcs11 URIs we have to use the Pkcs11 URIs shown in the local output. So, do not just copy all the command lines here! All URIs used on the command line have to be surrounded by single quotes (').
#> p11tool --list-tokens
[...]
Token 2:
URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=de23c1530413885f;token=mytoken
Label: mytoken
Type: Generic token
Flags: RNG, Requires login
Manufacturer: SoftHSM project
Model: SoftHSM v2
Serial: de23c1530413885f
Module: /usr/lib64/pkcs11/libsofthsm2.so
[...]
#> p11tool --generate-privkey=ecc --login --set-pin my-pin --label modsignkey \
'pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=de23c1530413885f;token=mytoken'
warning: no --outfile was specified and the generated public key will be printed on screen.
Generating an EC/ECDSA key...
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwHA9xtNnMXs/K2czYXIVzkGpbrG9
SGZS6bDyEeg00LV3IkLYysXkGdhuniDDGz9S5PNuxsCnn2rXT10p6JH4/g==
-----END PUBLIC KEY-----
#> GNUTLS_PIN=my-pin p11tool --list-privkeys --login \
'pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=ac9eb2cc597da816;token=mytoken'
Object 0:
URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=ac9eb2cc597da816;token=mytoken;id=%5E%F5%C0%23%AB%C9%B9%72%9F%23%24%C5%83%DB%42%44%83%14%BA%9C;object=modsignkey;type=private
Type: Private key (EC/ECDSA-SECP256R1)
Label: modsignkey
Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
ID: 5e:f5:c0:23:ab:c9:b9:72:9f:23:24:c5:83:db:42:44:83:14:ba:9c
#> KEYURI='pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=ac9eb2cc597da816;token=mytoken;id=%5E%F5%C0%23%AB%C9%B9%72%9F%23%24%C5%83%DB%42%44%83%14%BA%9C;object=modsignkey;type=private'
We now have our private key's URI in the URL line above and set it as a shell variable KEYURI. Now we need to create a self-signed certificate using certtool using this key URI. When we do this we accept most of the defaults and only enter 'testkey' for the Common name and '1000' for the number of days the certificate will be valid:
#> GNUTLS_PIN=my-pin certtool -s --load-privkey "${KEYURI}" --outfile pkcs11-cert.pem
Generating a self signed certificate...
Please enter the details of the certificate's distinguished name. Just press enter to ignore a field.
Common name: testkey
UID:
Organizational unit name:
Organization name:
Locality name:
State or province name:
Country name (2 chars):
Enter the subject's domain component (DC):
This field should not be used in new certificates.
E-mail:
Enter the certificate's serial number in decimal (123) or hex (0xabcd)
(default is 0x3a6f323679fe30e067199cb4261f84c7ecc9d384)
value:
Activation/Expiration time.
The certificate will expire in (days): 1000
Extensions.
Does the certificate belong to an authority? (y/N): N
Is this a TLS web client certificate? (y/N): N
Will the certificate be used for IPsec IKE operations? (y/N): N
Is this a TLS web server certificate? (y/N): N
Enter a dnsName of the subject of the certificate:
Enter a URI of the subject of the certificate:
Enter the IP address of the subject of the certificate:
Enter the e-mail of the subject of the certificate:
Will the certificate be used for data encryption? (y/N): N
Will the certificate be used to sign OCSP requests? (y/N): N
Will the certificate be used to sign code? (y/N): N
Will the certificate be used for time stamping? (y/N): N
Will the certificate be used for email protection? (y/N): N
Enter the URI of the CRL distribution point:
X.509 Certificate Information:
Version: 3
Serial Number (hex): 3a6f323679fe30e067199cb4261f84c7ecc9d384
Validity:
Not Before: Thu Mar 04 22:40:01 UTC 2021
Not After: Wed Nov 29 22:40:03 UTC 2023
Subject: CN=testkey
Subject Public Key Algorithm: EC/ECDSA
Algorithm Security Level: High (256 bits)
Curve: SECP256R1
X:
00:c0:70:3d:c6:d3:67:31:7b:3f:2b:67:33:61:72:15
ce:41:a9:6e:b1:bd:48:66:52:e9:b0:f2:11:e8:34:d0
b5
Y:
77:22:42:d8:ca:c5:e4:19:d8:6e:9e:20:c3:1b:3f:52
e4:f3:6e:c6:c0:a7:9f:6a:d7:4f:5d:29:e8:91:f8:fe
Extensions:
Basic Constraints (critical):
Certificate Authority (CA): FALSE
Key Usage (critical):
Digital signature.
Subject Key Identifier (not critical):
73ea316a8a2dc19292a6e0a8cbed9e723544e158
Other Information:
Public Key ID:
sha1:73ea316a8a2dc19292a6e0a8cbed9e723544e158
sha256:f047b0a769e92d59428f59886fbbb84603173f93c464590f47ba9d303e538fe3
Public Key PIN:
pin-sha256:8Eewp2npLVlCj1mIb7u4RgMXP5PEZFkPR7qdMD5Tj+M=
Is the above information ok? (y/N): y
Signing certificate...
In the next step we have to load the certificate into SoftHSM so it's available for the kernel module signing process. We again need the key URI.
GNUTLS_PIN=my-pin p11tool --load-certificate ./pkcs11-cert.pem --login --write --label testcert "${KEYURI}"
Now the key setup is done and we have to configure Linux to build the kernel with this module. The easiest way to do this is to edit Linux's .config
and set our key's Pkcs11 URI like this. Note that we appended ";pin-value=my-pin" to the URI so we don't have to pass the PIN when signing with the key. We modify CONFIG_MODULE_SIG_KEY
and set CONFIG_MODULE_SIG_KEY_TYPE_ECDSA=y
so that ECDSA support is built into the kernel so that ECDSA-signed modules can be loaded.
#
# Certificates for signature checking
#
CONFIG_MODULE_SIG_KEY="pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=ac9eb2cc597da816;token=mytoken;id=%5E%F5%C0%23%AB%C9%B9%72%9F%23%24%C5%83%DB%42%44%83%14%BA%9C;object=modsignkey;type=private;pin-value=my-pin"
# CONFIG_MODULE_SIG_KEY_TYPE_RSA is not set
CONFIG_MODULE_SIG_KEY_TYPE_ECDSA=y
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
CONFIG_SECONDARY_TRUSTED_KEYRING=y
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
CONFIG_SYSTEM_BLACKLIST_HASH_LIST=""
# end of Certificates for signature checking
Now we can build the kernel:
#> make -j32 && sudo SOFTHSM2_CONF=${HOME}/.config/softhsm2/softhsm2.conf make modules_install && sudo make install
When modules_install
is worked on you can see pcscd becoming busy. That's the sign that SoftHSM2 is signing modules.