diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6f8294f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,140 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +`rsh` is a self-hosted reverse-shell / remote-access system, similar in spirit to a lightweight +teleport/ssh-reverse-tunnel setup. A central **backend** exposes a public HTTP/WebSocket endpoint. +Target machines run a tiny **stub** binary that dials out to the backend and registers under a +named **session**. An **operator** uses the `rshc` CLI, authenticated with an SSH keypair, to list +sessions/connections and attach an interactive shell to any connected stub. + +## Workspace layout + +Cargo workspace with 4 crates (`Cargo.toml` at repo root): + +- `crates/rsh-types` — shared wire protocol types only (`StubMsg`, `BackendStubMsg`, `OpReq`, + `OpResp`, `OpEvent`, `OpMsg`, `BackendOpMsg`, ...), all serde-tagged enums (`#[serde(tag = "t", content = "c")]`). + This is the contract between all three binaries; changing a variant here touches backend, stub, + and client. +- `crates/rsh-backend` — the server (`axum`). Binary: `rsh-backend`. +- `crates/rsh` — the stub agent that runs on a target machine. Binary: `rsh`. Statically linked + (musl) so it runs on arbitrary Linux hosts with no dependencies. +- `crates/rshc` — the operator's CLI client. Binary: `rshc`. + +## Build & dev commands + +There are no automated tests in this repo currently. + +```sh +cargo build # build everything (debug) +cargo build --release # release build +cargo check # fast typecheck +cargo clippy # lint +cargo fmt # format +``` + +Backend development requires the musl stub binaries to be built first and embedded via env vars +(see "Stub embedding" below) — use the `justfile` targets rather than raw cargo: + +```sh +just stubs # cross-compiles the `rsh` stub for x86_64 and aarch64 musl targets +just backend # builds stubs, then builds rsh-backend with them embedded (release) +just dev # builds stubs, then `cargo run -p rsh-backend` bound to 127.0.0.1:7777, + # data dir /tmp/rsh-dev +``` + +`rshc` and `rsh` (stub) can be built/run directly with plain `cargo build -p rshc` / +`cargo run -p rsh -- ` — they don't need the stub-embedding dance. + +Container image (per user's global config, use `podman`/`podman compose` in place of any +`docker`/`docker compose` commands referenced by the justfile or docs): + +```sh +just docker-build # docker build -t rsh-backend:local . +just docker-run # run the built image, mounts a data volume, exposes 7777 +just docker-publish # tag + push to registry.walruslab.org/pub/rsh-backend +``` + +## Architecture + +### Protocol split: two independent WebSocket channels + +- `/ws/stub` (`rsh-backend/src/ws_stub.rs`) — target-machine stubs connect here. Messages: + `StubMsg` (stub → backend: `Hello`, `Stdout`/`Stderr`, `Exited`, `ShellReady`/`ShellStdout`/ + `ShellStderr`/`ShellExited`, `Pong`) and `BackendStubMsg` (backend → stub: `Accepted`/`Rejected`, + `Stdin`, `Resize`, `Kill`, `Ping`, `SpawnShell`/`ShellStdin`/`ShellResize`/`ShellKill`). +- `/ws/op` (`rsh-backend/src/ws_op.rs`) — the `rshc` operator client connects here. Messages: + `OpMsg`/`BackendOpMsg` wrapping request/response bodies `OpReq`/`OpResp` and pushed `OpEvent`s + (new/closed connections, new/deleted sessions). + +The backend is the hub connecting the two: `AppState` (`rsh-backend/src/state.rs`) holds live +stub connections (`connections: DashMap<(session_id, conn_id), Arc>`) and forwards +data between an operator's `AttachSink` and a stub's channel. `AttachIO` frames from an operator +become `Stdin`/`Resize`/`Kill` messages sent down `ConnHandle::to_stub`; stdout/stderr coming back +from the stub is forwarded to whichever operator is currently attached. + +### Sessions, connections, shells + +- A **session** is a named, optionally password-protected registration point (`SessionRecord`, + persisted to `sessions.json` via `rsh-backend/src/persist.rs`). Created/deleted/updated by + operators (`rshc session ...`). +- A **connection** is one stub process currently connected under a session (a session can have + multiple simultaneous stub connections, e.g. multiple machines using the same session name). + Connection IDs are allocated per-session (`AppState::alloc_conn_id`). +- Each connection has one primary attach point (`ConnHandle::attach`) plus any number of + **extra shells** (`ConnHandle::extra_shells`, keyed by `shell_id`), spawned on demand via + `OpReq::SpawnShell` → `BackendStubMsg::SpawnShell`. The backend tracks pending spawns in + `AppState::spawn_shell_pending` and waits (with a 10s timeout) for the stub's `ShellReady` + before replying to the operator. +- Only one operator can be attached to a given connection/shell at a time; attaching replaces + whatever `AttachSink` was previously stored. + +### Auth model (two different mechanisms for two different actors) + +- **Stub auth** (`rsh-backend/src/auth.rs::verify_password`): sessions may have an argon2 password + hash. The stub either checks it up front via `GET /check-auth?s=&pw=` (used by + `rsh auth` to cache a working password locally in `~/.config/rsh.yaml`) and/or presents it in the + `Hello` message on `/ws/stub`. +- **Operator auth** (`rsh-backend/src/ws_op.rs::auth_handshake`): SSH public-key challenge/response. + Client sends `AuthInit{pubkey_openssh}`; backend checks it against `authorized_keys` (file on + disk, reloadable via `rshc keys ...`, plus keys baked in via `RSH_AUTHORIZED_KEYS` env var — + `rsh-backend/src/keys.rs`), sends a random 32-byte `Challenge`, and expects a signature over that + nonce in SSH-signature (`SshSig`) format using namespace `"rsh-auth"`. `rshc` signs with the + private key at `ssh_key_file` from its config (prompting for a passphrase if encrypted). + +### Stub self-install / bootstrap (`rsh-backend/src/dist.rs`) + +`GET /` or `/run.sh?s=` serves a POSIX shell script (`SCRIPT_TEMPLATE`) that detects +arch, downloads the matching stub binary from `/rsh/:arch`, runs ` auth --url ` +to cache the session password, then launches ` stub --url .../ws/stub --session ` +as a backgrounded, disowned process. This is the one-liner meant to be curled onto a target host. + +### Stub embedding (why `just backend` needs `just stubs` first) + +`rsh-backend/build.rs` embeds two prebuilt `rsh` binaries into the `rsh-backend` binary itself via +`include_bytes!` (see `dist.rs`'s `STUB_X86_64`/`STUB_AARCH64` statics), reading their paths from +the `RSH_STUB_X86_64`/`RSH_STUB_AARCH64` env vars at build time. If those env vars aren't set (or +point to a missing file), the build succeeds anyway but embeds an empty placeholder, and `/rsh/:arch` +serves `503` for that arch instead of the binary — this lets `cargo build -p rsh-backend` work +standalone for iterating on non-stub-serving code, at the cost of a backend that can't actually +bootstrap new targets. The `Dockerfile` does the equivalent two-phase build (musl cross-compile +stages `stub-amd64`/`stub-arm64`, then `cargo chef` for the backend) so the shipped image always +has both stubs embedded. + +### `rshc` CLI structure + +`crates/rshc/src/cmd/` has one module per subcommand family (`session`, `connection`, `connect`, +`shell`, `keys`, `watch`); `main.rs` just parses `clap` args and dispatches. `AuthedClient` +(`crates/rshc/src/auth.rs`) owns the `/ws/op` connection after the handshake, multiplexing +request/response pairs by an incrementing `id` (oneshot for single responses, `mpsc` for streaming +ones like `Watch`/`Attach`) over one shared writer task. Config lives at `~/.config/rshc.yaml` +(`backend_url`, `ssh_key_file`) — `rshc` writes a stub file and errors out on first run if missing. + +### Deployment + +`Dockerfile` + `docker-compose.yml` + Helm chart at `deploy/helm/rsh-backend/` (standard +Deployment/Service/Ingress/PVC/Secret/ServiceAccount). Backend runtime config is all env vars +(`rsh-backend/src/config.rs`): `RSH_DATA` (default `/var/lib/rsh`), `RSH_BIND` (default +`0.0.0.0:7777`), `RSH_LOG`, `RSH_AUTHORIZED_KEYS`. diff --git a/Cargo.lock b/Cargo.lock index f664643..78c5fff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,14 +2,30 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aead" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common", - "generic-array", + "crypto-common 0.1.7", + "generic-array 0.14.7", +] + +[[package]] +name = "aead" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" +dependencies = [ + "crypto-common 0.2.2", + "inout 0.2.2", ] [[package]] @@ -19,8 +35,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "cipher 0.4.4", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +dependencies = [ + "cipher 0.5.2", + "cpubits", + "cpufeatures 0.3.0", + "zeroize", ] [[package]] @@ -29,14 +57,29 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", + "aead 0.5.2", + "aes 0.8.4", + "cipher 0.4.4", + "ctr 0.9.2", + "ghash 0.5.1", "subtle", ] +[[package]] +name = "aes-gcm" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf011db2e21ce0d575593d749db5554b47fed37aff429e4dc50bc91ac93a028" +dependencies = [ + "aead 0.6.1", + "aes 0.9.1", + "cipher 0.5.2", + "ctr 0.10.1", + "ghash 0.6.0", + "subtle", + "zeroize", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -46,6 +89,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "1.0.0" @@ -109,9 +161,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" dependencies = [ "base64ct", - "blake2", - "cpufeatures", - "password-hash", + "blake2 0.10.6", + "cpufeatures 0.2.17", + "password-hash 0.5.0", +] + +[[package]] +name = "argon2" +version = "0.6.0-rc.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7af50940b73bf4e16c15c448a2b121c63f2d68e3e54b6a8731673cb4aa0cdff5" +dependencies = [ + "base64ct", + "blake2 0.11.0-rc.6", + "cpufeatures 0.3.0", + "password-hash 0.6.1", ] [[package]] @@ -144,6 +208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" dependencies = [ "aws-lc-sys", + "untrusted 0.7.1", "zeroize", ] @@ -187,7 +252,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sha1", + "sha1 0.10.6", "sync_wrapper", "tokio", "tokio-tungstenite", @@ -235,6 +300,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + [[package]] name = "base64" version = "0.22.1" @@ -253,9 +324,20 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" dependencies = [ - "blowfish", - "pbkdf2", - "sha2", + "blowfish 0.9.1", + "pbkdf2 0.12.2", + "sha2 0.10.9", +] + +[[package]] +name = "bcrypt-pbkdf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144e573728da132683b9488acd528274c790e07fc06ff81ee29f9d8f8b1041e0" +dependencies = [ + "blowfish 0.10.0", + "pbkdf2 0.13.0", + "sha2 0.11.0", ] [[package]] @@ -276,7 +358,16 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "blake2" +version = "0.11.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061f1a09225e328e1ffbb378d2d49923c0ca5fee19fb5ac1cc9c1e9d52b93690" +dependencies = [ + "digest 0.11.3", ] [[package]] @@ -285,7 +376,17 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", + "zeroize", ] [[package]] @@ -294,7 +395,16 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" +dependencies = [ + "hybrid-array", ] [[package]] @@ -304,7 +414,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" dependencies = [ "byteorder", - "cipher", + "cipher 0.4.4", +] + +[[package]] +name = "blowfish" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ce3946557b35e71d1bbe07ec385073ce9eda05043f95de134eb578fcf1a298" +dependencies = [ + "byteorder", + "cipher 0.5.2", ] [[package]] @@ -334,7 +454,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "cipher", + "cipher 0.4.4", +] + +[[package]] +name = "cbc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" +dependencies = [ + "cipher 0.5.2", ] [[package]] @@ -368,8 +497,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "cipher 0.4.4", + "cpufeatures 0.2.17", +] + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cipher 0.5.2", + "cpufeatures 0.3.0", + "rand_core 0.10.1", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", ] [[package]] @@ -378,8 +533,20 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", - "inout", + "crypto-common 0.1.7", + "inout 0.1.4", +] + +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "inout 0.2.2", + "zeroize", ] [[package]] @@ -431,6 +598,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "colorchoice" version = "1.0.5" @@ -454,6 +627,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "core-foundation" version = "0.10.1" @@ -470,6 +649,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -479,6 +664,24 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -547,29 +750,86 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +dependencies = [ + "cpubits", + "ctutils", + "getrandom 0.4.2", + "hybrid-array", + "num-traits", + "rand_core 0.10.1", + "serdect", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "getrandom 0.4.2", + "hybrid-array", + "rand_core 0.10.1", +] + +[[package]] +name = "crypto-primes" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3633a51a39c69ebbaa4feaa694bd83d241e4093901c84a0963b19d9bb3f0cf8f" +dependencies = [ + "crypto-bigint 0.7.5", + "rand_core 0.10.1", +] + [[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher", + "cipher 0.4.4", +] + +[[package]] +name = "ctr" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21" +dependencies = [ + "cipher 0.5.2", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", ] [[package]] @@ -579,14 +839,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest", - "fiat-crypto", + "digest 0.10.7", + "fiat-crypto 0.2.9", "rustc_version", "subtle", ] +[[package]] +name = "curve25519-dalek" +version = "5.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c906a87e53a36ff795d72e06e8162a83c5436e3ea89e942a9cb9fc083f0a384f" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "curve25519-dalek-derive", + "digest 0.11.3", + "fiat-crypto 0.3.0", + "rustc_version", + "subtle", + "zeroize", +] + [[package]] name = "curve25519-dalek-derive" version = "0.1.1" @@ -618,13 +894,35 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +[[package]] +name = "delegate" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "780eb241654bf097afb00fc5f054a09b687dad862e485fdcf8399bb056565370" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "der" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", + "pem-rfc7468 1.0.0", "zeroize", ] @@ -637,18 +935,39 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "des" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a94e407b54f9034d71dd748234cd1e516ced6284009906ae246f177eafe5a" +dependencies = [ + "cipher 0.5.2", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "dirs" version = "5.0.1" @@ -735,12 +1054,27 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", + "der 0.7.10", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki 0.7.3", +] + +[[package]] +name = "ecdsa" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0" +dependencies = [ + "der 0.8.0", + "digest 0.11.3", + "elliptic-curve 0.14.1", + "rfc6979 0.6.0", + "signature 3.0.0", + "spki 0.8.0", + "zeroize", ] [[package]] @@ -749,7 +1083,17 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "signature", + "signature 2.2.0", +] + +[[package]] +name = "ed25519" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" +dependencies = [ + "pkcs8 0.11.0", + "signature 3.0.0", ] [[package]] @@ -758,31 +1102,81 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek", - "ed25519", - "sha2", + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "sha2 0.10.9", "subtle", ] +[[package]] +name = "ed25519-dalek" +version = "3.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1685663e23882cd8517dcbcb1c23a6ebff4433c22dfb681d760219b62cd1b849" +dependencies = [ + "curve25519-dalek 5.0.0-rc.1", + "ed25519 3.0.0", + "rand_core 0.10.1", + "serde", + "sha2 0.11.0", + "signature 3.0.0", + "subtle", + "zeroize", +] + [[package]] name = "elliptic-curve" version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.1", + "generic-array 0.14.7", + "group 0.13.0", + "pkcs8 0.10.2", "rand_core 0.6.4", - "sec1", + "sec1 0.7.3", "subtle", "zeroize", ] +[[package]] +name = "elliptic-curve" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" +dependencies = [ + "base16ct 1.0.0", + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "digest 0.11.3", + "ff 0.14.0", + "group 0.14.0", + "hkdf", + "hybrid-array", + "pem-rfc7468 1.0.0", + "pkcs8 0.11.0", + "rand_core 0.10.1", + "sec1 0.8.1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -815,12 +1209,28 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" +dependencies = [ + "rand_core 0.10.1", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "fiat-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + [[package]] name = "filedescriptor" version = "0.8.3" @@ -838,6 +1248,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -859,6 +1279,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.32" @@ -875,6 +1310,17 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.32" @@ -910,6 +1356,7 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -949,6 +1396,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb130435a959a8d525e6bca66ff6c40981a300ee96d70e3ef56f046556d614a3" +dependencies = [ + "generic-array 0.14.7", + "rustversion", + "typenum", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -983,10 +1441,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -996,7 +1457,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", - "polyval", + "polyval 0.6.2", +] + +[[package]] +name = "ghash" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" +dependencies = [ + "polyval 0.7.1", ] [[package]] @@ -1005,11 +1475,22 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.1", "rand_core 0.6.4", "subtle", ] +[[package]] +name = "group" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" +dependencies = [ + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -1037,13 +1518,43 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" + +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac 0.13.0", +] + [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", ] [[package]] @@ -1108,6 +1619,18 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "ctutils", + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "hyper" version = "1.9.0" @@ -1168,6 +1691,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.2.0" @@ -1295,8 +1842,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "block-padding", - "generic-array", + "block-padding 0.3.3", + "generic-array 0.14.7", +] + +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "block-padding 0.4.2", + "hybrid-array", ] [[package]] @@ -1316,6 +1873,18 @@ dependencies = [ "unicode-width 0.1.14", ] +[[package]] +name = "internal-russh-num-bigint" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8e22120c32fb4d19ec55fba35015f57095cd95a2e3b732e44457f5915b2ee8" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.10.2", + "rand_core 0.10.1", +] + [[package]] name = "ioctl-rs" version = "0.1.6" @@ -1365,6 +1934,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", +] + +[[package]] +name = "kem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edd" +dependencies = [ + "crypto-common 0.2.2", + "rand_core 0.10.1", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1464,6 +2053,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "md5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + [[package]] name = "memchr" version = "2.8.0" @@ -1485,6 +2080,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" version = "0.8.11" @@ -1509,6 +2114,31 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "ml-kem" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e15f3e5b957493873e396a66914e83e616b6afe335cdef7efe5c6e1216aba66" +dependencies = [ + "hybrid-array", + "kem", + "module-lattice", + "pkcs8 0.11.0", + "rand_core 0.10.1", + "sha3", +] + +[[package]] +name = "module-lattice" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe" +dependencies = [ + "ctutils", + "hybrid-array", + "num-traits", +] + [[package]] name = "newline-converter" version = "0.3.0" @@ -1532,6 +2162,18 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.11.1", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -1541,6 +2183,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num-bigint" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c863e9ab5e7bf9c99ba75e1050f1e4d624ae87ed3532d6238ffbdc7b585dbbe6" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -1635,10 +2287,23 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + +[[package]] +name = "p256" +version = "0.14.0-rc.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bb40a5099e2c38a09dd29321a7a7f045f165a54317679c7cdfb0cbaf8f6b1e" +dependencies = [ + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", ] [[package]] @@ -1647,10 +2312,24 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + +[[package]] +name = "p384" +version = "0.14.0-rc.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "492f329d7eb11d22dadc988626b9ea1f503b4ab043a8b1e4e2cc4ae45dabdd70" +dependencies = [ + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "fiat-crypto 0.3.0", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", ] [[package]] @@ -1659,12 +2338,46 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" dependencies = [ - "base16ct", - "ecdsa", - "elliptic-curve", - "primeorder", + "base16ct 0.2.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", "rand_core 0.6.4", - "sha2", + "sha2 0.10.9", +] + +[[package]] +name = "p521" +version = "0.14.0-rc.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff42e4ace5424e3b6d7cb82514be89866b85af87015f80341e37dcc21a66ce6e" +dependencies = [ + "base16ct 1.0.0", + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", +] + +[[package]] +name = "pageant" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3a5ae18f65a85c67a77d18d42d3606c07948e3c17c1e5f74852b26589e88a5" +dependencies = [ + "base16ct 1.0.0", + "byteorder", + "bytes", + "delegate", + "futures", + "log", + "rand 0.10.2", + "sha2 0.11.0", + "thiserror 2.0.18", + "tokio", + "windows", + "windows-strings", ] [[package]] @@ -1701,13 +2414,32 @@ dependencies = [ "subtle", ] +[[package]] +name = "password-hash" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aab41826031698d6ffcd9cff78ef56ef998e39dc7e5067cdfebe373842d4723b" +dependencies = [ + "phc", +] + [[package]] name = "pbkdf2" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" +dependencies = [ + "digest 0.11.3", + "hmac 0.13.0", ] [[package]] @@ -1719,12 +2451,31 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "phc" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44dc769b75f93afdddd8c7fa12d685292ddeff1e66f7f0f3a234cf1818afe892" +dependencies = [ + "base64ct", + "ctutils", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1743,9 +2494,36 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", - "pkcs8", - "spki", + "der 0.7.10", + "pkcs8 0.10.2", + "spki 0.7.3", +] + +[[package]] +name = "pkcs1" +version = "0.8.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" +dependencies = [ + "der 0.8.0", + "spki 0.8.0", +] + +[[package]] +name = "pkcs5" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d440a804ec8d6fafbb6b84471e013286658d373248927692ab3366686220ca" +dependencies = [ + "aes 0.9.1", + "aes-gcm 0.11.0", + "cbc 0.2.1", + "der 0.8.0", + "pbkdf2 0.13.0", + "rand_core 0.10.1", + "scrypt", + "sha2 0.11.0", + "spki 0.8.0", ] [[package]] @@ -1754,8 +2532,20 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.10", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" +dependencies = [ + "der 0.8.0", + "pkcs5", + "rand_core 0.10.1", + "spki 0.8.0", ] [[package]] @@ -1770,9 +2560,20 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", - "universal-hash", + "universal-hash 0.5.1", +] + +[[package]] +name = "poly1305" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00baa632505d05512f48a963e16051c54fda9a95cc9acea1a4e3c90991c4a2e" +dependencies = [ + "cpufeatures 0.3.0", + "universal-hash 0.6.1", + "zeroize", ] [[package]] @@ -1782,9 +2583,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", - "universal-hash", + "universal-hash 0.5.1", +] + +[[package]] +name = "polyval" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfc63250416fea14f5749b90725916a6c903f599d51cb635aa7a52bfd03eede" +dependencies = [ + "cpubits", + "cpufeatures 0.3.0", + "universal-hash 0.6.1", ] [[package]] @@ -1800,7 +2612,7 @@ dependencies = [ "lazy_static", "libc", "log", - "nix", + "nix 0.25.1", "serial", "shared_library", "shell-words", @@ -1842,13 +2654,40 @@ dependencies = [ "syn", ] +[[package]] +name = "primefield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" +dependencies = [ + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve", + "elliptic-curve 0.13.8", +] + +[[package]] +name = "primeorder" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c9f42978c78a00e3d68f69fc03e57a234debae69da4020a4fb588fcdcd07b06" +dependencies = [ + "elliptic-curve 0.14.1", + "once_cell", + "primefield", + "serdect", + "wnaf", ] [[package]] @@ -1957,6 +2796,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20 0.10.1", + "getrandom 0.4.2", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -1995,6 +2845,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -2098,10 +2954,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", "subtle", ] +[[package]] +name = "rfc6979" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b" +dependencies = [ + "crypto-bigint 0.7.5", + "hmac 0.13.0", +] + [[package]] name = "ring" version = "0.17.14" @@ -2112,7 +2978,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.17", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -2133,21 +2999,40 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", - "pkcs1", - "pkcs8", + "pkcs1 0.7.5", + "pkcs8 0.10.2", "rand_core 0.6.4", - "sha2", - "signature", - "spki", + "sha2 0.10.9", + "signature 2.2.0", + "spki 0.7.3", "subtle", "zeroize", ] +[[package]] +name = "rsa" +version = "0.10.0-rc.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b2aa4ba0d89f73d1e332df05be0eeab8840351c36ca5654341dfdb57bb3caf" +dependencies = [ + "const-oid 0.10.2", + "crypto-bigint 0.7.5", + "crypto-primes", + "digest 0.11.3", + "pkcs1 0.8.0-rc.4", + "pkcs8 0.11.0", + "rand_core 0.10.1", + "sha2 0.11.0", + "signature 3.0.0", + "spki 0.8.0", + "zeroize", +] + [[package]] name = "rsh" version = "0.1.0" @@ -2178,7 +3063,7 @@ name = "rsh-backend" version = "0.1.0" dependencies = [ "anyhow", - "argon2", + "argon2 0.5.3", "axum", "bytes", "dashmap", @@ -2187,8 +3072,8 @@ dependencies = [ "rsh-types", "serde", "serde_json", - "signature", - "ssh-key", + "signature 2.2.0", + "ssh-key 0.6.7", "thiserror 1.0.69", "time", "tokio", @@ -2211,7 +3096,7 @@ name = "rshc" version = "0.1.0" dependencies = [ "anyhow", - "argon2", + "argon2 0.5.3", "bytes", "clap", "comfy-table", @@ -2225,12 +3110,13 @@ dependencies = [ "reqwest", "rpassword", "rsh-types", + "russh", "serde", "serde_json", "serde_yaml", "shellexpand", - "signature", - "ssh-key", + "signature 2.2.0", + "ssh-key 0.6.7", "tempfile", "thiserror 1.0.69", "time", @@ -2250,6 +3136,102 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "russh" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20d2039c3e50abb1ec3bdadea27098679da12a33befa9ab4e62adad9a13ebcb2" +dependencies = [ + "aes 0.9.1", + "aws-lc-rs", + "bitflags 2.11.1", + "block-padding 0.4.2", + "byteorder", + "bytes", + "cbc 0.2.1", + "cipher 0.5.2", + "crypto-bigint 0.7.5", + "ctr 0.10.1", + "curve25519-dalek 5.0.0-rc.1", + "data-encoding", + "delegate", + "der 0.8.0", + "digest 0.11.3", + "ecdsa 0.17.0", + "ed25519-dalek 3.0.0-rc.1", + "elliptic-curve 0.14.1", + "enum_dispatch", + "flate2", + "futures", + "generic-array 1.4.2", + "getrandom 0.4.2", + "ghash 0.6.0", + "hex-literal", + "hmac 0.13.0", + "inout 0.2.2", + "internal-russh-num-bigint", + "keccak", + "log", + "md5", + "ml-kem", + "module-lattice", + "num-bigint", + "p256 0.14.0-rc.15", + "p384 0.14.0-rc.15", + "p521 0.14.0-rc.15", + "pageant", + "pbkdf2 0.13.0", + "pkcs1 0.8.0-rc.4", + "pkcs5", + "pkcs8 0.11.0", + "polyval 0.7.1", + "rand 0.10.2", + "rand_core 0.10.1", + "rsa 0.10.0-rc.18", + "russh-cryptovec", + "russh-util", + "salsa20", + "scrypt", + "sec1 0.8.1", + "sha1 0.11.0", + "sha2 0.11.0", + "sha3", + "signature 3.0.0", + "spki 0.8.0", + "ssh-encoding 0.3.0", + "ssh-key 0.7.0-rc.11", + "subtle", + "thiserror 2.0.18", + "tokio", + "typenum", + "universal-hash 0.6.1", + "zeroize", +] + +[[package]] +name = "russh-cryptovec" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aec6cb630dbe85d72ffd7bcd95f07e1bd69f9f270ee8adfa1afe443a6331438" +dependencies = [ + "log", + "nix 0.31.3", + "ssh-encoding 0.3.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "russh-util" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668424a5dde0bcb45b55ba7de8476b93831b4aa2fa6947e145f3b053e22c60b6" +dependencies = [ + "chrono", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", +] + [[package]] name = "rustc-hash" version = "2.1.2" @@ -2338,7 +3320,7 @@ dependencies = [ "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -2353,6 +3335,16 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "salsa20" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f874456e72520ff1375a06c588eaf074b0f01f9e9e1aada45bd9b7954a6e42c" +dependencies = [ + "cfg-if", + "cipher 0.5.2", +] + [[package]] name = "schannel" version = "0.1.29" @@ -2368,16 +3360,42 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87af57419b594aa23fa95f09f0e06d80d84ba01c26148c43844cad6ff4485f0" +dependencies = [ + "cfg-if", + "pbkdf2 0.13.0", + "salsa20", + "sha2 0.11.0", +] + [[package]] name = "sec1" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", + "base16ct 0.2.0", + "der 0.7.10", + "generic-array 0.14.7", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" +dependencies = [ + "base16ct 1.0.0", + "ctutils", + "der 0.8.0", + "hybrid-array", "subtle", "zeroize", ] @@ -2490,6 +3508,16 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "serdect" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3e" +dependencies = [ + "base16ct 1.0.0", + "serde", +] + [[package]] name = "serial" version = "0.4.0" @@ -2539,8 +3567,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -2550,8 +3589,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak", ] [[package]] @@ -2632,10 +3692,26 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" +dependencies = [ + "digest 0.11.3", + "rand_core 0.10.1", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "slab" version = "0.4.12" @@ -2671,7 +3747,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", +] + +[[package]] +name = "spki" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" +dependencies = [ + "base64ct", + "der 0.8.0", ] [[package]] @@ -2680,17 +3766,35 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" dependencies = [ - "aes", - "aes-gcm", - "cbc", - "chacha20", - "cipher", - "ctr", - "poly1305", - "ssh-encoding", + "aes 0.8.4", + "aes-gcm 0.10.3", + "cbc 0.1.2", + "chacha20 0.9.1", + "cipher 0.4.4", + "ctr 0.9.2", + "poly1305 0.8.0", + "ssh-encoding 0.2.0", "subtle", ] +[[package]] +name = "ssh-cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d801accda99469cde6d73da741422610fdf6508a72d9a69d1b55cb241c720597" +dependencies = [ + "aead 0.6.1", + "aes 0.9.1", + "aes-gcm 0.11.0", + "chacha20 0.10.1", + "cipher 0.5.2", + "ctutils", + "des", + "poly1305 0.9.0", + "ssh-encoding 0.3.0", + "zeroize", +] + [[package]] name = "ssh-encoding" version = "0.2.0" @@ -2698,8 +3802,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" dependencies = [ "base64ct", - "pem-rfc7468", - "sha2", + "pem-rfc7468 0.7.0", + "sha2 0.10.9", +] + +[[package]] +name = "ssh-encoding" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b54d0ed0498daf3f78d82e00e28c8eec9d75a067c4cfbcc7a0f7d0f4077749e" +dependencies = [ + "base64ct", + "bytes", + "crypto-bigint 0.7.5", + "ctutils", + "digest 0.11.3", + "pem-rfc7468 1.0.0", + "zeroize", ] [[package]] @@ -2708,23 +3827,49 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" dependencies = [ - "bcrypt-pbkdf", - "ed25519-dalek", + "bcrypt-pbkdf 0.10.0", + "ed25519-dalek 2.2.0", "num-bigint-dig", - "p256", - "p384", - "p521", + "p256 0.13.2", + "p384 0.13.1", + "p521 0.13.3", "rand_core 0.6.4", - "rsa", - "sec1", - "sha2", - "signature", - "ssh-cipher", - "ssh-encoding", + "rsa 0.9.10", + "sec1 0.7.3", + "sha2 0.10.9", + "signature 2.2.0", + "ssh-cipher 0.2.0", + "ssh-encoding 0.2.0", "subtle", "zeroize", ] +[[package]] +name = "ssh-key" +version = "0.7.0-rc.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a32fae177b74a22aa9c5b01bf7e68b33545be32d9e381e248058d2adc15ce3" +dependencies = [ + "argon2 0.6.0-rc.8", + "bcrypt-pbkdf 0.11.0", + "ctutils", + "ed25519-dalek 3.0.0-rc.1", + "hex", + "hmac 0.13.0", + "p256 0.14.0-rc.15", + "p384 0.14.0-rc.15", + "p521 0.14.0-rc.15", + "rand_core 0.10.1", + "rsa 0.10.0-rc.18", + "sec1 0.8.1", + "sha1 0.11.0", + "sha2 0.11.0", + "signature 3.0.0", + "ssh-cipher 0.3.0", + "ssh-encoding 0.3.0", + "zeroize", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -3085,7 +4230,7 @@ dependencies = [ "rand 0.8.6", "rustls", "rustls-pki-types", - "sha1", + "sha1 0.10.6", "thiserror 1.0.69", "utf-8", ] @@ -3132,16 +4277,32 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "universal-hash" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" +dependencies = [ + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -3380,12 +4541,107 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -3479,6 +4735,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3720,6 +4985,17 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "wnaf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab12e7090f27e2ffd9322651492942d50c2926094af30601e1964337db39daf1" +dependencies = [ + "ff 0.14.0", + "group 0.14.0", + "hybrid-array", +] + [[package]] name = "writeable" version = "0.6.3" @@ -3792,9 +5068,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" diff --git a/crates/rshc/Cargo.toml b/crates/rshc/Cargo.toml index 1ab82e6..bd8a284 100644 --- a/crates/rshc/Cargo.toml +++ b/crates/rshc/Cargo.toml @@ -32,3 +32,5 @@ rand = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } bytes = { workspace = true } +russh = "0.62.1" + diff --git a/crates/rshc/src/cmd/mod.rs b/crates/rshc/src/cmd/mod.rs index 1413ee6..0671deb 100644 --- a/crates/rshc/src/cmd/mod.rs +++ b/crates/rshc/src/cmd/mod.rs @@ -4,3 +4,4 @@ pub mod connect; pub mod keys; pub mod watch; pub mod shell; +pub mod serve_ssh; diff --git a/crates/rshc/src/cmd/serve_ssh.rs b/crates/rshc/src/cmd/serve_ssh.rs new file mode 100644 index 0000000..5d719a6 --- /dev/null +++ b/crates/rshc/src/cmd/serve_ssh.rs @@ -0,0 +1,290 @@ +use crate::auth::AuthedClient; +use crate::cmd::connection; +use crate::config::Config; +use crate::ui; +use anyhow::{anyhow, Result}; +use rsh_types::{AttachIOFrame, OpReq, OpResp}; +use russh::server::{Auth, Session}; +use russh::ChannelId; +use std::collections::HashMap; +use std::sync::Arc; +use bytes::Bytes; +use tokio::net::TcpListener; + +pub async fn run( + cfg: Config, + client: AuthedClient, + session_name: String, + listen_host: String, + listen_port: u16, + connection_id: Option, + shell: Option, +) -> Result<()> { + // Validate that we have connections before starting the server. + // Also resolve connection_id if not explicitly provided but only 1 exists. + let conns = connection::fetch(&client, Some(session_name.clone())).await?; + if conns.is_empty() { + return Err(anyhow!("no connections for session '{}'", session_name)); + } + let conn_id = match connection_id { + Some(id) => { + conns + .iter() + .find(|c| c.connection_id == id) + .ok_or_else(|| anyhow!("no connection {} in session '{}'", id, session_name))? + .connection_id + } + None => { + if conns.len() == 1 { + conns[0].connection_id + } else { + return Err(anyhow!( + "multiple connections found. please specify --connection " + )); + } + } + }; + + let mut config = russh::server::Config { + inactivity_timeout: Some(std::time::Duration::from_secs(3600)), + auth_rejection_time: std::time::Duration::from_secs(1), + auth_rejection_time_initial: Some(std::time::Duration::from_secs(0)), + ..Default::default() + }; + + // Use a static ephemeral key for the SSH server + let key_str = "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\nQyNTUxOQAAACBxYVtR5Xn/kk9PM26c//B9JlvqBBv4EbkWr3jRI8CLfQAAAJjAfItSwHyL\nUgAAAAtzc2gtZWQyNTUxOQAAACBxYVtR5Xn/kk9PM26c//B9JlvqBBv4EbkWr3jRI8CLfQ\nAAAEA3iPbbQVsorPV8V36bsOZWFHyYzqAx4SIPBQsVWW4RdHFhW1Hlef+ST08zbpz/8H0m\nW+oEG/gRuRaveNEjwIt9AAAAD2V0eEBldHgtZGVza3RvcAECAwQFBg==\n-----END OPENSSH PRIVATE KEY-----"; + let key = russh::keys::PrivateKey::from_openssh(key_str) + .map_err(|e| anyhow!("Failed to parse SSH host key: {}", e))?; + config.keys.push(key); + let config = Arc::new(config); + + let bind_addr = format!("{}:{}", listen_host, listen_port); + let listener = TcpListener::bind(&bind_addr).await.map_err(|e| anyhow!(e))?; + ui::print_info(&format!("serving SSH on {}", bind_addr)); + + loop { + let (stream, _) = match listener.accept().await { + Ok(res) => res, + Err(_) => continue, + }; + + let handler = SessionHandler { + cfg: cfg.clone(), + session_name: session_name.clone(), + connection_id: conn_id, + shell: shell.clone(), + clients: HashMap::new(), + pty_reqs: HashMap::new(), + }; + + let config_clone = config.clone(); + tokio::spawn(async move { + let _ = russh::server::run_stream(config_clone, stream, handler).await; + }); + } +} + +struct SessionHandler { + cfg: Config, + session_name: String, + connection_id: u64, + shell: Option, + + clients: HashMap>, + pty_reqs: HashMap, +} + +impl SessionHandler { + async fn spawn_shell( + &mut self, + channel: ChannelId, + session: &mut Session, + shell_cmd: Option, + ) -> Result<(), anyhow::Error> { + let pty = self.pty_reqs.contains_key(&channel); + let (cols, rows) = self.pty_reqs.get(&channel).cloned().unwrap_or((80, 24)); + + let client = AuthedClient::connect(&self.cfg).await?; + + let spawned = client + .req(OpReq::SpawnShell { + session: self.session_name.clone(), + connection_id: Some(self.connection_id), + shell: shell_cmd, + pty, + cols, + rows, + }) + .await?; + + let shell_id = match spawned { + OpResp::ShellSpawned { shell_id, .. } => shell_id, + OpResp::Err(e) => return Err(anyhow!(e)), + other => return Err(anyhow!("unexpected: {:?}", other)), + }; + + let (attach_id, mut resps) = client + .req_stream(OpReq::Attach { + session: self.session_name.clone(), + connection_id: Some(self.connection_id), + shell_id: Some(shell_id), + pty, + cols, + rows, + }) + .await?; + + let ready = resps.recv().await.ok_or_else(|| anyhow!("attach: no response"))?; + match ready { + OpResp::AttachReady { .. } => {} + OpResp::Err(e) => { + client.drop_stream(attach_id).await; + return Err(anyhow!(e)); + } + other => { + client.drop_stream(attach_id).await; + return Err(anyhow!("unexpected: {:?}", other)); + } + } + + let client = Arc::new(client); + self.clients.insert(channel, client.clone()); + + // Spawn a task to pump output from rsh-backend to russh + let handle = session.handle(); + tokio::spawn(async move { + while let Some(resp) = resps.recv().await { + match resp { + OpResp::Stdout(b) => { + let _ = handle.data(channel, Bytes::from(b)).await; + } + OpResp::Stderr(b) => { + let _ = handle.extended_data(channel, 1, Bytes::from(b)).await; + } + OpResp::Exited { code } => { + let _ = handle.exit_status_request(channel, code.unwrap_or(0) as u32).await; + let _ = handle.close(channel).await; + break; + } + OpResp::Err(_) => { + let _ = handle.close(channel).await; + break; + } + _ => {} + } + } + client.drop_stream(attach_id).await; + }); + + Ok(()) + } +} + +impl russh::server::Handler for SessionHandler { + type Error = anyhow::Error; + + async fn auth_publickey( + &mut self, + _: &str, + _: &russh::keys::PublicKey, + ) -> Result { + Ok(Auth::Accept) + } + + async fn auth_password(&mut self, _: &str, _: &str) -> Result { + Ok(Auth::Accept) + } + + async fn auth_none(&mut self, _: &str) -> Result { + Ok(Auth::Accept) + } + + async fn pty_request( + &mut self, + channel: ChannelId, + _term: &str, + col_width: u32, + row_height: u32, + _pix_width: u32, + _pix_height: u32, + _modes: &[(russh::Pty, u32)], + _session: &mut Session, + ) -> Result<(), Self::Error> { + self.pty_reqs.insert(channel, (col_width as u16, row_height as u16)); + Ok(()) + } + + async fn shell_request( + &mut self, + channel: ChannelId, + session: &mut Session, + ) -> Result<(), Self::Error> { + self.spawn_shell(channel, session, self.shell.clone()).await?; + Ok(()) + } + + async fn exec_request( + &mut self, + channel: ChannelId, + data: &[u8], + session: &mut Session, + ) -> Result<(), Self::Error> { + let command = String::from_utf8_lossy(data).to_string(); + self.spawn_shell(channel, session, Some(command)).await?; + Ok(()) + } + + async fn window_change_request( + &mut self, + channel: ChannelId, + col_width: u32, + row_height: u32, + _pix_width: u32, + _pix_height: u32, + _session: &mut Session, + ) -> Result<(), Self::Error> { + if let Some(client) = self.clients.get(&channel) { + let _ = client.send_attach_io(AttachIOFrame::Resize { + cols: col_width as u16, + rows: row_height as u16, + }).await; + } + Ok(()) + } + + async fn data( + &mut self, + channel: ChannelId, + data: &[u8], + _session: &mut Session, + ) -> Result<(), Self::Error> { + if let Some(client) = self.clients.get(&channel) { + let _ = client.send_attach_io(AttachIOFrame::Stdin(data.to_vec())).await; + } + Ok(()) + } + + async fn channel_eof( + &mut self, + channel: ChannelId, + _session: &mut Session, + ) -> Result<(), Self::Error> { + if let Some(client) = self.clients.get(&channel) { + let _ = client.send_attach_io(AttachIOFrame::Eof).await; + } + Ok(()) + } + + async fn channel_close( + &mut self, + channel: ChannelId, + _session: &mut Session, + ) -> Result<(), Self::Error> { + if let Some(client) = self.clients.remove(&channel) { + let _ = client.send_attach_io(AttachIOFrame::Kill).await; + } + self.pty_reqs.remove(&channel); + Ok(()) + } +} diff --git a/crates/rshc/src/main.rs b/crates/rshc/src/main.rs index 6a4b74f..3e885af 100644 --- a/crates/rshc/src/main.rs +++ b/crates/rshc/src/main.rs @@ -26,6 +26,7 @@ enum Cmd { Connect(ConnectArgs), #[command(alias = "sh")] Shell(ShellArgs), + ServeSsh(ServeSshArgs), Keys(KeysCmd), } @@ -97,6 +98,20 @@ struct ShellArgs { no_pty: bool, } +#[derive(Args, Debug)] +struct ServeSshArgs { + session: String, + #[arg(short = 'h', long, default_value = "127.0.0.1")] + listen_host: String, + #[arg(short = 'p', long, default_value_t = 2222)] + listen_port: u16, + #[arg(long)] + connection: Option, + #[arg(long)] + shell: Option, +} + + #[derive(Args, Debug)] struct KeysCmd { #[command(subcommand)] @@ -163,6 +178,8 @@ async fn run() -> Result<()> { }, Cmd::Connect(a) => cmd::connect::run(&client, a.session, a.connection_id, a.no_pty).await, Cmd::Shell(a) => cmd::shell::run(&client, a.session, a.connection, a.shell, a.no_pty).await, + Cmd::ServeSsh(a) => cmd::serve_ssh::run(cfg, client, a.session, a.listen_host, a.listen_port, a.connection, a.shell).await, + Cmd::Keys(k) => match k.sub { KeysSub::Append { key, file, url } => cmd::keys::append(&client, key, file, url).await, KeysSub::Rm { key, file, url } => cmd::keys::remove(&client, key, file, url).await,