Lugsole.net long logo

Securebooting Arch With Unified Kernel Image

TLDR:

If you do not secure boot with your keys and instead use someone else’s you can not guarantee you are booting securely.

a crypto nerd thinks his security is so strong since he thinks they need to use 100,000 f dollar to break the crypto. A thief says: a bit of drugs and a five-dollar wrench can do the same.

XKCD's very valid opinion about security

For starters, if you boot into your computer with the default Microsoft EFI keys they have been leaked or they were leaked back in 2016. This means that anyone who has access to Microsoft’s keys can hypothetically get the first execution in front of your EFI firmware. The reason this is problematic is that without being the first EFI file to execute you do not necessarily know if there is some in-memory kernel level process that has to fill access to your system. This might not yet be a thing that script kiddies can do or even reasonably advance adversaries, but once it hits it will be hard to detect. This is because if a kernel-level process could hook into the kernel-level process then the kernel-level process could filter what you see so that you do not see the implant.

With understanding the rough challenge that this poses there needs to be a more secure and safer way of going about this. In concept, this is different based on different computers/motherboards. The rough idea is going to be to set up a unified kernel image, set up a key set to sign and verify the kernel in the boot process, set up an automated signing process, and enable bios verification of the kernel image.

  1. set up a way to create a single file for the boot process
  2. Create a pair of keys
  3. add the keys to UEFI
  4. create an automated way of signing these keys
  5. get UEFI pre-boot to validate the file it runs with your keys

Programs that will be used and there packages

cert-to-efi-sig-list

This converts openssl certifications to EFI signature lists (file format)

Arch: extra/efitools

efibootmgr

This converts openssl certifications to EFI signature lists (file format)

Arch: core/efibootmgr

openssl

OpenSSL is one of the more popular programs that can generate X.509 certificates (it does more, but irrelevant for this use case)

used arguments:

req

-days n This is how many days the certifications are available for

-newkey this is the new key’s type fallowed by a colon and how many bits the keys are

-keyout the file to put the newly created private key

-nodes tells the computer to not encrypt the private key

-sha256 changes the digest algorithm to sha256

x509

-in input file to change the format of

-out the output file with the altered encoding

-outform the output file format [DER|PEM]

Arch: core/openssl

sbsign

This is an UEFI file signing tool that a

-key the private key file

-cert the certificate file

-output the newly signed file

Arch: extra/sbsigntools

sbverify

This is an UEFI secure boot verifivation program

--list list all signatures (but don’t verify)

Arch: extra/sbsigntools

sign-efi-sig-list

This generates

Arch: extra/efitools

uuidgen

this generated a UUID in this example the arguments that are used in for this program is --time which gives UUID version 1 or very close that uses the current time and mac address to generate the UUID. If a random UUID was desired it is possible to use the --random

Arch: core/util-linux

Create a Unified Kernel Image

This step should be very easy to do all that is needed is to update one file. To make the boot process look a bit nicer there are a few more steps. Part 1 the need portion

This is the most important part. In order to have EFI files automatically generated it is needed to edit /etc/mkinitcpio.d/linux.preset to have an option that generates the EFI file.

 1--- /proc/self/fd/11	2022-06-22 20:29:48.186393990 -0400
 2+++ /etc/mkinitcpio.d/linux.preset	2022-06-17 17:40:05.916223661 -0400
 3@@ -7,8 +7,11 @@
 4
 5 #default_config="/etc/mkinitcpio.conf"
 6 default_image="/boot/initramfs-linux.img"
 7+default_efi_image="/efi/EFI/Linux/archlinux-linux.efi"
 8+default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"
 9 #default_options=""
10
11 #fallback_config="/etc/mkinitcpio.conf"
12 fallback_image="/boot/initramfs-linux-fallback.img"
13-fallback_options="-S autodetect"
14+fallback_efi_image="/boot/archlinux-linux-fallback.efi"
15+fallback_options="-S autodetect --splash /usr/share/systemd/bootctl/splash-arch.bmp"
1efibootmgr --create --disk /dev/sdX --part partition_number --label "label" --loader 'EFI\Linux\file.efi' --verbose

Creating the keys

