Secure Boot
Secure Boot is a security feature found in the UEFI standard, designed to add a layer of protection to the pre-boot process: by maintaining a cryptographically signed list of binaries authorized or forbidden to run at boot, it helps in improving the confidence that the machine core boot components (boot manager, kernel, initramfs) have not been tampered with.
Preparations
To determine the current state of Secure Boot execute:
bootctl status
The output looks something like this:
System:
Firmware: UEFI 2.70 (American Megatrends 5.15)
Secure Boot: enabled
Setup Mode: user
Boot into FW: supported
...
In order to proceed "Secure Boot" should say "enabled" and "Setup Mode" should say "setup".
If the command displays the "Setup Mode" as "user" you need to enter your firmware settings and put the firmware into "setup" mode to proceed. This can usually be achieved by wiping the key store of the firmware.
Installation
InstallFor the followingmost packages for thestraigh-forward Secure Boot toolchain:toolchain install:
pacman -S efitools sbsigntools sbctl
Kernel Command Line Parameters
For the sake of clarity, all parameters are stored in environment variables first and then written to a file with the echo
command.
Saving parameters to a file has several advantages:
- We can always refer to this file to verify which parameters are written to the unified kernel image
- Subsequent changes can be made more easily by just editing this file
- The file can easily be included in the configuration of
sbupdate
and both configurations are cleanly separated from each other
Variable | Description |
---|---|
CRYPT_UUID |
The UUID of the LUKS container, as stated by blkid |
CRYPT_NAME |
The device mapper name which should be used for the unlocked LUKS container (optional, recommended) |
ROOT |
Root file system device aspecified by persistent block device naming |
RESUME |
SWAP space for restoring memory from hibernate (optional) |
CMDL |
Misc. kernel command line parameters |
ROOTFLAGS |
Flags to be passed to the root file system |
Command substitution ($(command)
) makes it easy, reliable and scriptable to find certain values for these variables.
For example, to get the UUID of the LUKS container simply do (assuming /dev/sda1
is the LUKS container):
export CRYPT_UUID=$(blkid -s UUID -o value /dev/sda1)
The command blkid -s UUID -o value /dev/sda1
just returns the UUID of the given block device. Appending export
saves it in an environment variable called CRYPT_UUID
which can be read by issuing echo $CRYPT_UUID
.
Examples
The following examples show different ways of preparing the final kernel command line to successfully boot a machine with Secure Boot. The output will be written to /etc/kernel/cmdline
as this is the place sbctl
expects the kernel command line to reside.
busybox-based initramfs
For busybox-based initramfs the LUKS container must be passed with the cryptdevice
parameter. The cryptdevice
parameter is passed the path to an encrypted block device, followed by a :
with the desired device mapper name. Usage of persistent block device naming (i.e. the UUID of the device as returned by blkid
) is strongly recommended.
NOTE: This is not relevant for LVM logical volumes as the /dev/VolumeGroupName/LogicalVolumeName
device paths already are persistent. If the LUKS container resides inside an LVM logical volume you could simply supply:
cryptdevice=/dev/VolumeGroupName/LogicalVolumeName:DeviceMapperName
NOTE: By default, dm-crypt does not allow TRIM for SSDs for security reasons (information leak). To override this behavior, append :allow-discards
as an option parameter after the device mapper name.
For an LVM on LUKS setup (with SWAP for resume) the variables could look like this:
export CRYPT_UUID=$(blkid -s UUID -o value /dev/sda1)
export CRYPT_NAME=cryptroot
export ROOT=/dev/mapper/vg0-lv_root
export RESUME=/dev/mapper/vg0-lv_swap
export CMDL=rw quiet splash add_efi_memmap
export ROOTFLAGS=subvol=@
echo cryptdevice=UUID=$CRYPT_UUID:$CRYPT_NAME root=$ROOT resume=$RESUME $CMDL rootflags=$ROOTFLAGS > /etc/kernel/cmdline
systemd-based initramfs
For systemd-based initramfs the LUKS container must be passed with the rd.luks.*
parameter. The LUKS container can either be passed with the rd.luks.uuid
or rd.luks.name
parameter. Both take the UUID of the LUKS container, with rd.luks.name
additionaly taking a parameter for a device mapper name. Usage of persistent block device naming (i.e. the UUID of the device as returned by blkid
) is mandatory.
When using rd.luks.name
as the boot parameter, rd.luks.uuid
can be omitted as it is implied.
NOTE: By default, dm-crypt does not allow TRIM for SSDs for security reasons (information leak). To override this behavior, add rd.luks.options=discard
as an additional parameter.
For a LUKS on LVM setup the variables could look like this:
export CRYPT_UUID=$(blkid -s UUID -o value /dev/sda1)
export CRYPT_NAME=cryptroot
export ROOT=/dev/mapper/$CRYPT_NAME
export CMDL=rw quiet splash add_efi_memmap
export ROOTFLAGS=subvol=@
echo rd.luks.name=$CRYPT_UUID=$CRYPT_NAME root=$ROOT $CMDL rootflags=$ROOTFLAGS > /etc/kernel/cmdline
Generating keys
FURTHER READING: The Meaning of all the UEFI Keys
Secure Boot implementations use these keys:
Key Type | Description |
---|---|
Platform Key (PK) | Top-level key |
Key Exchange Key (KEK) | Keys used to sign Signatures Database and Forbidden Signatures Database updates |
Signature Database (db) | Contains keys and/or hashes of allowed EFI binaries |
Forbidden Signatures Database (dbx) | Contains keys and/or hashes of denylisted EFI binaries |
To generate new keys and store them under /usr/share/secureboot/keys/
:
sbctl create-keys
Downloading and preparing Microsoft's keys
If you plan on dual booting Arch Linux alongside Windows you might also want to add Microsoft's keys to the firmware key store.
Download Microsoft’s KEK and convert it to PEM and ESL format (with Microsoft’s GUID):
cd /usr/share/secureboot/keys/KEK
curl -L -o MicCorKEKCA2011_2011-06-24.crt 'https://go.microsoft.com/fwlink/?LinkId=321185'
openssl x509 -inform DER -outform PEM -in MicCorKEKCA2011_2011-06-24.crt -out MicCorKEKCA2011_2011-06-24.pem
cert-to-efi-sig-list -g 77fa9abd-0359-4d32-bd60-28f4e78f784b MicCorKEKCA2011_2011-06-24.pem MicCorKEKCA2011_2011-06-24.esl
Download Microsoft’s DB certificates, convert to PEM and ESL (with Microsoft’s GUID):
cd /usr/share/secureboot/keys
curl -OL https://www.microsoft.com/pkiops/certs/MicWinProPCA2011_2011-10-19.crt
curl -OL https://www.microsoft.com/pkiops/certs/MicCorUEFCA2011_2011-06-27.crt
openssl x509 -inform DER -outform PEM -in MicWinProPCA2011_2011-10-19.crt -out MicWinProPCA2011_2011-10-19.pem
openssl x509 -inform DER -outform PEM -in MicCorUEFCA2011_2011-06-27.crt -out MicCorUEFCA2011_2011-06-27.pem
cert-to-efi-sig-list -g 77fa9abd-0359-4d32-bd60-28f4e78f784b MicWinProPCA2011_2011-10-19.pem MicWinProPCA2011_2011-10-19.esl
cert-to-efi-sig-list -g 77fa9abd-0359-4d32-bd60-28f4e78f784b MicCorUEFCA2011_2011-06-27.pem MicCorUEFCA2011_2011-06-27.esl
mkdir -p /efi/keys/{db,KEK}
cat MicWinProPCA2011_2011-10-19.esl MicCorUEFCA2011_2011-06-27.esl > /usr/share/secureboot/keys/db/microsoft_db.esl
Sign Microsoft’s keys with your PK and KEK respectively. Again, note the use of the append flag -a:
sign-efi-sig-list -a -g 77fa9abd-0359-4d32-bd60-28f4e78f784b \
-k /usr/share/secureboot/keys/PK/PK.key \
-c /usr/share/secureboot/keys/PK/PK.pem \
KEK /usr/share/secureboot/keys/KEK/MicCorKEKCA2011_2011-06-24.esl \
/efi/keys/KEK/MicCorKEKCA2011_2011-06-24.auth
sign-efi-sig-list -a -g 77fa9abd-0359-4d32-bd60-28f4e78f784b \
-k /usr/share/secureboot/keys/KEK/KEK.key \
-c /usr/share/secureboot/keys/KEK/KEK.pem \
db /usr/share/secureboot/keys/db/microsoft_db.esl \
/efi/keys/db/microsoft_db.auth
Enroll keys in firmware
WARNING: Replacing the platform keys with your own can end up bricking your machine, making it impossible to get into the UEFI/BIOS settings to rectify the situation. This is due to the fact that some device firmware (OpROMs, e.g. GPU firmware), that gets executed during boot, may be signed using Microsoft's keys. If in doubt, run sbctl enroll-keys --microsoft
(enrolling Microsoft's Secure Boot keys alongside your own custom ones) or sbctl enroll-keys --tpm-eventlog
(if your machine has a TPM and you don't need or want Microsoft's keys) to prevent bricking your machine.
ATTENTION: Make sure your firmware's Secure Boot mode is set to setup
mode! You can do this by going into your firmware settings and wiping the factory default keys. Additionally, keep an eye out for any setting that auto-restores the default keys on system start.
WARNING:TIP: ReplacingIf theyou platformplan to dual-boot Windows, run sbctl enroll-keys --microsoft
to enroll Microsoft's Secure Boot keys along with your own cancustom end up bricking hardware on some machines, including laptops, making it impossible to get into the UEFI/BIOS settings to rectify the situation. This is due to the fact that some device (e.g GPU) firmware (OpROMs), that get executed during boot, are signed using Microsoft's key.keys.
Own keys
To enroll your own keys, simply:
sbctl enroll-keys
Microsoft keys
To enroll the prepared Microsoft keys, you can either try your mainboard's firmware settings or use KeyTool.efi.
Using KeyTool.efi
Prepare a directory for KeyTool.efi:
mkdir /efi/EFI/KeyTool
Copy a signed version of KeyTool.efi to the ESP:
sbsign --key /usr/share/secureboot/keys/db/db.key \
--cert /usr/share/secureboot/keys/db/db.pem \
--output /efi/EFI/KeyTool/KeyTool-signed.efi \
/usr/share/efitools/efi/KeyTool.efi
Boot KeyTool-signed.efi via firmware or EFI Shell:
NOTE: If using EFI Shell, verify that fs0:\ is the ESP you copied KeyTool-signed.efi and the keys to!
fs0:\EFI\KeyTool\KeyTool-signed.efi
Proceed to add Microsoft keys to your motherboard's firmware with KeyTool.efi.
Automate unifying and resigning kernel images on update
is sbupdatesbctla tool that greatly simplyfies and streamlines the processcapable of unifying and signinggenerating unified kernel images and signing them in one command. It also comes with a pacman
hook to re-bundle and re-sign images on kernelsystem updates.upgrades.
InstallFirst, sbupdatesbctlfromneeds AUR:to be told which files to unify into a bundle and where to put it ($ESP
pointing to the mount point of your EFI System Partition):
yay# AMD systems
sbctl bundle -S-save sbupdate-git-a /boot/amd-ucode.img $ESP/EFI/Linux/archlinux-linux.efi
# Intel systems
sbctl bundle --save -i /boot/intel-ucode.img $ESP/EFI/Linux/archlinux-linux.efi
EditThis generates and saves the bundle to sbctl
's database. Repeat this for every image you wish to bundle.
TIP: Consider having a separate /etc/
for your fallback image which doesn't include the sbupdate.confkernel/fallback_cmdlinequiet
parameter to hide boot messages and setsupply parameters:it with an additional -c
option.
Next, add all generated bundles to the list of files to be signed (one at a time):
KEY_DIR="/usr/share/secureboot/keys/db"sbctl ESP_DIR="/efi"sign OUT_DIR="--save $ESP/EFI/Arch"
SPLASH="/dev/null"
CMDLINE_DEFAULT="$(< /etc/kernel/cmdline)"Linux/archlinux-linux.efi
CreateIf you plan on using a symlinkboot loader, you will also need to add its *.efi
executable to the dblist keyof forfiles sbupdate:to be signed.
cdUpon /usr/share/secureboot/keys/db/system ln -s db.pem db.crt
Reinstallupgrades the kernelpacman
tohook should trigger the sbupdatesbctl sign-all -gpacman hookcommand to create unifiedre-generate and signedre-sign kernelthe image:bundles listed in sbctl
's database.
pacman -S linux