diff --git a/.all-contributorsrc b/.all-contributorsrc index 1db94a0b..95b09876 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -175,11 +175,416 @@ "contributions": [ "code" ] + }, + { + "login": "Nurrl", + "name": "Maya the bee", + "avatar_url": "https://avatars.githubusercontent.com/u/15341887?v=4", + "profile": "https://github.com/Nurrl", + "contributions": [ + "code" + ] + }, + { + "login": "mmirate", + "name": "Milo Mirate", + "avatar_url": "https://avatars.githubusercontent.com/u/992859?v=4", + "profile": "https://github.com/mmirate", + "contributions": [ + "code" + ] + }, + { + "login": "george-hopkins", + "name": "George Hopkins", + "avatar_url": "https://avatars.githubusercontent.com/u/552590?v=4", + "profile": "https://github.com/george-hopkins", + "contributions": [ + "code" + ] + }, + { + "login": "akeamc", + "name": "Åke Amcoff", + "avatar_url": "https://avatars.githubusercontent.com/u/17624114?v=4", + "profile": "https://amcoff.net/", + "contributions": [ + "code" + ] + }, + { + "login": "bho01", + "name": "Brendon Ho", + "avatar_url": "https://avatars.githubusercontent.com/u/12106620?v=4", + "profile": "http://brendonho.com", + "contributions": [ + "code" + ] + }, + { + "login": "samuela", + "name": "Samuel Ainsworth", + "avatar_url": "https://avatars.githubusercontent.com/u/226872?v=4", + "profile": "http://samlikes.pizza/", + "contributions": [ + "code" + ] + }, + { + "login": "sherlock-holo", + "name": "Sherlock Holo", + "avatar_url": "https://avatars.githubusercontent.com/u/10096425?v=4", + "profile": "https://github.com/Sherlock-Holo", + "contributions": [ + "code" + ] + }, + { + "login": "ricott1", + "name": "Alessandro Ricottone", + "avatar_url": "https://avatars.githubusercontent.com/u/16502243?v=4", + "profile": "https://github.com/ricott1", + "contributions": [ + "code" + ] + }, + { + "login": "T0b1-iOS", + "name": "T0b1-iOS", + "avatar_url": "https://avatars.githubusercontent.com/u/15174814?v=4", + "profile": "https://github.com/T0b1-iOS", + "contributions": [ + "code" + ] + }, + { + "login": "shoaibmerchant", + "name": "Shoaib Merchant", + "avatar_url": "https://avatars.githubusercontent.com/u/4598631?v=4", + "profile": "https://mecha.so", + "contributions": [ + "code" + ] + }, + { + "login": "gleason-m", + "name": "Michael Gleason", + "avatar_url": "https://avatars.githubusercontent.com/u/86493344?v=4", + "profile": "https://github.com/gleason-m", + "contributions": [ + "code" + ] + }, + { + "login": "elegaanz", + "name": "Ana Gelez", + "avatar_url": "https://avatars.githubusercontent.com/u/16254623?v=4", + "profile": "https://ana.gelez.xyz", + "contributions": [ + "code" + ] + }, + { + "login": "tomknig", + "name": "Tom König", + "avatar_url": "https://avatars.githubusercontent.com/u/3586316?v=4", + "profile": "https://github.com/tomknig", + "contributions": [ + "code" + ] + }, + { + "login": "Barre", + "name": "Pierre Barre", + "avatar_url": "https://avatars.githubusercontent.com/u/45085843?v=4", + "profile": "https://www.legaltile.com/", + "contributions": [ + "code" + ] + }, + { + "login": "spoutn1k", + "name": "Jean-Baptiste Skutnik", + "avatar_url": "https://avatars.githubusercontent.com/u/22240065?v=4", + "profile": "http://skutnik.page", + "contributions": [ + "code" + ] + }, + { + "login": "packetsource", + "name": "Adam Chappell", + "avatar_url": "https://avatars.githubusercontent.com/u/6276475?v=4", + "profile": "http://blog.packetsource.net/", + "contributions": [ + "code" + ] + }, + { + "login": "CertainLach", + "name": "Yaroslav Bolyukin", + "avatar_url": "https://avatars.githubusercontent.com/u/6235312?v=4", + "profile": "https://github.com/CertainLach", + "contributions": [ + "code" + ] + }, + { + "login": "JuliDi", + "name": "Julian", + "avatar_url": "https://avatars.githubusercontent.com/u/20155974?v=4", + "profile": "http://www.systemscape.de", + "contributions": [ + "code" + ] + }, + { + "login": "grampelberg", + "name": "Thomas Rampelberg", + "avatar_url": "https://avatars.githubusercontent.com/u/47992?v=4", + "profile": "http://saunter.org", + "contributions": [ + "code" + ] + }, + { + "login": "belak", + "name": "Kaleb Elwert", + "avatar_url": "https://avatars.githubusercontent.com/u/107097?v=4", + "profile": "https://belak.io", + "contributions": [ + "doc" + ] + }, + { + "login": "nbdd0121", + "name": "Gary Guo", + "avatar_url": "https://avatars.githubusercontent.com/u/4065244?v=4", + "profile": "https://garyguo.net", + "contributions": [ + "code" + ] + }, + { + "login": "irvingoujAtDevolution", + "name": "irvingouj @ Devolutions", + "avatar_url": "https://avatars.githubusercontent.com/u/139169536?v=4", + "profile": "https://github.com/irvingoujAtDevolution", + "contributions": [ + "code" + ] + }, + { + "login": "Tehforsch", + "name": "Toni Peter", + "avatar_url": "https://avatars.githubusercontent.com/u/4614215?v=4", + "profile": "http://tonipeter.de", + "contributions": [ + "code" + ] + }, + { + "login": "Nathy-bajo", + "name": "Nathaniel Bajo", + "avatar_url": "https://avatars.githubusercontent.com/u/73991674?v=4", + "profile": "https://github.com/Nathy-bajo", + "contributions": [ + "code" + ] + }, + { + "login": "EpicEric", + "name": "Eric Rodrigues Pires", + "avatar_url": "https://avatars.githubusercontent.com/u/3129194?v=4", + "profile": "https://eric.dev.br", + "contributions": [ + "code" + ] + }, + { + "login": "jeromegn", + "name": "Jerome Gravel-Niquet", + "avatar_url": "https://avatars.githubusercontent.com/u/43325?v=4", + "profile": "http://www.fly.io", + "contributions": [ + "code" + ] + }, + { + "login": "qsantos", + "name": "Quentin Santos", + "avatar_url": "https://avatars.githubusercontent.com/u/8493765?v=4", + "profile": "https://qsantos.fr/", + "contributions": [ + "doc" + ] + }, + { + "login": "ogedei-khan", + "name": "André Almeida", + "avatar_url": "https://avatars.githubusercontent.com/u/181673956?v=4", + "profile": "https://github.com/ogedei-khan", + "contributions": [ + "code" + ] + }, + { + "login": "snaggen", + "name": "Mattias Eriksson", + "avatar_url": "https://avatars.githubusercontent.com/u/6420639?v=4", + "profile": "https://github.com/snaggen", + "contributions": [ + "code" + ] + }, + { + "login": "joshka", + "name": "Josh McKinney", + "avatar_url": "https://avatars.githubusercontent.com/u/381361?v=4", + "profile": "http://joshka.net", + "contributions": [ + "code" + ] + }, + { + "login": "citorva", + "name": "citorva", + "avatar_url": "https://avatars.githubusercontent.com/u/16229435?v=4", + "profile": "https://citorva.fr/", + "contributions": [ + "code" + ] + }, + { + "login": "eric-seppanen", + "name": "Eric Seppanen", + "avatar_url": "https://avatars.githubusercontent.com/u/109770420?v=4", + "profile": "https://github.com/eric-seppanen", + "contributions": [ + "code" + ] + }, + { + "login": "ericseppanen", + "name": "Eric Seppanen", + "avatar_url": "https://avatars.githubusercontent.com/u/36317762?v=4", + "profile": "https://codeandbitters.com/", + "contributions": [ + "code" + ] + }, + { + "login": "Patryk27", + "name": "Patryk Wychowaniec", + "avatar_url": "https://avatars.githubusercontent.com/u/3395477?v=4", + "profile": "https://pwy.io", + "contributions": [ + "code" + ] + }, + { + "login": "RandyMcMillan", + "name": "@RandyMcMillan", + "avatar_url": "https://avatars.githubusercontent.com/u/152159?v=4", + "profile": "https://www.randymcmillan.net", + "contributions": [ + "code" + ] + }, + { + "login": "handewo", + "name": "handewo", + "avatar_url": "https://avatars.githubusercontent.com/u/20971373?v=4", + "profile": "https://github.com/handewo", + "contributions": [ + "code" + ] + }, + { + "login": "ccbrown", + "name": "Chris", + "avatar_url": "https://avatars.githubusercontent.com/u/1731074?v=4", + "profile": "https://github.com/ccbrown", + "contributions": [ + "code" + ] + }, + { + "login": "procr1337", + "name": "procr1337", + "avatar_url": "https://avatars.githubusercontent.com/u/193802945?v=4", + "profile": "https://github.com/procr1337", + "contributions": [ + "code" + ] + }, + { + "login": "Itsusinn", + "name": "iHsin", + "avatar_url": "https://avatars.githubusercontent.com/u/30529002?v=4", + "profile": "https://github.com/Itsusinn", + "contributions": [ + "code" + ] + }, + { + "login": "psychon", + "name": "Uli Schlachter", + "avatar_url": "https://avatars.githubusercontent.com/u/89482?v=4", + "profile": "https://github.com/psychon", + "contributions": [ + "code" + ] + }, + { + "login": "jvanbrunt", + "name": "Jacob Van Brunt", + "avatar_url": "https://avatars.githubusercontent.com/u/3064793?v=4", + "profile": "https://github.com/jvanbrunt", + "contributions": [ + "code" + ] + }, + { + "login": "lgmugnier", + "name": "lgmugnier", + "avatar_url": "https://avatars.githubusercontent.com/u/10800317?v=4", + "profile": "https://github.com/lgmugnier", + "contributions": [ + "code" + ] + }, + { + "login": "MingweiSamuel", + "name": "Mingwei Samuel", + "avatar_url": "https://avatars.githubusercontent.com/u/6778341?v=4", + "profile": "https://github.com/MingweiSamuel", + "contributions": [ + "code" + ] + }, + { + "login": "pgrange", + "name": "Pascal Grange", + "avatar_url": "https://avatars.githubusercontent.com/u/378506?v=4", + "profile": "https://twitter.com/pascalgrange", + "contributions": [ + "code" + ] + }, + { + "login": "wyhaya", + "name": "wyhaya", + "avatar_url": "https://avatars.githubusercontent.com/u/23690145?v=4", + "profile": "https://github.com/wyhaya", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, "projectName": "russh", - "projectOwner": "warp-tech", + "projectOwner": "Eugeny", "repoType": "github", "repoHost": "https://github.com", "skipCi": true, diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..c236b04c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +github: eugeny +open_collective: tabby +ko_fi: eugeny diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 66ef82a8..a0164e99 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,16 +2,16 @@ name: Rust on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] env: CARGO_TERM_COLOR: always jobs: Build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -22,13 +22,51 @@ jobs: - name: Build (all features enabled) run: cargo build --verbose --all-features - - name: Check semver compatibility (russh) - uses: obi1kenobi/cargo-semver-checks-action@v2 - with: - package: russh + Build-Windows: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + + - name: install nasm + run: | + choco install nasm + echo "C:\Program Files\NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Build (no features enabled) + run: cargo build --verbose + + - name: Build (all features enabled) + run: cargo build --verbose --all-features + + Build-WASM: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v2 + + - name: Install target + run: | + rustup toolchain add 1.81.0 + rustup target add --toolchain 1.81.0 wasm32-wasip1 + + - name: Build (WASM-compatible features) + run: cargo +1.81.0 build --verbose --target wasm32-wasip1 --no-default-features --features flate2,ring -p russh + + Formatting: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v2 + + - name: Install rustfmt + run: rustup component add rustfmt + + - name: rustfmt + run: cargo fmt --check Clippy: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -43,7 +81,7 @@ jobs: run: cargo clippy --all-features -- -D warnings Test: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -61,3 +99,16 @@ jobs: cargo test --verbose --all-features env: RUST_BACKTRACE: 1 + + Minimal-versions: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v2 + - uses: taiki-e/install-action@cargo-hack + - uses: taiki-e/install-action@cargo-minimal-versions + + - name: Check with minimal dependency versions + run: | + rustup toolchain add 1.75.0 + cargo +1.75.0 minimal-versions check --all-features --no-dev-deps diff --git a/.github/workflows/semver.yml b/.github/workflows/semver.yml new file mode 100644 index 00000000..90a8ca4f --- /dev/null +++ b/.github/workflows/semver.yml @@ -0,0 +1,26 @@ +name: Semver check + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +env: + CARGO_TERM_COLOR: always + +jobs: + Build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Build (no features enabled) + run: cargo build --verbose + + - name: Check semver compatibility (russh) + uses: obi1kenobi/cargo-semver-checks-action@v2 + continue-on-error: true + with: + package: russh diff --git a/.gitignore b/.gitignore index abb7748a..c2d07934 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ target Cargo.lock .cargo-ok +ca-test* diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..8031f7f6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.check.command": "check" +} diff --git a/.well-known/funding-manifest-urls b/.well-known/funding-manifest-urls new file mode 100644 index 00000000..c510488c --- /dev/null +++ b/.well-known/funding-manifest-urls @@ -0,0 +1 @@ +https://null.page/funding.json diff --git a/Cargo.toml b/Cargo.toml index d4ed211c..766b149d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,36 @@ [workspace] -members = [ "russh-keys", "russh", "russh-config", "cryptovec"] +members = ["russh", "russh-config", "cryptovec", "pageant", "russh-util"] +resolver = "2" -[patch.crates-io] -russh = { path = "russh" } -russh-keys = { path = "russh-keys" } -russh-cryptovec = { path = "cryptovec" } -russh-config = { path = "russh-config" } +[workspace.dependencies] +aes = "0.8" +async-trait = "0.1.50" +byteorder = "1.4" +bytes = "1.7" +digest = "0.10" +delegate = "0.13" +env_logger = "0.6" +futures = "0.3" +home = "0.5" +hmac = "0.12" +log = "0.4.11" +rand = "0.8" +rsa = "0.9" +sha1 = { version = "0.10.5", features = ["oid"] } +sha2 = { version = "0.10.6", features = ["oid"] } +signature = "2.2" +ssh-encoding = { version = "0.2", features = ["bytes"] } +ssh-key = { version = "=0.6.11", features = [ + "ed25519", + "rsa", + "rsa-sha1", + "p256", + "p384", + "p521", + "encryption", + "ppk", + "hazmat-allow-insecure-rsa-keys", +], package = "internal-russh-forked-ssh-key" } +thiserror = "1.0.30" +tokio = { version = "1.17.0" } +tokio-stream = { version = "0.1.3", features = ["net", "sync"] } diff --git a/README.md b/README.md index 76346d74..22184062 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,45 @@ # Russh + [](https://github.com/warp-tech/russh/actions/workflows/rust.yml) -[](#contributors-) +[](#contributors-) Low-level Tokio SSH2 client and server implementation. +Examples: [simple client](russh/examples/client_exec_simple.rs), [interactive PTY client](russh/examples/client_exec_interactive.rs), [server](russh/examples/echoserver.rs), [SFTP client](russh/examples/sftp_client.rs), [SFTP server](russh/examples/sftp_server.rs). + This is a fork of [Thrussh](https://nest.pijul.com/pijul/thrussh) by Pierre-Étienne Meunier. > ✨ = added in Russh * [More panic safety](https://github.com/warp-tech/russh#safety) ✨ -* `async_trait` support ✨ +* async traits ✨ * `direct-tcpip` (local port forwarding) * `forward-tcpip` (remote port forwarding) ✨ * `direct-streamlocal` (local UNIX socket forwarding, client only) ✨ +* `forward-streamlocal` (remote UNIX socket forwarding) ✨ * Ciphers: * `chacha20-poly1305@openssh.com` + * `aes128-gcm@openssh.com` ✨ * `aes256-gcm@openssh.com` ✨ * `aes256-ctr` ✨ * `aes192-ctr` ✨ * `aes128-ctr` ✨ + * `aes256-cbc` ✨ + * `aes192-cbc` ✨ + * `aes128-cbc` ✨ + * `3des-cbc` ✨ * Key exchanges: * `curve25519-sha256@libssh.org` + * `diffie-hellman-group-sha1` (GEX) ✨ * `diffie-hellman-group1-sha1` ✨ * `diffie-hellman-group14-sha1` ✨ + * `diffie-hellman-group-sha256` (GEX) ✨ * `diffie-hellman-group14-sha256` ✨ + * `diffie-hellman-group16-sha512` ✨ + * `ecdh-sha2-nistp256` ✨ + * `ecdh-sha2-nistp384` ✨ + * `ecdh-sha2-nistp521` ✨ * MACs: * `hmac-sha1` ✨ * `hmac-sha2-256` ✨ @@ -32,15 +47,27 @@ This is a fork of [Thrussh](https://nest.pijul.com/pijul/thrussh) by Pierre-Éti * `hmac-sha1-etm@openssh.com` ✨ * `hmac-sha2-256-etm@openssh.com` ✨ * `hmac-sha2-512-etm@openssh.com` ✨ -* Host keys: +* Host keys and public key auth: * `ssh-ed25519` * `rsa-sha2-256` * `rsa-sha2-512` * `ssh-rsa` ✨ + * `ecdsa-sha2-nistp256` ✨ + * `ecdsa-sha2-nistp384` ✨ + * `ecdsa-sha2-nistp521` ✨ +* Authentication methods: + * `password` + * `publickey` + * `keyboard-interactive` + * `none` + * OpenSSH certificates ✨ * Dependency updates * OpenSSH keepalive request handling ✨ * OpenSSH agent forwarding channels ✨ * OpenSSH `server-sig-algs` extension ✨ +* PPK key format ✨ +* Pageant support ✨ +* `AsyncRead`/`AsyncWrite`-able channels ✨ ## Safety @@ -53,6 +80,7 @@ This is a fork of [Thrussh](https://nest.pijul.com/pijul/thrussh) by Pierre-Éti ### Panics * When the Rust allocator fails to allocate memory during a CryptoVec being resized. +* When `mlock`/`munlock` fails to protect sensitive data in memory. ### Unsafe code @@ -60,9 +88,32 @@ This is a fork of [Thrussh](https://nest.pijul.com/pijul/thrussh) by Pierre-Éti ## Ecosystem -* [russh-sftp](https://crates.io/crates/russh-sftp) - server-side SFTP subsystem support for `russh` - see `russh/examples/sftp_server.rs`. +* [russh-sftp](https://crates.io/crates/russh-sftp) - server-side and client-side SFTP subsystem support for `russh` - see `russh/examples/sftp_server.rs` or `russh/examples/sftp_client.rs`. * [async-ssh2-tokio](https://crates.io/crates/async-ssh2-tokio) - simple high-level API for running commands over SSH. +## Adopters + +* [HexPatch](https://github.com/Etto48/HexPatch) - A binary patcher and editor written in Rust with terminal user interface (TUI). + * Uses `russh::client` and `russh_sftp::client` to allow remote editing of files. +* [kartoffels](https://github.com/Patryk27/kartoffels) - A game where you're given a potato and your job is to implement a firmware for it + * Uses `russh:server` to deliver the game, using `ratatui` as the rendering engine. +* [kty](https://github.com/grampelberg/kty) - The terminal for Kubernetes. + * Uses `russh::server` to deliver the `ratatui` based TUI and `russh_sftp::server` to provide `scp` based file management. +* [lapdev](https://github.com/lapce/lapdev) - Self-Hosted Remote Dev Environment + * Uses `russh::server` to construct a proxy into your development environment. +* [medusa](https://github.com/evilsocket/medusa) - A fast and secure multi protocol honeypot. + * Uses `russh::server` to be the basis of the honeypot. +* [rebels-in-the-sky](https://github.com/ricott1/rebels-in-the-sky) - P2P terminal game about spacepirates playing basketball across the galaxy + * Uses `russh::server` to deliver the game, using `ratatui` as the rendering engine. +* [warpgate](https://github.com/warp-tech/warpgate) - Smart SSH, HTTPS and MySQL bastion that requires no additional client-side software + * Uses `russh::server` in addition to `russh::client` as part of the smart SSH functionality. +* [Devolutions Gateway](https://github.com/Devolutions/devolutions-gateway/) - Establish a secure entry point for internal or external segmented networks that require authorized just-in-time (JIT) access. + * Uses `russh::client` for the web-based SSH client of the standalone web application. +* [Sandhole](https://github.com/EpicEric/sandhole) - Expose HTTP/SSH/TCP services through SSH port forwarding. A reverse proxy that just works with an OpenSSH client. + * Uses `russh::server` for reverse forwarding connections, local forwarding tunnels, and the `ratatui` based admin interface. +* [Motor OS](https://github.com/moturus/motor-os) - A new Rust-based operating system for VMs. + * Uses `russh::server` as the base for its own [SSH Server](https://github.com/moturus/motor-os/tree/main/src/bin/russhd). + ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): @@ -73,29 +124,88 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d