Files
rustunnel/docs/superpowers/specs/2026-08-02-connection-key-rtun3-seed-design.md
T
bzuccaro 2bf8da739b
CI / cargo fmt (push) Canceled after 0s
CI / cargo clippy (macos-latest) (push) Canceled after 0s
CI / cargo clippy (ubuntu-latest) (push) Canceled after 0s
CI / cargo clippy (windows-latest) (push) Canceled after 0s
CI / cargo test (macos-latest) (push) Canceled after 0s
CI / cargo test (ubuntu-latest) (push) Canceled after 0s
CI / cargo test (windows-latest) (push) Canceled after 0s
CI / cargo build (macos-latest) (push) Canceled after 0s
CI / cargo build (ubuntu-latest) (push) Canceled after 0s
CI / cargo build (windows-latest) (push) Canceled after 0s
CI / cargo build --release (macos-latest) (push) Canceled after 0s
CI / cargo build --release (ubuntu-latest) (push) Canceled after 0s
CI / cargo build --release (windows-latest) (push) Canceled after 0s
CI / CLI smoke (macos-latest) (push) Canceled after 0s
CI / CLI smoke (ubuntu-latest) (push) Canceled after 0s
CI / CLI smoke (windows-latest) (push) Canceled after 0s
CI / Minimal E2E (macos-latest) (push) Canceled after 0s
CI / Minimal E2E (ubuntu-latest) (push) Canceled after 0s
CI / Minimal E2E (windows-latest) (push) Canceled after 0s
feat: replace connection keys with short seed-derived rtun3 keys
Connection keys are now a ~49-char seed (rtun3.) instead of a bundled
~1740-char certificate blob. Both endpoints deterministically derive an
identical Ed25519 CA from the seed and mint ephemeral server/client leaves
at startup (keyderive.rs); the app-layer auth token is derived from the seed.
Target is passed separately on connect (resocks-style).

- connkey.rs: rtun3 seed parse/format
- keyderive.rs: CA/server/client/token derivation
- keygen takes no args; connect requires --target
- remove miniz_oxide; TLS layer unchanged
- add determinism + key-based e2e + wrong-seed-rejected tests
- update wiki, README, design spec, CI smoke
2026-08-02 12:31:53 -06:00

77 lines
3.2 KiB
Markdown

# 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.<base64url(32-byte seed)>
```
- 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.<seed>`. 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.