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
2.6 KiB
Connection keys
A connection key is a short random seed from which both endpoints derive identical TLS material on the spot. It is the only value a user must copy/paste to stand up a tunnel.
Format
Connection keys are ~49 characters: the prefix rtun3. followed by a
base64url-encoded 32-byte seed:
rtun3.OH2TI3p1bM2dYjBcHxnLmZT9qKjW8tVvXQ0N7y4E3wA
The key ships no certificates. Instead, both endpoints derive an identical CA
from the seed and mint ephemeral leaf certificates locally (src/keyderive.rs):
- CA — Ed25519 keypair from the seed, self-signed and deterministic, so any two endpoints that share the seed produce the same CA.
- Server leaf — generated at
listenstartup, signed by the derived CA, with SANs for the bind address (and optional--advertisehost). - Client leaf — generated at
connectstartup, signed by the derived CA. - Auth token — derived as
sha256(seed || "rustunnel-auth-token")(first 16 bytes hex) and checked in the existing app-layer handshake.
Because the CA is derived from the seed, a connector holding a different seed cannot authenticate to a listener — possession of the key is what grants access.
Key abstractions
| Type/Function | File | Description |
|---|---|---|
ConnectionKey |
src/connkey.rs |
Seed value, new/encode/decode (rtun3) |
derive_server_material |
src/keyderive.rs |
CA + server leaf PEM for listen |
derive_client_material |
src/keyderive.rs |
CA + client leaf PEM for connect |
derive_auth_token |
src/keyderive.rs |
App-layer token derived from the seed |
looks_like_connection_key |
src/connkey.rs |
Quick check if a string starts with rtun3. |
Validation
ConnectionKey::decode validates:
- Prefix must be
rtun3.(legacyrtun1./rtun2.are rejected) - Base64url decode succeeds and yields exactly 32 bytes
- The seed is not all zeros
Integration
src/main.rs decodes a seed key (positional arg, --connection-key, or
RUSTUNNEL_KEY), derives the appropriate material at startup, and feeds the PEMs
into ServerTlsMaterial::Pem / ClientTlsMaterial::Pem. The TLS layer
(src/tls.rs) is unchanged. connect requires an explicit --target.
Entry points for modification
- To change derivation or signing parameters: modify
src/keyderive.rs. - To change the seed format or versioning: modify
src/connkey.rs.
Key source files
| File | Purpose |
|---|---|
src/connkey.rs |
Seed key struct, encoding, decoding |
src/keyderive.rs |
CA + leaf + token derivation from the seed |