Skip to content

Repository files navigation

elvboot — elevated boot

elvboot notices when somebody has been at your machine's boot path.

It is a FreeBSD verified-boot and tamper-detection project for a computer you own and carry around: a laptop whose firmware, boot medium or disk could be touched while you are not looking. The loader you boot is built, signed and deployed by you; at every boot it measures the platform it finds itself on — firmware tables, EFI variables, the images the firmware loaded, TPM counters and PCRs, the boot medium, the disk — compares them with what you declared, writes a tamper-evident record it can only write if it really ran, and tells you before it hands the disk key to the kernel. Nothing is enforced behind your back: the goal is to see manipulation, reliably, every boot, with evidence that survives a reboot.

Why would you want that? Because full-disk encryption protects data at rest, but not the code that asks for the passphrase. A modified loader, a swapped boot stick, a firmware setting changed in the night — those are the evil-maid moves, and they are invisible to a stock boot. elvboot makes them visible, with your own keys, on your own hardware, without a vendor cloud.

The family, by name:

  • elebake — the tool this repository ships: the compiler of the boot trust chain. It turns your decisions into a loader, a signed boot medium and the records that judge each boot.
  • platform trust gates — the loader-side engine, a FreeBSD patch series (see below): measurements, claims, gates, policies and the record chain, running inside the EFI loader before GELI and the kernel.
  • earlboot / elvbootd — the runtime witnesses generated by elebake: rc.d scripts that re-check after boot (PCR agreement, expected image set) and record what the loader published.

