Skip to content

Commit

Permalink
re-added support for ssh-rsa signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
Eugeny committed Nov 24, 2024
1 parent e435955 commit f602e45
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 53 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ futures = "0.3"
hmac = "0.12"
log = "0.4"
rand = "0.8"
rsa = "0.9"
sha1 = { version = "0.10", features = ["oid"] }
sha2 = { version = "0.10", features = ["oid"] }
signature = "2.2"
Expand Down
8 changes: 4 additions & 4 deletions pageant/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ version = "0.0.1-beta.3"
rust-version = "1.65"

[dependencies]
futures = { workspace = true }
thiserror = { workspace = true }
rand = { workspace = true }
futures.workspace = true
thiserror.workspace = true
rand.workspace = true
tokio = { workspace = true, features = ["io-util", "rt"] }
bytes = { workspace = true }
bytes.workspace = true
delegate.workspace = true

[target.'cfg(windows)'.dependencies]
Expand Down
6 changes: 3 additions & 3 deletions russh-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ rust-version = "1.65"

[dependencies]
home = "0.5"
futures = { workspace = true }
futures.workspace = true
globset = "0.4.14"
log = { workspace = true }
thiserror = { workspace = true }
log.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = ["io-util", "net", "macros", "process"] }
whoami = "1.2"
34 changes: 17 additions & 17 deletions russh-keys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@ version = "0.47.0-beta.2"
rust-version = "1.65"

