UEFI Secure Boot
About 1547 wordsAbout 5 min
2026-03-23
What Secure Boot Enforces
UEFI Secure Boot is an integrity verification mechanism defined in the UEFI specification (§32). Before UEFI loads any executable — a bootloader, OS loader, UEFI driver, or option ROM — it verifies the binary's cryptographic signature against an authorized key database. If verification fails, the executable is refused.
Secure Boot does not prevent booting a different OS. It prevents loading unsigned or improperly signed code. A user can enroll their own keys (in UEFI Setup mode) to authorize any code they trust.
Key Hierarchy
Secure Boot uses a four-tier key hierarchy. Each tier authorizes the one below it.
Platform Key (PK)
│ owns + authorizes
▼
Key Exchange Key (KEK)
│ authorizes updates to
▼
Signature Database (db) Forbidden Signature Database (dbx)
│ │
│ authorizes loading │ blocks loading (blacklist)
▼ ▼
UEFI executables (PE/COFF .efi binaries)Platform Key (PK)
- Exactly one PK is enrolled at any time
- Issued and held by the platform owner (OEM, enterprise IT, or user for custom builds)
- Changing the PK requires physical presence (user must press a button in UEFI setup — called "Setup Mode")
- Implemented as a
PKUEFI authenticated variable - Key type: X.509 certificate (typically RSA-2048 or RSA-4096)
Key Exchange Key (KEK)
- One or more KEKs; each is an X.509 cert or a raw SHA-256 hash
- KEK holders can update
dbanddbxwithout re-enrolling PK - Microsoft's KEK (
77fa9abd-0359-4d32-bd60-28f4e78f784b) is pre-enrolled on most commercial hardware, allowing Microsoft to pushdb/dbxupdates via Windows Update
Signature Database (db)
- Contains the public keys and/or SHA-256 hashes of allowed executables
- An executable is trusted if: its signing certificate chains to an entry in
db, OR its SHA-256 image hash is directly indb - Key types allowed: X.509 cert, SHA-1/SHA-256 hash, RSA-2048 hash
Forbidden Signature Database (dbx)
- Contains revoked certificates and image hashes
- Checked before
db— if a match is found indbx, the executable is blocked even if it would passdb - Critical security mechanism: when a bootloader vulnerability is discovered (e.g., BootHole/GRUB 2020), the affected binary hash or signing cert is added to
dbxand pushed to all systems via Windows Update
Additional Databases
| Variable | Purpose |
|---|---|
dbr (dbt) | Boot recovery database; used when booting recovery paths |
dbt (MOK) | Third-party database for MOK (Machine Owner Key) shim mechanism |
MokList | Machine Owner Key list maintained by Linux shim, not UEFI firmware |
UEFI Variable Security Model
Secure Boot keys are stored in authenticated UEFI non-volatile variables. Each is a EFI_SIGNATURE_LIST structure:
// UEFI Spec: Authentication 2 Descriptor
typedef struct {
EFI_GUID SignatureType; // cert type or hash type GUID
UINT32 SignatureListSize;
UINT32 SignatureHeaderSize;
UINT32 SignatureSize;
// EFI_SIGNATURE_DATA[] follows:
// EFI_GUID SignatureOwner; (identifies who enrolled this entry)
// UINT8 SignatureData[]; (DER-encoded X.509 cert or hash bytes)
} EFI_SIGNATURE_LIST;These variables have the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute. Any attempt to update them must include a valid EFI_VARIABLE_AUTHENTICATION_2 header — a PKCS#7 signature using the corresponding authorization key (PK for KEK updates, KEK for db/dbx updates).
Generating Secure Boot Keys
All keys are X.509 certificates backed by RSA private keys. Use OpenSSL:
# Step 1: Generate Platform Key (PK)
openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 \
-days 3650 \
-subj "/CN=MySoC Platform Key/" \
-out PK.crt
# Step 2: Generate Key Exchange Key (KEK)
openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 \
-days 3650 \
-subj "/CN=MySoC Key Exchange Key/" \
-out KEK.crt
# Step 3: Generate Image Signing Key (db key)
openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 \
-days 3650 \
-subj "/CN=MySoC Signing Key/" \
-out db.crt
# Convert to DER format (EDK2 tools expect DER)
openssl x509 -in PK.crt -outform DER -out PK.der
openssl x509 -in KEK.crt -outform DER -out KEK.der
openssl x509 -in db.crt -outform DER -out db.der
# Convert to PKCS#12 for some tooling
openssl pkcs12 -export -out db.pfx -inkey db.key -in db.crt -passout pass:Signing UEFI Executables
UEFI binaries are PE/COFF format. Signing embeds a PKCS#7 signature in the PE WIN_CERTIFICATE security directory entry.
Using sbsign (Linux)
# Install
sudo apt-get install sbsigntool
# Sign a UEFI binary
sbsign --key db.key --cert db.crt --output grubx64.efi.signed grubx64.efi
# Verify
sbverify --cert db.crt grubx64.efi.signed
# Check signature details
pesign -c db.crt -i grubx64.efi --show-signatureUsing osslsigncode (cross-platform)
# Install
sudo apt-get install osslsigncode
# Sign
osslsigncode sign \
-certs db.crt \
-key db.key \
-h sha256 \
-in grubx64.efi \
-out grubx64.efi.signed
# Verify
osslsigncode verify -certs db.crt grubx64.efi.signedSigning the EDK2-Built Firmware Itself
When building OVMF or a platform firmware with Secure Boot support, the firmware binary can also be signed for platform-level integrity:
# Produce a signed FDF output by adding a security section to the FV
# In the .fdf file:
[FV.FVMAIN_COMPACT]
# Wrap DXE FV in a PKCS#7-signed encapsulation section
# This is the "authenticated firmware volume" concept
# Handled by Conf/tools_def.txt PKCS7SIGN toolFor most embedded use cases, the firmware itself is authenticated by TF-A or BootROM (see Chain of Trust), and Secure Boot handles executables loaded by UEFI.
Enrolling Keys in EDK2 (OVMF / Development)
Method 1: UEFI Shell (Interactive)
# From UEFI Shell, mount the ESP containing your EFI sig list files
FS0:
cd SecureBoot
# Use the built-in KeyTool.efi (from efitools package) or EnrollDefaultKeys.efi
# (from OvmfPkg) to enroll keys
KeyTool.efiMethod 2: efitools (Linux userspace, for OVMF/QEMU)
sudo apt-get install efitools
# Create EFI Signature List for PK
cert-to-efi-sig-list -g "$(uuidgen)" PK.crt PK.esl
# Self-sign the EFI Signature List update (PK signs itself during initial enrollment)
sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl PK.auth
# Create signed update for KEK (signed by PK)
cert-to-efi-sig-list -g "$(uuidgen)" KEK.crt KEK.esl
sign-efi-sig-list -k PK.key -c PK.crt KEK KEK.esl KEK.auth
# Create signed update for db (signed by KEK)
cert-to-efi-sig-list -g "$(uuidgen)" db.crt db.esl
sign-efi-sig-list -k KEK.key -c KEK.crt db db.esl db.authMethod 3: EDK2 EnrollDefaultKeys.efi
OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.efi is an UEFI application that reads keys from the QEMU firmware configuration interface and enrolls them automatically. Used in OVMF test builds.
Method 4: Programmatic Enrollment via SetVariable
In a platform-specific PEI module or early DXE driver (before ReadyToLock), you can pre-provision the Secure Boot variables:
// In a DXE driver that runs before ReadyToLock
#include <Guid/AuthenticatedVariableFormat.h>
#include <Library/AuthVariableLib.h>
// Note: writing PK/KEK/db as "Authenticated Variables" requires:
// 1. System is in "Setup Mode" (PK variable is empty)
// 2. For PK: the auth descriptor is signed by the new PK itself (self-signed)
// 3. For KEK/db/dbx: auth descriptor signed by PK (for KEK) or KEK (for db/dbx)
Status = gRT->SetVariable (
EFI_PLATFORM_KEY_NAME, // L"PK"
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
sizeof(AuthDescriptor) + sizeof(EslData),
AuthDescriptor // contains the PKCS#7 signature + EFI_SIGNATURE_LIST
);EDK2 Secure Boot Build Configuration
DSC Configuration
[Defines]
# Enable Secure Boot support in the build
SECURE_BOOT_ENABLE = TRUE
[PcdsFixedAtBuild]
# Default state: Secure Boot is ENABLED on first boot
gEfiMdeModulePkgTokenSpaceGuid.PcdSecureBootEnable|TRUE
[PcdsDynamicDefault]
# Secure Boot can be toggled at runtime (controlled by PK enrollment state)
gEfiMdeModulePkgTokenSpaceGuid.PcdSecureBootEnable|1
[Components]
# Core variable driver with authenticated variable support
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
<LibraryClasses>
AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
}
# Secure Boot configuration DXE driver
SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
# Image verification (checks PE/COFF signatures against db/dbx)
SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.infThe Image Verification Flow
When EFI_SECURITY2_ARCH_PROTOCOL.FileAuthentication() is called for every image load:
LoadImage() called
│
▼
Security2Arch.FileAuthentication()
│
├── Extract WIN_CERTIFICATE from PE header
│
├── Check dbx: is this binary's hash or signing cert revoked?
│ └── if YES → EFI_SECURITY_VIOLATION → load rejected
│
├── Check db: does binary's signing cert chain to a trusted entry?
│ └── if YES → load allowed
│
├── Check db: is a direct SHA-256 hash of the binary in db?
│ └── if YES → load allowed
│
└── None matched → EFI_SECURITY_VIOLATION → load rejected (Secure Boot on)
OR load allowed (Secure Boot off)Linux Shim and MOK
On systems with Microsoft's KEK enrolled, Linux distributions cannot self-sign their bootloaders with a key Microsoft doesn't know about. The solution is shim:
UEFI db contains: Microsoft UEFI CA cert
│
│ verifies
▼
shim.efi (signed by Microsoft with UEFI CA key)
│
│ verifies using its own embedded cert + MokList variable
▼
grubx64.efi (signed by distribution's signing key)
│
│ verifies (via grub UEFI Secure Boot extension)
▼
vmlinuz (signed by distribution's signing key)MOK (Machine Owner Key) allows end users to enroll their own signing keys into the MokList variable without needing Microsoft's KEK. This is managed by mokutil:
# Add a custom key to MokList
sudo mokutil --import my-custom-key.der
# System reboots into MOKManager (a UEFI application by shim)
# User confirms enrollment
# List enrolled MOK keys
mokutil --list-enrolled
# Delete a key from MokList
sudo mokutil --delete enrolled-key.derSecure Boot State Machine
Setup Mode (PK not enrolled)
│
│ Enroll PK (self-signed auth variable)
▼
User Mode (PK enrolled, Secure Boot active)
│
│ Options:
│ 1. Delete PK → back to Setup Mode
│ 2. Audit Mode (log violations, don't block) → for testing
│ 3. Deployed Mode (cannot re-enter Setup Mode without physical presence)
▼
Deployed Mode (highest security; PK cannot be deleted without physical presence reset)EDK2 variables tracking Secure Boot state:
SecureBoot(UINT8, read-only) —1when Secure Boot is activeSetupMode(UINT8) —1when in Setup Mode (PK empty)AuditMode(UINT8) —1when in Audit ModeDeployedMode(UINT8) —1when in Deployed Mode