# 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. 

<p class="callout warning"><strong>ATTENTION:</strong> When using Secure Boot it's imperative to use it with disk encryption. If the storage device that stores the keys is not encrypted, anybody can read the keys and use them to sign bootable images, thereby defeating the purpose of using Secure Boot at all. Therefore, this guide will assume disk encryption is being used.</p>

## Preparations

To determine the current state of Secure Boot execute:

~~~bash
bootctl status
~~~

The output looks something like this:

~~~
System:
      Firmware: UEFI 2.70 (American Megatrends 5.17)
 Firmware Arch: x64
   Secure Boot: enabled (user)
  TPM2 Support: yes
  Measured UKI: yes
  Boot into FW: supported

...
~~~

In order to proceed you need to set your firmware's Secure Boot mode into "setup" mode. This can usually be achieved by wiping the key store of the firmware. Refer to your mainboard's user manual on how to do this.

## Installation

For the most straight-forward Secure Boot toolchain install `sbctl`:

~~~bash
pacman -S sbctl
~~~

It tremendously simplifies generating Secure Boot keys, loading keys into firmware and signing kernel images.

## Generating keys

<p class="callout info"><strong>SEE ALSO:</strong> <a href="https://blog.hansenpartnership.com/the-meaning-of-all-the-uefi-keys/">The Meaning of all the UEFI Keys</a></p>

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 `/var/lib/sbctl/keys`:

~~~bash
sbctl create-keys
~~~

## Kernel Lockdown Mode

To further strengthen security you might want to consider using the kernel's built-in Lockdown Mode. When engaging lockdown, access to certain features and facilities is blocked, even for the root user. This helps prevent Secure Boot from being bypassed through a compromised system, for example by editing EFI variables or replacing the kernel at runtime.

Lockdown Mode knows two modes of operation:

* `integrity`: kernel features that allow userland to modify the running kernel are disabled (kexec, bpf)
* `confidentiality`: kernel features that allow userland to extract confidential information from the kernel are also disabled

The recommended mode is `integrity`, as `confidentiality` can break certain applications (e.g. Docker).

To enable Lockdown Mode, set the `lockdown=MODE` kernel command line parameter with your preferred mode.

## Enroll keys in firmware

<p class="callout danger"><strong>WARNING:</strong> 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. Run <code>sbctl enroll-keys --microsoft</code> if you're unsure if this applies to you (enrolling Microsoft's Secure Boot keys alongside your own custom ones) or include the <a href="/books/arch-linux/page/trusted-platform-module">TPM</a> Event Log with <code>sbctl enroll-keys --tpm-eventlog</code> (if your machine has a TPM and you don't need or want Microsoft's keys) to prevent bricking your machine.</p>

<p class="callout warning"><strong>ATTENTION:</strong> Make sure your firmware's Secure Boot mode is set to <code>setup</code> 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.</p>

<p class="callout info"><strong>TIP:</strong> If you plan to dual-boot Windows, run <code>sbctl enroll-keys --microsoft</code> to enroll Microsoft's Secure Boot keys along with your own custom keys.</p>

To enroll your keys, simply:

~~~bash
sbctl enroll-keys
~~~

## Automated signing of UKIs

`sbctl` comes with a hook for `mkinitcpio` which runs after it has rebuilt an image. Manually specifying images to sign is therefore entirely optional.

## Signing the Bootloader

<p class="callout info"><strong>NOTE:</strong> This is the manual method. If you also want to automate the bootloader update process, skip to the section below.</p>

If you plan on using a boot loader, you will also need to add its `*.efi` executable(s) to the `sbctl` database, e.g. `systemd-boot`:

~~~bash
sbctl sign --save /efi/EFI/BOOT/BOOTX64.EFI
sbctl sign --save /efi/EFI/systemd/systemd-bootx64.efi
~~~

Upon system upgrades, `pacman` will call `sbctl` to sign the files listed in the `sbctl` database.

### Automate `systemd-boot` updates and signing

`systemd` comes with a `systemd-boot-update.service` unit file to automate updating the bootloader whenever `systemd` is updated. However, it only updates the bootloader **after** a reboot, by which time `sbctl` has already run the signing process. This would necessitate manual intervention.

Recent versions of `bootctl` look for a `.efi.signed` file before a regular `.efi` file when copying bootloader files during `install` and `update` operations. So to integrate better with the auto-update functionality of `systemd-boot-update.service`, the bootloader needs to be signed ahead of time.

~~~bash
sbctl sign --save \
  -o /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed \
  /usr/lib/systemd/boot/efi/systemd-bootx64.efi
~~~

This will add the source and target file paths to `sbctl`'s database. The pacman hook included with `sbctl` will trigger whenever a file in `usr/lib/**/efi/*.efi*` changes, which will be the case when `systemd` is updated and a new version of the unsigned bootloader is written to disk at `/usr/lib/systemd/boot/efi/systemd-bootx64.efi`.

Finally, enable the `systemd-boot-update.service` unit:

~~~bash
systemctl enable systemd-boot-update
~~~

Now when `systemd` is updated the **signed** version of the `systemd-bootx64.efi` booloader will be copied to the ESP after a reboot, completely automating the bootloader update and signing process!