[dependencies]
aes = { workspace = true }
async-trait = { workspace = true }
aes.workspace = true
async-trait.workspace = true
bcrypt-pbkdf = "0.10"
bytes = { workspace = true }
bytes.workspace = true
cbc = "0.1"
ctr = "0.9"
block-padding = { version = "0.3", features = ["std"] }
byteorder = { workspace = true }
byteorder.workspace = true
data-encoding = "2.3"
digest = { workspace = true }
digest.workspace = true
der = "0.7"
ecdsa = "0.16"
ed25519-dalek = { version = "2.0", features = ["rand_core", "pkcs8"] }
elliptic-curve = "0.13"
futures = { workspace = true }
hmac = { workspace = true }
futures.workspace = true
hmac.workspace = true
inout = { version = "0.1", features = ["std"] }
log = { workspace = true }
log.workspace = true
md5 = "0.7"
num-integer = "0.1"
p256 = "0.13"
Expand All @@ -39,22 +39,22 @@ pbkdf2 = "0.12"
pkcs1 = "0.7"
pkcs5 = "0.7"
pkcs8 = { version = "0.10", features = ["pkcs5", "encryption"] }
rand = { workspace = true }
rand.workspace = true
rand_core = { version = "0.6.4", features = ["std"] }
rsa = "0.9"
rsa.workspace = true
russh-cryptovec = { version = "0.8.0-beta.1", path = "../cryptovec", features = [
"ssh-encoding",
] }
russh-util = { version = "0.46.0", path = "../russh-util" }
sec1 = { version = "0.7", features = ["pkcs8"] }
serde = { version = "1.0", features = ["derive"] }
sha1 = { workspace = true }
sha2 = { workspace = true }
signature = { workspace = true }
sha1.workspace = true
sha2.workspace = true
signature.workspace = true
spki = "0.7"
ssh-encoding = { workspace = true }
ssh-key = { workspace = true }
thiserror = { workspace = true }
ssh-encoding.workspace = true
ssh-key.workspace = true
thiserror.workspace = true
typenum = "1.17"
yasna = { version = "0.5.0", features = [
"bit-vec",
Expand All @@ -74,7 +74,7 @@ tokio = { workspace = true, features = [
"time",
"net",
] }
tokio-stream = { workspace = true }
tokio-stream.workspace = true
home = "0.5"


Expand Down
33 changes: 17 additions & 16 deletions russh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,43 @@ default = ["flate2"]
legacy-ed25519-pkcs8-parser = ["russh-keys/legacy-ed25519-pkcs8-parser"]

[dependencies]
aes = { workspace = true }
aes.workspace = true
aes-gcm = "0.10"
cbc = { version = "0.1" }
async-trait = { workspace = true }
async-trait.workspace = true
bitflags = "2.0"
byteorder = { workspace = true }
bytes = { workspace = true }
byteorder.workspace = true
bytes.workspace = true
chacha20 = "0.9"
ctr = "0.9"
curve25519-dalek = "4.1.3"
delegate.workspace = true
digest = { workspace = true }
digest.workspace = true
elliptic-curve = { version = "0.13", features = ["ecdh"] }
flate2 = { version = "1.0", optional = true }
futures = { workspace = true }
futures.workspace = true
generic-array = "0.14"
hex-literal = "0.4"
hmac = { workspace = true }
log = { workspace = true }
hmac.workspace = true
log.workspace = true
num-bigint = { version = "0.4", features = ["rand"] }
once_cell = "1.13"
p256 = { version = "0.13", features = ["ecdh"] }
p384 = { version = "0.13", features = ["ecdh"] }
p521 = { version = "0.13", features = ["ecdh"] }
poly1305 = "0.8"
rand = { workspace = true }
rand.workspace = true
rand_core = { version = "0.6.4", features = ["getrandom"] }
rsa.workspace = true
russh-cryptovec = { version = "0.8.0-beta.2", path = "../cryptovec" }
russh-keys = { version = "0.47.0-beta.2", path = "../russh-keys" }
sha1 = { workspace = true }
sha2 = { workspace = true }
signature = { workspace = true }
ssh-encoding = { workspace = true }
ssh-key = { workspace = true }
sha1.workspace = true
sha2.workspace = true
signature.workspace = true
ssh-encoding.workspace = true
ssh-key.workspace = true
subtle = "2.4"
thiserror = { workspace = true }
thiserror.workspace = true
russh-util = { version = "0.46.0", path = "../russh-util" }
des = "0.8.1"
tokio = { workspace = true, features = ["io-util", "sync", "time"] }
Expand All @@ -78,4 +79,4 @@ ratatui = "0.29.0"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
russh-sftp = "2.0.5"
tokio = { workspace = true }
tokio.workspace = true
18 changes: 9 additions & 9 deletions russh/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ use futures::task::{Context, Poll};
use futures::Future;
use log::{debug, error, info, trace};
use russh_keys::map_err;
use signature::Verifier;
use ssh_encoding::{Decode, Encode, Reader};
use ssh_key::{Certificate, PrivateKey, PublicKey, Signature};
use ssh_key::{Certificate, PrivateKey, PublicKey};
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf};
use tokio::pin;
use tokio::sync::mpsc::{
Expand All @@ -67,8 +66,8 @@ use crate::session::{
use crate::ssh_read::SshRead;
use crate::sshbuffer::{SSHBuffer, SshId};
use crate::{
auth, msg, negotiation, strict_kex_violation, ChannelId, ChannelOpenFailure, CryptoVec,
Disconnect, Limits, Sig,
auth, msg, negotiation, sig_workaround, strict_kex_violation, ChannelId, ChannelOpenFailure,
CryptoVec, Disconnect, Limits, Sig,
};

mod encrypted;
Expand Down Expand Up @@ -1334,11 +1333,12 @@ impl KexDhDone {
};

debug!("signature: {:?}", signature);
let signature = Signature::new(pubkey.algorithm(), signature).map_err(|e| {
debug!("signature ctor failed: {e:?}");
crate::Error::WrongServerSig
})?;
if Verifier::verify(&pubkey, hash.as_ref(), &signature).is_err() {
let signature = sig_workaround::Sig::new(pubkey.algorithm(), signature.to_vec())
.map_err(|e| {
debug!("signature ctor failed: {e:?}");
crate::Error::WrongServerSig
})?;
if sig_workaround::verify(&pubkey, hash.as_ref(), &signature).is_err() {
debug!("wrong server sig");
return Err(crate::Error::WrongServerSig.into());
}
Expand Down
1 change: 1 addition & 0 deletions russh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pub mod compression;
pub mod kex;
/// MAC algorithm names
pub mod mac;
mod sig_workaround;

/// Re-export of the `russh-keys` crate.
pub use russh_keys as keys;
Expand Down
10 changes: 6 additions & 4 deletions russh/src/server/encrypted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ use log::{debug, error, info, trace, warn};
use negotiation::Select;
use russh_keys::helpers::NameList;
use russh_keys::map_err;
use signature::Verifier;
use ssh_encoding::{Decode, Encode, Reader};
use ssh_key::{PublicKey, Signature};
use ssh_key::PublicKey;
use tokio::time::Instant;
use {msg, negotiation};

use super::super::*;
use super::*;
use crate::msg::SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
use crate::parsing::{ChannelOpenConfirmation, ChannelType, OpenChannelMessage};
use crate::sig_workaround;

impl Session {
/// Returns false iff a request was rejected.
Expand Down Expand Up @@ -460,7 +460,9 @@ impl Encrypted {

let encoded_signature = map_err!(Vec::<u8>::decode(r))?;

let sig = map_err!(Signature::decode(&mut encoded_signature.as_slice()))?;
let sig = map_err!(sig_workaround::Sig::decode(
&mut encoded_signature.as_slice()
))?;

// SAFETY: both original_packet and pos0 are coming
// from the same allocation (pos0 is derived from
Expand Down Expand Up @@ -491,7 +493,7 @@ impl Encrypted {
map_err!(session_id.encode(&mut *buf))?;
buf.extend(init);

Ok(Verifier::verify(&pubkey, &buf, &sig).is_ok())
Ok(sig_workaround::verify(&pubkey, &buf, &sig).is_ok())
})? {
debug!("signature verified");
let auth = match pk_or_cert {
Expand Down
40 changes: 40 additions & 0 deletions russh/src/sig_workaround.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// TODO only needed until https://github.com/RustCrypto/SSH/pull/315 is released
use std::convert::TryFrom;

use signature::Verifier;
use ssh_encoding::Decode;
use ssh_key::{Algorithm, PublicKey, Signature};

pub enum Sig {
Normal(Signature),
SshRsa(Vec<u8>),
}

impl Sig {
pub fn new(algo: Algorithm, sigbuf: Vec<u8>) -> ssh_key::Result<Self> {
match algo {
Algorithm::Rsa { hash: None } => Ok(Sig::SshRsa(sigbuf)),
_ => Ok(Sig::Normal(Signature::new(algo, sigbuf)?)),
}
}

pub fn decode(reader: &mut &[u8]) -> ssh_key::Result<Self> {
let algo = Algorithm::decode(reader)?;
let sigbuf = Vec::decode(reader)?;
Self::new(algo, sigbuf)
}
}

// TODO only needed until https://github.com/RustCrypto/SSH/pull/315 is released
pub fn verify(pubkey: &PublicKey, buf: &[u8], sig: &Sig) -> Result<(), signature::Error> {
match sig {
Sig::Normal(sig) => Verifier::verify(pubkey, buf, sig),
Sig::SshRsa(sig) => {
let Some(rsa_key) = pubkey.key_data().rsa() else {
return Err(signature::Error::new());
};
let signature = rsa::pkcs1v15::Signature::try_from(sig.as_slice())?;
rsa::pkcs1v15::VerifyingKey::<sha1::Sha1>::try_from(rsa_key)?.verify(buf, &signature)
}
}
}

0 comments on commit f602e45

Please sign in to comment.