3 Commits
Author SHA1 Message Date
glm-5.3-flash 49d4432247 ADR-007: RFC 7250 cert-type negotiation — the offer follows the identity (OQ-TLS-10 resolved)
Resolve the cert-type negotiation gap (review 001 §U-3, OQ-TLS-10) by
deviation from alknet: the gap was a defect in the prior art (alknet's
code never delivered its spec's raw-key-over-TCP promise — ADR-082
"works for both QUIC and TCP+TLS"), not behavior to preserve.

- FingerprintPinVerifier::requires_raw_public_keys() derives from the
  pin format: ed25519: -> true (offer [RawPublicKey]), SHA256: ->
  false (X.509 offer). Crate pin client now completes against the
  crate raw-key server; SHA256: pins negotiate unchanged.
- RawKeyClientCertResolver presents the SPKI under the X.509 offer
  (only_raw_public_keys() == false): a raw-only client offer can only
  negotiate against a requires_raw server verifier, and
  AcceptAnyCertVerifier correctly stays on the default (accepts both
  cert types). The server extracts the ed25519: fingerprint from the
  SPKI bytes either way.
- Fail-closed preserved and strengthened: an ed25519: pin against an
  X.509 server now aborts at negotiation (suite 2b), never a
  downgrade; no API change (no public signature affected; the fix is
  invisible to consumers apart from working handshakes).
- tests/handshake_behavior.rs: suite 3 now runs crate-native (no
  custom iroh-shaped verifier), new negotiation fail-closed suite,
  suite 3b inverted to end-to-end success; invariant_pins.rs
  resolver-offer assertions flipped; unused imports dropped.
- Docs: ADR-007 written; OQ-TLS-10 -> resolved-by-deviation;
  client.md/server.md/overview/README/task postscript synced
  (incl. the strict-foreign-server limit in ADR-007 §Limits).

Verification: cargo test 81 / --features tcp 94 / --all-features
105 green; clippy -D warnings clean (default + all-features); fmt
clean; cargo doc warning-free.
2026-09-11 10:26:28 +00:00
glm-5.3-flash 4a4fae64af 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.
2026-09-11 08:17:28 +00:00
glm-5.3-flash d7db6b17a6 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.
2026-09-10 21:16:13 +00:00