- review 001: §Status carries the remediation status (S-1 + N-1 landed
in e86b8ba, OQ-TLS-09 open, probe permanent) and the N-4 correction
summary; §S-1 remediation-task line updated; §N-1 marked remediated;
§N-4 gains the corrected mechanism chain (rustls 0.23.41/0.23.44 send
[RawPublicKey] iff the resolver's only_raw_public_keys() is true —
no "offers both types" behavior exists; a raw-key client fails
IncorrectCertificateTypeExtension against this verifier; the S-1
probe presents the SPKI under the default X.509 offer instead)
- task fix-accept-any-cert-verifier-posture: drop the placeholder
fill-in lines (Notes/Summary carry the actual record)
- task docs-pin-c1-c4-n3-n4: N-4 work item rewritten from the
corrected chain so the implementing agent does not re-derive it;
references point at the rustls source lines and the probe's
resolver choice
- AcceptAnyCertVerifier doc: the presented CertificateVerify signature
is not verified (no proof-of-possession) — the server-extracted
fingerprint is attacker-suppliable from observed public cert/SPKI
bytes; states the two safe patterns (auth-layer challenge-response /
a verifying verifier) and points at OQ-TLS-09
- FingerprintPinVerifier doc (N-1): fixed the "stolen-but-stale
fingerprint" phrasing (the cert is presented fresh each handshake;
the signature check defeats a stolen/observed cert used by a party
without the private key) and added the server-verifier cross-reference
- OQ-TLS-09 recorded (open, high): which layer owns server-path
proof-of-possession — three options; deferral noted (needs the
auth-layer design or an API call before the first consumer)
- tests/impersonation_posture.rs (tcp-gated): the S-1 probe made
permanent, both variants — X.509 victim cert + attacker key and RFC
7250 victim SPKI + attacker key complete the handshake, application
data flows, and the server extracts the victim's fingerprint; any
future pop change must fail/update this test with the doc + OQ
- server.md / client.md synced with the same posture
- task note: the review's N-4 parenthetical ("alknet's client resolver
offers both types") is inaccurate — rustls 0.23.41/0.23.44 offer
[RawPublicKey] iff the resolver's only_raw_public_keys() is true;
task 6 should write N-4 from the rustls sources
Verified: cargo test 68 default / 77 all-features (+2) green; clippy
-D warnings clean (default + all-features); fmt clean; cargo doc
--no-deps warning-free
Checklist (all six PASS):
1. API surface == ADR-004 — every accessor signature verified verbatim
2. TlsError == ADR-002 — six variants, #[non_exhaustive], typed sources,
AcmeConfig holds exactly the two config-mismatch cases
3. Invariants: all five server invariants + client 0-RTT half +
fail-closed structure, each with a passing behavioral test at unit
and integration level
4. Deltas vs extraction: all ADR-pinned; two surfaced divergences
recorded as ADR amendments — zero un-pinned divergences remain
5. Feature hygiene: default = [] lean, tokio subset (no full),
doc comments on public API, no inline // comments, no panics
6. Docs sync: ADR-002 + ADR-003 amendment notes; overview/server/client
Draft → Reviewed; README carries the API-freeze lifecycle note
5 findings, all low severity, all resolved forward (table in task Notes)
Verification: cargo test (81), cargo test --all-features (92),
clippy -D warnings, fmt --check, doc --no-deps,
publish --dry-run — all green. API FROZEN for the alknet rewrite.
- rust-version 1.85 -> 1.88 (ecosystem-wide resolution from the audit
sessions; matches noq 1.2's floor, sits below iroh 1.91)
- Cargo.lock: time 0.3.36 pin removed (existed only to keep the 1.85
claim satisfiable); tree re-floated to current
- phase-0: MSRV thread marked RESOLVED; OQ-TLS-08 narrowed to the
quinn->noq feature-rename half; lesson recorded (rust-version is
passive metadata — claims must be compile-checked, not assumed)
Verified: cargo test, test --all-features, clippy -D warnings,
fmt --check, rustup run 1.88 cargo check