diff --git a/Cargo.lock b/Cargo.lock index a4c595b..4ed90da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.1.39 (git+https://github.com/rust-num/num)", "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -38,6 +39,30 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "num-bigint" +version = "0.1.39" +source = "git+https://github.com/rust-num/num#d159ed63be98c8ff01b62cbbf912d721e2b0eb41" +dependencies = [ + "num-integer 0.1.34 (git+https://github.com/rust-num/num)", + "num-traits 0.1.39 (git+https://github.com/rust-num/num)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.34" +source = "git+https://github.com/rust-num/num#d159ed63be98c8ff01b62cbbf912d721e2b0eb41" +dependencies = [ + "num-traits 0.1.39 (git+https://github.com/rust-num/num)", +] + +[[package]] +name = "num-traits" +version = "0.1.39" +source = "git+https://github.com/rust-num/num#d159ed63be98c8ff01b62cbbf912d721e2b0eb41" + [[package]] name = "rand" version = "0.3.15" @@ -95,6 +120,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "30885bcb161cf67054244d10d4a7f4835ffd58773bc72e07d35fecf472295503" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum num-bigint 0.1.39 (git+https://github.com/rust-num/num)" = "" +"checksum num-integer 0.1.34 (git+https://github.com/rust-num/num)" = "" +"checksum num-traits 0.1.39 (git+https://github.com/rust-num/num)" = "" "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" "checksum redox_syscall 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "9df6a71a1e67be2104410736b2389fb8e383c1d7e9e792d629ff13c02867147a" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" diff --git a/Cargo.toml b/Cargo.toml index 7c12d4a..250be36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ byteorder = "^1.0" log = "^0.3" rust-crypto = "^0.2" rand = "^0.3" +num-bigint = { git = "https://github.com/rust-num/num" } [target.'cfg(target_os = "redox")'.dependencies] redox_syscall = "0.1" diff --git a/src/algorithm.rs b/src/algorithm.rs index fd26546..4194dc5 100644 --- a/src/algorithm.rs +++ b/src/algorithm.rs @@ -3,29 +3,24 @@ use std::fmt; /// Slice of implemented key exchange algorithms, ordered by preference pub static KEY_EXCHANGE: &[KeyExchangeAlgorithm] = &[ - KeyExchangeAlgorithm::CURVE25519_SHA256 + KeyExchangeAlgorithm::DH_GROUP_EXCHANGE_SHA1, +// KeyExchangeAlgorithm::CURVE25519_SHA256, ]; /// Slice of implemented host key algorithms, ordered by preference -pub static HOST_KEY: &[PublicKeyAlgorithm] = &[ - PublicKeyAlgorithm::SSH_ED25519 +pub static HOST_KEY: &[PublicKeyAlgorithm] = &[PublicKeyAlgorithm::SSH_RSA, + // PublicKeyAlgorithm::SSH_ED25519 ]; /// Slice of implemented encryption algorithms, ordered by preference -pub static ENCRYPTION: &[EncryptionAlgorithm] = &[ - EncryptionAlgorithm::AES256_CTR -]; +pub static ENCRYPTION: &[EncryptionAlgorithm] = &[EncryptionAlgorithm::AES256_CTR]; /// Slice of implemented MAC algorithms, ordered by preference -pub static MAC: &[MacAlgorithm] = &[ - MacAlgorithm::HMAC_SHA2_512 -]; +pub static MAC: &[MacAlgorithm] = &[MacAlgorithm::HMAC_SHA2_512]; /// Slice of implemented compression algorithms, ordered by preference -pub static COMPRESSION: &[CompressionAlgorithm] = &[ - CompressionAlgorithm::None, - CompressionAlgorithm::Zlib -]; +pub static COMPRESSION: &[CompressionAlgorithm] = + &[CompressionAlgorithm::None, CompressionAlgorithm::Zlib]; /// Find the best matching algorithm pub fn negotiate(server: &[A], client: &[A]) -> Option { @@ -169,7 +164,7 @@ impl FromStr for EncryptionAlgorithm { "aes256-cbc" => Ok(AES256_CBC), "none" => Ok(EncryptionAlgorithm::None), _ => { - println!("Unknown encryption algorithm: `{}`", s); + debug!("Unknown encryption algorithm: `{}`", s); Err(()) } } @@ -209,7 +204,7 @@ impl FromStr for MacAlgorithm { "hmac-sha2-256" => Ok(MacAlgorithm::HMAC_SHA2_256), "hmac-sha2-512" => Ok(MacAlgorithm::HMAC_SHA2_512), _ => { - println!("Unknown mac algorithm: {}", s); + debug!("Unknown mac algorithm: {}", s); Err(()) } } @@ -223,7 +218,7 @@ impl fmt::Display for MacAlgorithm { &HMAC_SHA1 => "hmac-sha1", &HMAC_SHA2_256 => "hmac-sha2-256", &HMAC_SHA2_512 => "hmac-sha2-512", - &MacAlgorithm::None => "none" + &MacAlgorithm::None => "none", }) } } @@ -241,7 +236,7 @@ impl FromStr for CompressionAlgorithm { "zlib" => Ok(CompressionAlgorithm::Zlib), "none" => Ok(CompressionAlgorithm::None), _ => { - println!("Unknown compression algorithm: {}", s); + debug!("Unknown compression algorithm: {}", s); Err(()) } } @@ -252,7 +247,7 @@ impl fmt::Display for CompressionAlgorithm { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match self { &CompressionAlgorithm::Zlib => "zlib", - &CompressionAlgorithm::None => "none" + &CompressionAlgorithm::None => "none", }) } } diff --git a/src/key_exchange/curve25519.rs b/src/key_exchange/curve25519.rs index e9683f8..1af72e0 100644 --- a/src/key_exchange/curve25519.rs +++ b/src/key_exchange/curve25519.rs @@ -1,3 +1,18 @@ +use key_exchange::{KeyExchange, KeyExchangeResult}; +use packet::Packet; + pub struct Curve25519 { } + +impl Curve25519 { + pub fn new() -> Curve25519 { + Curve25519 { } + } +} + +impl KeyExchange for Curve25519 { + fn process(&self, packet: &Packet) -> KeyExchangeResult { + KeyExchangeResult::Ok(None) + } +} diff --git a/src/key_exchange/mod.rs b/src/key_exchange/mod.rs index 19d6ad0..e9ab740 100644 --- a/src/key_exchange/mod.rs +++ b/src/key_exchange/mod.rs @@ -1,9 +1,18 @@ mod curve25519; +mod dh_group_sha1; pub use self::curve25519::Curve25519; +pub use self::dh_group_sha1::DhGroupSha1; +use session::Session; use packet::Packet; -pub trait KeyExchange { - fn process(&self, packet: &Packet); +pub enum KeyExchangeResult { + Ok(Option), + Done(Option), + Error(Option) +} + +pub trait KeyExchange { + fn process(&self, packet: &Packet) -> KeyExchangeResult; } diff --git a/src/lib.rs b/src/lib.rs index 1104cd1..e884ec9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ extern crate byteorder; extern crate rand; extern crate crypto; +extern crate num_bigint; #[macro_use] extern crate log; diff --git a/src/packet.rs b/src/packet.rs index 8a2287b..cccfa0c 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -4,6 +4,7 @@ use std::string::ToString; use std::io::{self, BufReader, Write, Read, Result}; use message::MessageType; use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; +use num_bigint::BigInt; pub struct Packet { payload: Vec @@ -62,7 +63,7 @@ impl Packet { } pub fn reader<'a>(&'a self) -> BufReader<&'a [u8]> { - BufReader::new(self.payload.as_slice()) + BufReader::new(&self.payload.as_slice()[1..]) } pub fn padding_len(&self) -> usize { @@ -76,18 +77,15 @@ impl Packet { } pub trait ReadPacketExt: ReadBytesExt { - fn read_msg_type(&mut self) -> Result { - Ok(self.read_u8()?.into()) - } - fn read_string(&mut self) -> Result> { let len = self.read_u32::()?; self.read_bytes(len as usize) } - fn read_mpint(&mut self) -> Result> { + fn read_mpint(&mut self) -> Result { let len = self.read_u32::()?; - self.read_bytes(len as usize) + let bytes = self.read_bytes(len as usize)?; + Ok(BigInt::from_signed_bytes_be(bytes.as_slice())) } fn read_bytes(&mut self, len: usize) -> Result> { @@ -136,6 +134,12 @@ pub trait WritePacketExt: WriteBytesExt { self.write_u8(if value { 1 } else { 0 }) } + fn write_mpint(&mut self, value: BigInt) -> Result<()> { + let bytes = value.to_signed_bytes_be(); + self.write_u32::(bytes.len() as u32 + 1)?; + self.write_bytes(bytes.as_slice()) + } + fn write_list(&mut self, list: &[T]) -> Result<()> { let mut string = String::new(); let mut iter = list.iter(); diff --git a/src/server.rs b/src/server.rs index 7e7967c..0947c23 100644 --- a/src/server.rs +++ b/src/server.rs @@ -39,45 +39,17 @@ impl Server { )); println!("Incoming connection from {}", addr); + protocol::send_identification(&mut stream)?; let id = protocol::read_identification(&mut stream)?; println!("{} identifies as {}", addr, id); - protocol::send_identification(&mut stream)?; - let mut session = Session::new(SessionType::Server, stream.try_clone().unwrap()); loop { let packet = Packet::read_from(&mut stream).unwrap(); println!("packet: {:?}", packet); session.process(&packet); - - use rand::{OsRng, Rng}; - let mut rng = OsRng::new()?; - - /* - if message.msg_type() == MessageType::KexInit { -xs let cookie: Vec = rng.gen_iter::().take(16).collect(); - let kex = message::kex::KeyExchangeInit { - cookie: cookie, - kex_algorithms: vec![message::kex::KeyExchangeAlgorithm::CURVE25519_SHA256], - server_host_key_algorithms: vec![message::kex::HostKeyAlgorithm::SSH_ED25519], - encryption_algorithms_client_to_server: vec![message::kex::EncryptionAlgorithm::AES256_CTR], - encryption_algorithms_server_to_client: vec![message::kex::EncryptionAlgorithm::AES256_CTR], - mac_algorithms_client_to_server: vec![message::kex::MacAlgorithm::HMAC_SHA2_512], - mac_algorithms_server_to_client: vec![message::kex::MacAlgorithm::HMAC_SHA2_512], - compression_algorithms_client_to_server: vec![message::kex::CompressionAlgorithm::None], - compression_algorithms_server_to_client: vec![message::kex::CompressionAlgorithm::None], - languages_client_to_server: vec![], - languages_server_to_client: vec![], - first_kex_packet_follows: false - }; - protocol::write_message(&mut stream, &kex); - } - else { - println!("Unhandled Message Type"); - } - */ } Ok(()) } diff --git a/src/session.rs b/src/session.rs index fd10d97..8c95033 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,4 +1,4 @@ -use key_exchange::KeyExchange; +use key_exchange::{self, KeyExchange, KeyExchangeResult}; use message::MessageType; use packet::{Packet, ReadPacketExt, WritePacketExt}; use std::io::Write; @@ -7,29 +7,29 @@ use std::io::Write; enum SessionState { Initial, KeyExchange, - Established + Established, } #[derive(PartialEq)] pub enum SessionType { Server, - Client + Client, } -pub struct Session<'a, W: Write> { +pub struct Session { stype: SessionType, state: SessionState, - key_exchange: Option<&'a KeyExchange>, - stream: W + key_exchange: Option>, + stream: W, } -impl<'a, W: Write> Session<'a, W> { - pub fn new(stype: SessionType, stream: W) -> Session<'a, W> { +impl Session { + pub fn new(stype: SessionType, stream: W) -> Session { Session { stype: stype, state: SessionState::Initial, key_exchange: None, - stream: stream + stream: stream, } } @@ -39,6 +39,20 @@ impl<'a, W: Write> Session<'a, W> { println!("Starting Key Exchange!"); self.kex_init(packet); } + MessageType::KeyExchange(_) => { + if let Some(ref kex) = self.key_exchange { + match kex.process(packet) { + KeyExchangeResult::Ok(Some(packet)) => { packet.write_to(&mut self.stream); }, + KeyExchangeResult::Error(Some(packet)) => { packet.write_to(&mut self.stream); }, + KeyExchangeResult::Done(Some(packet)) => { packet.write_to(&mut self.stream); }, + KeyExchangeResult::Ok(None) | + KeyExchangeResult::Error(None) | + KeyExchangeResult::Done(None) => {} + }; + } else { + warn!("Received KeyExchange packet without KexInit"); + } + } _ => { println!("Unhandled packet: {:?}", packet); } @@ -49,7 +63,6 @@ impl<'a, W: Write> Session<'a, W> { use algorithm::*; let mut reader = packet.reader(); - reader.read_msg_type(); let cookie = reader.read_bytes(16); let kex_algos = reader.read_enum_list::(); let srv_host_key_algos = reader.read_enum_list::(); @@ -66,11 +79,11 @@ impl<'a, W: Write> Session<'a, W> { let mac_algo = negotiate(MAC, mac_algos_s2c.unwrap().as_slice()); let comp_algo = negotiate(COMPRESSION, comp_algos_s2c.unwrap().as_slice()); - println!("Negociated Kex Algorithm: {:?}", kex_algo); - println!("Negociated Host Key Algorithm: {:?}", srv_host_key_algo); - println!("Negociated Encryption Algorithm: {:?}", enc_algo); - println!("Negociated Mac Algorithm: {:?}", mac_algo); - println!("Negociated Comp Algorithm: {:?}", comp_algo); + println!("Negotiated Kex Algorithm: {:?}", kex_algo); + println!("Negotiated Host Key Algorithm: {:?}", srv_host_key_algo); + println!("Negotiated Encryption Algorithm: {:?}", enc_algo); + println!("Negotiated Mac Algorithm: {:?}", mac_algo); + println!("Negotiated Comp Algorithm: {:?}", comp_algo); use rand::{OsRng, Rng}; let mut rng = OsRng::new().unwrap(); @@ -94,6 +107,7 @@ impl<'a, W: Write> Session<'a, W> { }); self.state = SessionState::KeyExchange; + self.key_exchange = Some(Box::new(key_exchange::DhGroupSha1::new())); packet.write_to(&mut self.stream); } }