feat(airgapped): real offline keyless verification (#219, REQ-23) - #229
Merged
Conversation
AirGappedVerifier::verify_crypto was a stub — ed25519 over the full SPKI DER
(fails for any real Fulcio cert, which are ECDSA P-256), no cert-chain anchoring,
no Rekor SET check. Replace it with real verification that DELEGATES to the
existing tested online primitives, anchored to the provisioned TrustBundle
(which already carries the Fulcio roots + Rekor keys — the stub just never used
them). Order mirrors the online path (signer.rs:592-674):
1. hash-binding: module_hash == signature.module_hash (clear error)
2. cert chain: CertificatePool::from_pem_authorities → verify_pem_cert at
Rekor integrated_time (RFC-5280, validity, codeSigning EKU)
3. Rekor SET: RekorKeyring::from_pem_logs → verify_set (MANDATORY)
4. P-256 signature over module_hash via verify_prehash (self-binding)
5. Rekor body binding: verify_rekor_body_binds_to_bundle (#135 UCA-2 — without
it, a holder of a legit Fulcio cert can staple an unrelated Rekor entry to
a malicious module; the online path checks this, so offline must too)
6. revocation over the leaf DER fingerprint
New anchoring constructors CertificatePool::from_pem_authorities and
RekorKeyring::from_pem_logs mirror the tested from_trusted_root split (last cert
= root). Delete the broken extract_public_key_from_cert.
NOT verified offline, stated explicitly (VerificationResult.inclusion_verified
+ doc + DD-11/DD-12): Rekor Merkle inclusion (mirrors online skip, Rekor v2
shard bug / #137) and SCT (no CT-log key provisioned in the bundle).
Oracle: 11 offline tests, each negative test asserting its own failure step
(wrong root→chain, expired→time, wrong rekor key→SET, tampered→P-256,
body mismatch→body-binding, revoked→revocation, hash mismatch→step 1); positive
path builds a real hashedrekord body so body-binding is genuinely exercised.
wsc suite 619 passed / 0 failed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aR3Md1h46K9wAUWMQiESH
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Merged
avrabe
added a commit
that referenced
this pull request
Aug 8, 2026
…) (#230) Merged to main as 255a597; oracle 619/0, clean-room all-confirmed, #219 closed. Claude-Session: https://claude.ai/code/session_012aR3Md1h46K9wAUWMQiESH 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.
Closes #219 (REQ-23). Replaces the
AirGappedVerifier::verify_cryptostub with real offline Sigstore keyless verification, delegating to the existing tested online primitives anchored to the provisionedTrustBundle.The stub was broken and unsound
spki.raw) → fails for any real Fulcio cert (they're ECDSA P-256)Real verification (mirrors online order, signer.rs:592-674)
from_pem_authorities→verify_pem_certat Rekorintegrated_time, RFC-5280 + codeSigning EKU) · 3. Rekor SET (from_pem_logs→verify_set) · 4. P-256 sig overmodule_hashviaverify_prehash(self-binding) · 5. Rekor body-binding (wsc verify --keyless accepts tampered WASM (signed-payload byte flip not detected) #135 UCA-2) · 6. revocationSoundness note
Review caught that the first cut omitted Rekor body-binding — the online path verifies it (signer.rs:664) precisely because without it "a holder of a legitimate Fulcio cert can staple an unrelated public Rekor entry to a malicious module." Added it + a
test_offline_rekor_body_mismatchregression test. Clean-room confirmed it's load-bearing.Explicitly NOT verified offline (stated, not hidden — DD-11/DD-12)
VerificationResult.inclusion_verified = falseOracle
11 offline tests, each negative asserting its own failure step (wrong root→chain, expired→time, wrong rekor key→SET, tampered→P-256, body mismatch→body-binding, revoked→revocation, hash→step 1); positive path builds a genuine hashedrekord body.
cargo test -p wsc: 619 passed / 0 failed. Clean-room: all claims CONFIRMED.SigstoreBundle::verifydeferred to its own requirement (was optional).🤖 Generated with Claude Code