From 5d81f21f3ff126058f77c531af1578f788e8d809 Mon Sep 17 00:00:00 2001 From: Thomas Gatzweiler Date: Sat, 15 Jul 2017 15:59:37 +0200 Subject: [PATCH] Implement server host key file --- src/algorithm.rs | 9 ++++--- src/bin/ssh-keygen.rs | 2 +- src/bin/sshd.rs | 34 +++++++++++++++++++------ src/key_exchange/curve25519.rs | 41 +++++++++++++++++++++++++++---- src/key_exchange/dh_group_sha1.rs | 12 +++++---- src/packet.rs | 10 +++++--- src/server.rs | 11 ++------- src/session.rs | 29 +++++++++++----------- tests/public_key.rs | 4 +-- 9 files changed, 102 insertions(+), 50 deletions(-) diff --git a/src/algorithm.rs b/src/algorithm.rs index 4194dc5..7d5c195 100644 --- a/src/algorithm.rs +++ b/src/algorithm.rs @@ -3,13 +3,14 @@ use std::fmt; /// Slice of implemented key exchange algorithms, ordered by preference pub static KEY_EXCHANGE: &[KeyExchangeAlgorithm] = &[ - KeyExchangeAlgorithm::DH_GROUP_EXCHANGE_SHA1, -// KeyExchangeAlgorithm::CURVE25519_SHA256, + KeyExchangeAlgorithm::CURVE25519_SHA256, +// KeyExchangeAlgorithm::DH_GROUP_EXCHANGE_SHA1, ]; /// Slice of implemented host key algorithms, ordered by preference -pub static HOST_KEY: &[PublicKeyAlgorithm] = &[PublicKeyAlgorithm::SSH_RSA, - // PublicKeyAlgorithm::SSH_ED25519 +pub static HOST_KEY: &[PublicKeyAlgorithm] = &[ + PublicKeyAlgorithm::SSH_ED25519, +// PublicKeyAlgorithm::SSH_RSA, ]; /// Slice of implemented encryption algorithms, ordered by preference diff --git a/src/bin/ssh-keygen.rs b/src/bin/ssh-keygen.rs index 6ae50a1..ae0a107 100644 --- a/src/bin/ssh-keygen.rs +++ b/src/bin/ssh-keygen.rs @@ -6,6 +6,6 @@ use ssh::public_key; pub fn main() { let keypair = (public_key::ED25519.generate_key_pair)(None); - let mut buffer = File::create("key.pub").unwrap(); + let mut buffer = File::create("server.key").unwrap(); keypair.export(&mut buffer); } diff --git a/src/bin/sshd.rs b/src/bin/sshd.rs index ab166d1..542fee3 100644 --- a/src/bin/sshd.rs +++ b/src/bin/sshd.rs @@ -1,25 +1,45 @@ extern crate ssh; -use std::io::{self, Write}; -use std::str::FromStr; use std::env; +use std::fs::File; +use std::io::{self, Write}; use std::process; +use std::str::FromStr; + use ssh::{Server, ServerConfig}; +use ssh::public_key::ED25519; pub fn main() { let mut quiet = false; - let mut config = ServerConfig::default(); + let key_pair = File::open("server.key").and_then( + |mut f| (ED25519.import)(&mut f), + ); + + if let Some(ref err) = key_pair.as_ref().err() { + writeln!(io::stderr(), "sshd: failed to open server.key: {}", err) + .unwrap(); + process::exit(1); + } + + let mut config = ServerConfig { + host: String::from("0.0.0.0"), + port: 22, + key: key_pair.unwrap(), + }; let mut args = env::args().skip(1); while let Some(arg) = args.next() { - match arg.as_ref() { + match arg.as_ref() + { "-q" => quiet = true, "-p" => { - config.port = u16::from_str(&args.next().expect("sshd: no argument to -p option")) - .expect("sshd: invalid port number to -p option"); + config.port = + u16::from_str( + &args.next().expect("sshd: no argument to -p option"), + ).expect("sshd: invalid port number to -p option"); } - _ => () + _ => (), } } diff --git a/src/key_exchange/curve25519.rs b/src/key_exchange/curve25519.rs index 14c30fa..8db11ca 100644 --- a/src/key_exchange/curve25519.rs +++ b/src/key_exchange/curve25519.rs @@ -1,18 +1,49 @@ +use crypto::curve25519::curve25519; use key_exchange::{KeyExchange, KeyExchangeResult}; -use packet::Packet; +use message::MessageType; +use packet::{Packet, ReadPacketExt, WritePacketExt}; +use public_key::ED25519; -pub struct Curve25519 { +const ECDH_KEX_INIT: u8 = 30; +const ECDH_KEX_REPLY: u8 = 31; -} +pub struct Curve25519 {} impl Curve25519 { pub fn new() -> Curve25519 { - Curve25519 { } + Curve25519 {} } } impl KeyExchange for Curve25519 { fn process(&mut self, packet: &Packet) -> KeyExchangeResult { - KeyExchangeResult::Ok(None) + match packet.msg_type() + { + MessageType::KeyExchange(ECDH_KEX_INIT) => { + let mut reader = packet.reader(); + let qc = reader.read_string().unwrap(); + + let keypair = (ED25519.generate_key_pair)(None); + let mut public_key = Vec::new(); + keypair.write_public(&mut public_key); + + println!("Received qc: {:?}", qc); + let mut packet = + Packet::new(MessageType::KeyExchange(ECDH_KEX_REPLY)); + + packet.with_writer(&|w| { + w.write_bytes(public_key.as_slice())?; + w.write_bytes(qc.as_slice())?; + w.write_bytes(&[0; 256])?; + Ok(()) + }); + + KeyExchangeResult::Ok(Some(packet)) + } + _ => { + debug!("Unhandled key exchange packet: {:?}", packet); + KeyExchangeResult::Error(None) + } + } } } diff --git a/src/key_exchange/dh_group_sha1.rs b/src/key_exchange/dh_group_sha1.rs index 4d198ba..4340559 100644 --- a/src/key_exchange/dh_group_sha1.rs +++ b/src/key_exchange/dh_group_sha1.rs @@ -54,8 +54,9 @@ impl KeyExchange for DhGroupSha1 { let mut packet = Packet::new(MessageType::KeyExchange(DH_GEX_GROUP)); packet.with_writer(&|w| { - w.write_mpint(g.clone()); - w.write_mpint(p.clone()); + w.write_mpint(g.clone())?; + w.write_mpint(p.clone())?; + Ok(()) }); self.g = Some(g); @@ -71,9 +72,10 @@ impl KeyExchange for DhGroupSha1 { let mut packet = Packet::new(MessageType::KeyExchange(DH_GEX_REPLY)); packet.with_writer(&|w| { - w.write_string("HELLO WORLD"); - w.write_mpint(e.clone()); - w.write_string("HELLO WORLD"); + w.write_string("HELLO WORLD")?; + w.write_mpint(e.clone())?; + w.write_string("HELLO WORLD")?; + Ok(()) }); self.e = Some(e); diff --git a/src/packet.rs b/src/packet.rs index d33335d..1300c24 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -58,8 +58,8 @@ impl Packet { &mut self.payload } - pub fn with_writer(&mut self, f: &Fn(&mut Write) -> ()) { - f(&mut self.payload); + pub fn with_writer(&mut self, f: &Fn(&mut Write) -> Result<()>) -> Result<()> { + f(&mut self.payload) } pub fn reader<'a>(&'a self) -> BufReader<&'a [u8]> { @@ -130,7 +130,7 @@ pub trait WritePacketExt: WriteBytesExt { } fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> { - self.write_u32::(bytes.len() as u32)?; + self.write_uint32(bytes.len() as u32)?; self.write_all(bytes) } @@ -147,6 +147,10 @@ pub trait WritePacketExt: WriteBytesExt { self.write_bytes(bytes.as_slice()) } + fn write_uint32(&mut self, value: u32) -> Result<()> { + self.write_u32::(value as u32) + } + 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 0947c23..4467d29 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,20 +3,13 @@ use std::io::{self, Write}; use session::{Session, SessionType}; use packet::Packet; +use public_key::KeyPair; use protocol; pub struct ServerConfig { pub host: String, pub port: u16, -} - -impl Default for ServerConfig { - fn default() -> ServerConfig { - ServerConfig { - host: "0.0.0.0".to_owned(), - port: 22, - } - } + pub key: Box } pub struct Server { diff --git a/src/session.rs b/src/session.rs index bf9bac8..941e030 100644 --- a/src/session.rs +++ b/src/session.rs @@ -91,23 +91,24 @@ impl Session { let mut packet = Packet::new(MessageType::KexInit); packet.with_writer(&|w| { - w.write_raw_bytes(cookie.as_slice()); - w.write_list(KEY_EXCHANGE); - w.write_list(HOST_KEY); - w.write_list(ENCRYPTION); - w.write_list(ENCRYPTION); - w.write_list(MAC); - w.write_list(MAC); - w.write_list(COMPRESSION); - w.write_list(COMPRESSION); - w.write_string(""); - w.write_string(""); - w.write_bool(false); - w.write_bytes(&[0, 0, 0, 0]); + w.write_raw_bytes(cookie.as_slice())?; + w.write_list(KEY_EXCHANGE)?; + w.write_list(HOST_KEY)?; + w.write_list(ENCRYPTION)?; + w.write_list(ENCRYPTION)?; + w.write_list(MAC)?; + w.write_list(MAC)?; + w.write_list(COMPRESSION)?; + w.write_list(COMPRESSION)?; + w.write_string("")?; + w.write_string("")?; + w.write_bool(false)?; + w.write_uint32(0)?; + Ok(()) }); self.state = SessionState::KeyExchange; - self.key_exchange = Some(Box::new(key_exchange::DhGroupSha1::new())); + self.key_exchange = Some(Box::new(key_exchange::Curve25519::new())); packet.write_to(&mut self.stream); } } diff --git a/tests/public_key.rs b/tests/public_key.rs index 4b36edd..62a9ac2 100644 --- a/tests/public_key.rs +++ b/tests/public_key.rs @@ -3,7 +3,7 @@ extern crate rand; use rand::Rng; use std::io::Cursor; -use ssh::key::{self, CryptoSystem, KeyPair}; +use ssh::public_key::{self, CryptoSystem, KeyPair}; fn test_export_import(keypair: &Box) -> Box { // Export the keypair to a vector and import it again @@ -36,4 +36,4 @@ fn test_crypto_system(system: &CryptoSystem, key_size: Option) { } #[test] -fn test_ed25519() { test_crypto_system(&key::ED25519, None); } +fn test_ed25519() { test_crypto_system(&public_key::ED25519, None); }