# Connection Keys as Seeds (rtun3) — Design ## Goal Replace the bundled-certificate connection key (rtun1/rtun2, ~1740 chars) with a **~49-char seed key**. No certificates are ever shipped; both endpoints derive an identical CA from the seed and mint ephemeral leaf certs locally. Target is passed separately on `connect` (resocks-style). App-layer auth token is derived from the seed. Supersedes the rtun2 compression work entirely. Motivation: the connection key should be trivial to copy/paste. Compression could only halve the size; seed-derivation (as in resocks/kbtls) makes it ~35x smaller. ## Format ``` rtun3. ``` - Parse accepts only the `rtun3.` prefix; `rtun1.`/`rtun2.` are rejected. - Payload must decode to exactly 32 bytes; all-zero seed is rejected. - `keygen` now takes no arguments — it just prints a fresh seed key. ## Derivation (keyderive.rs) Deterministic and identical on both endpoints (same seed → same result): - **CA**: Ed25519 keypair from the seed (`Seed PKCS#8` → rcgen `KeyPair`), self-signed with fixed serial/CN/validity. Ed25519 signatures are deterministic, so both sides produce the **byte-identical CA**. - **Server leaf** (at `listen`): fresh random Ed25519 key signed by the derived CA, SANs = localhost/rustunnel/127.0.0.1 + bind IP + optional `--advertise` host. - **Client leaf** (at `connect`): fresh random Ed25519 key signed by the derived CA. - **Auth token**: `sha256(seed || "rustunnel-auth-token")` → first 16 bytes hex. Derived PEM strings feed the existing `build_server_config_from_pem` / `build_client_config_from_pem` builders — the TLS layer is unchanged. ## Command changes - `keygen`: `rustunnel keygen` → prints `rtun3.`. Removed `--target` and the CN flags (they only shaped bundled certs). - `connect`: `--target` is now required (there is no target in the key). - `listen --connection-key $KEY`: decode seed → derive server material + token. - Auto path (no certs/no key): generate fresh seed, print key + connect hint. - File-based mTLS (`generate --out`, `--cert/--key/--ca-cert`, `--auth-token`) unchanged. ## Files | File | Change | | ---- | ------ | | `Cargo.toml` | Remove `miniz_oxide` (no direct `ring` dep needed; rcgen provides crypto) | | `src/connkey.rs` | Rewrite: seed key parse/format (rtun3) | | `src/keyderive.rs` | New: CA/server/client/token derivation | | `src/redact.rs` | `is_connection_key` detects `rtun3.` | | `src/main.rs` | Rework listen/connect/keygen seed flow | | `src/tunnel.rs` | Add key-based e2e tests | ## Testing - Seed round-trip, format, reject bad/length/zero/rtun1/rtun2. - Determinism: same seed → identical CA + token; different seed → different. - Server/client material share the same CA. - Key-based e2e: derived material establishes an mTLS tunnel with no files. - Wrong-seed connector is rejected even with the correct token. - Redaction prefix tests. ## Docs Update wiki (`connection-keys.md`, `data-models.md`, `glossary.md`, `rustunnel-cli.md`, `getting-started.md`, `security.md`, `patterns-and-conventions.md`, `dependencies.md`, `overview/index.md`) and README. ## Out of scope - File-based mTLS, `insecure_skip_tls_verify`, performance tuning, key registry.