Files
alknet/docs/architecture/questions/029-callclient-tls-client-auth-and-remote-identity-verification.md
T
glm-5.2 1baa619ce9 docs(arch): decompose open-questions.md into per-OQ files under questions/
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.
2026-07-06 16:07:59 +00:00

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:

    1. 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's AcceptAnyCertVerifier already requests client certs and extracts the fingerprint — the gap was entirely on the client side (with_no_client_auth() → present the key). This activates the PeerEntry fingerprint → peer_id resolution path on quinn connections.

    2. Key-type-aware server cert verification. The client's ServerCertVerifier depends 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 WebPkiServerVerifier with the platform root store or a configured CA). AcceptAnyServerCertVerifier is 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.
    3. 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 as SHA256:<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_fingerprint already gets the NodeId. 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