Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/dwarves

.nornir/secure-boot-live-row-handoff.md

Handoff — what dwarves needs before a live secure-boot Build Thing row

Status: blocked on ONE knob in tunnr (not dwarves', not edda's, to add). Wanted: a ⚒ Build Thing matrix row that demos customer-owned Secure Boot live — the appliance's own key enrolled as PK/KEK/db, both boot-chain PEs signed with it, and the firmware refusing an unsigned one.

What already exists

What is missing

enroll_platform_keys returns a modified OVMF_VARS image, and the boot must run on Secure Boot firmware (/usr/share/OVMF/OVMF_CODE_4M.secboot.fd on this box). Neither is reachable from dwarves today:

The knob to add (tunnr) — LANDED, and this heading was stale

Both fields exist and have for some time, verbatim as specified below: ovmf_code and ovmf_vars_template at tunnr/src/boot_primitive.rs:140,151, plus two things this section never asked for and needed: resolve_ovmf (:524) refuses a named-but-absent image by name rather than falling back, and stage_firmware (:559) COPIES the VARS template per guest — a shared writable VARS across two VMs is a corruption waiting to happen, and nothing above tunnr would have noticed.

What was actually missing was everything ABOVE tunnr: grep -rn 'ovmf|firmware' over draupnir returned prose only, and jera the same. The fields existed and no caller could reach them, which is why this doc read as unbuilt to anyone checking from the GUI end. Closed 2026-08-25 — draupnir 8f2cf8b (the Firmware enum + host-path resolution), draupnir 97e1271 (to_tunnr_spec, which calls tunnr's own with_secure_boot_firmware rather than hand-rolling pflash argv), jera 85f63c3 (a pub use, not a twin enum — a second mapping is a second thing to test), and tunnr 47812c4.

That last one is worth reading: locate_ovmf picked CODE and VARS from two INDEPENDENT lists, so a host carrying OVMF_CODE_4M.fd without OVMF_VARS_4M.fd got the 4 MB CODE paired with the 2 MB OVMF_VARS.fd — which QEMU refuses outright ("device requires 4194304 bytes, block backend provides 2097152"). The halves are now paired by generation.

Kept rather than deleted, because a spec that silently loses its own history cannot be audited: what belongs in the record is that the knob was specified, and is built.

The original text follows.

Two optional fields on BootSpec, defaulting to today's behaviour — nothing else changes:

/// Override the read-only OVMF_CODE pflash (e.g. the `*.secboot.fd` build).
/// `None` → `locate_ovmf().0`, exactly as now.
pub ovmf_code: Option<PathBuf>,
/// The OVMF_VARS **template** copied into the per-VM workdir — the seam an enrolled
/// PK/KEK/db image plugs into. `None` → `locate_ovmf().1`, exactly as now.
pub ovmf_vars_template: Option<PathBuf>,

boot_test then reads spec.ovmf_code/spec.ovmf_vars_template where it calls locate_ovmf(). The per-VM writable copy stays per-VM — the template is what varies.

What dwarves does the moment that lands

  1. SigningIdentity::self_signed("korp appliance (customer key)") — one identity.
  2. sign_pe × 2 — the first stage and \vmlinuz, into the same 1 MiB ESP span.
  3. enroll_platform_keys(stock_vars, id.cert_der()) → the row's vars template; boot with ovmf_code = OVMF_CODE_4M.secboot.fd.
  4. Assert the positive: the signed chain still reaches KORP-BOOT: HANDOFF -> kernel → APP-ALIVE under Secure Boot. Then assert the negative with unsign_pe on \vmlinuz: the first stage's LoadImage fails EFI_SECURITY_VIOLATION and it halts on KORP-BOOT: FAILED load-image — never HANDOFF.

Step 4's negative is the row's whole point, and it is the reason to wait for the real firmware rather than ship a row that only proves bytes were signed. A green that says "Secure Boot" while nothing ever verified a signature is the same class of fake green as the terminal-stand-in boot chain this repo just finished removing.