Secure Boot
Secure Boot is designed to enhance the security of the pre-boot process of a UEFI system. When enabled, the UEFI firmware verifies the signature of every component used in the boot process. This results in boot files which are easily readable, but tamper evident.
Introduction
Implementing Secure Boot can significantly enhance the security of a system. The integrity of the boot chain is extremely important. If malicious code is able to interfere with the boot process, many other security measures are effectively nullified. The focus of this article is an in-depth explanation of how to interact with the secure boot process. To simply get Secure Boot working, something like app-crypt/sbctl can be used.
Cryptography
UEFI Secure Boot typically uses RSA-2048 and sha256RSA to perform public key cryptography.
Some UEFI implementations may support other algorithms/key sizes.
Secure Boot public keys should be stored in the X.509 format.
The private keys used to sign boot files must be kept secure, if keys are leaked, they could be used to sign malicious boot files.
Components
Secure Boot typically implements the following keys and lists: [1][2][3]:
- PK - Platform Key - Composed of two parts, PKpub (the public key) and PKpriv (the private key), used to sign the KEK.
- KEK - Key Exchange Key - The key used to sign the Signatures and Forbidden Signatures database, there can be more than one.
- db - Signature Database - Contains lists of public keys, signatures, and hashes which are allowed as part of the boot chain.
- dbx - Forbidden Signature Database - The opposite of the signature database, public keys, signatures, and hashes which should never be allowed to boot.
Only one Platform Key can be used on a system, each other type is actually a list or "database". It is common to include the device Manufacturer's Key Exchange Key, and sometimes Microsoft's. On some devices, removing either of these keys could disable all video output.
Key Formats
Several key formats and extensions are used with Secure Boot:
- .key - PEM - Used for private keys.
- .crt - PEM - Used for public keys.
- .cer - DER - Used for public keys.
- .esl - EFI Signature List - Used by EFI, a collection of public keys and hashes.
- .auth - Signed EFI Signature List - Used by EFI, signed form of an esl.
Implementation
Secure Boot is only as strong as the implementation. The UEFI must be protected with passwords, otherwise an attacker could simply turn Secure Boot off and bypass it. Additionally, weak key storage can render any protections Secure Boot provides useless.
Physical security plays a large factor in how well Secure Boot works. Even with an Admin Password set for a system's firmware, resetting the CMOS by removing the battery or using a jumper/button on the motherboard will often reset any passwords. Additionally, some laptop's UEFI password can easily be reset.
Key Storage
Secure Boot stores the public keys and Signature Lists, typically stored on the mainboard's NVRAM. This memory region is typically readable once booted, but can only be written using the EFI firmware. An example of this is efibootmgr being used to adjust the boot order while the system is running. Memory for Secure Boot keys is typically read-only, and depending on the implementation, variables may only be writable one time in Setup Mode. UEFI firmware may support updating using properly .auth files, but this is not universal.
Some UEFIs allow for improper/insecure key loading, such as db and KEKs which do not match, or esl loading without authorization when in UEFI configuration.
Installation
USE flags
USE flags for app-crypt/efitools Tools for manipulating UEFI secure boot platforms
static
|
!!do not set this during bootstrap!! Causes binaries to be statically linked instead of dynamically |
USE flags for app-crypt/sbsigntools Utilities for signing and verifying files for UEFI Secure Boot
USE flags for dev-libs/openssl Robust, full-featured Open Source Toolkit for the Transport Layer Security (TLS)
asm
|
Support assembly hand optimized crypto functions (i.e. faster run time) |
fips
|
Enable FIPS provider |
ktls
|
Enable support for Kernel implementation of TLS (kTLS) |
rfc3779
|
Enable support for RFC 3779 (X.509 Extensions for IP Addresses and AS Identifiers) |
sctp
|
Support for Stream Control Transmission Protocol |
static-libs
|
Build static versions of dynamic libraries as well |
test
|
Enable dependencies and/or preparations necessary to run tests (usually controlled by FEATURES=test but can be toggled independently) |
tls-compression
|
Enable support for discouraged TLS compression |
vanilla
|
Do not add extra patches which change default behaviour; DO NOT USE THIS ON A GLOBAL SCALE as the severity of the meaning changes drastically |
verify-sig
|
Verify upstream signatures on distfiles |
weak-ssl-ciphers
|
Build support for SSL/TLS ciphers that are considered "weak" |
Emerge
root #
emerge --ask app-crypt/efitools
root #
emerge --ask app-crypt/sbsigntools
root #
emerge --ask dev-libs/openssl
Backing up existing keys
Putting the system into Setup Mode removes all present keys, backups should be made before entering Setup Mode.
efi-readvar can be used to view the public contents of the UEFI signature database.
The keys can be saved using:
~/secure_boot/factory_config $
for key_type in PK KEK db dbx; do efi-readvar -v $key_type -o ${key_type}.esl; done
Or each var can manually be saved using:
~/secure_boot/factory_config $
efi-readvar -v PK -o PK.esl
~/secure_boot/factory_config $
efi-readvar -v KEK -o KEK.esl
~/secure_boot/factory_config $
efi-readvar -v db -o db.esl
~/secure_boot/factory_config $
efi-readvar -v dbx -o dbx.esl
Ensure these keys are stored in a manner which makes the origin of these keys clear. This guide puts them in a separate directory, they will be used later.
Generating new keys
OpenSSL can be used to generate the Secure Boot keys.
At a minimum, the PK, KEK, and db keys must be created. Each of these keys can be created similarly.
When generating keys, ensure they are not being written to unencrypted storage, or to an easily accessible place. Encrypting the private key files is an optional step, but greatly increases security.
Because the process of rekeying Secure Boot is rather cumbersome, an expiry period of 10 years is typically used, it can be reduced or extended, but must be rekeyed when the keys expire.
Entries in EFI Signature Lists must be given a GUID (UUID), it must be unique but can otherwise be anything fitting that format. The chosen UUID does not have to be the same for all components, but this practice can help with organization.
Generating a UUID
To generate a UUID using uuidgen, and write it to uuid.txt:
~/secure_boot/custom_config $
uuidgen > uuid.txt
uuidgen uses /dev/random by default if possible.
Batch asymmetrically protected key creation
To create a GPG encrypted file for each key type (PK, KEK, db, dbx):
~/secure_boot/custom_config $
mkfifo key_pipe & sleep 1 && for key_type in PK KEK db dbx; do openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Larry's ${key_type}" -keyout key_pipe -out ${key_type}.crt -days 9999 -nodes -sha256 & gpg --output ${key_type}.key.gpg --recipient larry@gentoo.org --encrypt < key_pipe ; done ; rm key_pipe
This is equivalent to:
~/secure_boot/custom_config $
mkfifo key_pipe &
~/secure_boot/custom_config $
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Larry's PK" -keyout key_pipe -out PK.crt -days 9999 -nodes -sha256 &
~/secure_boot/custom_config $
gpg --output PK.key.gpg --recipient larry@gentoo.org --encrypt < key_pipe
~/secure_boot/custom_config $
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Larry's KEK" -keyout key_pipe -out KEK.crt -days 9999 -nodes -sha256 &
~/secure_boot/custom_config $
gpg --output KEK.key.gpg --recipient larry@gentoo.org --encrypt < key_pipe
~/secure_boot/custom_config $
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Larry's db" -keyout key_pipe -out db.crt -days 9999 -nodes -sha256 &
~/secure_boot/custom_config $
gpg --output db.key.gpg --recipient larry@gentoo.org --encrypt < key_pipe
~/secure_boot/custom_config $
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Larry's dbx" -keyout key_pipe -out dbx.crt -days 9999 -nodes -sha256 &
~/secure_boot/custom_config $
gpg --output dbx.key.gpg --recipient larry@gentoo.org --encrypt < key_pipe
~/secure_boot/custom_config $
rm key_pipe
Manual key creation
To create key a Platform Key pair without protecting the PKpriv:
~/secure_boot/custom_config $
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Larry's Platform Key" -keyout PK.key -out PK.crt -days 9999 -nodes -sha256
The Common Name selected for the certificate can be anything, but should be descriptive.
To immediately GPG encrypt the PKpriv for additional protection, a named pipe can be used:
The recipient must correspond to the key being to encrypt the key files. -c can be used instead to symmetrically encrypt the created files.
~/secure_boot/custom_config $
mkfifo key_pipe & sleep 1; openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Larry's Platform Key" -keyout key_pipe -out PK.crt -days 9999 -nodes -sha256 & gpg --output PK.key.gpg --recipient larry@gentoo.org --encrypt < key_pipe && rm key_pipe
This waits a second, because it forks and there is a chance that the named pipe may not be created by the time openssl attempts to generate keys.
This process can be repeated for the Key Exchange Key (KEK), Signature Database Key (db), and optionally, Forbidden Signature Database Key (dbx).
Creating the new Signature Lists
cert-to-efi-list can be used to create an .esl file using a .crt file, that signature list can then be signed using sign-efi-sign-list and the private key. To perform these actions on the Platform Key which has been GPG encrypted:
Batch creation
This process can be done in a batch using:
~/secure_boot/custom_config $
for key_type in PK KEK db dbx; do cert-to-efi-sig-list -g $(< uuid.txt) ${key_type}.crt ${key_type}.esl; done
Manual creation
The Signing List for the Platform Key can be created using:
~/secure_boot/custom_config $
cert-to-efi-sig-list -g $(< uuid.txt) PK.crt PK.esl
This takes PK.crt as an input and outputs PK.esl. In this stage, nothing is signed.
This process should be repeated for every other used key type.
DER file creation (optional)
To create a DER (.cer) file for each of the generated keys:
~/secure_boot/custom_config $
for key_type in PK KEK db dbx; do openssl x509 -outform DER -in ${key_type}.crt -out ${key_type}.cer ; done
Preparing the keys
With the new keys created, they must be combined with existing keys, formatted and signed to be used.
Combining the Signature Lists
The created Signature Lists are not populated, it often makes sense to begin using the factory keys, these can later be removed if desired.
Some systems require the loading of GPU drivers signed with factory keys, if Secure Boot is enabled, but validation fails for these files, graphics output will be broken. If this occurs, Secure Boot must be disabled headlessly to recover the system.
Batch concatenation
To concatenate all new and old Signature Lists:
~/secure_boot $
for key_type in KEK db dbx; do cat factory_config/${key_type}.esl custom_config/${key_type}.esl > ${key_type}.esl; done
Manual concatenation
The KEK Signature Lists can be concatenated using:
~/secure_boot $
cat factory_config/KEK.esl custom_config/KEK.esl > KEK.esl
This process can be repeated for the db and dbx Signature Lists
Copying the Platform Key
For the sake of organization, the new Platform Key should be copied to the current directory:
~/secure_boot $
cp custom_config/PK.esl .
Signing the Signature Lists
With the Signature Lists finalized, they must be signed:
Platform Key
The signed PK Signature List can be created with:
~/secure_boot/ $
mkfifo key_pipe & sleep 1 && gpg --decrypt custom_config/PK.key.gpg > key_pipe & sign-efi-sig-list -k key_pipe -c custom_config/PK.crt PK PK.esl PK.auth ; rm key_pipe
Reset Key
If an empty file is passed as an esl, it creates an auth file which can be leaded into the Platform Key slot, disabling it:
This file is literally an empty file signed with the Platform Key, when it is loaded into the PK slot, as it is validly signed, it erases the contents, disabling Secure Boot.
~/secure_boot/ $
rm -f noPK.esl
~/secure_boot/ $
touch noPK.esl
~/secure_boot/ $
mkfifo key_pipe
~/secure_boot/ $
mkfifo nopk_pipe
~/secure_boot/ $
gpg --decrypt custom_config/PK.key.gpg > key_pipe & sign-efi-sig-list -k key_pipe -c custom_config/PK.crt PK noPK.esl nopk_pipe &
~/secure_boot/ $
gpg --recipient larry@gentoo.org --output noPK.auth.gpg --encrypt < nopk_pipe
~/secure_boot/ $
rm nopk_pipe
~/secure_boot/ $
rm key_pipe
Key Exchange Keys
The KEK is signed using the PK.
The signed KEK Signature List can be created with:
user $
mkfifo key_pipe & sleep 1 && gpg --decrypt custom_config/PK.key.gpg > key_pipe & sign-efi-sig-list -a -k key_pipe -c custom_config/PK.crt KEK KEK.esl KEK.auth ; rm key_pipe
Signature Databases
The db and dbx are signed using the KEK.
Finally, this process must be used with the db and dbx Signature Lists:
user $
mkfifo key_pipe & sleep 1 && for db_type in db dbx; do gpg --decrypt custom_config/KEK.key.gpg > key_pipe & sign-efi-sig-list -k key_pipe -c custom_config/KEK.crt $db_type ${db_type}.esl ${db_type}.auth ; done ; rm key_pipe
Installing the keys
On most systems, the keys and signature lists can be installed using efi-updatevar. If this is not possible, the keys must be loaded using the UEFI.
Before installing the keys, the system must be put into Setup Mode. This process differ widely across systems, but generally, there is an option under the Security tab allowing secure boot to be disabled, and for the keys to be cleared/setup mode to be entered.
Setup Mode is exited once the Platform Key has been written. Entering User Mode does not enable Secure Boot.
Entries other than the Platform Key can be installed using the .esl files while in Setup Mode.
When installing esl files, -e must be used.
Installing the Key Exchange Key
While in Setup Mode, the KEK can be installed with either the .auth, or .esl file:
~/secure_boot/
sudo efi-updatevar -e -f KEK.esl KEK
While in User Mode, the KEK can be installed with a valid KEK.auth:
~/secure_boot/
sudo efi-updatevar -f KEK.auth KEK
Installing the Database Keys
While in Setup Mode, the db and dbx can be installed with either the .auth, or .esl file:
~/secure_boot/
for db_type in db dbx; do sudo efi-updatevar -e -f ${db_type}.esl $db_type; done
While in User Mode, the KEK can be installed with a valid KEK.auth:
~/secure_boot/
for db_type in db dbx; do sudo efi-updatevar -f ${db_type}.auth $db_type; done
Installing the Platform Key
While in Setup Mode, the PK can be installed using:
~/secure_boot/
sudo efi-updatevar -f PK.auth PK
Successful execution of this command exits Setup Mode and enters User Mode
Signing Boot Files
Before activating secure boot, all boot files must be signed, this can be done using:
~/secure_boot/
mkfifo key_pipe & sleep 1 && gpg --decrypt custom_config/db.key.gpg > key_pipe & sudo sbsign --key key_pipe --cert custom_config/db.crt --output {output_filename} {input_file}; rm key_pipe
In this case, sudo is only required to write to /boot.
Basic usage with an unencrypted private key:
~/secure_boot/
sudo sbsign --key custom_config/db.key --cert custom_config/db.crt --output {output_filename} {input_file}
If a kernel image is built with an embedded initramfs, that is the only file which needs to be signed to boot:
~/secure_boot/
mkfifo key_pipe & sleep 1 && gpg --decrypt custom_config/db.key.gpg > key_pipe & sudo sbsign --key key_pipe --cert custom_config/db.crt /boot/vmlinuz-6.3.4-gentoo-r1-initramfs; rm key_pipe
This saves the signed file to a file with the same name, but the .signed extension.
This file can be moved to /boot/EFI/BOOT/BOOTx64.efi, or efibootmgr can be used to add a boot entry for this new signed file.
To create an EFI boot entry for /boot/vmlinuz-6.3.4-gentoo-r1-initramfs.signed which is under the root of /dev/sda1:
root #
efibootmgr --disk /dev/sda --create --label "Signed Gentoo 6.3.4" --loader vmlinuz-6.3.4-gentoo-r1-initramfs.signed
The label is for the user and should be descriptive.
Verifying Signatures
Files signed using this process can be checked using:
~/secure_boot/
sbverify --cert custom_config/db.crt /boot/vmlinuz-6.3.4-gentoo-r1-initramfs.signed
Listing Signatures
Signatures can be listed using:
user $
sbverify --list /boot/vmlinuz-6.3.4-gentoo-r1-initramfs.signed
signature 1 image signature issuers: - /CN=Larry's db image signature certificates: - subject: /CN=Larry's db issuer: /CN=Larry's db
Checking Secure Boot Status
When Secure Boot is enabled, dmesg should report:
root #
dmesg | grep -i "secure"
od can be used to read the Secure Boot status from /sys/firmware/efi/efivars/:
The UUID may differ, but the parameter should start with SecureBoot-.
user $
od --address-radix n --format x1 /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c
A value of 1 in the last portion indicates that Secure Boot is set to be active in the EFI variables.
--address-radix n removes output formatting, only displaying data. --format x1 formats the output data as hex.
efivar
efivar can be used to read and change the values of EFI variables:
Listing variables
The --list parameter can be used to read current EFI variables.
The output format is {UUID}-name" and the UUID essentially be ignored.
user $
efivar --list | grep -i secure
aa1305b9-01f3-4afb-920e-c9b979a852fd-SecureBootData 8be4df61-93ca-11d2-aa0d-00e098032b8c-SecureBoot 59d1c24f-50f1-401a-b101-f33e0daed443-SecureBootEnforce 382af2bb-ffff-abcd-aaee-cce099338877-SecureFlashInfo 59d1c24f-50f1-401a-b101-f33e0daed443-AdministerSecureBoot
Checking Secure Boot Status
The status of secure boot can be checked with:
user $
efivar --print --name 8be4df61-93ca-11d2-aa0d-00e098032b8c-SecureBoot
Name: "SecureBoot" Attributes: Boot Service Access Runtime Service Access Value: 00000000 01 |. |
An output of 1 indicates Secure Boot is enabled.
Resetting the Platform Key
Using a noPK.auth, to update the PK disables it:
~/secure_boot/ $
mkfifo auth_pipe & sleep 1 && gpg --decrypt noPK.auth.gpg > auth_pipe & sudo efi-updatevar -f auth_pipe PK
See also
- Full_Disk_Encryption_From_Scratch_Simplified — a guide which covers the process of configuring a drive to be encrypted using LUKS with LVM.
- Security_Handbook/Boot_Path_Security — boot path security.
- Trusted_Boot
- Trusted_Platform_Module — The Trusted Platform Module, or TPM for short, is a secure, isolated, cryptographic processor that is typically built into most modern computers.