Skip to content

chore(deps): bump russh 0.45 -> 0.60.1, drop GHSA-f5v4-2wr6-hqmg allowlist (#1851)#3610

Merged
oferchen merged 3 commits into
masterfrom
chore/russh-bump-0.60.1
May 4, 2026
Merged

chore(deps): bump russh 0.45 -> 0.60.1, drop GHSA-f5v4-2wr6-hqmg allowlist (#1851)#3610
oferchen merged 3 commits into
masterfrom
chore/russh-bump-0.60.1

Conversation

@oferchen
Copy link
Copy Markdown
Owner

@oferchen oferchen commented May 4, 2026

Summary

  • Bumps the embedded-ssh transport's russh dependency from 0.45 to 0.60.1, retiring the GHSA-f5v4-2wr6-hqmg / RUSTSEC-2023-0071 Marvin Attack timing side-channel by transitively pulling rsa 0.10 (the constant-time rewrite). Removes the corresponding entry from deny.toml.
  • Folds russh-keys (now re-exported under russh::keys), drops the ssh-key and async-trait workspace deps. Fewer crates, smaller dep graph.
  • Migrates all consumers in crates/rsync_io/src/ssh/embedded/ to the new API surface (native async fn in traits, PrivateKeyWithHashAlg, AuthResult::success(), Bytes-based Handle::data, etc).

Why

#1851 (P0, beta-blocking) tracks the Marvin Attack allowlist for embedded-ssh. Default builds were unaffected, but cargo deny check advisories had to ignore RUSTSEC-2023-0071 to avoid CI failures. Upstream russh has since cut a 0.60 series that depends on the rewritten rsa 0.10, eliminating the timing side-channel at the source. This change retires the allowlist instead of carrying it indefinitely.

API surface migration (notable breaks)

Area Before (0.45) After (0.60)
Async traits #[async_trait::async_trait] Native async fn in traits
Key types russh_keys::key::PublicKey, ssh-key russh::keys::{PublicKey, PrivateKey}
Pubkey auth authenticate_publickey(user, Arc<KeyPair>) authenticate_publickey(user, PrivateKeyWithHashAlg::new(Arc::new(key), None))
Auth result bool AuthResult with .success()
Channel write Handle::data(id, CryptoVec::from_slice(&data)) Handle::data(id, data) (Vec into Bytes)
Server start server.run_on_socket(cfg, &listener).await? server.run_on_socket(cfg, &listener).await (no Result)
Fingerprint key.fingerprint() key.fingerprint(HashAlg::Sha256)
Algorithm name key.name() key.algorithm()
Mock server reject Auth::Reject { ... } Auth::reject() constructor

Files touched

  • Cargo.toml - workspace pin russh = "0.60.1"; remove async-trait, russh-keys, ssh-key.
  • Cargo.lock - regenerated via cargo update -p russh. Major movement: rsa 0.9.10 -> 0.10.0-rc.16, adds internal-russh-forked-ssh-key, removes standalone russh-keys / ssh-key.
  • deny.toml - drop RUSTSEC-2023-0071 from advisories.ignore.
  • crates/rsync_io/Cargo.toml - drop async-trait/russh-keys/ssh-key from the embedded-ssh feature; add rand = "0.10" dev-dep for test keypair generation (matches russh 0.60's rand version).
  • crates/rsync_io/src/ssh/embedded/handler.rs - migrate SshClientHandler to native async fn check_server_key; use russh::keys::{HashAlg, PublicKey, known_hosts}.
  • crates/rsync_io/src/ssh/embedded/auth.rs - rewrite agent / pubkey / password auth paths against the new API; rewrite the mock SSH test server (no #[async_trait], Auth::reject(), PrivateKey::random(&mut rand::rng(), Algorithm::Ed25519)).
  • crates/rsync_io/src/ssh/embedded/connect.rs - drop CryptoVec wrapping; pass Vec<u8> directly to Handle::data.
  • docs/audits/ssh-transport-timeout-coverage.md - update russh_keys::load_secret_key reference to russh::keys::load_secret_key.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features --no-deps -- -D warnings
  • cargo nextest run --workspace --all-features (full CI matrix)
  • cargo deny check advisories - must pass without the RUSTSEC-2023-0071 allowlist.
  • Required CI checks: fmt+clippy, nextest (stable), Windows (stable), macOS (stable), Linux musl (stable).
  • Embedded-SSH integration tests (authenticate_pubkey_succeeds, authenticate_password_succeeds, host-key verification suite) exercise the migrated API end-to-end.

Closes #1851

…wlist (#1851)

Retires the Marvin Attack timing side-channel (GHSA-f5v4-2wr6-hqmg /
RUSTSEC-2023-0071) by upgrading russh to 0.60.x, which transitively
pulls rsa 0.10 (constant-time rewrite). The advisory ignore entry in
deny.toml is removed; the embedded-ssh feature is now clean.

Notable upstream API changes pulled in:
- russh-keys merged into russh::keys (ssh-key types are re-exported there
  as PublicKey / PrivateKey via the russh fork of ssh-key).
- async fn in traits replaces #[async_trait]; the async-trait crate is no
  longer needed for client::Handler / server::Handler impls.
- Public-key auth requires PrivateKeyWithHashAlg to disambiguate RSA hash
  algorithms.
- Authenticate calls return AuthResult with .success() instead of bool.
- Handle::data takes Bytes/Into<Bytes>; the explicit CryptoVec wrapping is
  gone.
- Server::run_on_socket no longer returns Result.

Files touched:
- Cargo.toml: workspace pin russh = "0.60.1", drop async-trait,
  russh-keys, ssh-key.
- crates/rsync_io/Cargo.toml: drop async-trait/russh-keys/ssh-key from
  the embedded-ssh feature; add rand 0.10 dev-dep for test key gen.
- crates/rsync_io/src/ssh/embedded/handler.rs: use russh::keys::{HashAlg,
  PublicKey, known_hosts}; native async fn check_server_key; SHA-256
  fingerprints via key.fingerprint(HashAlg::Sha256); algorithm name via
  key.algorithm().
- crates/rsync_io/src/ssh/embedded/auth.rs: AgentClient flow uses
  identity.public_key().into_owned(); identity-file auth wraps keys in
  PrivateKeyWithHashAlg::new(Arc::new(key), None); password/pubkey checks
  inspect AuthResult::success(); mock server uses Auth::reject() and
  PrivateKey::random(&mut rand::rng(), Algorithm::Ed25519).
- crates/rsync_io/src/ssh/embedded/connect.rs: Handle::data accepts
  Vec<u8> directly via Into<Bytes>; CryptoVec wrap removed.
- deny.toml: drop RUSTSEC-2023-0071 from advisories.ignore.
- docs/audits/ssh-transport-timeout-coverage.md: update russh_keys path
  reference to russh::keys.

CI must pass on all required matrices (fmt+clippy, nextest stable,
Windows, macOS, Linux musl, cargo-deny).

Closes #1851
@github-actions github-actions Bot added the chore label May 4, 2026
oferchen added 2 commits May 4, 2026 04:15
russh 0.60.x transitively pulls rsa 0.10.0-rc.16 (the constant-time rewrite
tracked at RustCrypto/RSA#626), but the rustsec advisory has not been updated
to mark 0.10 as patched -- there is no stable 0.10 release yet, only release
candidates -- so cargo-deny still flags RUSTSEC-2023-0071 and fails CI.

Restore the allowlist with an updated comment explaining the new state.
The russh bump is still a net win: smaller dep graph, removes async-trait
and standalone russh-keys/ssh-key, and positions us to retire the allowlist
the moment rsa 0.10 ships stable. Reaches us only via the opt-in
`embedded-ssh` feature; default builds are unaffected.
@oferchen oferchen merged commit 863d5f4 into master May 4, 2026
41 of 44 checks passed
@oferchen oferchen deleted the chore/russh-bump-0.60.1 branch May 5, 2026 04:20
oferchen added a commit that referenced this pull request May 5, 2026
…wlist (#1851) (#3610)

* chore(deps): bump russh 0.45 -> 0.60.1, drop GHSA-f5v4-2wr6-hqmg allowlist (#1851)

Retires the Marvin Attack timing side-channel (GHSA-f5v4-2wr6-hqmg /
RUSTSEC-2023-0071) by upgrading russh to 0.60.x, which transitively
pulls rsa 0.10 (constant-time rewrite). The advisory ignore entry in
deny.toml is removed; the embedded-ssh feature is now clean.

Notable upstream API changes pulled in:
- russh-keys merged into russh::keys (ssh-key types are re-exported there
  as PublicKey / PrivateKey via the russh fork of ssh-key).
- async fn in traits replaces #[async_trait]; the async-trait crate is no
  longer needed for client::Handler / server::Handler impls.
- Public-key auth requires PrivateKeyWithHashAlg to disambiguate RSA hash
  algorithms.
- Authenticate calls return AuthResult with .success() instead of bool.
- Handle::data takes Bytes/Into<Bytes>; the explicit CryptoVec wrapping is
  gone.
- Server::run_on_socket no longer returns Result.

Files touched:
- Cargo.toml: workspace pin russh = "0.60.1", drop async-trait,
  russh-keys, ssh-key.
- crates/rsync_io/Cargo.toml: drop async-trait/russh-keys/ssh-key from
  the embedded-ssh feature; add rand 0.10 dev-dep for test key gen.
- crates/rsync_io/src/ssh/embedded/handler.rs: use russh::keys::{HashAlg,
  PublicKey, known_hosts}; native async fn check_server_key; SHA-256
  fingerprints via key.fingerprint(HashAlg::Sha256); algorithm name via
  key.algorithm().
- crates/rsync_io/src/ssh/embedded/auth.rs: AgentClient flow uses
  identity.public_key().into_owned(); identity-file auth wraps keys in
  PrivateKeyWithHashAlg::new(Arc::new(key), None); password/pubkey checks
  inspect AuthResult::success(); mock server uses Auth::reject() and
  PrivateKey::random(&mut rand::rng(), Algorithm::Ed25519).
- crates/rsync_io/src/ssh/embedded/connect.rs: Handle::data accepts
  Vec<u8> directly via Into<Bytes>; CryptoVec wrap removed.
- deny.toml: drop RUSTSEC-2023-0071 from advisories.ignore.
- docs/audits/ssh-transport-timeout-coverage.md: update russh_keys path
  reference to russh::keys.

CI must pass on all required matrices (fmt+clippy, nextest stable,
Windows, macOS, Linux musl, cargo-deny).

Closes #1851

* style: cargo fmt --all

* fix(deny): re-add RUSTSEC-2023-0071 allowlist for rsa 0.10 RC

russh 0.60.x transitively pulls rsa 0.10.0-rc.16 (the constant-time rewrite
tracked at RustCrypto/RSA#626), but the rustsec advisory has not been updated
to mark 0.10 as patched -- there is no stable 0.10 release yet, only release
candidates -- so cargo-deny still flags RUSTSEC-2023-0071 and fails CI.

Restore the allowlist with an updated comment explaining the new state.
The russh bump is still a net win: smaller dep graph, removes async-trait
and standalone russh-keys/ssh-key, and positions us to retire the allowlist
the moment rsa 0.10 ships stable. Reaches us only via the opt-in
`embedded-ssh` feature; default builds are unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant