chore(deps): bump russh 0.45 -> 0.60.1, drop GHSA-f5v4-2wr6-hqmg allowlist (#1851)#3610
Merged
Conversation
…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
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
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
russhdependency from 0.45 to 0.60.1, retiring the GHSA-f5v4-2wr6-hqmg / RUSTSEC-2023-0071 Marvin Attack timing side-channel by transitively pullingrsa0.10 (the constant-time rewrite). Removes the corresponding entry fromdeny.toml.russh-keys(now re-exported underrussh::keys), drops thessh-keyandasync-traitworkspace deps. Fewer crates, smaller dep graph.crates/rsync_io/src/ssh/embedded/to the new API surface (nativeasync fnin traits,PrivateKeyWithHashAlg,AuthResult::success(),Bytes-basedHandle::data, etc).Why
#1851(P0, beta-blocking) tracks the Marvin Attack allowlist forembedded-ssh. Default builds were unaffected, butcargo deny check advisorieshad to ignore RUSTSEC-2023-0071 to avoid CI failures. Upstream russh has since cut a 0.60 series that depends on the rewrittenrsa0.10, eliminating the timing side-channel at the source. This change retires the allowlist instead of carrying it indefinitely.API surface migration (notable breaks)
#[async_trait::async_trait]async fnin traitsrussh_keys::key::PublicKey,ssh-keyrussh::keys::{PublicKey, PrivateKey}authenticate_publickey(user, Arc<KeyPair>)authenticate_publickey(user, PrivateKeyWithHashAlg::new(Arc::new(key), None))boolAuthResultwith.success()Handle::data(id, CryptoVec::from_slice(&data))Handle::data(id, data)(Vec into Bytes)server.run_on_socket(cfg, &listener).await?server.run_on_socket(cfg, &listener).await(no Result)key.fingerprint()key.fingerprint(HashAlg::Sha256)key.name()key.algorithm()Auth::Reject { ... }Auth::reject()constructorFiles touched
Cargo.toml- workspace pinrussh = "0.60.1"; removeasync-trait,russh-keys,ssh-key.Cargo.lock- regenerated viacargo update -p russh. Major movement:rsa 0.9.10 -> 0.10.0-rc.16, addsinternal-russh-forked-ssh-key, removes standalonerussh-keys/ssh-key.deny.toml- dropRUSTSEC-2023-0071fromadvisories.ignore.crates/rsync_io/Cargo.toml- dropasync-trait/russh-keys/ssh-keyfrom theembedded-sshfeature; addrand = "0.10"dev-dep for test keypair generation (matches russh 0.60's rand version).crates/rsync_io/src/ssh/embedded/handler.rs- migrateSshClientHandlerto nativeasync fn check_server_key; userussh::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- dropCryptoVecwrapping; passVec<u8>directly toHandle::data.docs/audits/ssh-transport-timeout-coverage.md- updaterussh_keys::load_secret_keyreference torussh::keys::load_secret_key.Test plan
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-features --no-deps -- -D warningscargo nextest run --workspace --all-features(full CI matrix)cargo deny check advisories- must pass without the RUSTSEC-2023-0071 allowlist.authenticate_pubkey_succeeds,authenticate_password_succeeds, host-key verification suite) exercise the migrated API end-to-end.Closes #1851