The monolithic open-questions.md (1310 lines, 47 OQs) was large enough to be unmanageable, with high size variance (OQ-42 at 220 lines next to OQ-06 at 8). Decomposed into one file per OQ under docs/architecture/questions/ (NNN-slug.md, mirroring the ADR convention), with open-questions.md retained as the index: theme-grouped tables plus a cross-theme Deferred/Blocked section that surfaces the 6 deferred OQs with their Blocked-on conditions inline (the safe-exit visibility surface). Per-OQ content moved verbatim; all 62 inbound links stay valid (none used anchors). README's curated OQ summary dropped (now redundant with the index tables). Also seeds tasks/architecture/ with this task plus two follow-ups found during the decompose: OQ-09/10 missing structured Blocked-on fields, and the tasks/architecture/ blocker-task half of the Safe Exit protocol being unenforced.
2.8 KiB
OQ-29: CallClient TLS Client-Auth and Remote-Identity Verification
-
Origin: client-and-adapters.md, ADR-017 §7
-
Status: resolved (2026-06-27 by ADR-030 §6 + this decision)
-
Door type: One-way (identity model interaction), two-way (mechanism)
-
Priority:
high→ resolved -
Resolution: Three things are decided:
-
Wire quinn client-auth. The client presents its Ed25519 key as an RFC 7250 raw public key client cert (the client-side equivalent of the server's
RawKeyCertResolver). The server'sAcceptAnyCertVerifieralready requests client certs and extracts the fingerprint — the gap was entirely on the client side (with_no_client_auth()→ present the key). This activates thePeerEntryfingerprint →peer_idresolution path on quinn connections. -
Key-type-aware server cert verification. The client's
ServerCertVerifierdepends on the remote's identity type:- Ed25519 raw key (the common case): accept the cert, extract the
fingerprint, match against
PeerEntry.fingerprints. The fingerprint IS the trust anchor — no CA needed. (Same model as iroh.) - X.509 (domain-facing endpoints, ACME): verify against a CA
(rustls's
WebPkiServerVerifierwith the platform root store or a configured CA).AcceptAnyServerCertVerifieris a security hole for X.509 — it's only safe for raw keys. - The verifier choice is driven by
CallCredentials.remote_identity, which carries the expected key type.
- Ed25519 raw key (the common case): accept the cert, extract the
fingerprint, match against
-
Fingerprint normalization (ADR-030 §6): the quinn path extracts the raw Ed25519 public key from the SPKI cert and formats it as
ed25519:<hex>, matching iroh. The same key has the same fingerprint regardless of transport. X.509 fingerprints stay asSHA256:<hex of DER>.
The iroh path already works — iroh uses RFC 7250 raw keys, both sides automatically exchange Ed25519 public keys during the TLS handshake, and
extract_iroh_client_fingerprintalready gets theNodeId. No client-auth wiring needed for iroh (direct or relay). The gap was quinn-only.What's genuinely additive (not blocking the ADR-029 migration): remote-identity verification (the client verifying the server's fingerprint against an expected value) is additive — the server-side fingerprint extraction is what matters for
PeerId, not the client-side verification. The verifier for raw keys can start as "accept any, extract fingerprint" and add fingerprint-pinning later.See ADR-030 §6 for the fingerprint normalization details.
-
-
Cross-references: ADR-014, ADR-017, ADR-027, ADR-029, ADR-030, client-and-adapters.md, endpoint.md, auth.md