A minimal, security-hardened U-Boot build and test environment targeting QEMU x86_64 with full TPM 2.0 (via swtpm), Measured Boot, FIT Image Signing (RSA-4096), and UEFI Secure Boot support. Designed as a firmware security reference for automotive and embedded Linux platforms.
- Architecture
- Security Features
- Prerequisites
- Quick Start
- Scripts Reference
- Secure Boot Workflow
- Configuration Guide
- TPM PCR Layout
- Testing Workflows Locally
- Contributing
- License
┌─────────────────────────────────────────────────────────┐
│ Host Machine │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ QEMU x86_64 │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌─────────────────────┐ │ │
│ │ │ U-Boot ROM │◄──►│ swtpm │ │ │
│ │ │ (2 MB) │ │ TPM 2.0 emulator │ │ │
│ │ │ │ │ Unix socket │ │ │
│ │ │ • Measured Boot │ └─────────────────────┘ │ │
│ │ │ • FIT Signing │ │ │
│ │ │ • EFI SecureBoot│ │ │
│ │ └──────────────────┘ │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Feature | Status | Details |
|---|---|---|
| TPM 2.0 (swtpm) | Enabled | MMIO interface; SHA-256/384/512 PCR banks |
| Measured Boot | Enabled | Firmware + DTB measured into TPM PCRs via TCG2 |
| FIT Image Signing | Enabled | RSA-4096, RSASSA-PSS, SHA-256 |
| EFI Secure Boot | Enabled | UEFI signature database + TCG2 protocol |
| TCG2 Event Log | Enabled | 8 KB event log buffer |
| Environment Protection | Enabled | ENV_IS_NOWHERE + ENV_WRITEABLE_LIST |
| ACPI Table | Patched | 200 KB (up from 192 KB — headroom for TPM2 ACPI table) |
Open the repository in VS Code and click Reopen in Container.
All tools are pre-installed. See .devcontainer/ for the full environment definition.
| Tool | Purpose |
|---|---|
gcc, make, flex, bison, bc |
U-Boot build toolchain |
python3 + pyelftools |
U-Boot host scripts |
openssl, libssl-dev |
Key generation and FIT signing |
u-boot-tools (mkimage) |
FIT image assembly and signing |
qemu-system-x86_64 |
x86_64 emulation |
swtpm, swtpm-tools |
TPM 2.0 software emulator |
device-tree-compiler |
DTB inspection and manipulation |
shellcheck |
Script linting (development) |
One-liner install:
sudo apt-get install -y gcc make flex bison bc \
python3 python3-dev python3-pip python3-setuptools swig \
openssl libssl-dev libgnutls28-dev u-boot-tools \
qemu-system-x86 swtpm swtpm-tools \
device-tree-compiler python3-pyelftools shellcheck# 1. Clone U-Boot source (shallow, tag v2026.01)
./setup.sh
# 2. Build U-Boot ROM with security config applied
./build.sh
# 3. Run in QEMU with software TPM 2.0
./qemu.sh
# 4. Clean all build artefacts
./clean.sh| Script | Description |
|---|---|
setup.sh [--version TAG] |
Clone U-Boot at a given tag. Prompts before re-cloning. |
build.sh |
Clean → patch → defconfig → merge config → compile. Logs to logs/build.log. |
qemu.sh [--no-tpm] [--no-kvm] [--boot-img FILE] |
Launch QEMU with swtpm. Auto-detects KVM; falls back to TCG. Pass --boot-img to enable verified boot. |
clean.sh [--build|--logs|--uboot|--all] [--force] |
Selective cleanup with confirmation prompt. |
scripts/check-deps.sh |
Shared helper: colored logging + check_deps function (source only). |
scripts/gen-keys.sh [name] |
Generate RSA-4096 key pair + X.509 cert in keys/. |
scripts/make-demo-fit.sh |
Assemble a demo FIT image (build/boot.itb) and raw boot disk (build/boot.img). |
scripts/embed-key.sh [name] |
Sign FIT image, embed cert into U-Boot DTB, re-link ROM. Run after build.sh + make-demo-fit.sh. |
scripts/sign-fit.sh [image.itb] [name] |
Sign and verify a FIT image with keys from keys/. |
FIT image signing allows U-Boot to cryptographically verify a payload before executing it. The signing certificate is embedded in the U-Boot ROM at build time — U-Boot will refuse to boot any image not signed with the embedded key.
# 1. Generate RSA-4096 key pair
./scripts/gen-keys.sh dev
# 2. Build U-Boot ROM (generates u-boot.dtb needed for cert embedding)
./build.sh
# 3. Assemble a demo FIT image + raw boot disk
./scripts/make-demo-fit.sh
# 4. Sign FIT, embed cert into DTB, re-link ROM
./scripts/embed-key.sh dev
# 5. Boot — U-Boot verifies the FIT image before loading
./qemu.sh --boot-img build/boot.imgExpected output in U-Boot serial console:
## Loading kernel from FIT Image at 01000000 ...
Using 'conf-1' configuration
Verifying Hash Integrity ... sha256,rsa4096:dev+ OK
Loading Kernel Image ...
sha256,rsa4096:dev+ OK confirms the signature verified against the certificate baked into the ROM.
| Step | Script | What it produces |
|---|---|---|
| 1 | gen-keys.sh |
keys/dev.key (private), keys/dev.crt (X.509 cert) |
| 2 | build.sh |
build/u-boot.rom, u-boot/u-boot.dtb |
| 3 | make-demo-fit.sh |
build/boot.itb (unsigned FIT), build/boot.img (raw disk) |
| 4 | embed-key.sh |
build/boot.itb (signed FIT), u-boot.dtb with cert, build/u-boot.rom with cert baked in |
| 5 | qemu.sh --boot-img |
U-Boot reads disk, verifies FIT, prints OK or Signature check Failed! |
Note: Steps 2 and 4 both run
make. Step 2 is a full build (distclean). Step 4 is an incremental re-link only — it takes ~2 seconds because only the DTB-linked objects are rebuilt.
Replace make-demo-fit.sh with your own boot.its pointing at a real Image/uImage, then run embed-key.sh and qemu.sh --boot-img as above. The FIT source template is in the scripts reference.
Custom options live in config/qemu-x86_64 and are merged on top of the upstream qemu-x86_64_defconfig at build time.
| Option | Value | Notes |
|---|---|---|
CONFIG_ROM_SIZE |
2097152 |
2 MB ROM image |
CONFIG_BAUDRATE |
115200 |
UART baud rate |
CONFIG_BOOTDELAY |
5 |
5-second autoboot countdown |
CONFIG_FIT_SIGNATURE |
y |
Enforce FIT image signature verification |
CONFIG_FIT_RSASSA_PSS |
y |
RSASSA-PSS padding (recommended over PKCS#1 v1.5) |
CONFIG_RSA_VERIFY_WITH_PKEY |
y |
Verify against embedded X.509 public key |
CONFIG_TPM_V2 + CONFIG_TPM2_MMIO |
y |
TPM 2.0 via MMIO |
CONFIG_MEASURED_BOOT |
y |
Extend TPM PCRs with firmware measurements |
CONFIG_TPM2_EVENT_LOG_SIZE |
8192 |
8 KB TCG2 event log |
CONFIG_EFI_SECURE_BOOT |
y |
UEFI Secure Boot variable enforcement |
CONFIG_EFI_TCG2_PROTOCOL |
y |
EFI TCG2 (TCG PC Client Platform specification) |
CONFIG_ENV_IS_NOWHERE |
y |
No persistent environment — prevents saveenv tampering |
CONFIG_ENV_WRITEABLE_LIST |
y |
Restricts setenv to an explicit allowlist |
CONFIG_AUTOBOOT_KEYED |
y |
Console interrupt requires a passphrase (see below) |
The autoboot countdown cannot be interrupted by pressing any random key. A SHA-256-hashed passphrase is required. The demo passphrase is stop.
When you see this prompt in the QEMU serial console:
Passphrase required to abort autoboot (5 s) — type silently
Type stop (characters are not echoed) to drop into the U-Boot shell.
To set a custom passphrase, regenerate the hash and update the config:
printf '%s' 'your-passphrase' | sha256sum
# Paste the result into CONFIG_AUTOBOOT_STOP_STR_SHA256 in config/qemu-x86_64
# Then rebuild: ./build.shStandard TCG PC Client Platform PCR assignments used by U-Boot's measured boot:
| PCR | Content |
|---|---|
| 0 | Core Root of Trust for Measurement — BIOS/ROM code |
| 1 | Platform configuration (SMBIOS, ACPI tables) |
| 2 | ROM code — option ROMs |
| 3 | ROM configuration and data |
| 4 | IPL code — bootloader (U-Boot itself) |
| 5 | IPL configuration — U-Boot environment |
| 7 | Secure Boot state and key database |
| 8–15 | Reserved for OS and application use |
Read PCR values at runtime:
- U-Boot shell:
tpm pcr_read 0- Host (after boot):
tpm2_pcrread(tpm2-tools)
Use act to run GitHub Actions workflows locally via Docker before pushing.
Install once:
gh extension install https://github.com/nektos/gh-actRun each workflow:
# Lint all shell scripts
gh act push -W .github/workflows/shellcheck.yml -P ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04
# Build U-Boot ROM
gh act push -W .github/workflows/build.yml -P ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04
# Boot smoke test in QEMU (TCG mode, 30 s timeout)
gh act push -W .github/workflows/qemu-smoke-test.yml -P ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04Artifact upload steps are automatically skipped when running under
act(theACTenv var is set by the runner).
See CONTRIBUTING.md for the Gitflow workflow, signed-commit requirements, and branch naming conventions.
MIT — see LICENSE.