Project 15: Secure Boot Exploration

Set up a complete UEFI Secure Boot environment from scratch—generate your own PKI hierarchy, sign custom EFI binaries, enroll keys in firmware, and verify that the chain of trust correctly accepts signed code while rejecting unsigned or maliciously-signed binaries.

Quick Reference

Attribute Value
Difficulty ★★★★☆ Expert
Time Estimate 2-3 weeks
Language C (bootloader), Python/Shell (signing tools)
Prerequisites Projects 7-8 completed, basic cryptography concepts, x509 certificate understanding
Key Topics Public Key Infrastructure (PKI), x509 certificates, Authenticode signatures, UEFI Secure Boot key hierarchy, trust chains, PE/COFF signing

1. Learning Objectives

After completing this project, you will be able to:

  1. Understand the UEFI Secure Boot architecture - Know the complete trust chain from Platform Key (PK) to signed bootloaders
  2. Generate a complete PKI hierarchy - Create Platform Keys, Key Exchange Keys, and signature database certificates using OpenSSL
  3. Sign EFI binaries with Authenticode - Use sbsign and related tools to create valid signatures on PE32+ executables
  4. Enroll custom keys in UEFI firmware - Configure OVMF and real hardware to trust your certificates
  5. Debug signature verification failures - Diagnose and fix common Secure Boot enrollment and signing issues
  6. Understand the security implications - Know how Secure Boot prevents bootkits and rootkits, and its limitations

2. Theoretical Foundation

2.1 What is Secure Boot?

Secure Boot is a UEFI security feature that ensures only cryptographically signed and verified code can execute during the boot process. It establishes a chain of trust from firmware to bootloader to operating system kernel.

┌─────────────────────────────────────────────────────────────────────────────┐
│                         SECURE BOOT OVERVIEW                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   WITHOUT SECURE BOOT:                                                       │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                     │    │
│   │   Firmware ──→ ANY bootloader ──→ ANY kernel ──→ OS loads          │    │
│   │      │              │                  │                            │    │
│   │      │         (Could be               │                            │    │
│   │      │          malware!)          (Rootkit?)                       │    │
│   │      │                                                              │    │
│   │   PROBLEM: No verification at boot level                           │    │
│   │            Bootkits can hide from ALL OS security                  │    │
│   │                                                                     │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│   WITH SECURE BOOT:                                                          │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                     │    │
│   │   Firmware ──┬──→ Signed bootloader ──┬──→ Signed kernel ──→ OS    │    │
│   │      │       │         │               │         │                  │    │
│   │      │       │    Verify signature     │    Verify signature        │    │
│   │   Trusts     │    against db           │    (bootloader does this)  │    │
│   │   built-in   │         │               │                            │    │
│   │   keys       │    ┌────▼────┐          │                            │    │
│   │              │    │ PASS?   │──NO──→ REJECT (boot halted)          │    │
│   │              │    └────┬────┘                                       │    │
│   │              │         │YES                                         │    │
│   │              │         ▼                                            │    │
│   │              │    Execute bootloader                                │    │
│   │                                                                     │    │
│   │   RESULT: Only trusted code can run before OS loads                │    │
│   │                                                                     │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.2 The Secure Boot Key Hierarchy

UEFI Secure Boot uses a hierarchical key structure. Understanding this hierarchy is essential:

┌─────────────────────────────────────────────────────────────────────────────┐
│                      SECURE BOOT KEY HIERARCHY                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│                           ┌─────────────────┐                                │
│                           │  PLATFORM KEY   │                                │
│                           │      (PK)       │                                │
│                           │                 │                                │
│                           │ The "root" key  │                                │
│                           │ Owner: Hardware │                                │
│                           │ manufacturer or │                                │
│                           │ system owner    │                                │
│                           └────────┬────────┘                                │
│                                    │                                         │
│                                    │ Signs/authorizes                        │
│                                    ▼                                         │
│                           ┌─────────────────┐                                │
│                           │ KEY EXCHANGE KEY│                                │
│                           │      (KEK)      │                                │
│                           │                 │                                │
│                           │ Can update db   │                                │
│                           │ and dbx         │                                │
│                           │                 │                                │
│                           │ Owner: OS vendor│                                │
│                           │ (Microsoft,     │                                │
│                           │ Canonical, etc.)│                                │
│                           └────────┬────────┘                                │
│                                    │                                         │
│                                    │ Signs/authorizes                        │
│                   ┌────────────────┴────────────────┐                        │
│                   │                                 │                        │
│                   ▼                                 ▼                        │
│        ┌─────────────────┐               ┌─────────────────┐                 │
│        │ SIGNATURE DB    │               │ FORBIDDEN       │                 │
│        │     (db)        │               │ SIGNATURES (dbx)│                 │
│        │                 │               │                 │                 │
│        │ Trusted signing │               │ Revoked keys    │                 │
│        │ certificates    │               │ and hashes      │                 │
│        │                 │               │                 │                 │
│        │ Bootloaders are │               │ Known-bad       │                 │
│        │ verified against│               │ bootloaders     │                 │
│        │ these certs     │               │ blocked here    │                 │
│        └────────┬────────┘               └─────────────────┘                 │
│                 │                                                            │
│                 │ Verifies                                                   │
│                 ▼                                                            │
│        ┌─────────────────┐                                                   │
│        │ SIGNED EFI      │                                                   │
│        │ BINARIES        │                                                   │
│        │                 │                                                   │
│        │ • Bootloaders   │                                                   │
│        │ • OS Loaders    │                                                   │
│        │ • UEFI Drivers  │                                                   │
│        │ • Option ROMs   │                                                   │
│        └─────────────────┘                                                   │
│                                                                              │
│   TRUST FLOW:                                                                │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                     │    │
│   │   PK (root of trust)                                               │    │
│   │    │                                                                │    │
│   │    └──→ Authorizes who can modify KEK                              │    │
│   │                                                                     │    │
│   │   KEK (key exchange)                                                │    │
│   │    │                                                                │    │
│   │    └──→ Authorizes who can modify db/dbx                           │    │
│   │                                                                     │    │
│   │   db (allowed signatures)                                          │    │
│   │    │                                                                │    │
│   │    └──→ Contains certificates that can sign bootloaders            │    │
│   │                                                                     │    │
│   │   dbx (forbidden signatures)                                       │    │
│   │    │                                                                │    │
│   │    └──→ Contains revoked certificates and blocked hashes           │    │
│   │                                                                     │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.3 Certificate Chain Verification Flow

When UEFI firmware loads an EFI binary with Secure Boot enabled, it performs this verification:

