From d4e840b5353fd1d6acde84964dcb2d42563fa63c Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 14 Jan 2025 11:57:30 +0100 Subject: [PATCH] Allow setting hash algorithm to use for signing requests of SSH agent Fixes: https://github.com/Eugeny/russh/issues/444 Fixes: https://github.com/Eugeny/russh/issues/445 Signed-off-by: Wiktor Kwapisiewicz --- russh/src/auth.rs | 8 ++++++-- russh/src/client/mod.rs | 5 +++-- russh/src/keys/agent/client.rs | 23 +++++++++++------------ 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/russh/src/auth.rs b/russh/src/auth.rs index 1cdf2579..cf53070e 100644 --- a/russh/src/auth.rs +++ b/russh/src/auth.rs @@ -18,7 +18,7 @@ use std::str::FromStr; use std::sync::Arc; use async_trait::async_trait; -use ssh_key::{Certificate, PrivateKey}; +use ssh_key::{Certificate, HashAlg, PrivateKey}; use thiserror::Error; use tokio::io::{AsyncRead, AsyncWrite}; @@ -154,6 +154,7 @@ pub trait Signer: Sized { async fn auth_publickey_sign( &mut self, key: &ssh_key::PublicKey, + hash_alg: Option, to_sign: CryptoVec, ) -> Result; } @@ -175,9 +176,12 @@ impl Signer async fn auth_publickey_sign( &mut self, key: &ssh_key::PublicKey, + hash_alg: Option, to_sign: CryptoVec, ) -> Result { - self.sign_request(key, to_sign).await.map_err(Into::into) + self.sign_request(key, hash_alg, to_sign) + .await + .map_err(Into::into) } } diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index f50830d8..a5b6d1ed 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -47,7 +47,7 @@ use kex::ClientKex; use log::{debug, error, trace}; use russh_util::time::Instant; use ssh_encoding::Decode; -use ssh_key::{Certificate, PrivateKey, PublicKey}; +use ssh_key::{Certificate, HashAlg, PrivateKey, PublicKey}; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf}; use tokio::pin; use tokio::sync::mpsc::{ @@ -401,6 +401,7 @@ impl Handle { &mut self, user: U, key: ssh_key::PublicKey, + hash_alg: Option, signer: &mut S, ) -> Result { let user = user.into(); @@ -423,7 +424,7 @@ impl Handle { proceed_with_methods: remaining_methods, }) => return Ok(AuthResult::Failure { remaining_methods }), Some(Reply::SignRequest { key, data }) => { - let data = signer.auth_publickey_sign(&key, data).await; + let data = signer.auth_publickey_sign(&key, hash_alg, data).await; let data = match data { Ok(data) => data, Err(e) => return Err(e), diff --git a/russh/src/keys/agent/client.rs b/russh/src/keys/agent/client.rs index 7969df8a..de9fedb7 100644 --- a/russh/src/keys/agent/client.rs +++ b/russh/src/keys/agent/client.rs @@ -4,7 +4,7 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; use log::debug; use ssh_encoding::{Decode, Encode, Reader}; -use ssh_key::{Algorithm, HashAlg, PrivateKey, PublicKey, Signature}; +use ssh_key::{HashAlg, PrivateKey, PublicKey, Signature}; use tokio; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; @@ -284,10 +284,11 @@ impl AgentClient { pub async fn sign_request( &mut self, public: &PublicKey, + hash_alg: Option, mut data: CryptoVec, ) -> Result { debug!("sign_request: {:?}", data); - let hash = self.prepare_sign_request(public, &data)?; + let hash = self.prepare_sign_request(public, hash_alg, &data)?; self.read_response().await?; @@ -307,6 +308,7 @@ impl AgentClient { fn prepare_sign_request( &mut self, public: &ssh_key::PublicKey, + hash_alg: Option, data: &[u8], ) -> Result { self.buf.clear(); @@ -315,14 +317,9 @@ impl AgentClient { public.key_data().encoded()?.encode(&mut self.buf)?; data.encode(&mut self.buf)?; debug!("public = {:?}", public); - let hash = match public.algorithm() { - Algorithm::Rsa { - hash: Some(HashAlg::Sha256), - } => 2, - Algorithm::Rsa { - hash: Some(HashAlg::Sha512), - } => 4, - Algorithm::Rsa { hash: None } => 0, + let hash = match hash_alg { + Some(HashAlg::Sha256) => 2, + Some(HashAlg::Sha512) => 4, _ => 0, }; hash.encode(&mut self.buf)?; @@ -352,10 +349,11 @@ impl AgentClient { pub fn sign_request_base64( mut self, public: &ssh_key::PublicKey, + hash_alg: Option, data: &[u8], ) -> impl futures::Future)> { debug!("sign_request: {:?}", data); - let r = self.prepare_sign_request(public, data); + let r = self.prepare_sign_request(public, hash_alg, data); async move { if let Err(e) = r { return (self, Err(e)); @@ -380,11 +378,12 @@ impl AgentClient { pub async fn sign_request_signature( &mut self, public: &ssh_key::PublicKey, + hash_alg: Option, data: &[u8], ) -> Result { debug!("sign_request: {:?}", data); - self.prepare_sign_request(public, data)?; + self.prepare_sign_request(public, hash_alg, data)?; self.read_response().await?; match self.buf.split_first() {