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

53 lines
2.8 KiB
Markdown

# OQ-29: CallClient TLS Client-Auth and Remote-Identity Verification
- **Origin**: [client-and-adapters.md](crates/call/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](crates/call/client-and-adapters.md),
[endpoint.md](crates/core/endpoint.md), [auth.md](crates/core/auth.md)