Domain-separated signatures + dogfood the deploy signer#17
Merged
Conversation
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to every target uniformly, including the host, where +crt-static makes proc-macro dylibs impossible to build. stage1 already has a self-sufficient .cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld), so the env var only masked them. Remove it. The env was overriding the config rustflags, so with it gone cargo now applies the per-target rustflags. Paired with the shared workspace config dropping its duplicate musl rustflags (cargo concatenates rustflags across config files), the stage1 and stage2 binaries and the measured linux.efi UKI hash identically before and after, and the full chain still passes SIGN=1 / MANIFEST=1 / SIGN_ARGS=1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
HarryR
marked this pull request as ready for review
July 9, 2026 16:48
Release-prep hygiene over the domain-separation + rustflags changes, no logic: - Dockerfile.build: collapse the 3-line comment narrating the removed ENV RUSTFLAGS to a one-line statement of the rule. - Makefile: drop "instead of shelling out to openssl" from the deploy-bin note. - README: drop the trailing "There is no openssl in the signing path" sentence. - deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand), keeping the reason (no C toolchain on the host). - ed25519-sign: drop the "(no hex dep)" aside on the golden vector. Kept the openssl-genpkey PEM-format note: it documents a live interop property, not a removed dependency. deploy + ed25519-sign compile clean (comment-only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage
sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}):lockboot.v1.stage1.uki/.stage1.args/.stage1.manifest/.stage2.payload/.stage2.args/.stage2.manifest. A signature minted for one context is structurally invalid in every other.Alongside: stop signing with
opensslin the test Makefile and dogfood the realdeploysigner, folding in key generation.Changes
crates/ed25519-sign:Domainenum (all six roles) +tag();sign()/verify()take aDomainand operate on the preimage (callers still pass the raw message).pem_from_seed/pubkey_b64_from_seedpromoted topub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.crates/stage1,crates/mkuki: verify/sign sites pass their role.crates/deploy: newkeygen(random ed25519 key via/dev/urandom, nogetrandom/libc) and low-levelsign --domain;createthreads the rightDomaininto each artifact.Makefile: release key + every signature now vialockboot-deploy(noopenssl).Verification
make test-chain-x86_64 SIGN=1/SIGN=1 MANIFEST=1/SIGN=1 SIGN_ARGS=1all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.
🤖 Generated with Claude Code