2 Commits
Author SHA1 Message Date
glm-5.3-flash ac440f3a9a ADR-008: server-path possession verification — the verifying verifier is the default (OQ-TLS-09 resolved)
Close review 001 §S-1: the default client-cert verifier never checked
the client's CertificateVerify, so anyone holding a peer's *public*
cert/SPKI bytes (public by design — peers publish them to be dialable)
could complete a handshake as that peer, and the auth layer could not
detect it. The consumer designs are known (X.509 and raw-key TCP/QUIC
endpoints with identity-bearing clients), so implementing now — the
zero-consumer moment — avoids the guaranteed breaking republish of
flipping the default later.

- VerifyPresentedCertVerifier (new): request, don't require, verify
  possession — permissive verify_client_cert (self-signed chains and
  bare SPKIs stay valid presentation) + CertificateVerify routing by
  presented cert kind (Ed25519 SPKI -> verify_tls13_signature_with_
  raw_key both TLS versions; X.509 -> standard route), the same
  routing FingerprintPinVerifier implements. Nine-scheme list
  verbatim (shared fn, exact-list pin covers both).
- Default on every TlsServerConfig path — X509 / RawKey / SelfSigned
  / ACME (the verifier install is crate-side rustls in new_acme, not
  rustls-acme's).
- AcceptAnyCertVerifier stays public as the explicit no-pop escape
  hatch, no longer installed by any crate path.
- tests/impersonation_posture.rs: four pins — default rejects the
  attacker (X.509: UnsupportedSignatureAlgorithmForPublicKeyContext;
  raw-key: BadSignature), escape hatch still accepts + extracts the
  victim's fingerprint (both cert types).
- tests/handshake_behavior.rs: suites 4/4b — possession-checked legit
  clients (raw-key pin vs raw-key server; X.509 client vs X.509
  server) complete and the server extracts the fingerprint; suite 3b
  doc updated.
- Docs: ADR-008 written; OQ-TLS-09 -> resolved (option (b));
  ADR-007 §Limits deferral retired to not-planned; server.md/client.md
  invariants/README/overview synced.

Verification: cargo test 81 / --features tcp 95 / --all-features 104
green; clippy -D warnings clean (default + all-features); fmt clean;
cargo doc warning-free.
2026-09-11 11:12:48 +00:00
glm-5.3-flash e86b8ba1b5 task 1: S-1 remediation — no-pop posture doc + OQ-TLS-09 + permanent impersonation pin
- 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
2026-09-10 22:00:57 +00:00