What elebake gives you

  • A boot trust chain you compile. Expectations, claims, gates and policies are named records in a database; stage site mk, stage build, stage sign and stage deploy turn them into a loader with generated C policy tables, veriexec manifests and site baselines, signed with your UEFI db key, on a removable card the machine boots from.
  • Measurements of the real platform. ACPI tables, EFI variables and the firmware's loaded images as learned sets (what stays the same across your boots, what moves), the TPM PCR bank, TPM reset and clock counters, NVMe power cycles, the boot origin, and the fingerprint of the GELI key the loader derived — each a claim with a verdict, each verdict in the record.
  • A record chain the loader must write. An EFI variable, keyed HMAC, counter and anchors: a boot that did not run your loader leaves no valid record, and you see the gap.
  • Dump and restore. dump writes the whole database as an executable script of its own commands; restore replays it. Adds are idempotent, so a replay is safe and a dump kept in git is a reproducible configuration.
  • Export and import. A signed, sealed pair — the dump and a bundle of the artifacts it names — attested with one OpenPGP key (a Nitrokey works), pinned on the receiving side, with serials against downgrade and provenance receipts. A second machine, a rescue medium or a fresh install can take over the exact state; this repository's own restore probe found its first real bug this way.
  • Reproducible artifacts. The database is the single source of truth: every generated file (policy tables, manifests, loader.conf, earlboot scripts) is regenerated from records, builds run in isolated checkouts of a pinned source branch, signatures are deterministic. A restored database rebuilds the same chain.
  • Backups and rollback with evidence. Deployed loaders are backup records with label and description; stage rollback saves the suspect loader first, then puts the known-good one back.
  • Emit and inspect. Every command generates shell. Pipeline commands print it for review (append | sh to act); bookkeeping is pinned to act directly. You can read what the tool is about to do, and the test suites analyse that output instead of touching the system.
  • Help that cannot erode. elebake help and the manual page are generated from the same help blocks the architecture tests check.
  • One process when it counts. elebake-binary.sh <db> <command...> runs a command, or a whole dump (batch <file>), inside one process: the anchors are functions, the emitted lines are calls. The import of a full database went from 22 minutes to 20 seconds on an old desktop. make install RUNNER=binary makes it the elebake you type. elebake-compile.sh is the same file by its other name and writes the script instead of running it -- what a run would do, for reading (the file's header says when that is the right tool and when it is not). elebake-walkthrough.sh <db> <command...> is the third name: the whole tree of a command as text, checks answered against the database as it is, every act shown under its anchor, nothing run -- in seconds.

The FreeBSD sources -- read this first

elebake is nothing without the loader it compiles for. The measurement/claim/gate/policy engine that reads the compiled decisions at boot is a FreeBSD patch series, platform trust gates, and the catalogs elebake offers are parsed from the headers of that series. Against a stock FreeBSD tree the catalogs are empty and nothing measures anything.

git clone -b platform-trust-gates-15.1 \
    https://github.com/johannes-bruegmann/freebsd-src.git ~/git/freebsd-src
./elebake.sh setenv ELEBAKE_FREEBSD_SRC ~/git/freebsd-src

Branch platform-trust-gates-15.1 is based on releng/15.1; the loader-side engine lives under stand/efi/loader/local/ and its README points back here. Parts of the series are on their way upstream.

Ideas that carry the tool

  • Detection, not enforcement. The design assumes the boot medium can be tampered with and concentrates on noticing — measurements are published, findings survive reboots, the owner decides what happens on a shortfall.
  • Catalogs come from the World, records hold decisions. What the loader can measure is parsed live from the checked-out sources; what you want lives in the database as named, reusable records (expectations, claims, gates, triggers, policies) — validated sharply where arsenal meets catalog.
  • Replays are an architecture principle. dump exports the whole database as an executable script; adds are idempotent-immutable, so restores and re-runs are safe.
  • No implicit defaults. The kernel that guards a machine, the license header of a generated file, the curation of a boot tree, the directory a command writes to — all explicit decisions, all fail-early when missing.
  • One anchor, one thing. Commands expand their arguments to the right until every detail is known (stage keysstage keys phasestage keys policystage keys claim); the architecture suite refuses nested loops, dispatch inside an anchor and oversized bodies.

Status

Working today, on real hardware: database and environment model, key registries (pem/openpgp/pkcs11, Nitrokey signing), stages (checkout, isolated stand/ and kernel builds, curation filter, include, manifest, verify, attest, sign, deploy to a removable card, markers, backups, rollback), the foundation compiler (measurement catalogs, arsenal, per-phase policy binding, generated foundation.c), compile-time baselines and run-time kenv records, inventory sets learned from boots (ACPI, EFI variables, loaded images), the record chain, earlboot and elvbootd rc.d witnesses, dump/restore, the signed export/import pair with the minimized rescue variant, and three test suites (architecture, unit, integration) that run in parallel.

The walk that built all this is recorded in docs/TUTORIAL.md; its current state is the silent boot: every gate green, no claim skipped, the database published as an attested, encrypted dump.

Open: the restore probe into a second database (in progress), the earlboot witnesses bound into custody, time windows after a series of settled boots.

Getting started

  • docs/QUICKSTART.md — the short path.
  • docs/TUTORIAL.md — a full guided walk, recorded live on real hardware, including the findings that walk fixed.
  • docs/ARCHITECTURE.md — the combinator model (_ terminals emit shell, __ combinators re-invoke once, ___ batches sequence).
  • docs/DESIGN_*.md — the design of stages and the foundation, of dump, archive and the exchange pair, of help and the manual.
  • elebake help — fully generated, cannot erode; docs/elebake.8 is rendered from the same corpus (make man).

Requirements: FreeBSD (base system tools; uefisign, gpg and a PKCS#11 stack where the respective backends are used), the patched source tree above, a machine with UEFI Secure Boot you control the keys of, and ideally a TPM.

License

BSD-2-Clause — see LICENSE. Contributions welcome, see CONTRIBUTING.md.

About

Boot trust chain compiler for FreeBSD verified boot — build, sign, attest, deploy. Tamper detection for your own boot path: decisions live in a database, artifacts are generated, everything is inspectable and replayable loaded images, TPM and disk at every boot, writes a tamper-evident record, and tells you before it unlocks the disk. Dump/restore,

Resources

Contributing

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages