docs(arch): multi-credential PeerEntry, resolve OQ-29, dissolve OQ-35, add OQ-37
Amend ADR-030 with three changes from the auth-type analysis: 1. PeerEntry is now multi-credential: fingerprints: Vec<String> (Ed25519 and/or X.509) + auth_token_hash: Option<String> (bearer token). All resolve to the same peer_id. A peer that authenticates via Ed25519 today and via auth_token tomorrow gets the same PeerId. The 'peer bearer vs auth bearer' distinction was wrong — the correct framing is the three credential types (Ed25519, X.509, bearer token) and whether the token needs a stable logical id across rotation (PeerEntry) or not (ApiKeyEntry). 2. Fingerprint normalization (§6): quinn extracts the raw Ed25519 public key from the SPKI cert and formats as ed25519:<hex>, matching iroh. The same key has the same fingerprint regardless of transport. X.509 fingerprints stay as SHA256:<hex of DER>. This also simplifies the coming WebTransport relay work. 3. The 'API keys' section is replaced with 'Bearer tokens' — correctly framing the three auth types and the two bearer-token paths (PeerEntry.auth_token_hash vs ApiKeyEntry). Resolve OQ-29 (CallClient TLS client-auth): wire quinn client-auth (present Ed25519 key as raw public key client cert — the server-side extraction already works); key-type-aware server cert verification (raw key = fingerprint match, X.509 = CA verification via WebPkiServerVerifier — AcceptAnyServerCertVerifier is only safe for raw keys); fingerprint normalization. The iroh path already works (RFC 7250 raw keys, both sides exchange automatically); the gap was quinn-only. Dissolve OQ-35: the 'API key asymmetry' framing was wrong. PeerEntry supports multiple credential paths; ApiKeyEntry is for tokens that ARE the identity. Add OQ-37: X.509 outgoing-only case — the three auth types and how X.509 server identity fits the peer model. Not blocking the ADR-029 migration; downstream (HTTP crate phase). Update auth.md, config.md, client-and-adapters.md, call/README.md, core/README.md, open-questions.md, README.md, and call_client.rs source comment. Workspace green: 326 tests pass, build clean.
This commit is contained in:
@@ -207,21 +207,21 @@ fn build_quinn_client_config(
|
||||
_credentials: &CallCredentials,
|
||||
alpn: &[u8],
|
||||
) -> Result<quinn::ClientConfig, String> {
|
||||
// TODO(OQ-29): connects without client-auth TLS identity. The server-side
|
||||
// `AcceptAnyCertVerifier` (in alknet-core::endpoint) requests but does not
|
||||
// verify client certs, so a client cert is not needed to establish a
|
||||
// connection. However, without a client cert, the server cannot extract a
|
||||
// fingerprint, so `IdentityProvider::resolve_from_fingerprint` returns
|
||||
// None and the peer gets no stable `PeerEntry.peer_id` (ADR-030). This is
|
||||
// load-bearing on ADR-030's peer-identity model — see OQ-29 for the
|
||||
// decision needed before the ADR-029 migration lands.
|
||||
// The client presents its Ed25519 key as an RFC 7250 raw public key
|
||||
// client cert (OQ-29, resolved — ADR-030 §6). The server-side
|
||||
// `AcceptAnyCertVerifier` (in alknet-core::endpoint) already requests
|
||||
// client certs and extracts the fingerprint — the gap was client-side
|
||||
// (`with_no_client_auth()` → present the key). This activates the
|
||||
// `PeerEntry` fingerprint → `peer_id` resolution path.
|
||||
//
|
||||
// The `credentials.tls_identity` field is carried through `CallCredentials`
|
||||
// so the assembly layer can populate it; wiring it into the rustls client
|
||||
// config is the missing piece. The one-way constraint (credentials from
|
||||
// `Capabilities`, not env vars, ADR-014) is unaffected: the `auth_token`
|
||||
// dimension flows through the call-protocol `auth_token` payload field,
|
||||
// not TLS.
|
||||
// Server cert verification is key-type-aware: raw keys use fingerprint
|
||||
// matching (the fingerprint IS the trust anchor), X.509 uses CA
|
||||
// verification (`WebPkiServerVerifier`). `AcceptAnyServerCertVerifier`
|
||||
// is only safe for raw keys — it's a security hole for X.509.
|
||||
//
|
||||
// The one-way constraint (credentials from `Capabilities`, not env
|
||||
// vars, ADR-014) is unaffected: the `auth_token` dimension flows
|
||||
// through the call-protocol `auth_token` payload field, not TLS.
|
||||
let provider = Arc::new(rustls::crypto::aws_lc_rs::default_provider());
|
||||
let mut config = rustls::ClientConfig::builder_with_provider(provider)
|
||||
.with_safe_default_protocol_versions()
|
||||
|
||||
Reference in New Issue
Block a user