review-001 decomposition: 6 remediation tasks from verified findings

Verify every review-001 finding before decomposition:
- S-1 re-confirmed by fresh executable probe (X.509 + raw-key
  impersonation both complete the handshake with the victim's
  fingerprint extracted server-side)
- U-2/U-3 uncovered-line inventory re-derived from cargo llvm-cov
  (--all-features); matches Part C exactly
- rcgen 1975/4096 defaults, rustls cert-type negotiation arm,
  packaging list, doc texts: all verified against sources

Tasks (all verified, none speculative):
- fix-accept-any-cert-verifier-posture (S-1 + N-1 + OQ-TLS-09 + probe)
- handshake-tests (U-3 suites 1-3; suite 4 lives in the S-1 task)
- coverage-cheap-closes (U-2's seven groups)
- acme-event-loop-test (U-1; depends on coverage-cheap-closes for the
  tracing-capture pattern)
- config-validation-and-trivia (C-2 ALPN dedup, C-3 empty-domains,
  N-6 excludes, N-7 https doc line)
- docs-pin-c1-c4-n3-n4 (C-1, C-4, N-3 decision note, N-4 negotiation
  note)

Graph: acme-event-loop-test is generation 2; the rest run in
generation 1. taskgraph validate: 14 tasks, no cycles.

Verification: cargo test (default + --all-features) green before and
after; probe file deleted after its run.
This commit is contained in:
2026-09-10 21:16:13 +00:00
parent bb0d060135
commit d7db6b17a6
6 changed files with 580 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
---
id: handshake-tests
name: Handshake-level test suite — pin, fail-closed, raw-key path executed (U-3)
status: pending
depends_on: []
scope: moderate
risk: medium
impact: component
level: implementation
tags: [tests, tcp, review-001, u3]
---
## Description
Every existing test asserts config *construction*; the crate's actual
TLS behavior (server accepts, pin verifies, fail-closed manifests) is
never executed — no handshake-level test exists. These are the
highest-value missing tests in the crate: they turn "fail closed" and
"pin" from documentation into executed behavior. The ADR-006 boundary
(handshakes belong to transport crates) is not violated by a
duplex-pair handshake: no external transport dep, just tokio +
tokio-rustls under the existing `tcp` feature (dev/test only — the
feature gate already exists for `for_tcp_tls`).
The four handshake-level gaps (review 001 §U-3):
1. **The pin path end-to-end**: client config with
`FingerprintPinVerifier` handshaking a server whose presentation
matches the pin → ok; mismatched pin → fails.
2. **The fail-closed path**: `remote_identity: None` + raw-key server
→ handshake fails (the structural claim, executed).
3. **The RFC 7250 raw-key server path end-to-end**: `RawKeyCertResolver`
+ client → handshake completes with the raw-key cert type negotiated
(currently only `only_raw_public_keys()` is asserted).
4. **S-1's impersonation probe made permanent** — covered by
`fix-accept-any-cert-verifier-posture` (kept separate: different
remediation owner, doc+ADR+probe).
## Work
1. Add `tests/handshake_behavior.rs` (`#![cfg(feature = "tcp")]`):
tokio duplex pair + `for_tcp_tls()` acceptor / `into_rustls_config()`
connector — or raw `ServerConnection`/`ClientConnection` with
`complete_io` (the review-probe shape; fewer moving parts).
2. Suite (1): server = `TlsIdentity::RawKey(sk)`, client pin =
`fingerprint_from_cert_der(spki)` → handshake ok + app-data
round-trip; wrong pin → error.
3. Suite (2): server = RawKey, credentials without `remote_identity`
handshake fails (`UnknownCertificateType`/alert — assert failure,
not the specific error text unless rustls pins it).
4. Suite (3): raw-key server + raw-key client (RFC 7250 both sides):
handshake ok; server `peer_certificates()` is an SPKI; client
presented X509+RawPublicKey cert types per N-4's correction (the
client resolver already offers the right shape — see N-4).
5. Keep every test within the crate's public API + rustls types; no new
dependencies.
## Verification
- [ ] All three executed handshake tests pass under
`cargo test --features tcp` (and `--all-features`)
- [ ] The fail-closed test actually fails the handshake (assert error,
not success)
- [ ] `cargo test` (default) still green — the file is feature-gated
and contributes nothing without `tcp`
- [ ] `cargo clippy --all-targets --all-features -- -D warnings`,
`cargo fmt --check` green
## Acceptance Criteria
- [ ] Pin / fail-closed / raw-key are executed behaviors in the suite,
not just structural assertions
- [ ] No new dependencies; the default build stays lean
## References
- docs/reviews/001-implementation-review.md §U-3, §N-4 (the cert-type
negotiation correction — read before writing suite (3))
- src/client.rs (`FingerprintPinVerifier`, `select_server_verifier`),
src/server.rs (`RawKeyCertResolver`)
- ADR-006 (the handshake scope boundary — and why the duplex-pair shape
stays inside it)
- tasks/integration-suite.md (the existing suite this extends)
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.