1
0
Fork 0
mirror of https://gitlab.redox-os.org/CoffeeCode/redox-ssh.git synced 2025-12-28 17:02:19 +01:00

Implement ConnectionError

This commit is contained in:
Thomas Gatzweiler 2017-07-16 13:44:31 +02:00
parent cf7644a5ed
commit 86d7d48a29
7 changed files with 104 additions and 56 deletions

View file

@ -1,6 +1,8 @@
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use error::{ConnectionError, ConnectionResult};
/// Slice of implemented key exchange algorithms, ordered by preference /// Slice of implemented key exchange algorithms, ordered by preference
pub static KEY_EXCHANGE: &[KeyExchangeAlgorithm] = pub static KEY_EXCHANGE: &[KeyExchangeAlgorithm] =
&[ &[
@ -26,13 +28,16 @@ pub static COMPRESSION: &[CompressionAlgorithm] =
&[CompressionAlgorithm::None, CompressionAlgorithm::Zlib]; &[CompressionAlgorithm::None, CompressionAlgorithm::Zlib];
/// Find the best matching algorithm /// Find the best matching algorithm
pub fn negotiate<A: PartialEq + Copy>(server: &[A], client: &[A]) -> Option<A> { pub fn negotiate<A: PartialEq + Copy>(
server: &[A],
client: &[A],
) -> ConnectionResult<A> {
for algorithm in client.iter() { for algorithm in client.iter() {
if server.iter().any(|a| a == algorithm) { if server.iter().any(|a| a == algorithm) {
return Some(*algorithm); return Ok(*algorithm);
} }
} }
None Err(ConnectionError::NegotiationError)
} }
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]

View file

@ -1,9 +1,9 @@
use std::io::{self, BufRead, BufReader, Read, Write}; use std::io::{self, BufRead, BufReader, Read, Write};
use error::{ConnectionError, ConnectionResult};
use key_exchange::{self, KeyExchange, KeyExchangeResult}; use key_exchange::{self, KeyExchange, KeyExchangeResult};
use message::MessageType; use message::MessageType;
use packet::{Packet, ReadPacketExt, WritePacketExt}; use packet::{Packet, ReadPacketExt, WritePacketExt};
use public_key::KeyPair;
#[derive(PartialEq)] #[derive(PartialEq)]
enum ConnectionState { enum ConnectionState {
@ -42,7 +42,7 @@ impl<W: Write> Connection<W> {
} }
} }
pub fn run(&mut self, mut stream: &mut Read) -> io::Result<()> { pub fn run(&mut self, mut stream: &mut Read) -> ConnectionResult<()> {
self.stream.write(self.my_id.as_bytes())?; self.stream.write(self.my_id.as_bytes())?;
self.stream.flush()?; self.stream.flush()?;
@ -53,7 +53,7 @@ impl<W: Write> Connection<W> {
} }
loop { loop {
let packet = Packet::read_from(&mut stream).unwrap(); let packet = Packet::read_from(&mut stream)?;
println!("packet: {:?}", packet); println!("packet: {:?}", packet);
self.process(&packet); self.process(&packet);
} }
@ -73,62 +73,64 @@ impl<W: Write> Connection<W> {
Ok(id.trim_right().to_owned()) Ok(id.trim_right().to_owned())
} }
pub fn process(&mut self, packet: &Packet) { pub fn process(&mut self, packet: &Packet) -> ConnectionResult<()> {
match packet.msg_type() match packet.msg_type()
{ {
MessageType::KexInit => { MessageType::KexInit => {
println!("Starting Key Exchange!"); println!("Starting Key Exchange!");
self.kex_init(packet); self.kex_init(packet)
} }
MessageType::KeyExchange(_) => { MessageType::KeyExchange(_) => {
if let Some(ref mut kex) = self.key_exchange { let ref mut kex = self.key_exchange.as_mut().ok_or(
match kex.process(packet) ConnectionError::KeyExchangeError,
{ )?;
KeyExchangeResult::Ok(Some(packet)) => {
packet.write_to(&mut self.stream); 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(packet) => {
if let Some(packet) = packet {
packet.write_to(&mut self.stream)?;
} }
KeyExchangeResult::Error(Some(packet)) => { self.state = ConnectionState::Established;
packet.write_to(&mut self.stream); }
} KeyExchangeResult::Ok(None) |
KeyExchangeResult::Done(Some(packet)) => { KeyExchangeResult::Error(None) => {}
packet.write_to(&mut self.stream); };
} Ok(())
KeyExchangeResult::Ok(None) |
KeyExchangeResult::Error(None) |
KeyExchangeResult::Done(None) => {}
};
}
else {
warn!("Received KeyExchange packet without KexInit");
}
} }
_ => { _ => {
println!("Unhandled packet: {:?}", packet); println!("Unhandled packet: {:?}", packet);
Err(ConnectionError::KeyExchangeError)
} }
} }
} }
pub fn kex_init(&mut self, packet: &Packet) { pub fn kex_init(&mut self, packet: &Packet) -> ConnectionResult<()> {
use algorithm::*; use algorithm::*;
let mut reader = packet.reader(); let mut reader = packet.reader();
let cookie = reader.read_bytes(16); let _ = reader.read_bytes(16)?; // Cookie. Throw it away.
let kex_algos = reader.read_enum_list::<KeyExchangeAlgorithm>(); let kex_algos = reader.read_enum_list::<KeyExchangeAlgorithm>()?;
let srv_host_key_algos = reader.read_enum_list::<PublicKeyAlgorithm>(); let srv_host_key_algos = reader.read_enum_list::<PublicKeyAlgorithm>()?;
let enc_algos_c2s = reader.read_enum_list::<EncryptionAlgorithm>(); let enc_algos_c2s = reader.read_enum_list::<EncryptionAlgorithm>()?;
let enc_algos_s2c = reader.read_enum_list::<EncryptionAlgorithm>(); let enc_algos_s2c = reader.read_enum_list::<EncryptionAlgorithm>()?;
let mac_algos_c2s = reader.read_enum_list::<MacAlgorithm>(); let mac_algos_c2s = reader.read_enum_list::<MacAlgorithm>()?;
let mac_algos_s2c = reader.read_enum_list::<MacAlgorithm>(); let mac_algos_s2c = reader.read_enum_list::<MacAlgorithm>()?;
let comp_algos_c2s = reader.read_enum_list::<CompressionAlgorithm>(); let comp_algos_c2s = reader.read_enum_list::<CompressionAlgorithm>()?;
let comp_algos_s2c = reader.read_enum_list::<CompressionAlgorithm>(); let comp_algos_s2c = reader.read_enum_list::<CompressionAlgorithm>()?;
let kex_algo = negotiate(KEY_EXCHANGE, kex_algos.unwrap().as_slice()); let kex_algo = negotiate(KEY_EXCHANGE, kex_algos.as_slice())?;
let srv_host_key_algo = let srv_host_key_algo =
negotiate(HOST_KEY, srv_host_key_algos.unwrap().as_slice()); negotiate(HOST_KEY, srv_host_key_algos.as_slice())?;
let enc_algo = negotiate(ENCRYPTION, enc_algos_s2c.unwrap().as_slice()); let enc_algo = negotiate(ENCRYPTION, enc_algos_s2c.as_slice())?;
let mac_algo = negotiate(MAC, mac_algos_s2c.unwrap().as_slice()); let mac_algo = negotiate(MAC, mac_algos_s2c.as_slice())?;
let comp_algo = let comp_algo = negotiate(COMPRESSION, comp_algos_s2c.as_slice())?;
negotiate(COMPRESSION, comp_algos_s2c.unwrap().as_slice());
println!("Negotiated Kex Algorithm: {:?}", kex_algo); println!("Negotiated Kex Algorithm: {:?}", kex_algo);
println!("Negotiated Host Key Algorithm: {:?}", srv_host_key_algo); println!("Negotiated Host Key Algorithm: {:?}", srv_host_key_algo);
@ -137,7 +139,7 @@ impl<W: Write> Connection<W> {
println!("Negotiated Comp Algorithm: {:?}", comp_algo); println!("Negotiated Comp Algorithm: {:?}", comp_algo);
use rand::{OsRng, Rng}; use rand::{OsRng, Rng};
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new()?;
let cookie: Vec<u8> = rng.gen_iter::<u8>().take(16).collect(); let cookie: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
let mut packet = Packet::new(MessageType::KexInit); let mut packet = Packet::new(MessageType::KexInit);
@ -156,10 +158,11 @@ impl<W: Write> Connection<W> {
w.write_bool(false)?; w.write_bool(false)?;
w.write_uint32(0)?; w.write_uint32(0)?;
Ok(()) Ok(())
}); })?;
self.state = ConnectionState::KeyExchange; self.state = ConnectionState::KeyExchange;
self.key_exchange = Some(Box::new(key_exchange::Curve25519::new())); self.key_exchange = Some(Box::new(key_exchange::Curve25519::new()));
packet.write_to(&mut self.stream); packet.write_to(&mut self.stream)?;
Ok(())
} }
} }

