Gate the A.4 leg on content type, and stop it answering with Mls - #111
Merged
Conversation
Two problems at process_a4_leg, both about a door that carries application messages only. The routing tag is chosen by the sender, and process_incoming_message validates and APPLIES atomically. So a Commit behind the EK tag was applied — moving the recv-PQ epoch — and only then refused by the match below. The content type rides the PrivateMessage's plaintext framing, so MlsMessage::description() can reject a non-application leg before any keys or state are touched. And every rejection here reported Mls, which carries the fatal disposition: "our own state may be inconsistent, discard the session". A host reading that literally tears the session down, so a frame the PEER chose must never be able to ask for one. All of them are DecryptionFailed now. The new test pins the refusal's shape — frame-level, nothing staged, no epoch moved — and its doc says plainly what it does not pin: the injected Commit is from the classical group, so mls-rs refuses it on group id alone. Pinning the gate itself needs an unapplied commit for the recv-PQ group at its current epoch while pq_inflight is simultaneously open, and those conditions fight each other through the public API. Verified by mutation that the test fails under the pre-change behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The gate and the DecryptionFailed rejections carry over onto the generic process_a4_leg unchanged. Two reconciliations where main met this change: the smuggled-proposal test now pins the pre-ingest gate refusal (with the legacy arm's cache-drop as the backstop for paths that do ingest), and the non-application-leg test's scope note is rewritten for the classical door — its commit now passes the guard phase but still dies at PSK resolution, so the recv-classical epoch is asserted directly and the gate remains defense in depth, verified by mutation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 27, 2026
germ-mark
added a commit
that referenced
this pull request
Jul 27, 2026
Pre-release fixes for 0.15.0: #111 changeset + archive-version rule
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.
Follow-up to #110, which noted this in its "not fixed here" section.
Two problems at
process_a4_leg, both about a door that carries application messages only.A non-application leg was applied before being refused. The routing tag is chosen by the sender, and
process_incoming_messagevalidates and applies atomically. So a Commit behind the EK tag was applied — moving the recv-PQ epoch — and only then refused by the match below. The content type rides thePrivateMessage's plaintext framing, soMlsMessage::description()can reject a non-application leg before any keys or state are touched.Every rejection reported
Mls. That carries thefataldisposition: "our own state may be inconsistent, discard the session". A host reading it literally tears the session down and re-establishes — so a frame the peer chose must never be able to ask for one. All of them areDecryptionFailednow, which is where #110 already put the decrypt failure itself.Test notes
test_non_application_leg_is_refused_with_the_group_untouchedpins the refusal's shape: frame-level, nothing staged, no epoch moved. Verified by mutation that it fails under the pre-change behavior (gate removed andmap_err(|_| Mls)restored).Its doc says plainly what it does not pin. The Commit it injects belongs to the classical group, so mls-rs refuses it on group id alone — which makes it a test of the refusal's shape, not of the gate. Pinning the gate itself needs an unapplied commit for the recv-PQ group at exactly its current epoch while the
pq_inflightguard is simultaneously open, and those two conditions fight each other through the public API. I'd rather leave the gate as documented defense-in-depth than ship a test that looks like it covers it and doesn't.cargo test(291 passing),cargo clippy --all-targets --features awslc,benchmark_util -- -D warningsandcargo fmt --checkall clean.🤖 Generated with Claude Code