test+hardening: pin the untested defenses, cap what limits couldn't, heal the fuzzers - #80
Merged
Merged
Conversation
…ps it that way Merged follow-through from two independent reviews (the multi-agent security audit and an external product review), scoped strictly inside the 1.x format freeze: docs, metadata, and one XML-docs addition. No byte meaning, reader acceptance, or API change. Resurrect the docs-consistency guard: - .github/workflows/docs-consistency.yml now exists — the workflow the 1.7.0 changelog advertised but never shipped. It runs check-docs-consistency.sh on every push and PR. - The script is portable (no GNU-only grep -P, so it runs on macOS) and now also checks the SECURITY.md supported-versions cell, the ROADMAP-2.0 "Today" cell, the AUDIT-SCOPE pinned tag, artifact-name examples, release-download / reproducibility / clone-at-tag commands, and install snippets in all Markdown (CHANGELOG excluded as history). Verified green on this tree and on macOS. Version sweep to 1.7.1 (was scattered across 1.0.1–1.7.0): SECURITY.md table, ROADMAP "Now" heading, KNOWN-GAPS + GOLD-STANDARD review markers, ROADMAP-2.0 Today cell, AUDIT-SCOPE pinned tag (v1.7.1 / e0d332a), README + SUPPLY-CHAIN + REPRODUCIBLE-BUILDS worked examples, ANNOUNCE snippets, CHANGELOG compare-link footer (adds 1.7.0/1.7.1). PackageValidationBaselineVersion 1.5.0 → 1.7.1 (pack verified against the published baseline). PackageReleaseNotes reworded version-agnostic so they cannot silently go stale on nuget.org. Recalibrate claims to what the code does and tests pin: - SECURITY.md: no-oracle bullet now states the true property (one exception type; byte-identical messages for key-dependent failures; structural diagnostics are key-independent); integrity scoped to the authenticated envelope (trailing bytes after the final frame are ignored — KNOWN-GAPS); bounded-work notes tight ceilings are opt-in via PqDecryptionLimits.Untrusted; Dependencies now names Signing's BouncyCastle use and the Rust demo core's pre-1.0 RustCrypto crates; SBOM list covers all eight per-package SBOMs. - SUPPLY-CHAIN.md: artifact table lists all nine packages; snupkg files are documented as NOT attested (verifying one fails by construction); the reproducibility script's 4-of-9 package coverage is stated; "every push" heading acknowledges scheduled jobs. - GOLD-STANDARD.md: binary-compat row downgraded to⚠️ — validation is overridden off in Aws/AzureKeyVault/Gcp/Analyzers (stale pre-first-publish gate); PublicAPI baseline count corrected to seven packages. Correct the rotation story (KEY-MANAGEMENT.md): header-only CEK rewrap cannot ship on format v2 — the header is AAD for every frame, so a rewrap re-tags every chunk, and doing so under the same CEK and nonces with new AAD emits second GCM tags for existing (key, nonce) pairs while old copies coexist, making the GCM authentication key recoverable. Rotation is now documented as a streaming transcode (fresh CEK + nonce prefix, full-file I/O, detached signatures invalidated); true header-only rewrap is banked as a format-v3 candidate. Status list also gains the shipped Gcp provider and multi-recipient moves to past tense. Format-doc errata (doc-only, matching the frozen implementation): - KEY-FILE-FORMAT.md: a PQKF body is a KeySource-1 passphrase container whose KeyParams carry KdfId 1 (PBKDF2) or 2 (Argon2id) — previous text conflated KeySource with KdfId and would misdirect an independent implementer. - FILE-FORMAT.md: KeySource-2 HKDF formulas now state salt = absent. KNOWN-GAPS.md gains five verified entries: header-only rewrap (v3 candidate), IContentKeyProvider key-freshness contract and its GCM consequences, passphrase Unicode normalization, non-interruptible KDF derivation, and default permissions on decrypted output. IContentKeyProvider.WrapNewKeyAsync's XML docs now state why the fresh-key contract is load-bearing (build clean, 0 warnings). CLAUDE.md's version-bump checklist now names every reference class that drifted, so the next release sweep is complete by construction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sym7RJ7ehNhbMXytE5rMmS
…heal the fuzzers The assurance batch from the merged review follow-through (multi-agent audit + two external reviews), all inside the 1.x format freeze — no byte meaning or reader acceptance changes; the corpus grows, nothing in it changes. Conformance corpus (+9 vectors, both implementations green): - Deterministic two-chunk positive pos-passphrase-pbkdf2-multichunk. - Argon2id bounds negatives (memory/iterations/parallelism/salt): the Rust reader's cost checks previously had zero test coverage anywhere. - Framing negatives: clean-boundary truncation (first exercise of the Rust saw_final path), frame swap (first Rust ordinal-binding coverage), dropped final frame, and a cross-container frame transplant backing SECURITY.md's "splicing between containers" claim with committed bytes. - The generator now reuses the pinned hybrid lenient vector instead of re-randomizing it on regen, and regeneration reproduces the corpus bit-for-bit (verified: regen produced only additions). Limits: PqDecryptionLimits.MaxArgon2Parallelism (default 255 = format maximum, so acceptance is unchanged; Untrusted caps at 8), enforced pre-derivation beside the memory/iteration ceilings. A hostile header could previously demand 255 Argon2 lanes and no limit could say no. Key-file hardening: PqKeyFileFormat.Decrypt output is a fixed-capacity buffer sized to the expected key rather than the whole file — kills the attacker-proportional allocation and the wrong-type reallocation that escaped the zeroing finally. Same exceptions, same messages. Fuzz health: both .NET targets now run under Untrusted limits (format-legal 2 GiB-KDF headers stalled single iterations ~20 min and failed 13/30 recent scheduled runs), plus -timeout=20 and timeout-*/oom-* artifact upload in CI. Tests: ZeroizationTests (engine success/failure/cancellation + Dispose paths — a documented defense with previously zero coverage that has regressed before), cross-container transplant, KeySource-4 block swap/strip/duplicate, SHA256SUMS integrity (was verified by nothing), Argon2 parallelism limits. Suite: 636 passing across net8.0+net10.0; cargo conformance suite green. Hygiene: analyzer rules PQFE101-104 moved to the shipped ledger (1.5.0); System.Formats.Asn1 transitive floored at 8.0.1 in the analyzer test project (CVE-2024-38095, test-only). Docs made true: SECURITY.md discloses the stage-distinguishable error caveat (key-unwrap vs body-auth — recorded in KNOWN-GAPS with the unification decision explicitly open); CONFORMANCE.md §3 names the corpus vector for each MUST; REPRODUCIBLE-BUILDS.md retracts the cross-OS claim — a macOS arm64 rebuild of v1.7.1 differs from the published package (reproduced locally with the repo's own verifier; Linux CI remains the demonstrated envelope); README says "provenance-attested releases" (there is no author/tag signing). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sym7RJ7ehNhbMXytE5rMmS
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.
Replaces #78 (auto-closed when its stacked base branch was deleted on merge of #77 — same branch, same single commit, full description and verification record in #78).
🤖 Generated with Claude Code
https://claude.ai/code/session_01Sym7RJ7ehNhbMXytE5rMmS