┌─────────────────────────────────────────────────────────────────────────────┐
│                    SIGNATURE VERIFICATION FLOW                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   EFI Binary Loaded                                                          │
│        │                                                                     │
│        ▼                                                                     │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │ Step 1: Extract Authenticode signature from PE header               │   │
│   │         (Located in Security Directory of PE Optional Header)       │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│        │                                                                     │
│        ▼                                                                     │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │ Step 2: Check if binary hash is in dbx (forbidden)                  │   │
│   │         ┌──────────────────────┐                                    │   │
│   │         │ Hash in dbx?         │                                    │   │
│   │         │                      │                                    │   │
│   │         │   YES ─────────────────────────────────→ REJECT           │   │
│   │         │    │                 │                                    │   │
│   │         │   NO                 │                                    │   │
│   │         └────┬─────────────────┘                                    │   │
│   └──────────────┼──────────────────────────────────────────────────────┘   │
│                  │                                                           │
│                  ▼                                                           │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │ Step 3: Check if signing certificate is in dbx                      │   │
│   │         ┌──────────────────────┐                                    │   │
│   │         │ Cert in dbx?         │                                    │   │
│   │         │                      │                                    │   │
│   │         │   YES ─────────────────────────────────→ REJECT           │   │
│   │         │    │                 │                                    │   │
│   │         │   NO                 │                                    │   │
│   │         └────┬─────────────────┘                                    │   │
│   └──────────────┼──────────────────────────────────────────────────────┘   │
│                  │                                                           │
│                  ▼                                                           │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │ Step 4: Verify signature against db certificates                    │   │
│   │                                                                     │   │
│   │   For each certificate in db:                                       │   │
│   │   ┌─────────────────────────────────────────────────────────────┐   │   │
│   │   │ a) Extract public key from db certificate                    │   │   │
│   │   │ b) Decrypt signature using public key → claimed hash        │   │   │
│   │   │ c) Calculate actual hash of PE binary (Authenticode hash)   │   │   │
│   │   │ d) Compare claimed hash with actual hash                     │   │   │
│   │   │                                                              │   │   │
│   │   │    ┌──────────────────────┐                                  │   │   │
│   │   │    │ Hashes match?        │                                  │   │   │
│   │   │    │                      │                                  │   │   │
│   │   │    │   YES ──────────────────────────────→ ACCEPT            │   │   │
│   │   │    │    │                 │                (Boot continues)  │   │   │
│   │   │    │   NO                 │                                  │   │   │
│   │   │    └────┬─────────────────┘                                  │   │   │
│   │   │         │                                                    │   │   │
│   │   │    Try next certificate                                      │   │   │
│   │   └─────────────────────────────────────────────────────────────┘   │   │
│   │                                                                     │   │
│   │   No certificate verified the signature?                           │   │
│   │         │                                                          │   │
│   │         └─────────────────────────────────────────→ REJECT         │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   REJECTION BEHAVIOR:                                                        │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   Secure Boot Violation                                            │   │
│   │   ─────────────────────                                            │   │
│   │                                                                     │   │
│   │   Invalid signature detected in BOOTX64.EFI                        │   │
│   │                                                                     │   │
│   │   The system cannot verify the signature.                          │   │
│   │   This file will not be loaded.                                    │   │
│   │                                                                     │   │
│   │   Press any key to continue...                                     │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.4 The Authenticode Signature Format

UEFI uses Microsoft’s Authenticode format for signing PE32+ executables. Understanding this structure helps with debugging:

