Dual Booting Linux with Windows
If you already have Windows installed, but still want run Linux natively, you might consider setting up a dual boot system. However, developing the Linux kernel on dual boot machines shipped with Windows (8 and above) may not go as smoothly as you'd like. Windows PCs by default enable a security feature called Secure Boot, which will prevent you from running the kernel and modules you compile unless they are signed by a system trusted key. The easiest way to circumvent this issue and maintain security is to develop the kernel in a virtual machine, and you can find those instructions here (you can still setup a dual boot, and run the VM from either your Linux or Widows OS).
Dealing with UEFI Secure Boot
From the Microsoft Support Website, "Secure Boot is an important security feature designed to prevent malicious software from loading when your PC starts up (boots)." Essentially, when your machine starts up, the UEFI firmware checks that all binaries being run are signed by a trusted key stored in designated place in memory (NVRAM). Signing a binary requires a private key, but to verify a signature, you only need the corresponding public key. So, Microsoft signs its bootloader and boot-image with its private key, then ships your PC with its public key stored in your hardware.
Then, in order to run another operating system, you have three options:
- Disable Secure Boot
- Get Microsoft to sign your new bootloader and boot-image with its private key
- Create your own key pair and add the public key to NVRAM
Fortunately, common Linux distributions manage to do a combination of 2) & 3). Fedora created a "first stage" bootloader, Shim, and similarly the Linux Foundation created PreLoader, which are signed by Microsoft and can be validated and run by the firmware. These initial bootloaders however are designed to validate and allow another bootloader, such as GRUB2, to take over the process. Using Shim, Linux distributions can sign their boot image (i.e. the kernel) and bootloader (e.g. GRUB2) with their own private key, and Shim registers their public key on start-up.
But what if you want to run a different kernel or bootloader? Since you don't have your distribution's private key, you can't use it to sign the binaries you compile yourself. Instead, you have to create your own key pair, and import the public key into your hardware.
Disabling Secure Boot
This option is not recommended.
In order to disable secure boot, you need to restart your machine and enter the your firmware setting's page. One way to do this is by figuring out which is the correct function key (f2, f10, f8...) and pressing it just after your machine restarts. If you have already installed Linux, you can instead open up a terminal and run (as root)
systemctl reboot --firmware
Then you can find the settings for Secure Boot and disable it. Here is a good guide for navigating this on a variety of machines Disabling Secure Boot by Rod Smith
Creating Your Own Signing Key
A better option for booting your self-compiled kernel is to create your own signing key pair and store it in NVRAM with the assistance of mokutil (Machine Owner Key), an extension of Shim. You'll need to sign the kernel before rebooting with it.
The following guide assumes you have already downloaded and installed Ubuntu 22.04.1 LTS alongside Windows. If you are using a different version or distribution, there may be different steps involved. For example, some distributions do not come with Shim preinstalled, and you will have to download a signed version. Very old versions of Shim do not have the MOK extension. For a comprehensive guide on using Shim/MOK with different distributions, check out Using the Shim Program by Rod Smith.
Generating a Key
We aren't just creating any random key-- we need to make a X509 certificate. However, this is still simple to do with command line tool openssl.
1. Create a file 'openssl.cnf' in your home directory
# This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd [ req ] distinguished_name = req_distinguished_name x509_extensions = v3 string_mask = utf8only prompt = no [ req_distinguished_name ] commonName = Secure Boot Signing [ v3 ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical,CA:FALSE extendedKeyUsage = codeSigning,22.214.171.124.4.1.3126.96.36.199 nsComment = "OpenSSL Generated Certificate"
2. Use the openssl command to generate key pair. Note that MOK.priv is your private key, and MOK.der is you public key
openssl req -config ./mokconfig.cnf \ -new -x509 -newkey rsa:2048 \ -nodes -days 36500 -outform DER \ -keyout "MOK.priv" \ -out "MOK.der"
Importing your Public Key
1. Install mokutil and import your new key. You will be asked to set a password, make sure to write it down because you will need to use it in the next step.
sudo apt-get install mokutil sudo mokutil --import MOK.der
To see your current enrolled keys, you can run
sudo mokutil --list-enrolled
Note that the key you just added is not yet in the list. You need to complete the next step before its fully enrolled into your hardware.
2. Reboot your machine. When your machine starts, instead of GRUB2, you will see a blue screen belonging to the MOK Manager. From the options, choose "Enroll MOK" and then "View key". Make sure that this is the correct key that you just made (should have the common name Secure Boot Signing). When prompted,enter the password your wrote down, and continue with booting.
3. Check that your key is now enrolled
sudo mokutil --list-enrolled
Signing with Your Key
1. Convert your public key from the .der format to the .pem in order to sign the kernel
sudo sbsign --key MOK.priv --cert MOK.pem /boot/vmlinuz-[KERNEL-VERSION] --output /boot/vmlinuz-[KERNEL-VERSION].signed
If you don't know the version of the kernel you just compiled, you can check in /boot for the most recent version.
2. Copy the previously generated initrd.img to initrd.img.signed. The initrd doesn't need to be signed, but coping it with .signed allows GRUB to associate it with the signed kernel.
sudo cp /boot/initrd.img-[KERNEL-VERSION] /boot/initrd.img-[KERNEL-VERSION].signed
3. Update GRUB and reboot. When the GRUB boot menu appear, choose the kernel with the .signed extension.
sudo update-grub sudo reboot
If it all works, you can remove the unsigned copy of the kernel in /boot. Make sure to run update-grub if make those changes.
4. Finally, store your MOK keys somewhere secure, since you will need reuse them anytime you need to sign a kernel module or recompile the kernel. When you need to sign a kernel module you can run,
kmodsign sha512 MOK.priv MOK.der module.ko