feat(signing): replace HMAC envelope with ed25519 detached signature#125
Merged
feat(signing): replace HMAC envelope with ed25519 detached signature#125
Conversation
The pre-0.1.5 HMAC-SHA256 envelope over `(SHA256SUMS, index.json)` was correct for in-organization integrity, but the API/docs called it a "signature" — a misnomer. HMAC is a Message Authentication Code (FIPS 198-1): the verifier needs the same shared secret as the signer, so it cannot provide non-repudiation and cannot satisfy cross-organizational provenance expectations (DO-178C §7 SCM "protection against unauthorized changes" allows it; DO-178C supplier→authority handoffs and SLSA L2+ build provenance do not). This PR replaces the cryptographic primitive with ed25519 while preserving the envelope shape, the `BUNDLE.sig` filename (now legitimate), the `sign_bundle` / `verify_bundle_signature` API names, and the `SIGN_*` diagnostic codes (now accurate). `VERIFY_HMAC_FAILURE` becomes `VERIFY_SIGNATURE_INVALID` (the only diagnostic-code rename); the total code count is unchanged. Layered integrity model now documented (SYS-001, README, QUALIFICATION): 1. Content layer — sha256sum -c SHA256SUMS, no key required 2. Metadata layer — verify with 32-byte ed25519 public key 3. Provenance layer — non-repudiation via the asymmetric primitive CLI continues to take a key path; the file format is now 64 chars of hex (32 raw bytes) instead of arbitrary HMAC secret bytes. `cargo evidence verify --verify-key cert/signing.pub` and `cargo evidence generate --signing-key cert/signing.key`. Default path resolution + a native `cargo evidence keygen` subcommand land in a follow-up PR-C; for now the README documents an `openssl` recipe. Workspace dep delta: +ed25519-dalek (with rand_core, zeroize), +rand_core; -hmac. Pure-Rust, no FFI, matches the project's "Offline-capable" invariant. cargo-evidence/test_count floor bumped 142 → 142 (no change after verify.rs split); evidence-core/test_count floor bumped 360 → 367 to absorb the seven new ed25519 unit tests in signing.rs. Override-Deterministic-Baseline: ed25519 swap rotates Cargo.lock (adds ed25519-dalek + rand_core + curve25519-dalek transitive deps, removes hmac), which rotates `cargo_lock_hash` in deterministic-manifest.json. The deterministic_hash projection legitimately drifts from the prior main baseline. Co-Authored-By: Claude Opus 4.7 (1M context) <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.
Summary
Pre-0.1.5 used HMAC-SHA256 over the
(SHA256SUMS, index.json)envelope and called it a "signature" — a misnomer. HMAC is a Message
Authentication Code (FIPS 198-1); the verifier needs the same shared
secret as the signer, so it cannot provide non-repudiation and cannot
satisfy cross-organizational provenance expectations.
This PR keeps the envelope shape and replaces the cryptographic
primitive with ed25519. The
BUNDLE.sigfilename, thesign_bundle/verify_bundle_signatureAPI names, and theSIGN_*diagnostic codes are now legitimate.
Three-layer integrity model (now documented in SYS-001 + README + QUALIFICATION)
sha256sum -c SHA256SUMS, no key requiredWhat changed
crates/evidence-core/src/bundle/signing.rs: ed25519 sign + verify, key file IO helperscrates/evidence-core/src/lib.rs: re-exportSigningKey,VerifyingKey,Signature, key helperscargo-evidenceCLI:--signing-key/--verify-keypaths now read 32-byte hex files (was raw HMAC secret bytes)VERIFY_HMAC_FAILURE→VERIFY_SIGNATURE_INVALID(total code count unchanged)+ed25519-dalek(rand_core,zeroize),+rand_core;-hmaccert/QUALIFICATION.mdadds an "Integrity layers" section pointing at the relevant DO-178C §7 SCM language and FIPS 198-1's HMAC-vs-signature distinctionevidence-core/test_countfloor bumped 360 → 367 (seven new ed25519 unit tests in signing.rs)What's deferred (PR-C, separate)
cargo evidence keygensubcommand with refuse-overwrite +--rotatecert/signing.{key,pub}path resolutionsigning.pubanchor consistency check at generate (refuses if local pubkey doesn't match the signing key just used)cert/signing.pubFor now, README documents an
opensslkeygen recipe; the CLI takes explicit--signing-key/--verify-keypaths.Standards alignment
Override-Deterministic-Baseline
Test plan
🤖 Generated with Claude Code