Expand native auth and benchmark gates
This commit is contained in:
+47
-19
@@ -93,11 +93,13 @@ Tunables: `scripts/bench-local.sh [ITERATIONS]` (default 20), `DOSH_BENCH_JSON=1
|
||||
### `make bench-docker-ssh` / `make bench-docker-mosh` (`scripts/ci-docker-ssh-bench.sh`)
|
||||
|
||||
Builds one Ubuntu image with OpenSSH, `dosh-server`, `dosh-auth` (and Mosh for the
|
||||
`-mosh` target), then runs `ssh_true_ms`, cold + ControlMaster `dosh_attach_ms`,
|
||||
`dosh_cached_attach_ms`, and optionally `mosh_start_true_ms` against the same
|
||||
container, key, and loopback network path. This is the gate CI enforces; it asserts
|
||||
cold Dosh stays within 500 ms of SSH and that cached attach stays under a small
|
||||
budget. See `README.md` "Develop" for the exact invocations.
|
||||
`-mosh` target), then runs `ssh_true_ms`, cold + ControlMaster SSH-bootstrap
|
||||
`dosh_attach_ms`, one-time `dosh trust` followed by native-cold
|
||||
`dosh_cold_native_ms`, `dosh_cached_attach_ms`, and optionally
|
||||
`mosh_start_true_ms` against the same container, key, and loopback network path.
|
||||
This is the gate CI enforces; it asserts cold SSH-bootstrap Dosh stays within
|
||||
500 ms of SSH, native-cold Dosh beats SSH mean by default, and cached attach stays
|
||||
under a small budget. See `README.md` "Develop" for the exact invocations.
|
||||
|
||||
## Methodology and caveats
|
||||
|
||||
@@ -130,8 +132,8 @@ budget. See `README.md` "Develop" for the exact invocations.
|
||||
|
||||
## Sample results (loopback, self-contained)
|
||||
|
||||
Captured with `make bench-local` (`scripts/bench-local.sh 30`), all times in
|
||||
milliseconds, 30 samples per metric.
|
||||
Captured with `make bench-local` (`scripts/bench-local.sh 20`), all times in
|
||||
milliseconds, 20 samples per metric.
|
||||
|
||||
- Machine: Intel Core i5-9500 @ 3.00 GHz, 6 cores
|
||||
- OS: Ubuntu 24.04.4 LTS, Linux 6.8.0-124-generic, x86_64
|
||||
@@ -141,27 +143,24 @@ milliseconds, 30 samples per metric.
|
||||
|
||||
| Metric | n | min | median | p95 | mean | max |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `dosh_cold_native_ms` | 30 | 8.10 | 9.01 | 10.40 | 9.18 | 10.82 |
|
||||
| `dosh_cached_attach_ms` | 30 | 2.73 | 2.96 | 3.25 | 2.96 | 3.30 |
|
||||
| `dosh_local_attach_ms` | 30 | 2.66 | 2.78 | 3.24 | 2.87 | 3.33 |
|
||||
| `dosh_cold_native_ms` | 20 | 8.32 | 8.77 | 9.34 | 8.82 | 9.52 |
|
||||
| `dosh_cached_attach_ms` | 20 | 2.83 | 3.23 | 3.75 | 3.24 | 3.77 |
|
||||
| `dosh_local_attach_ms` | 20 | 2.84 | 3.21 | 3.96 | 3.28 | 3.98 |
|
||||
|
||||
Raw samples (ms):
|
||||
|
||||
```
|
||||
dosh_cold_native_ms:
|
||||
8.32, 8.23, 10.31, 10.37, 8.83, 8.81, 9.20, 9.04, 10.14, 8.98, 10.82, 9.87,
|
||||
10.22, 10.42, 9.76, 9.09, 9.19, 8.94, 8.69, 8.67, 8.74, 9.33, 9.25, 8.92, 8.39,
|
||||
8.55, 8.38, 9.81, 8.17, 8.10
|
||||
8.82, 8.60, 8.69, 8.71, 9.33, 8.82, 8.90, 8.64, 8.39, 8.75, 8.79, 8.70, 8.64,
|
||||
9.52, 8.72, 8.32, 9.06, 8.93, 8.96, 9.04
|
||||
|
||||
dosh_cached_attach_ms:
|
||||
2.99, 2.99, 2.93, 2.87, 2.95, 2.80, 2.80, 2.90, 3.10, 2.73, 3.19, 2.80, 2.87,
|
||||
2.82, 2.89, 3.03, 3.06, 3.21, 2.97, 2.83, 3.00, 2.82, 3.04, 2.97, 3.03, 3.24,
|
||||
3.30, 2.73, 2.79, 3.25
|
||||
3.04, 3.06, 2.98, 2.91, 2.96, 2.95, 3.05, 3.66, 3.37, 2.88, 2.83, 3.16, 3.49,
|
||||
3.30, 3.77, 3.32, 3.49, 3.75, 3.56, 3.33
|
||||
|
||||
dosh_local_attach_ms:
|
||||
3.05, 3.00, 2.84, 3.04, 3.33, 2.89, 2.76, 2.74, 2.73, 3.32, 3.14, 2.75, 2.83,
|
||||
2.88, 2.99, 2.77, 2.75, 2.79, 2.69, 2.78, 2.75, 2.77, 2.75, 2.77, 3.03, 2.75,
|
||||
2.94, 2.74, 2.82, 2.66
|
||||
3.08, 3.96, 3.36, 3.30, 2.88, 2.99, 3.96, 3.98, 3.25, 2.84, 3.29, 3.59, 3.65,
|
||||
3.47, 3.13, 2.92, 2.87, 2.91, 2.98, 3.18
|
||||
```
|
||||
|
||||
Reading these numbers: cold native auth is ~9 ms because it pays the native
|
||||
@@ -171,3 +170,32 @@ overhead floor. Over a real link, expect cached attach ≈ this floor + one netw
|
||||
round trip — which is exactly the "near network RTT" target in the spec. There is
|
||||
no SSH/Mosh baseline in this loopback table because those paths need an SSH server;
|
||||
use `make bench-docker-ssh` / `make bench-docker-mosh` for the head-to-head.
|
||||
|
||||
## Sample results (Docker SSH/Mosh comparison)
|
||||
|
||||
Captured with `make bench-docker-mosh`, all times in milliseconds. This is the
|
||||
same-container comparison gate: one generated key, one OpenSSH server, one
|
||||
`dosh-server`, loopback-published TCP/UDP ports.
|
||||
|
||||
| Metric | n | min | median | p95 | mean | max |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `ssh_true_ms` (cold SSH baseline for native-cold gate) | 5 | 214.53 | 216.84 | 220.55 | 217.60 | 220.91 |
|
||||
| `dosh_cold_native_ms` | 5 | 8.62 | 8.96 | 9.78 | 9.15 | 9.88 |
|
||||
| `dosh_cached_attach_ms` | 10 | 8.41 | 8.83 | 9.52 | 8.90 | 9.53 |
|
||||
| `mosh_start_true_ms` | 3 | 528.03 | 530.87 | 539.23 | 533.02 | 540.16 |
|
||||
|
||||
Raw samples (ms):
|
||||
|
||||
```
|
||||
ssh_true_ms (native-cold gate):
|
||||
216.84, 216.61, 214.53, 220.91, 219.09
|
||||
|
||||
dosh_cold_native_ms:
|
||||
9.39, 8.88, 8.96, 8.62, 9.88
|
||||
|
||||
dosh_cached_attach_ms:
|
||||
8.44, 8.41, 8.80, 8.48, 9.53, 9.51, 8.85, 8.69, 9.33, 8.96
|
||||
|
||||
mosh_start_true_ms:
|
||||
540.16, 528.03, 530.87
|
||||
```
|
||||
|
||||
+17
-10
@@ -7,16 +7,22 @@
|
||||
> - Milestone 1 — host identity and trust: **done.** Host key generation, `dosh trust`,
|
||||
> `known_hosts`, and mismatch hard-fail are implemented.
|
||||
> - Milestone 2 — native user auth: **done.** `ClientHello`/`ServerHello`/`UserAuth`/
|
||||
> `AuthOk`, ssh-agent and encrypted-key Ed25519, and `authorized_keys` verification
|
||||
> exist. ECDSA/RSA user keys are still pending (Ed25519 only today).
|
||||
> `AuthOk`, ssh-agent and OpenSSH identity-file auth for Ed25519, ECDSA P-256,
|
||||
> and RSA-SHA2, plus `authorized_keys` verification, exist.
|
||||
> - Milestone 3 — default native auth: **done.** `auth_preference = "native,ssh"` is
|
||||
> the default with explicit, visible SSH fallback. Cold-auth benchmark gates are
|
||||
> pending (Track C / `BENCHMARKS.md`).
|
||||
> - Milestone 4 — forwarding: **done.** Stream mux, `-L`, `-R`, `-D`, `-N`, `-f`, and
|
||||
> per-stream flow control are implemented; hostile-network and load tests pending.
|
||||
> - Milestone 5 — hardening: **in progress.** Full per-IP token-bucket rate limiting,
|
||||
> protocol VERSION negotiation hardening, fuzzing in CI, and external review are not
|
||||
> yet complete. The threat model is published (`docs/THREAT_MODEL.md`).
|
||||
> the default with explicit, visible SSH fallback. Local and Docker benchmark gates
|
||||
> cover cached attach, SSH fallback, and native cold auth (Track C /
|
||||
> `BENCHMARKS.md`).
|
||||
> - Milestone 4 — forwarding: **implemented.** Stream mux, `-L`, `-R`, `-D`, `-N`,
|
||||
> `-f`, and per-stream flow control exist; terminal-priority/load regressions are
|
||||
> covered, and hostile-network/long-soak proof is still being expanded before parity
|
||||
> is claimed.
|
||||
> - Milestone 5 — hardening: **partly done.** Per-IP token-bucket rate limiting,
|
||||
> fail-closed protocol-version checks, parser fuzz targets, fuzz-smoke CI, scripted
|
||||
> TUI transport tests, forwarding load/priority tests, and independent persistent
|
||||
> session restart tests exist. External review, long soak, and future multi-version
|
||||
> compatibility policy are not yet complete. The threat model is published
|
||||
> (`docs/THREAT_MODEL.md`).
|
||||
> - Milestone 6 — workflow parity: **mostly done.** `dosh doctor`, host-trust
|
||||
> management, and the encrypted-key prompt flow exist; cross-OS daily-driver soak is
|
||||
> ongoing.
|
||||
@@ -124,7 +130,8 @@ Native v1 must be boring under real use:
|
||||
- A closed laptop must not kill the remote session.
|
||||
- A client crash must not kill the remote session.
|
||||
- A server restart must not kill the remote session when `persist_sessions` is on
|
||||
(the default): each session's shell runs in a detached per-session *holder*
|
||||
(currently opt-in until stress-tested): each session's shell runs in a detached
|
||||
per-session *holder*
|
||||
process whose PTY master fd the server passes back to itself via SCM_RIGHTS, so
|
||||
the shell + scrollback survive a server crash/upgrade/`systemctl restart` and a
|
||||
reattaching client lands on the same shell with its screen restored. With
|
||||
|
||||
+41
-34
@@ -8,14 +8,14 @@ The plan for replacing the day-to-day SSH workflow with native Dosh authenticati
|
||||
and forwarding is specified in `docs/NATIVE_V1_SPEC.md`, and the published threat
|
||||
model is in `docs/THREAT_MODEL.md`. Native v1 is now substantially implemented:
|
||||
native key-exchange + user auth, host-key pinning/trust, `-L`/`-R`/`-D` forwarding,
|
||||
and `dosh doctor` all exist (see the feature matrix and the verification-checklist
|
||||
status table below). It is **not yet fully verified**: per-IP token-bucket rate
|
||||
limiting, protocol-version negotiation hardening, fuzzing in CI, and external review
|
||||
are still open. Until the verification checklist (`NATIVE_V1_SPEC.md` section 16) is
|
||||
green and that review is done, Dosh's defensible public security claim remains fast
|
||||
encrypted native attach/reconnect with SSH-equivalent transport security and an
|
||||
explicit SSH bootstrap fallback — not a fully verified, externally reviewed SSH
|
||||
replacement.
|
||||
`dosh doctor`, token-bucket auth rate limiting, and fuzz-smoke CI all exist (see the
|
||||
feature matrix and the verification-checklist status table below). It is **not yet
|
||||
fully verified**: long sleep/roaming soak, adversarial UDP forwarding tests, deeper
|
||||
fuzzing, protocol-version compatibility policy, and external review are still open.
|
||||
Until the verification checklist (`NATIVE_V1_SPEC.md` section 16) is green and that
|
||||
review is done, Dosh's defensible public security claim remains fast encrypted native
|
||||
attach/reconnect with SSH-equivalent transport security and an explicit SSH bootstrap
|
||||
fallback — not a fully verified, externally reviewed SSH replacement.
|
||||
|
||||
## Objective Benchmarks
|
||||
|
||||
@@ -58,31 +58,31 @@ with ordinary SSH.
|
||||
| Feature | Mosh | Dosh now | Public status |
|
||||
| --- | --- | --- | --- |
|
||||
| SSH-based first authentication | yes | yes | ready |
|
||||
| Native UDP key auth (no SSH per attach) | no | yes, Ed25519 via ssh-agent or encrypted key | implemented; pending full verification |
|
||||
| Native UDP key auth (no SSH per attach) | no | yes, Ed25519, ECDSA P-256, and RSA-SHA2 via ssh-agent or OpenSSH identity files | implemented; pending full verification |
|
||||
| Dosh host-key pinning and trust | no | yes, `known_hosts` + `dosh trust` + mismatch hard-fail | implemented |
|
||||
| `authorized_keys` policy enforcement | no | yes, `from=`/`no-port-forwarding`/`permitopen=`, unsupported fail closed | implemented |
|
||||
| `dosh doctor` diagnostics | no | yes, config/auth/UDP/forwarding-policy check | implemented |
|
||||
| Encrypted UDP terminal data | yes | yes | ready |
|
||||
| Roaming by client address change | yes | yes | needs more hostile-network tests |
|
||||
| Roaming by client address change | yes | yes | implemented; needs more hostile-network/soak proof |
|
||||
| Survive sleep or network loss | yes | yes | needs long-running soak tests |
|
||||
| Fast repeat attach without SSH | no | yes, via attach tickets | core differentiator |
|
||||
| Resident server daemon | no | yes | core differentiator |
|
||||
| One UDP port for all sessions | port range by default | yes | ready |
|
||||
| Fresh session by default | yes | yes | ready |
|
||||
| Named persistent sessions | no built-in shared session model | yes | ready |
|
||||
| Multiple clients on one session | no | yes | needs conflict-policy docs |
|
||||
| Named persistent sessions | no built-in shared session model | yes, plus opt-in server-restart holders | implemented; holder mode needs stress-testing |
|
||||
| Multiple clients on one session | no | yes | implemented; needs conflict-policy docs |
|
||||
| View-only clients | no | yes | ready |
|
||||
| Full-screen TUI correctness | yes | improving | must stay green before public push |
|
||||
| Full-screen TUI correctness | yes | yes, scripted transport coverage for control sequences | implemented; needs broader app matrix |
|
||||
| Predictive local echo | mature | guarded printable-only opt-in | not parity |
|
||||
| Non-destructive disconnect UI | yes | not currently | needed |
|
||||
| Non-destructive disconnect UI | yes | yes, bottom-row save/restore status line | implemented |
|
||||
| Unicode edge-case handling | strong | basic terminal emulator dependent | not parity |
|
||||
| X11 forwarding | no | no | non-goal unless tunneled separately |
|
||||
| SSH agent forwarding | no | no | planned as forwarding channel |
|
||||
| Local TCP forwarding, `-L` | no | yes, native encrypted stream mux | implemented; needs hostile-network tests |
|
||||
| Remote TCP forwarding, `-R` | no | yes, loopback bind by default | implemented; needs hostile-network tests |
|
||||
| Dynamic SOCKS forwarding, `-D` | no | yes, SOCKS5 over native streams | implemented; needs hostile-network tests |
|
||||
| SSH agent forwarding | no | yes, explicit `-A` / `forward_agent` plus server allow-list | implemented; opt-in only |
|
||||
| Local TCP forwarding, `-L` | no | yes, native encrypted stream mux | implemented; load/priority tested, adversarial UDP pending |
|
||||
| Remote TCP forwarding, `-R` | no | yes, loopback bind by default | implemented; adversarial UDP pending |
|
||||
| Dynamic SOCKS forwarding, `-D` | no | yes, SOCKS5 over native streams | implemented; adversarial UDP pending |
|
||||
| Forward-only / background forwarding, `-N` / `-f` | no | yes, `-f` requires `-N` | implemented |
|
||||
| Per-stream flow control / terminal priority | no | yes, windowed credit per stream | implemented; needs load tests |
|
||||
| Per-stream flow control / terminal priority | no | yes, windowed credit per stream | implemented; covered by blocked-stream and local-forward load tests |
|
||||
|
||||
## SSH Config Inheritance
|
||||
|
||||
@@ -131,7 +131,8 @@ Implemented:
|
||||
Still open before claiming forwarding parity:
|
||||
|
||||
- A dedicated dropped/reordered/replayed-UDP forwarding test suite.
|
||||
- Load tests proving large forwarded transfers add no visible terminal input lag.
|
||||
- More real-host load soak. The integration suite already covers terminal-priority
|
||||
behavior while a local forward is under blocked-stream pressure.
|
||||
|
||||
## Native v1 Verification Checklist Status
|
||||
|
||||
@@ -145,15 +146,17 @@ from code; in progress = partially implemented; pending = not yet implemented.
|
||||
| Known host-key mismatch hard fails | done | `KnownHostStatus::Mismatch` aborts; `trust_host` refuses overwrite without `--replace`. |
|
||||
| Native Ed25519 auth via ssh-agent | done | `src/ssh_agent.rs` signs the user-auth transcript. |
|
||||
| Native Ed25519 auth via encrypted key prompt | done | `load_ed25519_identity_with_passphrase` decrypts OpenSSH keys. |
|
||||
| Native ECDSA P-256 auth | done | ssh-agent and OpenSSH identity-file paths are wired; `native_user_auth_accepts_ecdsa_p256_private_key` verifies the direct key path. |
|
||||
| Native RSA-SHA2 auth | done | ssh-agent requests `rsa-sha2-512`; direct OpenSSH RSA identities sign with `rsa-sha2-512`; legacy SHA-1 `ssh-rsa` signatures are rejected. |
|
||||
| Removed authorized key can no longer authenticate | done | Covered by `native_user_auth_accepts_authorized_key_and_rejects_removed_key`. |
|
||||
| Unsupported authorized-key options fail closed | done | `ensure_native_allowed` bails on any unsupported option. |
|
||||
| Replayed handshake packets rejected | done | Handshake is transcript-bound and signature-verified; pending entries TTL-evicted. |
|
||||
| Replayed transport packets rejected | done | `ReplayWindow` (128-wide) over per-direction counter. |
|
||||
| Stale encrypted packets after reconnect ignored, not fatal | done | `session_key_id` mismatch drops the packet instead of erroring fatally. |
|
||||
| Client IP/port change preserves session | done | Server matches by `ClientId`/session key id, updates endpoint. |
|
||||
| Native cold auth beats cold `ssh host true` | pending | Benchmark gate not yet run for native cold path (Track C / `BENCHMARKS.md`). |
|
||||
| Cached attach near network RTT | pending | Same benchmark dependency. |
|
||||
| `-L` works without delaying terminal input | in progress | Implemented with per-stream window; load proof pending. |
|
||||
| Native cold auth beats cold `ssh host true` | done | Docker gate runs `dosh-bench --cold-native` after one-time `dosh trust` and requires Dosh mean <= SSH mean. |
|
||||
| Cached attach near network RTT | done | Local loopback samples are ~3 ms; Docker cached gate is under 25 ms. See `docs/BENCHMARKS.md`. |
|
||||
| `-L` works without delaying terminal input | done | Per-stream windowing plus `native_local_forward_bulk_load_does_not_delay_interactive_terminal` and blocked-stream priority regression. |
|
||||
| `-R` enforces bind and permission policy | done | `remote_bind_allowed` + `start_remote_forwards` policy checks. |
|
||||
| `-N -L` does not allocate a PTY | done | `forward-only` mode skips PTY allocation. |
|
||||
| `-f -N -L` backgrounds only after listener readiness | done | `spawn_background_forwarder` waits for a readiness token. |
|
||||
@@ -161,26 +164,30 @@ from code; in progress = partially implemented; pending = not yet implemented.
|
||||
| `dosh doctor` identifies UDP-blocked/auth-denied/mismatch/forwarding-denied | done | `run_doctor_command` reports each state. |
|
||||
| Closing laptop 30+ min does not kill session | in progress | Long `client_timeout_secs` + resume; 30-min soak evidence pending. |
|
||||
| Three concurrent terminals independent unless named | done | Generated session names per attach; named sessions shared on purpose. |
|
||||
| Large forwarded transfers add no visible input lag | in progress | Per-stream flow control exists; load test pending. |
|
||||
| Fuzz targets run in CI | pending | No `fuzz/` dir; CI runs fmt/test/build/bench only. |
|
||||
| Large forwarded transfers add no visible input lag | done | Covered by the local-forward bulk-load integration test; still needs real-host soak before launch claims. |
|
||||
| Fuzz targets run in CI | done | `fuzz/` has parser/auth targets and CI runs a nightly `fuzz-smoke` job when cargo-fuzz is available. |
|
||||
| Threat model updated with accepted residual risks | done | `docs/THREAT_MODEL.md`. |
|
||||
|
||||
Additional security hardening tracked outside the section 16 list:
|
||||
|
||||
- Full per-IP token-bucket rate limiting: in progress (another track). Today only
|
||||
handshake-map eviction and a static `rate_limit_remaining` hint exist.
|
||||
- Protocol VERSION negotiation: in progress. Single version, fail-closed reject; no
|
||||
multi-version negotiation yet.
|
||||
- ECDSA P-256 / SHA-2 RSA user keys: pending. Ed25519 only today.
|
||||
- Full per-IP token-bucket rate limiting: implemented for native auth and covered by
|
||||
unit/integration tests. It still needs real-host tuning under abusive traffic.
|
||||
- Protocol VERSION handling: current behavior is single-version, fail-closed reject
|
||||
at the packet/header and native-handshake layers. Future multi-version
|
||||
compatibility/downgrade policy is still open.
|
||||
- ECDSA P-256 / SHA-2 RSA user keys: implemented for ssh-agent and OpenSSH
|
||||
identity-file native auth. RSA is compatibility-only and uses SHA-2 signatures;
|
||||
legacy SHA-1 `ssh-rsa` signatures are not accepted.
|
||||
|
||||
## Before Public Launch
|
||||
|
||||
- Keep `cargo test`, `make bench-docker-ssh`, and `make bench-docker-mosh` green.
|
||||
- Add a non-destructive disconnect indicator.
|
||||
- Run scripted TUI tests for alternate-screen apps, arrow keys, resize, mouse mode,
|
||||
bracketed paste, and terminal cleanup.
|
||||
- Keep scripted TUI tests green and add a broader app matrix for real alternate-screen
|
||||
tools.
|
||||
- Publish benchmark output with raw samples, not just averages.
|
||||
- Mark prediction as experimental until it has a real framebuffer model.
|
||||
- Land full per-IP token-bucket auth rate limiting and wire fuzz targets into CI.
|
||||
- Stress-test `persist_sessions = true` before making restart-survivable holders the
|
||||
default.
|
||||
- Tune the native auth token bucket under abusive real-host traffic.
|
||||
- Complete the native-v1 verification checklist above and an external security review
|
||||
before making any "native SSH replacement" claim (`NATIVE_V1_SPEC.md` section 17).
|
||||
|
||||
+27
-24
@@ -72,13 +72,13 @@ compromised endpoint or a malicious authorized peer.
|
||||
| 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. |
|
||||
| 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/Ed25519 crates only. |
|
||||
| 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. |
|
||||
|
||||
@@ -94,8 +94,9 @@ compromised endpoint or a malicious authorized peer.
|
||||
- **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.
|
||||
- **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.
|
||||
@@ -114,9 +115,12 @@ These reflect the code in `src/crypto.rs`, `src/native.rs`, `src/auth.rs`, and
|
||||
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.
|
||||
- **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 as `ssh-rsa` authorized keys, but
|
||||
native signatures must be `rsa-sha2-256` or `rsa-sha2-512`; legacy SHA-1
|
||||
`ssh-rsa` signatures 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.
|
||||
@@ -179,26 +183,25 @@ be evaluated honestly. Items here are *not* yet "green".
|
||||
|
||||
### 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
|
||||
- **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 policy is still simple.** 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.
|
||||
- **Fuzzing is smoke-tested in CI, not yet a deep campaign.** CI runs parser/auth
|
||||
fuzz targets briefly with nightly/cargo-fuzz when available. That catches obvious
|
||||
panics and parser robustness regressions; it is not a substitute for longer
|
||||
coverage-guided fuzz campaigns before public security claims.
|
||||
- **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-rsa` signatures.
|
||||
- **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
|
||||
|
||||
Reference in New Issue
Block a user