diff --git a/docs/architecture/crates/core/config.md b/docs/architecture/crates/core/config.md index 6b1c7a5..f71e744 100644 --- a/docs/architecture/crates/core/config.md +++ b/docs/architecture/crates/core/config.md @@ -13,22 +13,46 @@ Immutable configuration resolved at startup. Cannot be changed without restartin ```rust pub struct StaticConfig { - /// Bind address for the QUIC endpoint (e.g., "0.0.0.0:4433"). - pub listen_addr: SocketAddr, + /// Bind address for the quinn endpoint (e.g., "0.0.0.0:4433"). + /// None if the quinn endpoint is not configured (iroh-only node). + pub listen_addr: Option, - /// Path to TLS certificate file (PEM). - /// Required for QUIC+TLS. The endpoint will not start without TLS configuration. - pub tls_cert: Option, + /// TLS identity mode for the quinn endpoint. + /// Required if listen_addr is Some. + pub tls_identity: Option, - /// Path to TLS private key file (PEM). - /// Required alongside tls_cert. - pub tls_key: Option, + /// iroh relay URL (e.g., "https://relay.iroh.network/"). + /// None if the iroh endpoint is not configured. + pub iroh_relay: Option, /// Drain timeout for graceful shutdown (default: 2 seconds). pub drain_timeout: Duration, } + +/// TLS identity configuration for the quinn endpoint. +pub enum TlsIdentity { + /// X.509 certificate for domain-facing identity. + /// Required for browser/WebTransport clients. + X509 { + cert: PathBuf, + key: PathBuf, + }, + + /// RFC 7250 raw Ed25519 public key. + /// No domain, no CA, no cert renewal. Key = identity. + /// Same model as iroh's NodeId, but for direct QUIC connections. + RawKey(SecretKey), + + /// Self-signed X.509 cert for development. + /// Generated on startup, not validated by external clients. + SelfSigned, +} ``` +### Why `TlsIdentity` instead of `tls_cert`/`tls_key` options + +The original `tls_cert: Option` / `tls_key: Option` assumed X.509 was the only TLS identity model. RFC 7250 raw public keys (used by iroh, supported by rustls) provide an alternative: Ed25519 key as identity, no X.509, no CA, no domain. This is a separate mode, not just "no cert." + ### Key differences from reference implementation The reference `StaticConfig` (in `alknet-main/crates/alknet-core/src/config/static_config.rs`) is SSH-centric: it holds `host_key`, `host_key_algorithm`, `proxy_config`, `stealth`, `transport_mode`, and `listeners`. The new model removes all of these: @@ -36,8 +60,7 @@ The reference `StaticConfig` (in `alknet-main/crates/alknet-core/src/config/stat - **No `host_key`/`host_key_algorithm`**: SSH host keys are managed by the SSH handler, not by core config. The endpoint uses TLS certs, not SSH host keys. - **No `proxy_config`**: Outbound proxy is an SSH-specific concern (SOCKS5/HTTP CONNECT forwarding). Not in core config. - **No `stealth`**: ALPN eliminates the need for stealth/byte-peeking. See [ADR-001](../../decisions/001-alpn-protocol-dispatch.md). -- **No `transport_mode`/`listeners`**: The old `ServeTransportMode` and `ListenerConfig` enum are replaced by a single `listen_addr`. QUIC+TLS+ALPN replaces multiple listener types. See [ADR-010](../../decisions/010-alpn-router-and-endpoint.md). -- **No `iroh_relay`**: iroh transport is deferred (OQ-05). The v1 endpoint uses quinn directly. +- **No `transport_mode`/`listeners`**: The old `ServeTransportMode` and `ListenerConfig` enum are replaced by `listen_addr` (quinn) and `iroh_relay` (iroh). Both are optional — a node can use either or both. See [ADR-010](../../decisions/010-alpn-router-and-endpoint.md). ### Construction diff --git a/docs/architecture/crates/core/endpoint.md b/docs/architecture/crates/core/endpoint.md index 31630cf..7095d04 100644 --- a/docs/architecture/crates/core/endpoint.md +++ b/docs/architecture/crates/core/endpoint.md @@ -161,13 +161,31 @@ A key distinction that the ALPN model makes explicit: | Layer | Purpose | Mechanism | |-------|---------|-----------| -| **Network identity** | How a client finds and verifies the node | TLS cert (quinn), NodeId (iroh) | +| **Network identity** | How a client finds and verifies the node | X.509 cert (domain) or RFC 7250 raw key (Ed25519) or iroh NodeId | | **Auth identity** | Who the peer is and what they can do | SSH key, API token, certificate (handlers) | -The TLS cert is the node's network-facing identity — it's what `alknet.example.com` resolves to. It's NOT the node's authentication identity. Auth happens inside the handler via `IdentityProvider`. +The TLS cert (or raw public key, or NodeId) is the node's network-facing identity. It's NOT the node's authentication identity. Auth happens inside the handler via `IdentityProvider`. This matches the reference implementation: the TLS cert encrypts and camouflages, but SSH key exchange handles the actual authentication. +## RFC 7250: Raw Public Keys in TLS + +iroh uses RFC 7250 raw public keys instead of X.509 certificates for TLS. The implementation is ~100 lines (see `iroh/iroh/src/tls/resolver.rs`): take an Ed25519 key, wrap its SPKI public key as a `CertificateDer`, tell rustls `only_raw_public_keys() -> true`. No X.509, no CAs, no domain names, no cert renewal. + +rustls already supports RFC 7250. This means the quinn endpoint can also use raw Ed25519 public keys instead of X.509 certs: + +- **No domain required**: A node without a domain name can use raw public keys for the quinn path — key-based identity, but with direct QUIC over UDP instead of relay-assisted connections. +- **Key = identity**: The Ed25519 public key IS the node's identity. No CA trust chain, no cert expiry. The key can be derived from alknet-vault. +- **X.509 is optional**: Domain-facing identity (replicators, public services) uses X.509 certs. Key-based identity (personal nodes, P2P) uses raw public keys. Both work with the same quinn endpoint. +- **Browser limitation**: Browsers don't support RFC 7250. For browser/WebTransport clients, X.509 certs are needed. For alknet-native clients, raw public keys work fine. + +This reframes the connectivity model. The quinn and iroh paths share the same key-based identity model via RFC 7250. They're distinguished by **connection establishment** (direct UDP vs relay-assisted), not by identity: + +| Path | Connection establishment | Identity (domain-facing) | Identity (key-facing) | +|------|------------------------|------------------------|---------------------| +| quinn | Direct UDP, public IP | X.509 cert (domain name) | RFC 7250 raw key | +| iroh | Relay-assisted P2P | N/A | RFC 7250 raw key (NodeId) | + ## TLS Certificate Provisioning For the quinn endpoint, `StaticConfig` provides TLS configuration via file paths: diff --git a/docs/architecture/decisions/010-alpn-router-and-endpoint.md b/docs/architecture/decisions/010-alpn-router-and-endpoint.md index b6ede2d..0fac869 100644 --- a/docs/architecture/decisions/010-alpn-router-and-endpoint.md +++ b/docs/architecture/decisions/010-alpn-router-and-endpoint.md @@ -132,6 +132,24 @@ This is the same model as the reference implementation's TLS mode: the cert make For the iroh endpoint, the `NodeId` serves as network identity. No TLS cert is needed — iroh's QUIC uses the NodeId for connection verification. +### RFC 7250: Raw Public Keys in TLS + +iroh uses RFC 7250 raw public keys instead of X.509 certificates for TLS. The implementation is strikingly simple (see `iroh/iroh/src/tls/resolver.rs`): take an Ed25519 key, wrap its SPKI public key as a `CertificateDer`, and tell rustls `only_raw_public_keys() -> true`. No X.509, no CAs, no domain names, no cert renewal. + +rustls already supports RFC 7250. This means the quinn endpoint can also use raw Ed25519 public keys instead of X.509 certs. The implications: + +1. **No domain required.** A node without a domain name can use raw public keys for the quinn path — the same key-based identity model as iroh, but with direct QUIC over UDP instead of relay-assisted connections. +2. **Key = identity.** The Ed25519 public key IS the node's identity. No CA trust chain, no cert expiry, no renewal. The key is derived from alknet-vault or generated at startup. +3. **X.509 is optional.** Domain-facing identity (for replicators, public services) uses X.509 certs. Key-based identity (for personal nodes, P2P) uses raw public keys. Both work with the same quinn endpoint. +4. **Browser compatibility.** Browsers don't support RFC 7250 — they require X.509. For browser/WebTransport clients, X.509 certs are needed. For alknet-native clients, raw public keys work fine. + +This reframes the connectivity model. The quinn and iroh paths are not distinguished by their identity model (both can use Ed25519 keys). They're distinguished by how the connection is established: + +| Path | Connection establishment | Identity model (v1) | Identity model (future) | +|------|------------------------|--------------------|-------------------------| +| quinn | Direct UDP, public IP | X.509 (domain) | X.509 or RFC 7250 raw key | +| iroh | Relay-assisted P2P | RFC 7250 raw key (NodeId) | Same | + ### Error taxonomy ```rust