For generating the keys I based my lines off of the lines of code i seen in the First you have to create yout key pairs that latter gets used to sign unified kernel images.

1openssl req -new -x509 -newkey rsa:4096 -subj "/CN=$NAME PK/" -keyout PK.key \
2        -out PK.crt -days 3650 -nodes -sha256
3openssl req -new -x509 -newkey rsa:4096 -subj "/CN=$NAME KEK/" -keyout KEK.key \
4        -out KEK.crt -days 3650 -nodes -sha256
5
6openssl req -new -x509 -newkey rsa:4096 -subj "/CN=$NAME DB/" -keyout DB.key \
7        -out DB.crt -days 3650 -nodes -sha256

This converts the file to a DER file format since some sets of firmware require this

1openssl x509 -in PK.crt -out PK.cer -outform DER
2openssl x509 -in KEK.crt -out KEK.cer -outform DER
3openssl x509 -in DB.crt -out DB.cer -outform DER

Since most files on the EFI system needs a GUID this creates the GUID

1GUID=`uuidgen --time`
2echo $GUID > myGUID.txt

This converts the keys to the file format that is supported by the

1cert-to-efi-sig-list -g $GUID PK.crt PK.esl
2cert-to-efi-sig-list -g $GUID KEK.crt KEK.esl
3cert-to-efi-sig-list -g $GUID DB.crt DB.esl

This file is latter used to be capable of revoking the the PK certificate

1rm -f noPK.esl
2touch noPK.esl

This converts the files to auth files so that the UEFI firmware can unserstand the keys.

1sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
2                  -k PK.key -c PK.crt PK PK.esl PK.auth
3sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
4                  -k PK.key -c PK.crt PK noPK.esl noPK.auth
5sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
6                  -k PK.key -c PK.crt KEK KEK.esl KEK.auth
7sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
8                  -k KEK.key -c KEK.crt db DB.esl DB.auth

This prevents other users from reading the file.

1chmod 0600 *.key

add keys to the EFI system

Automatically sign the EFI file

Two things need to happen. First, thing needed to enable will be creating a pacman hook so that when kernel updates happen a script runs to sign the kernel images. The second thind that needs to happen is to build a script to sign the kernel images.

This first part looks for a new vmlinuz file or looks for a initcpio then it runs the signing script. Since this file starts with 91 it gets ran after the 90-mkinitcpio-install.hook which sets up the EFI files.

 1cat << __EOF__ | sudo tee /etc/pacman.d/hooks/91-mkinitcpio-sbsign.hook
 2[Trigger]
 3Type = Path
 4Operation = Install
 5Operation = Upgrade
 6Target = usr/lib/modules/*/vmlinuz
 7Target = usr/lib/initcpio/*
 8
 9[Action]
10Description = Signing linux kernels...
11When = PostTransaction
12Exec = /usr/local/share/libalpm/scripts/mkinitcpio-sbsign
13NeedsTargets
14__EOF__

This is a simple script that checks that a kernel has changed then it goes to sign the kernel image and puts it in the the EFI directory.

 1cat << __EOF__ | sudo tee /usr/local/share/libalpm/scripts/mkinitcpio-sbsign
 2#!/bin/bash -e
 3
 4while read -r line; do
 5    if [[ \$line != */vmlinuz ]]; then
 6        # triggers when it's a change to usr/lib/initcpio/*
 7        continue
 8    fi
 9
10    if ! read -r pkgbase > /dev/null 2>&1 < "\${line%/vmlinuz}/pkgbase"; then
11        # if the kernel has no pkgbase, we skip it
12        continue
13    fi
14
15    # always sign the kernel
16    if [[ -f /boot/archlinux-\${pkgbase}.efi ]]; then
17        sbsign --key /etc/efi-keys/DB.key --cert /etc/efi-keys/DB.crt --output "/efi/EFI/Linux/archlinux-\${pkgbase}-signed.efi" "/boot/archlinux-\${pkgbase}.efi"
18    fi
19done
20__EOF__
21sudo chmod +x /usr/local/share/libalpm/scripts/mkinitcpio-sbsign

enable secure boot

The best that I can say is that you need to go into your UEFI settings and enable secure boot.

Links: