Skip to content

Instantly share code, notes, and snippets.

@sbueringer
Forked from dojoe/dkms-module-signing.md
Created October 16, 2019 04:22
Show Gist options
  • Save sbueringer/bd8cec239c44d66967cf307d808f10c4 to your computer and use it in GitHub Desktop.
Save sbueringer/bd8cec239c44d66967cf307d808f10c4 to your computer and use it in GitHub Desktop.
Make DKMS sign kernel modules on installation, with full script support and somewhat distro independent

On systems with UEFI Secure Boot enabled, recent Linux kernels will only load signed modules, so it's about time DKMS grew the capability to sign modules it's building.

These scripts are extended and scriptified variants of https://computerlinguist.org/make-dkms-sign-kernel-modules-for-secure-boot-on-ubuntu-1604.html and https://askubuntu.com/questions/760671/could-not-load-vboxdrv-after-upgrade-to-ubuntu-16-04-and-i-want-to-keep-secur/768310#768310 and add some error checking, a passphrase around your signing key, and support for compressed modules.

dkms-sign-module is a wrapper for the more generic sign-modules which can also be used outside of DKMS.

Installation

  1. Create a directory under /root, say /root/module-signing, put the three scripts below in there and make them executable: chmod u+x one-time-setup sign-modules dkms-sign-module
  2. Run one-time-setup
  3. Reboot your computer to deploy the MOK
  4. For each module you will want to sign via DKMS, create a file /etc/dkms/<module_name>.conf with the following content:
    POST_BUILD=../../../../../../root/module-signing/dkms-sign-module
    
    The awkward relative pathname is important since DKMS prepends its own path to it, so an absolute path will not work.
#!/bin/bash
export PROMPT="Enter Machine Owner Key (MOK) passphrase to sign $module $module_version: "
export KERNELVER=$kernelver
$(dirname $0)/sign-modules ../$kernelver/$arch/module/*.ko*
#!/bin/bash
mydir=$(dirname $0)
echo "I am about to generate the Machine Owner Key (MOK)."
echo "The passphrase you enter for this key will be required every time you want to sign a module."
read -p "Please press Return to go on..."
openssl req -new -x509 -newkey rsa:2048 -keyout $mydir/MOK.priv -outform DER -out $mydir/MOK.der -days 36500 -subj "/CN=$(hostname) module signing key/" || exit 1
echo
echo "Now I will import the generated key into the secure keystore."
echo "The passphrase you will enter is only required once, during the following reboot."
read -p "Please press Return to go on..."
mokutil --import $mydir/MOK.der || exit 1
echo
echo "Please reboot your computer now to complete the enrollment of your new MOK."
echo "This is going to look somewhat similar to https://sourceware.org/systemtap/wiki/SecureBoot"
#!/bin/bash
if [[ -z "$1" ]]; then
echo "Usage: $0 module [module...]"
exit 1
fi
mydir=$(dirname $0)
PROMPT="${PROMPT:-Enter Machine Owner Key (MOK) passphrase: }"
KERNELVER=${KERNELVER:-$(uname -r)}
read_passphrase() {
# We write to /dev/tty to get around DKMS' redirection to /dev/null if it's being run with -q (e.g. during rpm installs)
echo -n "$PROMPT" > /dev/tty
read -s KBUILD_SIGN_PIN < /dev/tty
export KBUILD_SIGN_PIN
echo > /dev/tty
openssl rsa -check -noout -passin env:KBUILD_SIGN_PIN -in $mydir/MOK.priv > /dev/null 2>&1
}
do_sign() {
/lib/modules/$KERNELVER/build/scripts/sign-file sha256 $mydir/MOK.priv $mydir/MOK.der "$1"
}
while ! read_passphrase; do echo "Wrong passphrase, please try again."; done
for module in $@; do
echo "Signing module: $module"
module_basename=${module:0:-3}
module_suffix=${module: -3}
if [[ "$module_suffix" == ".xz" ]]; then
unxz $module
do_sign $module_basename
xz -f $module_basename
elif [[ "$module_suffix" == ".gz" ]]; then
gunzip $module
do_sign $module_basename
gzip -9f $module_basename
else
do_sign $module
fi
done
@dtatulea
Copy link

Nice guide. Thanks!

This works in Fedora (33 in my case) as well if you tweak the POST_BUILD path with and additional ../. Figuring out the path where dkms runs is not trivial :).

@dasunsrule32
Copy link

dasunsrule32 commented Jul 24, 2021

Nice guide. Thanks!

This works in Fedora (33 in my case) as well if you tweak the POST_BUILD path with and additional ../. Figuring out the path where dkms runs is not trivial :).

@dtatulea Do you have this working on F34? I had to manually do the sign-modules script with the absolute path to the module. So:

./sign-modules /lib/modules/5.13.4-200.fc34.x86_64/extra/*.ko*
Enter Machine Owner Key (MOK) passphrase: 
Signing module: /lib/modules/5.13.4-200.fc34.x86_64/extra/razerkbd.ko.xz

The modules would never sign using the depmod method with the POST_BUILD. For what it's worth, the openrazer-drivers are located in:

/lib/modules/$kernelver/extra/

Thanks in advance for the help! :)


EDIT: I resolved this. I was creating conf files for the individual modules and not the actual dkms source name. So in this instance openrazer-driver. Once I created /etc/dkms/openrazer-driver.conf with the following POST_BUILD var set, it built and signed the modules succesfully.

POST_BUILD=../../../../../../root/module-signing/dkms-sign-module

Build:

sudo dkms build -m openrazer-driver/3.0.1 

Creating symlink /var/lib/dkms/openrazer-driver/3.0.1/source ->
                 /usr/src/openrazer-driver-3.0.1

DKMS: add completed.

Kernel preparation unnecessary for this kernel.  Skipping...

Building module:
cleaning build area...
KERNELDIR=/lib/modules/5.13.4-200.fc34.x86_64/build make driver....

Running the post_build script:
Enter Machine Owner Key (MOK) passphrase to sign openrazer-driver 3.0.1: 
Signing module: ../5.13.4-200.fc34.x86_64/x86_64/module/razeraccessory.ko.xz
Signing module: ../5.13.4-200.fc34.x86_64/x86_64/module/razerkbd.ko.xz
Signing module: ../5.13.4-200.fc34.x86_64/x86_64/module/razerkraken.ko.xz
Signing module: ../5.13.4-200.fc34.x86_64/x86_64/module/razermouse.ko.xz
cleaning build area...

DKMS: build completed.

Install:

sudo dkms install -m openrazer-driver/3.0.1 

razerkbd.ko.xz:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.13.4-200.fc34.x86_64/extra/

razermouse.ko.xz:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.13.4-200.fc34.x86_64/extra/

razerkraken.ko.xz:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.13.4-200.fc34.x86_64/extra/

razeraccessory.ko.xz:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.13.4-200.fc34.x86_64/extra/

depmod....

DKMS: install completed.

DKMS installed:

dkms status 
openrazer-driver, 3.0.1, 5.13.4-200.fc34.x86_64, x86_64: installed

Modules loaded:

lsmod|grep razer
razermouse            110592  0
razerkbd               77824  0

@sprshp
Copy link

sprshp commented Oct 16, 2021

With Debian 11 using dkms 2.8 (or Debian 10 with the backported package) there is a build-in function 👍

enable it in /etc/dkms/framework.conf:
uncomment line "sign_tool="/etc/dkms/sign_helper.sh""

eventually tweak the /etc/dkms/sign_helper.sh to match your signature.

@nbx3
Copy link

nbx3 commented Mar 15, 2022

This is working well for me on Fedora 34 thanks

@eike-fokken
Copy link

With Debian 11 using dkms 2.8 (or Debian 10 with the backported package) there is a build-in function +1

enable it in /etc/dkms/framework.conf: uncomment line "sign_tool="/etc/dkms/sign_helper.sh""

eventually tweak the /etc/dkms/sign_helper.sh to match your signature.

Have you used this procedure? I fail to get it to work, apparently because I am not prompted for a password for my mok:

Building initial module for 5.16.0-5-amd64
At main.c:163:
- SSL error:0907B068:PEM routines:PEM_read_bio_PrivateKey:bad password read: ../crypto/pem/pem_pkey.c:64

@eike-fokken
Copy link

This gist works exactly as advertised on Debian 12!

As per my last message I couldn't get the dkms-version to work. I suspect that it might work with a non-password protected MOK.

@sprshp
Copy link

sprshp commented Apr 2, 2022

Hello, I can't tell, i've never used a protected MOK.

@eike-fokken
Copy link

Hello, I can't tell, i've never used a protected MOK.

So you have tried this:

With Debian 11 using dkms 2.8 (or Debian 10 with the backported package) there is a build-in function +1

enable it in /etc/dkms/framework.conf:
uncomment line "sign_tool="/etc/dkms/sign_helper.sh""

eventually tweak the /etc/dkms/sign_helper.sh to match your signature.

and it works with an unprotected MOK?

@2ndBillGates
Copy link

After enroll and reboot
My system does not boot.

I've set up secure boot before this.

@MatiasFS99
Copy link

Work perfect on debian 11 installing the rtl8821ce module, this tutorial saved me from disabling the secure boot

@siddhpant
Copy link

On 31 Mar 2022 16:15 +0530, @eike-fokken wrote:

On 17 Oct 2021 0343 +0530, @sprshp wrote:

With Debian 11 using dkms 2.8 (or Debian 10 with the backported package) there is a build-in function +1
enable it in /etc/dkms/framework.conf: uncomment line "sign_tool="/etc/dkms/sign_helper.sh""
eventually tweak the /etc/dkms/sign_helper.sh to match your signature.

Have you used this procedure? I fail to get it to work, apparently because I am not prompted for a password for my mok:

Building initial module for 5.16.0-5-amd64
At main.c:163:
- SSL error:0907B068:PEM routines:PEM_read_bio_PrivateKey:bad password read: ../crypto/pem/pem_pkey.c:64

You can make use of keyrings. It is very easy, I detail it here: https://gist.github.com/siddhpant/19c07b07d912811f5a4b2893ca706c99

@SaBenBurra
Copy link

Not works with rtl8821ce module (Fedora 36)

@enigma131
Copy link

Signature is automatic from dkms-3.0.10

@Roblex09
Copy link

Works on fedora 39 with the rtl8821ce modul. Tysm :)

@De-Clan-C
Copy link

works on fedora 40, but is there a way for it to not ask for my password every time is signs? Because I believe the password breaks the update process through gnome software.

@dominikegert
Copy link

dominikegert commented Jul 10, 2024

Addendum to make it work with .zst compressed modules as well.

Here the complete loop from the third file, but you only need to add the first if-statement

for module in $@; do
echo "Signing module: $module"
module_basename=${module:0:-3}
module_suffix=${module: -3}
module_basename2=${module:0:-4}
module_suffix2=${module: -4}

if [[ "$module_suffix2" == ".zst" ]]; then
  zstd -q -f -d $module
  do_sign $module_basename2
  zstd -q -19 --check -f -o $module $module_basename2.
elif [[ "$module_suffix" == ".xz" ]]; then
  unxz $module
  do_sign $module_basename
  xz -f $module_basename
elif [[ "$module_suffix" == ".gz" ]]; then
  gunzip $module
  do_sign $module_basename
  gzip -9f $module_basename
else
  do_sign $module
fi

done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment