Skip to content

Commit

Permalink
Migrate to RustCrypto/SSH
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur Gautier <[email protected]>
  • Loading branch information
baloo committed Mar 14, 2024
1 parent 8721f83 commit 612657b
Show file tree
Hide file tree
Showing 15 changed files with 817 additions and 892 deletions.
516 changes: 505 additions & 11 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,21 @@ keywords = ["ssh", "agent", "authentication", "openssh", "async"]
categories = ["authentication", "cryptography", "encoding", "network-programming", "parsing"]
exclude = [".github"]

[patch.crates-io]
#ssh-key = { path = "../../SSH/ssh-key" }

[dependencies]
byteorder = "1.4.3"
serde = {version = "1", features = ["derive"]}

async-trait = { version = "0.1.77", optional = true }
bytes = { version = "1.5.0", optional = true }
futures = { version = "0.3.30", optional = true }
log = { version = "0.4.6", optional = true }
tokio = { version = "1", optional = true, features = ["rt", "net"] }
tokio-util = { version = "0.7.1", optional = true, features = ["codec"] }
ssh-encoding = { version = "0.2.0" }
ssh-key = { version = "0.6.4", features = ["rsa", "alloc"] }
signature = "2"

[features]
default = ["agent"]
Expand Down
58 changes: 32 additions & 26 deletions examples/key_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ use tokio::net::UnixListener;
use ssh_agent_lib::agent::{Agent, Session};
use ssh_agent_lib::error::AgentError;
use ssh_agent_lib::proto::message::{self, Message, SignRequest};
use ssh_agent_lib::proto::private_key::{PrivateKey, RsaPrivateKey};
use ssh_agent_lib::proto::public_key::PublicKey;
use ssh_agent_lib::proto::signature::{self, Signature};
use ssh_agent_lib::proto::{from_bytes, to_bytes};
use ssh_agent_lib::proto::signature::{self};
use ssh_key::{
private::{KeypairData, PrivateKey, RsaKeypair},
public::PublicKey,
Algorithm, HashAlg, Signature,
};

use std::error::Error;
use std::fs::remove_file;
Expand Down Expand Up @@ -74,33 +76,34 @@ impl KeyStorage {
}

fn sign(&self, sign_request: &SignRequest) -> Result<Signature, Box<dyn Error>> {
let pubkey: PublicKey = from_bytes(&sign_request.pubkey_blob)?;
let pubkey: PublicKey = sign_request.pubkey.clone().try_into()?;

if let Some(identity) = self.identity_from_pubkey(&pubkey) {
match identity.privkey {
PrivateKey::Rsa(ref key) => {
match identity.privkey.key_data() {
KeypairData::Rsa(ref key) => {
let algorithm;
let digest;

if sign_request.flags & signature::RSA_SHA2_512 != 0 {
algorithm = "rsa-sha2-512";
algorithm = Algorithm::Rsa {
hash: Some(HashAlg::Sha512),
};
digest = MessageDigest::sha512();
} else if sign_request.flags & signature::RSA_SHA2_256 != 0 {
algorithm = "rsa-sha2-256";
algorithm = Algorithm::Rsa {
hash: Some(HashAlg::Sha256),
};
digest = MessageDigest::sha256();
} else {
algorithm = "ssh-rsa";
algorithm = Algorithm::Rsa { hash: None };
digest = MessageDigest::sha1();
}

let keypair = PKey::from_rsa(rsa_openssl_from_ssh(key)?)?;
let mut signer = Signer::new(digest, &keypair)?;
signer.update(&sign_request.data)?;

Ok(Signature {
algorithm: algorithm.to_string(),
blob: signer.sign_to_vec()?,
})
Ok(Signature::new(algorithm, signer.sign_to_vec()?).unwrap())
}
_ => Err(From::from("Signature for key type not implemented")),
}
Expand All @@ -116,27 +119,30 @@ impl KeyStorage {
let mut identities = vec![];
for identity in self.identities.read().unwrap().iter() {
identities.push(message::Identity {
pubkey_blob: to_bytes(&identity.pubkey)?,
pubkey: identity.pubkey.key_data().clone(),
comment: identity.comment.clone(),
})
}
Ok(Message::IdentitiesAnswer(identities))
}
Message::RemoveIdentity(identity) => {
let pubkey: PublicKey = from_bytes(&identity.pubkey_blob)?;
let pubkey: PublicKey = identity.pubkey.try_into()?;
self.identity_remove(&pubkey)?;
Ok(Message::Success)
}
Message::AddIdentity(identity) => {
println!("add_identity0");
let privkey = PrivateKey::try_from(identity.privkey).unwrap();
self.identity_add(Identity {
pubkey: PublicKey::from(&identity.privkey),
privkey: identity.privkey,
pubkey: PublicKey::from(&privkey),
privkey: privkey,
comment: identity.comment,
});
println!("add_identity1");
Ok(Message::Success)
}
Message::SignRequest(request) => {
let signature = to_bytes(&self.sign(&request)?)?;
let signature = self.sign(&request)?;
Ok(Message::SignResponse(signature))
}
_ => Err(From::from(format!("Unknown message: {:?}", request))),
Expand All @@ -162,13 +168,13 @@ impl Agent for KeyStorage {
}
}

fn rsa_openssl_from_ssh(ssh_rsa: &RsaPrivateKey) -> Result<Rsa<Private>, Box<dyn Error>> {
let n = BigNum::from_slice(&ssh_rsa.n)?;
let e = BigNum::from_slice(&ssh_rsa.e)?;
let d = BigNum::from_slice(&ssh_rsa.d)?;
let qi = BigNum::from_slice(&ssh_rsa.iqmp)?;
let p = BigNum::from_slice(&ssh_rsa.p)?;
let q = BigNum::from_slice(&ssh_rsa.q)?;
fn rsa_openssl_from_ssh(ssh_rsa: &RsaKeypair) -> Result<Rsa<Private>, Box<dyn Error>> {
let n = BigNum::from_slice(&ssh_rsa.public.n.as_bytes())?;
let e = BigNum::from_slice(&ssh_rsa.public.e.as_bytes())?;
let d = BigNum::from_slice(&ssh_rsa.private.d.as_bytes())?;
let qi = BigNum::from_slice(&ssh_rsa.private.iqmp.as_bytes())?;
let p = BigNum::from_slice(&ssh_rsa.private.p.as_bytes())?;
let q = BigNum::from_slice(&ssh_rsa.private.q.as_bytes())?;
let dp = &d % &(&p - &BigNum::from_u32(1)?);
let dq = &d % &(&q - &BigNum::from_u32(1)?);

Expand Down
12 changes: 9 additions & 3 deletions src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use byteorder::{BigEndian, ReadBytesExt};
use bytes::{Buf, BufMut, BytesMut};
use futures::{SinkExt, TryStreamExt};
use log::{error, info};
use ssh_encoding::{Decode, Encode};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::{TcpListener, TcpStream, UnixListener, UnixStream};
use tokio_util::codec::{Decoder, Encoder, Framed};
Expand All @@ -14,7 +15,6 @@ use std::mem::size_of;

use super::error::AgentError;
use super::proto::message::Message;
use super::proto::{from_bytes, to_bytes};

#[derive(Debug)]
pub struct MessageCodec;
Expand All @@ -36,7 +36,7 @@ impl Decoder for MessageCodec {
return Ok(None);
}

let message: Message = from_bytes(bytes)?;
let message: Message = Message::decode(&mut bytes)?;
src.advance(size_of::<u32>() + length);
Ok(Some(message))
}
Expand All @@ -46,7 +46,13 @@ impl Encoder<Message> for MessageCodec {
type Error = AgentError;

fn encode(&mut self, item: Message, dst: &mut BytesMut) -> Result<(), Self::Error> {
let bytes = to_bytes(&to_bytes(&item)?)?;
let mut bytes = Vec::new();

let len = item.encoded_len().unwrap() as u32;
len.encode(&mut bytes)?;

item.encode(&mut bytes)?;

dst.put(&*bytes);
Ok(())
}
Expand Down
15 changes: 11 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
use super::proto::error::ProtoError;
use std::io;

#[derive(Debug)]
pub enum AgentError {
User,
Proto(ProtoError),
Ssh(ssh_key::Error),
Proto(ssh_encoding::Error),
IO(io::Error),
}

impl From<ProtoError> for AgentError {
fn from(e: ProtoError) -> AgentError {
impl From<ssh_encoding::Error> for AgentError {
fn from(e: ssh_encoding::Error) -> AgentError {
AgentError::Proto(e)
}
}

impl From<ssh_key::Error> for AgentError {
fn from(e: ssh_key::Error) -> AgentError {
AgentError::Ssh(e)
}
}

impl From<io::Error> for AgentError {
fn from(e: io::Error) -> AgentError {
AgentError::IO(e)
Expand All @@ -23,6 +29,7 @@ impl From<io::Error> for AgentError {
impl std::fmt::Display for AgentError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AgentError::Ssh(e) => write!(f, "Agent: Ssh key error: {e}"),
AgentError::User => write!(f, "Agent: User error"),
AgentError::Proto(proto) => write!(f, "Agent: Protocol error: {}", proto),
AgentError::IO(error) => write!(f, "Agent: I/O error: {}", error),
Expand Down
Loading

0 comments on commit 612657b

Please sign in to comment.