39
src/error.rs Normal file
View file

@ -0,0 +1,39 @@
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io;
pub type ConnectionResult<T> = Result<T, ConnectionError>;
#[derive(Debug)]
pub enum ConnectionError {
IoError(io::Error),
ProtocolError,
NegotiationError,
KeyExchangeError,
}
impl fmt::Display for ConnectionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "connection error: {}", (self as &Error).description())
}
}
impl Error for ConnectionError {
fn description(&self) -> &str {
use self::ConnectionError::*;
match self
{
&IoError(_) => "io error",
&ProtocolError => "protocol error",
&NegotiationError => "negotiation error",
&KeyExchangeError => "key exchange error",
}
}
}
impl From<io::Error> for ConnectionError {
fn from(err: io::Error) -> ConnectionError {
ConnectionError::IoError(err)
}
}

View file

@ -5,6 +5,7 @@ extern crate num_bigint;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
mod error;
mod algorithm; mod algorithm;
mod packet; mod packet;
mod message; mod message;

View file

@ -1,5 +1,3 @@
use std::fmt::Debug;
#[derive(PartialEq, Clone, Copy, Debug)] #[derive(PartialEq, Clone, Copy, Debug)]
pub enum MessageType { pub enum MessageType {
Disconnect, Disconnect,

View file

@ -109,11 +109,11 @@ pub trait ReadPacketExt: ReadBytesExt {
} }
fn read_utf8(&mut self) -> Result<String> { fn read_utf8(&mut self) -> Result<String> {
Ok( str::from_utf8(self.read_string()?.as_slice())
str::from_utf8(self.read_string()?.as_slice()) .map(|s| s.to_owned())
.unwrap_or("") .map_err(|_| {
.to_owned(), io::Error::new(io::ErrorKind::InvalidData, "invalid utf-8")
) })
} }
fn read_bool(&mut self) -> Result<bool> { fn read_bool(&mut self) -> Result<bool> {

View file

@ -1,8 +1,7 @@
use std::io::{self, Write}; use std::io;
use std::net::TcpListener; use std::net::TcpListener;
use connection::{Connection, ConnectionType}; use connection::{Connection, ConnectionType};
use packet::Packet;
use public_key::KeyPair; use public_key::KeyPair;
pub struct ServerConfig { pub struct ServerConfig {
@ -41,7 +40,10 @@ impl Server {
stream.try_clone().unwrap(), stream.try_clone().unwrap(),
); );
connection.run(&mut stream); let result = connection.run(&mut stream);
if let Some(error) = result.err() {
println!("sshd: {}", error)
}
} }
Ok(()) Ok(())