15 KiB
Dosh Threat Model
This is the published threat model for Dosh native v1, derived from
docs/NATIVE_V1_SPEC.md sections 4-6. It states the assets Dosh protects, the
attackers it does and does not defend against, the security properties Dosh claims
relative to SSH, the cryptographic building blocks actually in use, and an honest
list of accepted residual risks and known gaps.
Dosh is a remote-login transport for Dosh-installed servers. It is intended to
replace the day-to-day ssh host workflow for terminals and TCP forwarding while
keeping OpenSSH as a recovery and bootstrap fallback. Dosh is not an
RFC-compatible SSH implementation and does not claim SSH's entire protocol security
surface. It claims security that is equivalent to, and in some respects stronger
than, SSH for the Dosh terminal and forwarding use case on hosts running
dosh-server.
1. Assets
Dosh protects:
- Terminal session contents. Keystrokes, command output, and the authoritative screen state for every named or generated session.
- Forwarded TCP streams. Bytes carried over
-L,-R, and-Dchannels. - User authentication credentials. The user's SSH/Dosh private keys and any ssh-agent identities. Dosh never sees private key material in plaintext on the wire; signatures are produced locally or by the agent.
- Server-issued credentials. Session keys,
ClientIdassociation state, server-sealed attach tickets, and the client-held attach-ticket PSK. - Server identity. The persistent Dosh host key (
~/.config/dosh/host_key) and the server secret used to seal attach tickets and derive bootstrap material. - Host-trust state. The client's pinned known-hosts file
(
~/.config/dosh/known_hosts). - Authorization policy.
~/.ssh/authorized_keys/~/.config/dosh/authorized_keysand the forwarding policy they encode.
2. Attackers
In scope (Dosh must defend against these)
- Passive network observer. May record all UDP traffic between client and server.
- Active network attacker. May spoof, drop, replay, reorder, or modify any packet, and may attempt to inject forged packets in either direction.
- NAT rebinding / roaming. Client source IP and port may change mid-session, including across sleep, network switch, and NAT timeout.
- Stolen attach-ticket cache without the user's private key. An attacker who reads a client cache copies a server-sealed ticket plus its PSK but does not have the user's SSH private key.
- Server restart and key rotation. Stale session keys, tickets, and replay state must not be usable after the server rotates its secret or host key.
- Malicious unauthenticated client flooding auth attempts. A peer that has no authorized key tries to exhaust server resources or guess credentials.
- Compromised low-privilege local user on a shared client. A different local user attempts to read Dosh credential caches on the same machine.
Out of scope (explicitly not defended against)
- Compromised client machine. If the endpoint running
dosh-clientis owned by the attacker, the attacker has the user's keys and terminal. - Compromised server account. If the login account on the server is owned, the attacker already has the shell Dosh would have given them.
- Malicious kernel, terminal emulator, or PTY implementation on either side.
- A server that was legitimately authorized and later turns malicious. Host-key pinning detects a substituted server, not a trusted server that decides to misbehave.
These exclusions match SSH's own boundaries: SSH likewise cannot protect a compromised endpoint or a malicious authorized peer.
3. Security Properties Claimed vs SSH
| Property | SSH | Dosh native v1 | Notes |
|---|---|---|---|
| Server authentication before trusting session data | yes | yes | Host key signs the handshake transcript; client verifies before sending user auth or accepting terminal bytes. |
| User authentication by private-key possession | yes | yes | Ed25519, ECDSA P-256, and RSA-SHA2 via ssh-agent or OpenSSH key; signature binds the full transcript. |
| Forward secrecy | yes | yes | Ephemeral X25519 per connection; long-term host/user keys never derive the traffic key. |
| AEAD on every post-handshake packet | yes | yes | ChaCha20-Poly1305 with per-direction, per-sequence nonces. |
| Replay protection | yes | yes | Sliding replay window over the AEAD packet counter, plus transcript-bound handshake. |
| Host-key pinning with explicit first use | TOFU, weakly tied to transport | yes, with explicit policy | Default refuses unknown host keys; TOFU only when trust_on_first_use is set; mismatch hard-fails and never auto-replaces. |
| No plaintext terminal bytes after handshake | yes | yes | All Frame/Input/stream packets are AEAD-sealed. |
| No custom cryptographic primitives | yes | yes | Standard X25519/HKDF-SHA256/ChaCha20-Poly1305/signature crates only. |
| Fail-closed downgrade behavior | yes | yes | Native auth failure surfaces an explicit error and SSH fallback is explicit; it never silently drops to an unauthenticated mode. |
| Fast resumption without re-auth | ControlMaster only | yes, native | Cached session/ticket attach skips a fresh round of public-key proof; this is a deliberate speed/security trade discussed in section 6. |
Where Dosh aims to exceed SSH for this use case
- Tighter transcript binding. A user-auth signature binds both ephemeral keys, both randoms, the server host key, requested user/session/mode/terminal size, selected algorithms, and protocol version into one transcript. This forecloses cross-protocol and partial-replay confusion classes for the narrow Dosh surface.
- Smaller attack surface. Dosh deliberately omits the full SSH transport/channel machinery, arbitrary subsystems, X11, SFTP/SCP, and forced-command subsystems. Fewer features means fewer parsers and fewer reachable states.
- Explicit, file-pinned host trust. Host trust is a first-class, inspectable
known-hosts entry with source provenance (
tofu/ssh/manual) and a hard-fail mismatch path, rather than the looser default TOFU behavior most SSH clients ship. - Modern primitives only. Ed25519 and X25519 by default; ECDSA P-256 and RSA-SHA2 are accepted for SSH-key compatibility; no DSA, no SHA-1 signatures, no CBC-and-MAC constructions.
Dosh does not claim generic SSH compatibility and must not be described as an SSH-protocol implementation.
4. Cryptographic Building Blocks (as implemented)
These reflect the code in src/crypto.rs, src/native.rs, src/auth.rs, and
src/protocol.rs, not just the spec.
- Key exchange: X25519 ephemeral-ephemeral (
x25519-dalek). The shared secret is checked for contributory behaviour; a non-contributory result is rejected. - Handshake/transport KDF: HKDF-SHA256 (
hkdf), salted with the SHA-256 of the serializedClientHelloandServerHello, binding traffic keys to the transcript. - AEAD: ChaCha20-Poly1305 (
chacha20poly1305) for every encrypted packet and for sealed attach tickets. Nonces are derived asdirection || sequence, giving a unique nonce per(key, direction, sequence). AES-GCM is reserved for later and is not selectable today. - Host-key signatures: Ed25519 (
ed25519-dalek) over the handshake transcript. - User-auth signatures: Ed25519, ECDSA P-256, and RSA-SHA2, produced either by
ssh-agent over a Unix socket (
src/ssh_agent.rs) or from an encrypted/plaintext OpenSSH private key (ssh-key). The signature covers the user-auth transcript described above. RSA public keys are matched asssh-rsaauthorized keys, but native signatures must bersa-sha2-256orrsa-sha2-512; legacy SHA-1ssh-rsasignatures are rejected. - Bootstrap auth (SSH fallback path): HMAC-SHA256 attach tokens and HKDF-SHA256 derived session keys, with attach tickets sealed under an HKDF-derived ticket key. Token comparison is constant-time.
- Hashing/transcript: SHA-256 (
sha2). - Randomness: OS CSPRNG via
rand::thread_rng()/OsRng.
No homegrown ciphers, MACs, padding schemes, or key derivation are used. No nonce or key pair is reused within a direction.
5. How the Properties Are Enforced (handshake and transport)
- Server authentication.
ServerHellocarries the host public key and an Ed25519 signature overdosh/native/server-hello/v1 || ClientHello || ServerHello(unsigned). The client verifies this signature and checks the host key against its pinned known-hosts entry before sending user auth or accepting terminal bytes. Unknown keys are refused unless TOFU is enabled; mismatches hard-fail with both fingerprints and the file path. - User authentication.
UserAuthcarries an Ed25519 signature overdosh/native/user-auth/v1 || ClientHello || ServerHello || UserAuth(unsigned). The server looks the public key up inauthorized_keys, enforces authorized-key options, then verifies the signature. A removed key can no longer authenticate. - Authorization options.
from=(with CIDR, glob, and negation),no-port-forwarding, andpermitopen=are enforced.command=is rejected for native terminal login. Any unrecognized restrictive option fails closed rather than being silently ignored. - Forwarding policy. The server enforces
allow_tcp_forwarding,allow_remote_forwarding, and a loopback-only default for remote binds (allow_remote_non_loopback_bind), in addition to per-keypermitopen=/no-port-forwarding. - Replay protection. A 128-wide sliding window over the per-direction packet counter rejects duplicates and stale sequences. Sequence 0 is never accepted.
- Stale-key tolerance. Each encrypted packet carries a
session_key_id; packets under an old key are dropped as "stale or wrong session key id" rather than treated as fatal decrypt failures, so reconnect after rotation is non-destructive. - Roaming. The server keys clients by
ClientIdand session key id, not by source address, and updates the endpoint after any valid encrypted packet from a new address — without weakening authentication, because the packet must still decrypt and verify.
6. Accepted Residual Risks and Known Gaps
These are stated openly so the public claim gate (NATIVE_V1_SPEC.md section 17) can
be evaluated honestly. Items here are not yet "green".
Accepted residual risks (by design)
- Attach tickets prove recent server-issued possession, not fresh private-key possession. A stolen client cache containing both the sealed ticket and its PSK can attach until the ticket expires (default TTL 24h, configurable down to zero) or until the server rotates its secret/host key or the user key is removed. This is the deliberate speed trade. It is bounded by TTL, scoped to host/user/session/mode, and can be disabled. SSH ControlMaster has an analogous live-socket exposure.
- Local cache confidentiality relies on filesystem permissions. Host keys,
server secret, known-hosts, and credential caches are written
0600. A same-machine attacker who can already read another user's0600files (e.g. via root) is out of scope, as with SSH's~/.ssh. - A trusted server that turns malicious is not detected. Host-key pinning detects substitution, not betrayal by an already-authorized server. This matches SSH.
Known gaps / work in progress (must close before the public claim)
- Native-auth rate limiting needs tuning, not first implementation. The server
enforces a per-source token bucket before expensive native-auth work, evicts
half-finished handshakes on a TTL, and reports remaining capacity in
ServerHello. It is covered by unit/integration tests, but still needs abusive real-host tuning before public hardening claims. - Protocol VERSION compatibility is intentionally single-version for v1. The
packet header rejects any non-matching
VERSIONbyte and the native handshake rejects any non-matchingprotocol_version; peers get a named upgrade error, not a silent downgrade.docs/PROTOCOL_VERSIONING.mddefines the bump rules and the post-v1 requirements for any future multi-version negotiation. - Deep fuzzing still needs launch evidence. CI runs parser/auth fuzz targets for
20 seconds per target on push/PR and 300 seconds per target on weekly/manual runs
when nightly/cargo-fuzz is available. That catches obvious panics and parser
robustness regressions; public security claims should cite a completed
make fuzz-deepor scheduled CI run with durations. - User-key algorithm coverage now matches the v1 target. Ed25519, ECDSA P-256,
and compatibility RSA-SHA2 native auth are implemented for ssh-agent and OpenSSH
identity files. RSA remains compatibility-only and deliberately rejects legacy
SHA-1
ssh-rsasignatures. - Forwarded stream data is not yet reliable across arbitrary UDP loss. Terminal
frames have retransmit coverage; forwarding streams have flow control and
replay/reorder tests, but dropped
StreamDatarecovery requires stream retransmission before Dosh should claim TCP-forwarding parity on lossy links. - Long-soak evidence is a launch gate. Roaming, retransmit, resize, and
multi-client tests exist, and
sleep_roaming_soak_30m/make soak-localprovide the 30-minute sleep/roaming gate. That gate should be run and published before public security/reliability claims. - No external security review yet. The spec's milestone 5 requires an external review checklist before public security claims. That review has not happened.
Auth posture
Native auth is opt-in alongside SSH fallback. auth_preference defaults to
native,ssh: Dosh tries the native authenticated path first and falls back to SSH
bootstrap explicitly and visibly when native auth is disabled, unavailable, or
rejected. Native auth failure never silently degrades to an unauthenticated mode.
Forwarding (-L/-R/-D) requires the native authenticated path and refuses to run
under --local-auth.
7. Verification and Public-Claim Status
Dosh may claim "native SSH replacement for Dosh-installed servers" only after the
conditions in NATIVE_V1_SPEC.md section 17 are met: native auth default on a real
host, SSH fallback available, the section 16 checklist green, this threat model
published, and benchmarks with raw samples for SSH cold, Dosh native cold, Dosh
cached attach, and Mosh startup.
Current status: this threat model is published (this document). The verification
checklist is not yet fully green — see the item-by-item status table in
docs/PUBLIC_READINESS.md ("Native v1 verification checklist status") and the known
gaps in section 6 above. Until the gaps close and an external review is complete,
Dosh's defensible public claim remains fast, encrypted native attach/reconnect with
SSH-equivalent transport security and SSH bootstrap fallback — not a fully verified,
externally reviewed SSH replacement.