Add stage0: measured kernel-less UEFI network bootloader#7
Merged
Conversation
stage0 is the kernel-less sibling of stage1: a pure-UEFI application the
firmware boots directly, which fetches a `_stage0` user-data document from the
cloud metadata service, downloads a UEFI payload over the network, measures it
into the TPM (PCR 14), and chain-loads it — no Linux kernel in the chain.
Key design points:
- Reuses vaportpm-attest unchanged via its TpmTransport seam (git dep); a
Tcg2Transport ships raw TPM commands over EFI_TCG2_PROTOCOL.SubmitCommand
(src/tcg2.rs), so the same pcr_extend used on Linux runs here.
- Payload download uses raw EFI_TCP4 (src/tcp4.rs), because OVMF/EDK2 HttpDxe
won't drain a multi-segment response body; hostname URLs resolve over
EFI_DNS4 (src/dns4.rs). Metadata still uses EFI_HTTP at fixed link-local IPs.
- Two admission policies (src/config.rs, src/sig.rs): pinned sha256, or an
ed25519 detached signature (<url>.sig) verified against a release pubkey
pinned in metadata — letting payloads roll forward without editing metadata.
- Payloads are not db-signed. stage0 loads them through a temporary
EFI_SECURITY2_ARCH_PROTOCOL.FileAuthentication override (src/secauth.rs,
shim's security_policy_install trick), so the deployment keeps its
ephemeral-key/locked-varstore lockdown while still chain-loading late-bound
payloads. Only PCR 14 is measured — the attestation surface is just
"stage0 ran and loaded this hash".
Build/test (all in the build container; never on the host):
make tools/build-stage0/<arch>/stage0.efi
make test-stage0-<arch> # builds+signs a test payload, serves it over a
# DNS name, boots stage0 end to end under QEMU
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
acae776 to
d501f22
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
stage0is the kernel-less sibling ofstage1: a pure-UEFI application the firmware boots directly, which fetches a_stage0user-data document from the cloud metadata service, downloads a UEFI payload over the network, measures it into the TPM (PCR 14), and chain-loads it — no Linux kernel in the chain.Design
vaportpm-attestunchanged via itsTpmTransportseam (git dep, pinned tomain@15770b1); aTcg2Transportships raw TPM commands overEFI_TCG2_PROTOCOL.SubmitCommand(src/tcg2.rs), so the samepcr_extendused on Linux runs here.EFI_TCP4(src/tcp4.rs) because OVMF/EDK2HttpDxewon't drain a multi-segment response body; hostname URLs resolve overEFI_DNS4(src/dns4.rs). Metadata still usesEFI_HTTPat fixed link-local IPs.src/config.rs,src/sig.rs): pinnedsha256, or an ed25519 detached signature (<url>.sig) verified against a release pubkey pinned in metadata — letting payloads roll forward without editing VM metadata. The release private key stays offline and never touches a deployed machine.EFI_SECURITY2_ARCH_PROTOCOL.FileAuthenticationoverride (src/secauth.rs, shim'ssecurity_policy_installtrick), so the deployment keeps its ephemeral-key / locked-varstore lockdown (thedbkey signs onlystage0, then is destroyed) and can still chain-load late-bound payloads — otherwise mutually exclusive.Tested
Under QEMU (x86_64 + aarch64), end to end: DNS4 → TCP4 download → ed25519 verify → PCR 14 extend → security-arch-override
LoadImage→ payload runs and reads back PCR 14. Builds clean for both*-unknown-uefitargets; clippy + rustfmt pass. All builds run in the build container, never on the host.Follow-ups (not blocking)
EFI_TCP4/EFI_DNS4(andEFI_HTTP) drivers are present on real AWS Nitro firmware — same unknown noted in the README's risk section.🤖 Generated with Claude Code