task 2: handshake-level suites — pin, fail-closed, RFC 7250 paths executed (U-3)

tests/handshake_behavior.rs (tcp-gated, tokio duplex + tokio-rustls,
no new deps) turns the fail-closed / pin / raw-key language into
executed behavior:

- pin match: X.509 server + SHA256 pin -> handshake completes, app
  data round-trips, server extracts the client cert fingerprint
- pin mismatch: wrong pin -> handshake error (the pin IS the anchor)
- fail closed: remote_identity None + raw-key server -> HandshakeFailure
- raw-key server path end-to-end: completes with the iroh-shaped
  client verifier (requires_raw_public_keys == true); presented cert
  asserted to be the SPKI carrying the raw Ed25519 key
- N-4's interop trap executed: raw-key client resolver vs
  AcceptAnyCertVerifier -> IncorrectCertificateTypeExtension alert

Major finding, recorded as OQ-TLS-10 (open): a crate-built pin
client cannot reach a crate-built raw-key server over rustls TCP+TLS
— the raw-key resolver requires the client to offer [RawPublicKey]
server cert types, sent only when the client verifier overrides
requires_raw_public_keys() == true. FingerprintPinVerifier keeps the
trait default false (AcceptAnyCertVerifier too); iroh's verifier
overrides true on both sides. Gap inherited from alknet
(behavior-preserving); pinned both ways by the suite.

client.md / server.md carry the interop notes; task file updated
(premise adjustments documented in Notes, summary filled).

Verification: 81 default / 91 tcp / 99 all-features tests green
(+5 new), clippy -D warnings clean both configs, fmt clean,
cargo doc warning-free, taskgraph validate 14 tasks.
This commit is contained in:
2026-09-11 08:17:28 +00:00
parent d82956385b
commit 4a4fae64af
5 changed files with 511 additions and 7 deletions
+14 -1
View File
@@ -1,6 +1,6 @@
---
status: reviewed
last_updated: 2026-09-10
last_updated: 2026-09-11
---
# alktls — Client side
@@ -78,6 +78,19 @@ boundary in action.
**Fail-closed is structural**: known peer + fingerprint → pin;
unknown + X.509 → CA; unknown + raw key → fail. No fourth path.
All three outcomes are **executed** in
`tests/handshake_behavior.rs` (real rustls handshakes over a duplex
pair, `tcp`-gated).
**RFC 7250 over TCP is a negotiation gap, not a verified path**
(OQ-TLS-10): `FingerprintPinVerifier` keeps rustls' trait-default
`requires_raw_public_keys() == false`, so a crate-built pin client
cannot reach a crate-built raw-key server — the handshake fails
closed (`HandshakeFailure`). The executed raw-key-over-TCP pin
(`raw_key_server_path_completes_with_requires_raw_verifier`) uses the
iroh-shaped verifier (`requires_raw_public_keys() == true`) any
raw-key-over-TCP consumer must bring. Raw-key peers that ride
iroh/noq use those transports' own TLS and are unaffected.
## `FingerprintPinVerifier`