Files
dosh/docs/THREAT_MODEL.md
T
DuProcessandClaude Opus 4.8 828206f757 Publish threat model and refresh native v1 docs
Add docs/THREAT_MODEL.md deriving a publishable threat model from
NATIVE_V1_SPEC.md sections 4-6: assets, in/out-of-scope attackers,
security properties vs SSH (including where Dosh aims to exceed it),
cryptographic building blocks as implemented, and an honest
accepted-residual-risks / known-gaps section.

Refresh docs/PUBLIC_READINESS.md: feature matrix now reflects native
auth, host-key trust, authorized_keys policy, doctor, and -L/-R/-D
forwarding; add a per-item "Native v1 verification checklist status"
table mapping spec section 16 to done/in-progress/pending from code.

Update README.md status with a native v1 section and honest claim
posture pointing to THREAT_MODEL.md. Annotate NATIVE_V1_SPEC.md with a
v1 status block summarizing milestone progress. Point SPEC.md security
model and header at native auth and the threat model.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 10:27:40 -04:00

14 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 -D channels.
  • 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, ClientId association 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_keys and 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-client is 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 via ssh-agent or encrypted 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/Ed25519 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; 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 serialized ClientHello and ServerHello, binding traffic keys to the transcript.
  • AEAD: ChaCha20-Poly1305 (chacha20poly1305) for every encrypted packet and for sealed attach tickets. Nonces are derived as direction || 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, 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.
  • 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. ServerHello carries the host public key and an Ed25519 signature over dosh/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. UserAuth carries an Ed25519 signature over dosh/native/user-auth/v1 || ClientHello || ServerHello || UserAuth(unsigned). The server looks the public key up in authorized_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, and permitopen= 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-key permitopen= / 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 ClientId and 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's 0600 files (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)

  • Per-IP rate limiting is partial. The server evicts half-finished native handshakes on a TTL so a flood of ClientHello packets cannot grow the pending map without bound, and it reports a static rate_limit_remaining hint in ServerHello. A full per-source token-bucket limiter is in progress on another track and is not yet enforced. Until it lands, sustained auth flooding is mitigated only by the handshake-eviction TTL and OS-level limits.
  • Protocol VERSION negotiation is being hardened. The wire format pins a single protocol version: the packet header rejects any non-matching VERSION byte and the native handshake rejects any non-matching protocol_version. There is no multi-version negotiation yet, so cross-version interop and downgrade-resistance for future versions are still being designed. Today's behavior is fail-closed (reject), not silent downgrade.
  • Fuzzing is not yet wired into CI. CI currently runs format, tests, release build, and the Docker SSH benchmark gate. Fuzz targets for packet parsing, authorized-key parsing, known-host parsing, and handshake state (spec milestone 5) are being wired in and are not yet running in CI.
  • User-key algorithm coverage is Ed25519-only today. The spec permits ECDSA P-256 and (compatibility-only, SHA-2) RSA, but native auth currently accepts and produces ssh-ed25519 only. ECDSA/RSA support is pending. This is a parity gap, not a weakening of what is supported.
  • Hostile-network and long-soak integration tests are partial. Roaming, retransmit, resize, and multi-client tests exist; a dedicated adversarial drop/reorder/replay suite and 30-minute-sleep soak (spec section 16) are still being expanded.
  • 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.