┌─────────────────────────────────────────────────────────────────────────────┐
│                    PE/COFF AUTHENTICODE STRUCTURE                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   PE32+ EXECUTABLE STRUCTURE:                                                │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │  ┌──────────────────────────────────────────────────────────────┐  │   │
│   │  │              DOS Header (64 bytes)                            │  │   │
│   │  │  e_magic: "MZ" (0x5A4D)                                      │  │   │
│   │  │  e_lfanew: Offset to PE header                               │  │   │
│   │  └──────────────────────────────────────────────────────────────┘  │   │
│   │                              │                                      │   │
│   │                              ▼                                      │   │
│   │  ┌──────────────────────────────────────────────────────────────┐  │   │
│   │  │              PE Header                                        │  │   │
│   │  │  Signature: "PE\0\0" (0x00004550)                            │  │   │
│   │  │                                                               │  │   │
│   │  │  ┌────────────────────────────────────────────────────────┐  │  │   │
│   │  │  │ File Header (20 bytes)                                  │  │  │   │
│   │  │  │   Machine: 0x8664 (x86-64)                             │  │  │   │
│   │  │  │   NumberOfSections                                      │  │  │   │
│   │  │  │   SizeOfOptionalHeader                                  │  │  │   │
│   │  │  └────────────────────────────────────────────────────────┘  │  │   │
│   │  │                                                               │  │   │
│   │  │  ┌────────────────────────────────────────────────────────┐  │  │   │
│   │  │  │ Optional Header (PE32+: 240 bytes)                      │  │  │   │
│   │  │  │   ...                                                   │  │  │   │
│   │  │  │   CheckSum (offset 0x58) ← SET TO ZERO FOR HASHING     │  │  │   │
│   │  │  │   ...                                                   │  │  │   │
│   │  │  │   ┌─────────────────────────────────────────────────┐  │  │  │   │
│   │  │  │   │ Data Directories (16 entries, 8 bytes each)     │  │  │  │   │
│   │  │  │   │                                                  │  │  │  │   │
│   │  │  │   │ Entry 4: Security Directory ← SIGNATURE HERE    │  │  │  │   │
│   │  │  │   │   VirtualAddress: Offset to signature           │  │  │  │   │
│   │  │  │   │   Size: Size of signature data                  │  │  │  │   │
│   │  │  │   │                                                  │  │  │  │   │
│   │  │  │   │ NOTE: This entry is EXCLUDED from hash          │  │  │  │   │
│   │  │  │   └─────────────────────────────────────────────────┘  │  │  │   │
│   │  │  └────────────────────────────────────────────────────────┘  │  │   │
│   │  └──────────────────────────────────────────────────────────────┘  │   │
│   │                              │                                      │   │
│   │                              ▼                                      │   │
│   │  ┌──────────────────────────────────────────────────────────────┐  │   │
│   │  │              Section Headers                                  │  │   │
│   │  │  .text, .data, .rdata, etc.                                  │  │   │
│   │  └──────────────────────────────────────────────────────────────┘  │   │
│   │                              │                                      │   │
│   │                              ▼                                      │   │
│   │  ┌──────────────────────────────────────────────────────────────┐  │   │
│   │  │              Section Data                                     │  │   │
│   │  │  Code, initialized data, etc.                                │  │   │
│   │  └──────────────────────────────────────────────────────────────┘  │   │
│   │                              │                                      │   │
│   │                              ▼                                      │   │
│   │  ┌──────────────────────────────────────────────────────────────┐  │   │
│   │  │              AUTHENTICODE SIGNATURE                           │  │   │
│   │  │  (Pointed to by Security Directory)                          │  │   │
│   │  │                                                               │  │   │
│   │  │  ┌────────────────────────────────────────────────────────┐  │  │   │
│   │  │  │ WIN_CERTIFICATE structure:                              │  │  │   │
│   │  │  │   dwLength: Total size                                  │  │  │   │
│   │  │  │   wRevision: 0x0200                                     │  │  │   │
│   │  │  │   wCertificateType: 0x0002 (PKCS#7)                    │  │  │   │
│   │  │  │   bCertificate[]: PKCS#7 SignedData blob               │  │  │   │
│   │  │  └────────────────────────────────────────────────────────┘  │  │   │
│   │  │                                                               │  │   │
│   │  │  PKCS#7 SignedData contains:                                 │  │   │
│   │  │  ┌────────────────────────────────────────────────────────┐  │  │   │
│   │  │  │ • DigestAlgorithm (SHA-256 for modern)                 │  │  │   │
│   │  │  │ • ContentInfo (indirect data - hash of file)           │  │  │   │
│   │  │  │ • Certificates (x509 signing certificate chain)        │  │  │   │
│   │  │  │ • SignerInfo (actual signature data)                   │  │  │   │
│   │  │  └────────────────────────────────────────────────────────┘  │  │   │
│   │  │                                                               │  │   │
│   │  └──────────────────────────────────────────────────────────────┘  │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   AUTHENTICODE HASH CALCULATION:                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   The hash covers the entire PE file EXCEPT:                       │   │
│   │   1. The CheckSum field in Optional Header (set to 0)              │   │
│   │   2. The Security Directory entry (VirtualAddress + Size)          │   │
│   │   3. The actual signature data at the end                          │   │
│   │                                                                     │   │
│   │   This allows the signature to be appended without changing        │   │
│   │   the hash of the code and data sections.                          │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.5 UEFI Signature Database Format

The db, dbx, KEK, and PK variables use a specific format defined by UEFI:

┌─────────────────────────────────────────────────────────────────────────────┐
│                    EFI SIGNATURE DATABASE FORMAT                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   EFI_SIGNATURE_LIST structure:                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │ SignatureType: GUID identifying the signature type           │ │   │
│   │   │                                                              │ │   │
│   │   │ Common types:                                                │ │   │
│   │   │ • EFI_CERT_SHA256_GUID - SHA256 hash of binary               │ │   │
│   │   │ • EFI_CERT_RSA2048_GUID - Raw RSA-2048 public key           │ │   │
│   │   │ • EFI_CERT_X509_GUID - x509 certificate (most common)       │ │   │
│   │   │ • EFI_CERT_X509_SHA256_GUID - SHA256 hash of x509 cert      │ │   │
│   │   │ • EFI_CERT_X509_SHA384_GUID - SHA384 hash of x509 cert      │ │   │
│   │   │ • EFI_CERT_X509_SHA512_GUID - SHA512 hash of x509 cert      │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │ SignatureListSize: Total size of this list including header  │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │ SignatureHeaderSize: Size of optional header (usually 0)     │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │ SignatureSize: Size of each signature entry                  │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │ Signatures[]: Array of EFI_SIGNATURE_DATA structures         │ │   │
│   │   │                                                              │ │   │
│   │   │   ┌──────────────────────────────────────────────────────┐  │ │   │
│   │   │   │ EFI_SIGNATURE_DATA:                                   │  │ │   │
│   │   │   │   SignatureOwner: GUID identifying who added this    │  │ │   │
│   │   │   │   SignatureData[]: The actual signature/cert data    │  │ │   │
│   │   │   └──────────────────────────────────────────────────────┘  │ │   │
│   │   │                                                              │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   AUTHENTICATED VARIABLE STRUCTURE (for PK, KEK, db, dbx):                  │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   These variables have authentication attributes set and must      │   │
│   │   be updated using a signed payload:                               │   │
│   │                                                                     │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │ EFI_VARIABLE_AUTHENTICATION_2:                                │ │   │
│   │   │   TimeStamp: Monotonic timestamp to prevent rollback         │ │   │
│   │   │   AuthInfo: WIN_CERTIFICATE containing PKCS#7 signature      │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   │   To update db:                                                    │   │
│   │   1. Create new EFI_SIGNATURE_LIST with your certificate          │   │
│   │   2. Sign the update with a key in KEK                            │   │
│   │   3. Submit via SetVariable() with authentication header          │   │
│   │                                                                     │   │
│   │   To update KEK:                                                   │   │
│   │   1. Create new EFI_SIGNATURE_LIST with KEK certificate           │   │
│   │   2. Sign the update with the Platform Key (PK)                   │   │
│   │   3. Submit via SetVariable() with authentication header          │   │
│   │                                                                     │   │
│   │   To update PK (take ownership):                                   │   │
│   │   1. If no PK set: Can enroll directly (Setup Mode)               │   │
│   │   2. If PK exists: Must sign with existing PK                     │   │
│   │   3. Clearing PK returns system to Setup Mode                     │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.6 Trust Chain from Firmware to OS Kernel

┌─────────────────────────────────────────────────────────────────────────────┐
│                    COMPLETE TRUST CHAIN                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   HARDWARE ROOT OF TRUST                                            │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │                                                              │ │   │
│   │   │   Firmware stored in SPI flash (read-only portions)         │ │   │
│   │   │   Platform Key embedded or enrolled at factory              │ │   │
│   │   │   Secure Boot policy enforced by firmware                   │ │   │
│   │   │                                                              │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                              │                                      │   │
│   │                         Trusts PK                                   │   │
│   │                              │                                      │   │
│   │                              ▼                                      │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │                     PLATFORM KEY (PK)                        │ │   │
│   │   │                                                              │ │   │
│   │   │   Owner: Hardware manufacturer or system administrator      │ │   │
│   │   │   Purpose: Ultimate authority over Secure Boot policy       │ │   │
│   │   │   Can: Update/replace KEK, clear all keys, disable SB      │ │   │
│   │   │                                                              │ │   │
│   │   │   Microsoft PK is pre-enrolled on most consumer devices    │ │   │
│   │   │   You can enroll your own PK (taking ownership)            │ │   │
│   │   │                                                              │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                              │                                      │   │
│   │                      Authorizes KEK                                 │   │
│   │                              │                                      │   │
│   │                              ▼                                      │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │                  KEY EXCHANGE KEY (KEK)                      │ │   │
│   │   │                                                              │ │   │
│   │   │   Owner: OS vendors (Microsoft, Canonical, Red Hat, etc.)   │ │   │
│   │   │   Purpose: Manage which bootloaders are trusted             │ │   │
│   │   │   Can: Add/remove certificates in db, add hashes to dbx    │ │   │
│   │   │   Cannot: Modify PK, bypass Secure Boot                     │ │   │
│   │   │                                                              │ │   │
│   │   │   Typically includes:                                       │ │   │
│   │   │   • Microsoft KEK (for Windows updates to db)               │ │   │
│   │   │   • OEM KEK (for firmware updates)                          │ │   │
│   │   │                                                              │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                              │                                      │   │
│   │                      Authorizes db/dbx                              │   │
│   │                              │                                      │   │
│   │                    ┌─────────┴─────────┐                           │   │
│   │                    │                   │                           │   │
│   │                    ▼                   ▼                           │   │
│   │   ┌──────────────────────┐   ┌──────────────────────┐             │   │
│   │   │   SIGNATURE DB (db)  │   │  FORBIDDEN DB (dbx)  │             │   │
│   │   │                      │   │                      │             │   │
│   │   │ Trusted certificates:│   │ Revoked/blocked:     │             │   │
│   │   │ • Microsoft UEFI CA  │   │ • Revoked certs      │             │   │
│   │   │ • Microsoft Windows  │   │ • Known-bad hashes   │             │   │
│   │   │   Production PCA     │   │ • Vulnerable shim    │             │   │
│   │   │ • Your custom cert   │   │   versions           │             │   │
│   │   │   (after enrollment) │   │                      │             │   │
│   │   │                      │   │ Checked FIRST -      │             │   │
│   │   │                      │   │ if hash/cert is in   │             │   │
│   │   │                      │   │ dbx, REJECT even if  │             │   │
│   │   │                      │   │ also in db           │             │   │
│   │   └──────────┬───────────┘   └──────────────────────┘             │   │
│   │              │                                                     │   │
│   │         Verifies                                                   │   │
│   │              │                                                     │   │
│   │              ▼                                                     │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │                  UEFI BOOTLOADER                              │ │   │
│   │   │                                                              │ │   │
│   │   │   Signed by a certificate in db                             │ │   │
│   │   │                                                              │ │   │
│   │   │   Examples:                                                  │ │   │
│   │   │   • shim (signed by Microsoft, chains to distro cert)       │ │   │
│   │   │   • grubx64.efi (signed by distro)                          │ │   │
│   │   │   • bootmgfw.efi (Windows, signed by Microsoft)             │ │   │
│   │   │   • Your BOOTX64.EFI (signed by your db cert)              │ │   │
│   │   │                                                              │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                              │                                      │   │
│   │              Bootloader verifies (for shim/GRUB)                   │   │
│   │                              │                                      │   │
│   │                              ▼                                      │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │                     OS KERNEL                                 │ │   │
│   │   │                                                              │ │   │
│   │   │   Linux: vmlinuz (signed, verified by shim/GRUB)            │ │   │
│   │   │   Windows: winload.efi (signed, verified by bootmgfw)       │ │   │
│   │   │                                                              │ │   │
│   │   │   Kernel then verifies modules (kernel lockdown mode)       │ │   │
│   │   │                                                              │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.7 Why Secure Boot Matters

Understanding the security implications:

┌─────────────────────────────────────────────────────────────────────────────┐
│                    THREATS MITIGATED BY SECURE BOOT                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   BOOTKIT ATTACK (Without Secure Boot):                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   1. Attacker gains temporary admin access                          │   │
│   │   2. Replaces bootloader with malicious version                    │   │
│   │   3. System reboots...                                              │   │
│   │   4. Malicious bootloader runs FIRST                               │   │
│   │   5. Installs rootkit in kernel before OS loads                    │   │
│   │   6. Hides from all OS-level security tools                        │   │
│   │                                                                     │   │
│   │   Result: Undetectable persistent compromise                        │   │
│   │                                                                     │   │
│   │   Real examples:                                                    │   │
│   │   • TDL4/TDSS (2008) - Infected millions of PCs                    │   │
│   │   • Rovnix (2011) - Bootkited banking trojan                       │   │
│   │   • FinSpy (2011+) - Commercial spyware with bootkit               │   │
│   │   • MosaicRegressor (2020) - First in-the-wild UEFI bootkit        │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   WITH SECURE BOOT ENABLED:                                                  │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   1. Attacker gains temporary admin access                          │   │
│   │   2. Attempts to replace bootloader...                              │   │
│   │   3. System reboots...                                              │   │
│   │   4. Firmware checks bootloader signature                          │   │
│   │   5. Signature INVALID - malicious code not signed by trusted key  │   │
│   │   6. Boot HALTED - attack prevented!                               │   │
│   │                                                                     │   │
│   │   Alternative attack paths blocked:                                 │   │
│   │   • Modified kernel: Also must be signed                           │   │
│   │   • Evil maid attack: Physical access doesn't help without key     │   │
│   │   • Supply chain attack: Must compromise signing keys              │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   LIMITATIONS OF SECURE BOOT:                                                │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   Does NOT protect against:                                         │   │
│   │   • Firmware vulnerabilities (SMM attacks, SPI flash writes)       │   │
│   │   • Signed but vulnerable bootloaders (need dbx updates)           │   │
│   │   • Physical attacks that bypass firmware entirely                 │   │
│   │   • Attacks after OS loads (kernel exploits, userspace malware)   │   │
│   │   • Side-channel attacks on TPM                                     │   │
│   │                                                                     │   │
│   │   Real bypass examples:                                             │   │
│   │   • BlackLotus (2023) - Exploits CVE-2022-21894 in Windows BCD    │   │
│   │   • Various shim vulnerabilities requiring dbx updates             │   │
│   │   • GRUB vulnerabilities (BootHole, 2020)                          │   │
│   │                                                                     │   │
│   │   Secure Boot is ONE layer in defense-in-depth                     │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.8 Historical Context

  • 2011: UEFI Secure Boot introduced in UEFI 2.3.1
  • 2012: Windows 8 ships with Secure Boot requirement for logo certification
  • 2012: Linux community concern about Microsoft control; shim solution developed
  • 2013: Ubuntu, Fedora, SUSE ship with Microsoft-signed shim
  • 2020: BootHole vulnerability affects GRUB2, requires mass dbx updates
  • 2021: Microsoft begins requiring Secure Boot for Windows 11
  • 2023: BlackLotus becomes first in-the-wild bootkit to bypass Secure Boot

3. Project Specification

3.1 What You Will Build

A complete Secure Boot environment demonstrating the full key hierarchy:

  1. Generate your own PKI - Platform Key (PK), Key Exchange Key (KEK), and signature database (db) certificates
  2. Sign custom EFI binaries - Create Authenticode signatures on your bootloader from Project 7 or 8
  3. Enroll keys in OVMF - Configure the UEFI firmware to trust your certificates
  4. Verify the trust chain - Demonstrate that signed binaries boot and unsigned binaries are rejected

3.2 Functional Requirements

ID Requirement Description
FR-1 Generate PK certificate Create self-signed x509 certificate for Platform Key
FR-2 Generate KEK certificate Create x509 certificate signed by or co-equal to PK
FR-3 Generate db certificate Create x509 certificate for signing bootloaders
FR-4 Sign EFI binary Use sbsign to add Authenticode signature to BOOTX64.EFI
FR-5 Enroll keys in OVMF Configure Secure Boot with your custom keys
FR-6 Boot signed binary Verify signed bootloader executes successfully
FR-7 Reject unsigned binary Verify unsigned bootloader is blocked
FR-8 Reject wrongly-signed binary Verify binary signed with unknown key is blocked

3.3 Non-Functional Requirements

ID Requirement Description
NFR-1 Reproducible Scripted key generation and enrollment process
NFR-2 Documented Clear explanation of each cryptographic step
NFR-3 OVMF compatible Works with standard OVMF Secure Boot builds
NFR-4 Debuggable Can inspect signature and enrollment state

3.4 Example Usage / Expected Output

# Step 1: Generate your own PKI hierarchy
$ ./generate-keys.sh
Generating Platform Key (PK)...
  Creating private key: PK.key (RSA 2048)
  Creating certificate: PK.crt (self-signed, valid 10 years)
  Converting to DER: PK.cer
  Creating EFI signature list: PK.esl
  Creating signed auth file: PK.auth

Generating Key Exchange Key (KEK)...
  Creating private key: KEK.key (RSA 2048)
  Creating certificate: KEK.crt (self-signed, valid 10 years)
  Converting to DER: KEK.cer
  Creating EFI signature list: KEK.esl
  Creating signed auth file: KEK.auth (signed with PK)

Generating Signature Database certificate (db)...
  Creating private key: db.key (RSA 2048)
  Creating certificate: db.crt (self-signed, valid 10 years)
  Converting to DER: db.cer
  Creating EFI signature list: db.esl
  Creating signed auth file: db.auth (signed with KEK)

Keys generated successfully!

# Step 2: Sign your bootloader
$ sbsign --key db.key --cert db.crt --output BOOTX64.EFI.signed BOOTX64.EFI
Signing BOOTX64.EFI...
Signature successful!

# Verify the signature
$ sbverify --cert db.crt BOOTX64.EFI.signed
Signature verification OK

# Step 3: Create OVMF VARS file with your keys enrolled
$ ./enroll-keys.sh
Creating OVMF_VARS.fd from template...
Enrolling PK...
Enrolling KEK...
Enrolling db...
Setting Secure Boot mode to User Mode...
OVMF_VARS.fd created with your keys!

# Step 4: Test with signed binary (SUCCESS)
$ qemu-system-x86_64 \
    -machine q35 \
    -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.secboot.fd \
    -drive if=pflash,format=raw,file=OVMF_VARS.fd \
    -drive file=disk-signed.img,format=raw \
    -net none

# Output in QEMU:
Hello from Secure Boot!
========================
Secure Boot Status: ENABLED
This binary is properly signed and trusted.
Bootloader executing successfully...

# Step 5: Test with unsigned binary (REJECTED)
$ qemu-system-x86_64 \
    -machine q35 \
    -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.secboot.fd \
    -drive if=pflash,format=raw,file=OVMF_VARS.fd \
    -drive file=disk-unsigned.img,format=raw \
    -net none

# Output in QEMU:
┌───────────────────────────────────────────────────────┐
│                                                       │
│   Secure Boot Violation                               │
│                                                       │
│   Invalid signature detected in:                      │
│   \EFI\BOOT\BOOTX64.EFI                              │
│                                                       │
│   The file is not signed, or the signature           │
│   cannot be verified against the signature           │
│   database (db).                                      │
│                                                       │
│   Press any key to continue...                        │
│                                                       │
└───────────────────────────────────────────────────────┘

# Step 6: Test with wrongly-signed binary (REJECTED)
$ sbsign --key rogue.key --cert rogue.crt --output BOOTX64.EFI.rogue BOOTX64.EFI

$ qemu-system-x86_64 \
    -machine q35 \
    -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.secboot.fd \
    -drive if=pflash,format=raw,file=OVMF_VARS.fd \
    -drive file=disk-rogue.img,format=raw \
    -net none

# Output: Same Secure Boot Violation (signature exists but cert not in db)

3.5 Real World Outcome

Upon completion, you will have:

  1. Understanding of PKI - Practical experience with x509 certificates and key hierarchies
  2. Secure Boot expertise - Can configure Secure Boot for enterprise or embedded deployments
  3. Security debugging skills - Can diagnose signature verification failures
  4. Portfolio demonstration - Shows security and firmware expertise

4. Solution Architecture

4.1 High-Level Design

┌─────────────────────────────────────────────────────────────────────────────┐
│                    SECURE BOOT PROJECT ARCHITECTURE                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   KEY GENERATION WORKFLOW:                                                   │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   openssl req/x509                                                  │   │
│   │        │                                                            │   │
│   │        ▼                                                            │   │
│   │   ┌──────────┐    ┌──────────┐    ┌──────────┐                     │   │
│   │   │  PK.key  │    │ KEK.key  │    │  db.key  │  (Private keys)     │   │
│   │   │  PK.crt  │    │ KEK.crt  │    │  db.crt  │  (Certificates)     │   │
│   │   └────┬─────┘    └────┬─────┘    └────┬─────┘                     │   │
│   │        │               │               │                            │   │
│   │        ▼               ▼               ▼                            │   │
│   │   cert-to-efi-sig-list                                              │   │
│   │        │               │               │                            │   │
│   │        ▼               ▼               ▼                            │   │
│   │   ┌──────────┐    ┌──────────┐    ┌──────────┐                     │   │
│   │   │  PK.esl  │    │ KEK.esl  │    │  db.esl  │  (Signature lists)  │   │
│   │   └────┬─────┘    └────┬─────┘    └────┬─────┘                     │   │
│   │        │               │               │                            │   │
│   │        ▼               ▼               ▼                            │   │
│   │   sign-efi-sig-list                                                 │   │
│   │        │               │               │                            │   │
│   │        │ (self-sign)   │ (sign w/PK)   │ (sign w/KEK)              │   │
│   │        ▼               ▼               ▼                            │   │
│   │   ┌──────────┐    ┌──────────┐    ┌──────────┐                     │   │
│   │   │ PK.auth  │    │ KEK.auth │    │ db.auth  │  (Auth update files)│   │
│   │   └──────────┘    └──────────┘    └──────────┘                     │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   SIGNING WORKFLOW:                                                          │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   ┌──────────────┐                                                  │   │
│   │   │ BOOTX64.EFI  │  (Unsigned bootloader from Project 7/8)         │   │
│   │   │  (unsigned)  │                                                  │   │
│   │   └──────┬───────┘                                                  │   │
│   │          │                                                          │   │
│   │          ▼                                                          │   │
│   │   ┌─────────────────────────────────────────────────────────────┐  │   │
│   │   │                        sbsign                                │  │   │
│   │   │                                                              │  │   │
│   │   │   sbsign --key db.key --cert db.crt \                       │  │   │
│   │   │          --output BOOTX64.EFI.signed BOOTX64.EFI            │  │   │
│   │   │                                                              │  │   │
│   │   │   Steps performed by sbsign:                                │  │   │
│   │   │   1. Calculate Authenticode hash of PE file                 │  │   │
│   │   │   2. Create PKCS#7 SignedData structure                     │  │   │
│   │   │   3. Sign hash with db.key private key                      │  │   │
│   │   │   4. Embed db.crt certificate in signature                  │  │   │
│   │   │   5. Append signature to PE file                            │  │   │
│   │   │   6. Update PE Security Directory pointer                   │  │   │
│   │   │                                                              │  │   │
│   │   └─────────────────────────────────────────────────────────────┘  │   │
│   │          │                                                          │   │
│   │          ▼                                                          │   │
│   │   ┌──────────────┐                                                  │   │
│   │   │ BOOTX64.EFI  │                                                  │   │
│   │   │   (signed)   │  Ready for Secure Boot!                         │   │
│   │   └──────────────┘                                                  │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   ENROLLMENT WORKFLOW:                                                       │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   Option A: OVMF Setup Menu (Manual)                               │   │
│   │   ┌─────────────────────────────────────────────────────────────┐  │   │
│   │   │                                                              │  │   │
│   │   │   1. Boot OVMF with empty VARS                              │  │   │
│   │   │   2. Press ESC to enter Setup                               │  │   │
│   │   │   3. Device Manager → Secure Boot Configuration             │  │   │
│   │   │   4. Enroll PK from file (PK.cer or PK.auth)               │  │   │
│   │   │   5. Enroll KEK from file                                   │  │   │
│   │   │   6. Enroll db from file                                    │  │   │
│   │   │   7. Enable Secure Boot                                     │  │   │
│   │   │   8. Save and Reset                                         │  │   │
│   │   │                                                              │  │   │
│   │   └─────────────────────────────────────────────────────────────┘  │   │
│   │                                                                     │   │
│   │   Option B: efi-updatevar (Scripted, from Linux)                   │   │
│   │   ┌─────────────────────────────────────────────────────────────┐  │   │
│   │   │                                                              │  │   │
│   │   │   # Boot into OVMF with Secure Boot in Setup Mode           │  │   │
│   │   │   efi-updatevar -e -f db.esl db                             │  │   │
│   │   │   efi-updatevar -e -f KEK.esl KEK                           │  │   │
│   │   │   efi-updatevar -f PK.auth PK  # This enables User Mode     │  │   │
│   │   │                                                              │  │   │
│   │   └─────────────────────────────────────────────────────────────┘  │   │
│   │                                                                     │   │
│   │   Option C: Pre-built VARS file                                    │   │
│   │   ┌─────────────────────────────────────────────────────────────┐  │   │
│   │   │                                                              │  │   │
│   │   │   Use virt-fw-vars or similar tool to create OVMF_VARS.fd  │  │   │
│   │   │   with keys pre-enrolled (best for automation)              │  │   │
│   │   │                                                              │  │   │
│   │   └─────────────────────────────────────────────────────────────┘  │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   VERIFICATION WORKFLOW:                                                     │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                                                                     │   │
│   │   QEMU with Secure Boot OVMF                                       │   │
│   │        │                                                            │   │
│   │        │ Loads BOOTX64.EFI                                         │   │
│   │        │                                                            │   │
│   │        ▼                                                            │   │
│   │   ┌──────────────────────────────────────────────────────────────┐ │   │
│   │   │              UEFI Secure Boot Verification                   │ │   │
│   │   │                                                              │ │   │
│   │   │   1. Check SecureBoot variable = 0x01 (enabled)             │ │   │
│   │   │   2. Extract signature from BOOTX64.EFI                     │ │   │
│   │   │   3. Verify signature against db certificates               │ │   │
│   │   │                                                              │ │   │
│   │   │   SIGNED WITH db.key:                                       │ │   │
│   │   │   ┌──────────────────────────────────────────────────────┐  │ │   │
│   │   │   │ Certificate in signature matches db.crt in db       │  │ │   │
│   │   │   │ → Signature verification PASSES                      │  │ │   │
│   │   │   │ → Binary executes!                                   │  │ │   │
│   │   │   └──────────────────────────────────────────────────────┘  │ │   │
│   │   │                                                              │ │   │
│   │   │   UNSIGNED OR WRONG KEY:                                    │ │   │
│   │   │   ┌──────────────────────────────────────────────────────┐  │ │   │
│   │   │   │ No signature, or certificate not in db              │  │ │   │
│   │   │   │ → Signature verification FAILS                       │  │ │   │
│   │   │   │ → "Secure Boot Violation" error displayed           │  │ │   │
│   │   │   │ → Binary does NOT execute                            │  │ │   │
│   │   │   └──────────────────────────────────────────────────────┘  │ │   │
│   │   │                                                              │ │   │
│   │   └──────────────────────────────────────────────────────────────┘ │   │
│   │                                                                     │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

4.2 Project Structure

secure-boot-lab/
├── keys/                          # Generated keys and certificates
│   ├── PK.key                     # Platform Key private key
│   ├── PK.crt                     # Platform Key certificate (PEM)
│   ├── PK.cer                     # Platform Key certificate (DER)
│   ├── PK.esl                     # Platform Key EFI signature list
│   ├── PK.auth                    # Platform Key authenticated variable
│   ├── KEK.key                    # Key Exchange Key private key
│   ├── KEK.crt                    # KEK certificate (PEM)
│   ├── KEK.cer                    # KEK certificate (DER)
│   ├── KEK.esl                    # KEK EFI signature list
│   ├── KEK.auth                   # KEK authenticated variable
│   ├── db.key                     # Signature database private key
│   ├── db.crt                     # db certificate (PEM)
│   ├── db.cer                     # db certificate (DER)
│   ├── db.esl                     # db EFI signature list
│   ├── db.auth                    # db authenticated variable
│   └── noPK.auth                  # Empty PK for resetting to Setup Mode
├── bootloader/                    # Your EFI binaries
│   ├── BOOTX64.EFI               # Unsigned bootloader
│   └── BOOTX64.EFI.signed        # Signed bootloader
├── scripts/
│   ├── generate-keys.sh          # Key generation script
│   ├── sign-binary.sh            # Signing script
│   ├── enroll-keys-ovmf.sh       # OVMF enrollment script
│   └── verify-signature.sh       # Verification script
├── ovmf/
│   ├── OVMF_CODE.secboot.fd      # OVMF firmware with Secure Boot
│   └── OVMF_VARS.fd              # OVMF variables with your keys
├── images/
│   ├── disk-signed.img           # Disk with signed bootloader
│   ├── disk-unsigned.img         # Disk with unsigned bootloader
│   └── disk-rogue.img            # Disk with wrongly-signed bootloader
├── Makefile                       # Build automation
└── README.md                      # Documentation

5. Implementation Guide

5.1 Development Environment Setup

Required packages (Ubuntu/Debian):

sudo apt update
sudo apt install \
    openssl \
    efitools \
    sbsigntool \
    qemu-system-x86 \
    ovmf \
    uuid-runtime \
    python3 \
    mtools \
    dosfstools

Required packages (Fedora):

sudo dnf install \
    openssl \
    efitools \
    sbsigntools \
    qemu-system-x86 \
    edk2-ovmf \
    uuid \
    python3 \
    mtools \
    dosfstools

Locate OVMF files:

# Ubuntu/Debian
OVMF_CODE=/usr/share/OVMF/OVMF_CODE.secboot.fd
OVMF_VARS=/usr/share/OVMF/OVMF_VARS.fd

# Fedora
OVMF_CODE=/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd
OVMF_VARS=/usr/share/edk2/ovmf/OVMF_VARS.fd

# Verify Secure Boot capable OVMF exists
ls -la $OVMF_CODE

5.2 The Core Question You’re Answering

How does cryptographic verification establish trust in the boot process, and how can you configure and manage this trust hierarchy?

This project forces you to understand:

  • How public key cryptography enables signature verification
  • Why hierarchical trust (PK → KEK → db) provides flexibility
  • How UEFI stores and manages cryptographic material
  • What happens when signature verification fails

5.3 Concepts You Must Understand First

Before implementing, verify you understand:

  1. Public key cryptography basics
    • Self-assessment: What’s the relationship between a private key and public key? Why can you verify a signature with only the public key?
    • Reference: “Serious Cryptography” Chapter 11
  2. x509 certificates
    • Self-assessment: What information does a certificate contain? What makes it “self-signed”?
    • Reference: RFC 5280
  3. Hash functions
    • Self-assessment: Why is SHA-256 used in Authenticode? What would happen if two files had the same hash?
    • Reference: “Serious Cryptography” Chapter 6
  4. PE executable format
    • Self-assessment: Where is the Authenticode signature stored in a PE file? What parts of the file are hashed?
    • Reference: “Practical Binary Analysis” Chapter 3
  5. UEFI variables
    • Self-assessment: What’s the difference between runtime and boot-time-only variables? Why are Secure Boot variables authenticated?
    • Reference: UEFI Specification Chapter 8

5.4 Questions to Guide Your Design

Key Generation:

  • Why RSA-2048 for Secure Boot keys? Would RSA-4096 be better? What about ECC?
  • What subject name should your certificates have? Does it matter?
  • How long should your certificates be valid?

Signing:

  • What hash algorithm does sbsign use by default? Is SHA-1 still acceptable?
  • Can you sign a binary multiple times (dual-sign)? Why would you?
  • How do you verify a signature without Secure Boot (offline)?

Enrollment:

  • What happens if you enroll KEK before PK?
  • Why does enrolling PK transition from Setup Mode to User Mode?
  • How do you return to Setup Mode if you lose your PK private key?

Security:

  • What if an attacker gets your db.key? What’s the recovery process?
  • How do you revoke a compromised bootloader without revoking the signing key?
  • Why is dbx checked before db?

5.5 Thinking Exercise

Before generating keys, work through this scenario:

You’re setting up Secure Boot for an embedded device. The device manufacturer wants to:

  1. Maintain ultimate control (they own the PK)
  2. Allow OS vendor updates (OS vendor has KEK access)
  3. Support both Windows and Linux bootloaders (both certs in db)
  4. Be able to revoke specific bootloader versions (use dbx)

Questions:

  1. How many keys/certificates do you need? (Answer: 4 - PK, KEK, db-windows, db-linux)
  2. Who signs updates to db? (Answer: KEK holder - could be manufacturer or OS vendor)
  3. How do you add a hash to dbx? (Answer: KEK holder signs the dbx update)
  4. What if the OS vendor’s signing key is compromised? (Answer: Add their cert to dbx using KEK)

5.6 Hints in Layers

Hint 1: Getting Started (Conceptual Direction)

Start with the simplest working case: generate all three keys (PK, KEK, db) yourself, with the same owner. This is a “self-signed” hierarchy for testing. Later you can explore more complex scenarios.

The key tools are:

  • openssl - Generate keys and certificates
  • cert-to-efi-sig-list - Convert certificates to UEFI format
  • sign-efi-sig-list - Create authenticated variable updates
  • sbsign - Sign EFI binaries
  • OVMF Setup menu - Enroll keys interactively

Hint 2: Key Generation Commands (More Specific)

# Create directory for keys
mkdir -p keys
cd keys

# Define a GUID for your keys (use same GUID for all)
MY_GUID=$(uuidgen)
echo "Using GUID: $MY_GUID"

# Generate Platform Key (PK)
openssl req -newkey rsa:2048 -nodes -keyout PK.key \
    -new -x509 -sha256 -days 3650 \
    -subj "/CN=My Platform Key/" -out PK.crt

# Generate Key Exchange Key (KEK)
openssl req -newkey rsa:2048 -nodes -keyout KEK.key \
    -new -x509 -sha256 -days 3650 \
    -subj "/CN=My Key Exchange Key/" -out KEK.crt

# Generate Signature Database key (db)
openssl req -newkey rsa:2048 -nodes -keyout db.key \
    -new -x509 -sha256 -days 3650 \
    -subj "/CN=My Signature Database Key/" -out db.crt

Hint 3: Converting to UEFI Format (Technical Details)

# Convert certificates to DER format
openssl x509 -outform DER -in PK.crt -out PK.cer
openssl x509 -outform DER -in KEK.crt -out KEK.cer
openssl x509 -outform DER -in db.crt -out db.cer

# Create EFI Signature Lists
cert-to-efi-sig-list -g "$MY_GUID" PK.crt PK.esl
cert-to-efi-sig-list -g "$MY_GUID" KEK.crt KEK.esl
cert-to-efi-sig-list -g "$MY_GUID" db.crt db.esl

# Create authenticated variable updates
# Note: Order matters! PK is self-signed, KEK is signed by PK, db is signed by KEK

# PK signs itself (bootstrap)
sign-efi-sig-list -g "$MY_GUID" -k PK.key -c PK.crt PK PK.esl PK.auth

# PK signs KEK update
sign-efi-sig-list -g "$MY_GUID" -k PK.key -c PK.crt KEK KEK.esl KEK.auth

# KEK signs db update
sign-efi-sig-list -g "$MY_GUID" -k KEK.key -c KEK.crt db db.esl db.auth

# Create empty PK for clearing (returns to Setup Mode)
sign-efi-sig-list -g "$MY_GUID" -k PK.key -c PK.crt PK /dev/null noPK.auth

Hint 4: Signing and Verification (Advanced Details)

# Sign your bootloader
sbsign --key db.key --cert db.crt \
       --output BOOTX64.EFI.signed \
       BOOTX64.EFI

# Verify signature (without Secure Boot)
sbverify --cert db.crt BOOTX64.EFI.signed
# Should output: "Signature verification OK"

# Inspect signature details
sbverify --list BOOTX64.EFI.signed
# Shows: signature type, signer, digest algorithm

# Verify against wrong certificate (should fail)
sbverify --cert KEK.crt BOOTX64.EFI.signed
# Should output: "Signature verification failed"

# Extract the embedded certificate from signed binary
sbverify --cert /dev/null BOOTX64.EFI.signed 2>&1 | grep -A20 "Certificate"

QEMU Command for Testing:

# Copy OVMF_VARS to get a writable copy
cp /usr/share/OVMF/OVMF_VARS.fd ./OVMF_VARS.fd

# Boot with Secure Boot capable OVMF
qemu-system-x86_64 \
    -machine q35 \
    -m 256M \
    -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.secboot.fd \
    -drive if=pflash,format=raw,file=./OVMF_VARS.fd \
    -drive file=disk.img,format=raw \
    -net none \
    -serial stdio

# In OVMF:
# 1. Press ESC to enter Setup
# 2. Device Manager → Secure Boot Configuration
# 3. Current Secure Boot State: should show "Setup Mode"
# 4. Secure Boot Mode → Custom Mode
# 5. Custom Secure Boot Options → PK Options → Enroll PK → Enroll PK Using File
# 6. Select your PK.cer file from the ESP
# 7. Repeat for KEK and db
# 8. Attempt to Boot → should succeed with signed, fail with unsigned

5.7 The Interview Questions They’ll Ask

If you mention Secure Boot on your resume, expect:

  1. “Explain the UEFI Secure Boot key hierarchy”
    • Strong answer: “Secure Boot uses a three-tier hierarchy. The Platform Key (PK) is the root of trust, controlled by the hardware owner. PK authorizes Key Exchange Keys (KEK), typically held by OS vendors. KEK holders can update the signature database (db) and forbidden signature database (dbx). Binaries are signed with certificates in db. When loading an EFI binary, firmware first checks dbx for revocation, then verifies the signature against db certificates.”
  2. “How would you set up Secure Boot for a custom embedded device?”
    • Strong answer: “First, generate a complete key hierarchy with OpenSSL - PK for device owner, KEK for authorized update providers, db certificates for bootloader signing. Sign the bootloader with sbsign. Enroll keys either in firmware Setup Mode or by pre-provisioning the NVRAM. Test by verifying signed binaries boot and unsigned binaries are rejected. Document the key management process and secure storage requirements for private keys.”
  3. “What happens if a signing key is compromised?”
    • Strong answer: “Depends on which key. If db key is compromised, add the compromised certificate to dbx using a KEK-signed update. All binaries signed by that key become invalid. If KEK is compromised, the PK holder must revoke it and issue a new KEK. If PK is compromised, the device is fully compromised - recovery requires physical intervention like reflashing firmware. This is why PK private keys must be extremely well protected, often in HSMs.”
  4. “How does shim work with Secure Boot?”
    • Strong answer: “Shim is a first-stage bootloader signed by Microsoft’s UEFI CA, which is pre-enrolled in db on most devices. Shim contains an embedded ‘Machine Owner Key’ (MOK) database. When shim loads, it verifies the next-stage bootloader (like GRUB) against either the UEFI db or its MOK list. This allows Linux distributions to use their own signing keys without requiring Microsoft to sign every bootloader update. Users can also enroll their own keys in MOK for custom kernels.”
  5. “What vulnerabilities have affected Secure Boot?”
    • Strong answer: “Several classes of vulnerabilities exist. BootHole (2020) was a buffer overflow in GRUB2 that allowed arbitrary code execution before signature verification. BlackLotus (2023) exploits CVE-2022-21894 in Windows Boot Manager to bypass Secure Boot entirely. There have also been firmware vulnerabilities allowing direct NVRAM manipulation, and issues where dbx updates weren’t deployed widely enough to revoke known-bad bootloaders. The key lesson is that Secure Boot is one layer in defense-in-depth, not a complete solution.”

5.8 Books That Will Help

Topic Book Chapter
Public Key Cryptography “Serious Cryptography” by Jean-Philippe Aumasson Ch. 10-11
x509 Certificates “Bulletproof SSL and TLS” by Ivan Ristic Ch. 3-4
Authenticode Format “Practical Binary Analysis” by Dennis Andriesse Ch. 3
UEFI Security “Beyond BIOS” by Vincent Zimmer Ch. 21
Boot Security “Rootkits and Bootkits” by Alex Matrosov Ch. 8-9

5.9 Implementation Phases

Phase 1: Environment Setup (Day 1)

  1. Install all required tools
  2. Locate OVMF Secure Boot files
  3. Verify QEMU can boot OVMF
  4. Access OVMF Setup menu

Milestone: OVMF boots, shows “Setup Mode” in Secure Boot Configuration

Phase 2: Key Generation (Days 2-3)

  1. Generate PK key pair and certificate
  2. Generate KEK key pair and certificate
  3. Generate db key pair and certificate
  4. Convert to DER format
  5. Create EFI signature lists
  6. Create authenticated variable files

Milestone: All .key, .crt, .cer, .esl, .auth files generated

Phase 3: Binary Signing (Days 4-5)

  1. Build or obtain unsigned BOOTX64.EFI (from Project 7)
  2. Sign with sbsign using db key
  3. Verify signature with sbverify
  4. Create test binaries: signed, unsigned, wrongly-signed

Milestone: Three test binaries ready (signed, unsigned, rogue)

Phase 4: Key Enrollment (Days 6-8)

  1. Create disk images with key files and bootloaders
  2. Boot OVMF in Setup Mode
  3. Enroll db certificate
  4. Enroll KEK certificate
  5. Enroll PK (transitions to User Mode)
  6. Enable Secure Boot

Milestone: OVMF shows “User Mode” and “Secure Boot Enabled”

Phase 5: Verification Testing (Days 9-11)

  1. Boot with signed binary - should succeed
  2. Boot with unsigned binary - should fail
  3. Boot with wrongly-signed binary - should fail
  4. Document error messages and behavior

Milestone: All three test cases produce expected results

Phase 6: Automation and Polish (Days 12-14)

  1. Create shell scripts for key generation
  2. Create scripts for signing
  3. Create pre-enrolled OVMF_VARS.fd
  4. Document the entire process
  5. Create Makefile for automation

Milestone: Single make test runs all scenarios


6. Testing Strategy

6.1 Test Matrix

Test Case Binary Type Expected Result Verification
TC-1 Signed with db key Boot succeeds Bootloader message appears
TC-2 Unsigned Boot fails “Secure Boot Violation” shown
TC-3 Signed with unknown key Boot fails “Secure Boot Violation” shown
TC-4 Signed, cert in dbx Boot fails “Secure Boot Violation” shown
TC-5 Hash in dbx Boot fails “Secure Boot Violation” shown
TC-6 Secure Boot disabled All boot Any binary runs

6.2 Verification Commands

# Check Secure Boot state from Linux (if testing on real HW)
mokutil --sb-state
# Expected: "SecureBoot enabled" or "SecureBoot disabled"

# List enrolled keys
efi-readvar -v PK
efi-readvar -v KEK
efi-readvar -v db
efi-readvar -v dbx

# Verify signature on binary
sbverify --list BOOTX64.EFI.signed

# Check PE headers
objdump -x BOOTX64.EFI.signed | grep -A5 "Security Directory"

6.3 QEMU Test Script

#!/bin/bash
# test-secure-boot.sh

OVMF_CODE="/usr/share/OVMF/OVMF_CODE.secboot.fd"
OVMF_VARS="./OVMF_VARS.fd"

test_boot() {
    local disk="$1"
    local expected="$2"

    echo "Testing: $disk (expecting: $expected)"

    timeout 30 qemu-system-x86_64 \
        -machine q35 \
        -m 256M \
        -drive if=pflash,format=raw,readonly=on,file="$OVMF_CODE" \
        -drive if=pflash,format=raw,file="$OVMF_VARS" \
        -drive file="$disk",format=raw \
        -net none \
        -nographic \
        2>&1 | tee /tmp/boot-output.txt

    if grep -q "$expected" /tmp/boot-output.txt; then
        echo "PASS: $disk"
    else
        echo "FAIL: $disk - expected '$expected'"
    fi
}

# Reset OVMF_VARS to enrolled state
cp OVMF_VARS.enrolled.fd "$OVMF_VARS"

# Test signed (should boot)
test_boot "disk-signed.img" "Hello from Secure Boot"

# Reset OVMF_VARS
cp OVMF_VARS.enrolled.fd "$OVMF_VARS"

# Test unsigned (should fail)
test_boot "disk-unsigned.img" "Secure Boot Violation"

7. Common Pitfalls and Debugging

7.1 Key Generation Issues

Problem Symptom Solution
Wrong certificate format “Invalid certificate” during enrollment Use DER format (.cer) not PEM (.crt) for OVMF enrollment
Missing GUID efi-sig-list tools fail Generate GUID with uuidgen, use consistently
RSA key too short Signature rejected Use RSA-2048 minimum (RSA-4096 works too)
Self-signed CA issues Certificate chain validation fails For testing, self-signed is fine; in production, use proper CA

7.2 Signing Issues

Problem Symptom Solution
sbsign not found Command not found Install sbsigntool package
Wrong key/cert pair Signature created but invalid Ensure .key and .crt are from same keypair
SHA-1 hash May be rejected by strict firmware Use --hash sha256 with sbsign
Binary already signed Can’t re-sign Use sbattach --remove first or sign fresh binary

7.3 Enrollment Issues

Problem Symptom Solution
Can’t find files in OVMF Files not visible Ensure ESP has correct structure (/EFI/BOOT/)
“Not in Setup Mode” Can’t enroll keys Clear PK first or use signed auth files
KEK/db enrollment fails Access denied Ensure PK enrolled first, use correct auth files
PK enrollment fails Invalid signature For first PK, system must be in Setup Mode

7.4 Boot Verification Issues

Problem Symptom Solution
Signed binary rejected “Secure Boot Violation” Verify db certificate matches signing cert
All binaries boot No Secure Boot enforcement Check Secure Boot actually enabled in OVMF
QEMU doesn’t show SB error Black screen Add -serial stdio to see console output
Wrong OVMF_VARS used Keys not enrolled Verify correct VARS file path

7.5 Debugging Commands

# Check certificate fingerprint
openssl x509 -in db.crt -noout -fingerprint -sha256

# Compare enrolled vs generated certificate
efi-readvar -v db -o enrolled-db.esl
# Then compare with your db.esl

# Examine signature in PE file
osslsigncode verify -in BOOTX64.EFI.signed

# Debug OVMF with serial output
qemu-system-x86_64 ... -serial stdio -D qemu-debug.log -d guest_errors

# Check PE security directory
objdump -x BOOTX64.EFI.signed | grep -A10 "Security"

8. Extensions and Challenges

Extension 1: Add Certificate to dbx (Revocation)

Revoke your db certificate by adding it to dbx, demonstrating how compromised keys are handled.

# Create dbx entry for your db certificate
cert-to-efi-sig-list -g "$MY_GUID" db.crt dbx-revoke.esl
sign-efi-sig-list -a -g "$MY_GUID" -k KEK.key -c KEK.crt dbx dbx-revoke.esl dbx-revoke.auth

# After enrolling, previously-signed binaries should be rejected

Extension 2: Add Hash to dbx

Revoke a specific binary by its hash (without revoking the signing key).

# Calculate Authenticode hash
pesign --hash --in BOOTX64.EFI.signed

# Create dbx entry for this specific hash
# (Requires creating EFI_SIGNATURE_LIST with SHA256 type)

Extension 3: Shim Bootloader Integration

Set up a Linux-style boot chain with shim → GRUB → kernel.

  1. Download or build shim (signed by Microsoft CA)
  2. Enroll Microsoft UEFI CA in db
  3. Enroll your MOK (Machine Owner Key)
  4. Sign GRUB with your MOK
  5. Test the full chain

Extension 4: Custom CA Chain

Instead of self-signed certificates, create a proper CA hierarchy:

# Create CA
openssl req -x509 -newkey rsa:4096 -keyout CA.key -out CA.crt ...

# Create db certificate signed by CA
openssl req -newkey rsa:2048 -keyout db.key -out db.csr ...
openssl x509 -req -in db.csr -CA CA.crt -CAkey CA.key -out db.crt ...

Extension 5: Hardware Security Module (HSM) Signing

For production, use an HSM for key storage:

# Sign using PKCS#11 token (example with SoftHSM)
sbsign --engine pkcs11 \
       --key "pkcs11:object=db-key" \
       --cert db.crt \
       BOOTX64.EFI

Extension 6: Test on Real Hardware

Deploy your Secure Boot configuration to actual hardware:

  1. Create bootable USB with keys and signed bootloader
  2. Enter UEFI Setup, clear existing keys
  3. Enroll your keys
  4. Test signed vs unsigned boot
  5. Document any hardware-specific issues

9. Real-World Connections

Enterprise Secure Boot Deployment

Use Case How Secure Boot is Used
Corporate Laptops IT department enrolls corporate KEK, can push bootloader updates
Servers/Data Centers Custom PK per organization, strict control over boot chain
Embedded Devices Manufacturer PK, prevents end-user from running unauthorized firmware
Cloud VMs Confidential computing VMs use Secure Boot with vTPM

Linux Distribution Implementation

Distribution Approach
Ubuntu Uses Microsoft-signed shim, Canonical MOK for kernel signing
Fedora Uses Microsoft-signed shim, Red Hat MOK
Arch Linux Does not ship with Secure Boot by default; users self-enroll
openSUSE Uses Microsoft-signed shim, SUSE MOK

Career Applications

  • Firmware Security Engineer - Design Secure Boot configurations for products
  • Security Researcher - Find and responsibly disclose boot-level vulnerabilities
  • Enterprise IT - Deploy and manage Secure Boot across organization
  • Embedded Systems - Implement Secure Boot for IoT and industrial devices
  • Cloud Security - Configure Secure Boot for VM infrastructure

10. Resources

Official Documentation

Tools Documentation

Tutorials and Guides

Security Research


11. Self-Assessment Checklist

Understanding

  • I can explain the PK → KEK → db hierarchy and why each level exists
  • I understand the difference between db and dbx
  • I know what Authenticode is and how PE signing works
  • I can explain why Secure Boot prevents bootkits
  • I understand Setup Mode vs User Mode
  • I know how shim enables Linux distribution signing

Implementation

  • I can generate a complete key hierarchy with OpenSSL
  • I can convert certificates to UEFI signature list format
  • I can sign EFI binaries with sbsign
  • I can verify signatures with sbverify
  • I can enroll keys in OVMF (manually or scripted)
  • My signed binary boots successfully
  • Unsigned/wrongly-signed binaries are rejected

Debugging

  • I can inspect PE signature details
  • I can read enrolled keys with efi-readvar
  • I can diagnose “Secure Boot Violation” errors
  • I know how to reset to Setup Mode

Portfolio

  • Scripts are clean and documented
  • README explains the full process
  • I can demonstrate and explain the project in an interview

12. Submission / Completion Criteria

Your project is complete when:

  1. Key generation works: All scripts produce valid PK, KEK, and db certificates

  2. Signing works:
    • sbsign successfully signs your bootloader
    • sbverify confirms the signature is valid
  3. Enrollment works:
    • Keys are enrolled in OVMF (Setup Mode → User Mode)
    • Secure Boot shows “Enabled”
  4. Verification works:
    • Signed binary boots successfully
    • Unsigned binary is rejected with “Secure Boot Violation”
    • Binary signed with unknown key is rejected
  5. Documentation:
    • Scripts are commented
    • README explains the process
    • You can explain the key hierarchy to someone else
  6. Understanding demonstrated:
    • You can answer the interview questions
    • You can explain why each step is necessary

Congratulations! Upon completing this project, you understand one of the most important security mechanisms in modern computing. Secure Boot protects billions of devices from boot-level malware. This knowledge is directly applicable to firmware security, enterprise IT, and embedded systems development.


Previous: P14 - Graphics Mode Bootloader Next: P16 - Bootloader with Interactive Shell