mirror of
https://gitlab.redox-os.org/CoffeeCode/redox-ssh.git
synced 2025-12-28 15:22:18 +01:00
Complete Curve25519 implementation
This commit is contained in:
parent
c44b63c32c
commit
d71b352b54
9 changed files with 326 additions and 112 deletions
|
|
@ -10,10 +10,10 @@ Currently implemented features, ordered by priority:
|
|||
- [ ] SSH Client
|
||||
- [ ] Key Exchange algorithms
|
||||
- [ ] `diffie-hellman-group-exchange-sha1`
|
||||
- [ ] `curve25519-sha256`
|
||||
- [x] `curve25519-sha256`
|
||||
- [ ] Public Key algorithms
|
||||
- [ ] `ssh-rsa`
|
||||
- [ ] `ssh-ed25519`
|
||||
- [x] `ssh-ed25519`
|
||||
- [ ] Encryption algorithms
|
||||
- [ ] `aes256-ctr`
|
||||
- [ ] `aes256-gcm`
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use std::io::{self, BufRead, BufReader, Read, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
use error::{ConnectionError, ConnectionResult};
|
||||
use key_exchange::{self, KeyExchange, KeyExchangeResult};
|
||||
use key_exchange::{self, KexResult, KeyExchange};
|
||||
use message::MessageType;
|
||||
use packet::{Packet, ReadPacketExt, WritePacketExt};
|
||||
use server::ServerConfig;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum ConnectionState {
|
||||
|
|
@ -12,55 +14,72 @@ enum ConnectionState {
|
|||
Established,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(Clone)]
|
||||
pub enum ConnectionType {
|
||||
Server,
|
||||
Server(Arc<ServerConfig>),
|
||||
Client,
|
||||
}
|
||||
|
||||
pub struct Connection<W: Write> {
|
||||
ctype: ConnectionType,
|
||||
state: ConnectionState,
|
||||
key_exchange: Option<Box<KeyExchange>>,
|
||||
stream: W,
|
||||
my_id: String,
|
||||
peer_id: Option<String>,
|
||||
#[derive(Default, Debug)]
|
||||
pub struct HashData {
|
||||
pub client_id: Option<String>,
|
||||
pub server_id: Option<String>,
|
||||
pub client_kexinit: Option<Vec<u8>>,
|
||||
pub server_kexinit: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<W: Write> Connection<W> {
|
||||
pub fn new(ctype: ConnectionType, stream: W) -> Connection<W> {
|
||||
pub struct Connection {
|
||||
pub conn_type: ConnectionType,
|
||||
pub hash_data: HashData,
|
||||
state: ConnectionState,
|
||||
key_exchange: Option<Box<KeyExchange>>,
|
||||
stream: Box<Write>,
|
||||
session_id: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<'a> Connection {
|
||||
pub fn new(conn_type: ConnectionType, stream: Box<Write>) -> Connection {
|
||||
Connection {
|
||||
ctype: ctype,
|
||||
conn_type: conn_type,
|
||||
hash_data: HashData::default(),
|
||||
state: ConnectionState::Initial,
|
||||
key_exchange: None,
|
||||
stream: stream,
|
||||
my_id: format!(
|
||||
"SSH-2.0-RedoxSSH_{}\r\n",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
),
|
||||
peer_id: None,
|
||||
stream: Box::new(stream),
|
||||
session_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self, stream: &mut Read) -> ConnectionResult<()> {
|
||||
self.stream.write(self.my_id.as_bytes())?;
|
||||
self.stream.flush()?;
|
||||
let mut reader = BufReader::new(stream);
|
||||
|
||||
let mut stream = BufReader::new(stream);
|
||||
self.peer_id = Some(self.read_id(&mut stream)?);
|
||||
|
||||
if let Some(ref peer_id) = self.peer_id {
|
||||
println!("Identifies as {:?}", peer_id);
|
||||
}
|
||||
self.send_id()?;
|
||||
self.read_id(&mut reader)?;
|
||||
|
||||
loop {
|
||||
let packet = Packet::read_from(&mut stream)?;
|
||||
println!("packet: {:?}", packet);
|
||||
self.process(&packet)?;
|
||||
let packet = Packet::read_from(&mut reader)?;
|
||||
trace!("Packet received: {:?}", packet);
|
||||
self.process(packet)?;
|
||||
}
|
||||
}
|
||||
|
||||
fn read_id(&mut self, mut reader: &mut BufRead) -> io::Result<String> {
|
||||
pub fn send(&mut self, packet: &Packet) -> io::Result<()> {
|
||||
packet.write_to(&mut self.stream)
|
||||
}
|
||||
|
||||
fn send_id(&mut self) -> io::Result<()> {
|
||||
let id = format!("SSH-2.0-RedoxSSH_{}", env!("CARGO_PKG_VERSION"));
|
||||
info!("Identifying as {:?}", id);
|
||||
|
||||
self.stream.write(id.as_bytes())?;
|
||||
self.stream.write(b"\r\n")?;
|
||||
self.stream.flush()?;
|
||||
|
||||
self.hash_data.server_id = Some(id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_id(&mut self, mut reader: &mut BufRead) -> io::Result<()> {
|
||||
// The identification string has a maximum length of 255 bytes
|
||||
// TODO: Make sure to stop reading if the client sends too much
|
||||
|
||||
|
|
@ -70,38 +89,88 @@ impl<W: Write> Connection<W> {
|
|||
reader.read_line(&mut id)?;
|
||||
}
|
||||
|
||||
Ok(id.trim_right().to_owned())
|
||||
let peer_id = id.trim_right().to_owned();
|
||||
info!("Peer identifies as {:?}", peer_id);
|
||||
self.hash_data.client_id = Some(peer_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process(&mut self, packet: &Packet) -> ConnectionResult<()> {
|
||||
fn generate_key(
|
||||
&mut self,
|
||||
id: &[u8],
|
||||
len: usize,
|
||||
) -> ConnectionResult<Vec<u8>> {
|
||||
use self::ConnectionError::KeyGenerationError;
|
||||
|
||||
let kex = self.key_exchange.take().ok_or(KeyGenerationError)?;
|
||||
|
||||
let key = kex.hash(
|
||||
&[
|
||||
kex.shared_secret().ok_or(KeyGenerationError)?,
|
||||
kex.exchange_hash().ok_or(KeyGenerationError)?,
|
||||
id,
|
||||
self.session_id
|
||||
.as_ref()
|
||||
.ok_or(KeyGenerationError)?
|
||||
.as_slice(),
|
||||
],
|
||||
);
|
||||
|
||||
self.key_exchange = Some(kex);
|
||||
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
pub fn process(&mut self, packet: Packet) -> ConnectionResult<()> {
|
||||
match packet.msg_type()
|
||||
{
|
||||
MessageType::KexInit => {
|
||||
println!("Starting Key Exchange!");
|
||||
self.kex_init(packet)
|
||||
}
|
||||
MessageType::NewKeys => {
|
||||
println!("Switching to new Keys");
|
||||
|
||||
let iv_c2s = self.generate_key(b"A", 256)?;
|
||||
let iv_s2c = self.generate_key(b"B", 256)?;
|
||||
let enc_c2s = self.generate_key(b"C", 256)?;
|
||||
let enc_s2c = self.generate_key(b"D", 256)?;
|
||||
let int_c2s = self.generate_key(b"E", 256)?;
|
||||
let int_s2c = self.generate_key(b"F", 256)?;
|
||||
|
||||
println!("c2s enc key: {:?}", enc_c2s);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
MessageType::KeyExchange(_) => {
|
||||
let ref mut kex = self.key_exchange.as_mut().ok_or(
|
||||
let mut kex = self.key_exchange.take().ok_or(
|
||||
ConnectionError::KeyExchangeError,
|
||||
)?;
|
||||
|
||||
match kex.process(packet)
|
||||
match kex.process(self, 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)?;
|
||||
}
|
||||
KexResult::Done(packet) => {
|
||||
self.state = ConnectionState::Established;
|
||||
self.send(&packet)?;
|
||||
|
||||
if self.session_id.is_none() {
|
||||
self.session_id =
|
||||
kex.exchange_hash().map(|h| h.to_vec());
|
||||
}
|
||||
|
||||
let packet = Packet::new(MessageType::NewKeys);
|
||||
self.send(&packet)?;
|
||||
Ok(())
|
||||
}
|
||||
KeyExchangeResult::Ok(None) |
|
||||
KeyExchangeResult::Error(None) => {}
|
||||
};
|
||||
KexResult::Ok(packet) => {
|
||||
self.send(&packet)?;
|
||||
Ok(())
|
||||
}
|
||||
KexResult::Error => Err(ConnectionError::KeyExchangeError),
|
||||
}?;
|
||||
|
||||
self.key_exchange = Some(kex);
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -111,35 +180,43 @@ impl<W: Write> Connection<W> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn kex_init(&mut self, packet: &Packet) -> ConnectionResult<()> {
|
||||
pub fn kex_init(&mut self, packet: Packet) -> ConnectionResult<()> {
|
||||
use algorithm::*;
|
||||
let mut reader = packet.reader();
|
||||
{
|
||||
let mut reader = packet.reader();
|
||||
let _ = reader.read_bytes(16)?; // Cookie. Throw it away.
|
||||
let kex_algos = reader.read_enum_list::<KeyExchangeAlgorithm>()?;
|
||||
let srv_host_key_algos =
|
||||
reader.read_enum_list::<PublicKeyAlgorithm>()?;
|
||||
let enc_algos_c2s = 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_s2c = reader.read_enum_list::<MacAlgorithm>()?;
|
||||
let comp_algos_c2s = reader
|
||||
.read_enum_list::<CompressionAlgorithm>()?;
|
||||
let comp_algos_s2c = reader
|
||||
.read_enum_list::<CompressionAlgorithm>()?;
|
||||
|
||||
let _ = reader.read_bytes(16)?; // Cookie. Throw it away.
|
||||
let kex_algos = reader.read_enum_list::<KeyExchangeAlgorithm>()?;
|
||||
let srv_host_key_algos = reader.read_enum_list::<PublicKeyAlgorithm>()?;
|
||||
let enc_algos_c2s = 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_s2c = reader.read_enum_list::<MacAlgorithm>()?;
|
||||
let comp_algos_c2s = reader.read_enum_list::<CompressionAlgorithm>()?;
|
||||
let comp_algos_s2c = reader.read_enum_list::<CompressionAlgorithm>()?;
|
||||
let kex_algo = negotiate(KEY_EXCHANGE, kex_algos.as_slice())?;
|
||||
let srv_host_key_algo =
|
||||
negotiate(HOST_KEY, srv_host_key_algos.as_slice())?;
|
||||
let enc_algo = negotiate(ENCRYPTION, enc_algos_s2c.as_slice())?;
|
||||
let mac_algo = negotiate(MAC, mac_algos_s2c.as_slice())?;
|
||||
let comp_algo = negotiate(COMPRESSION, comp_algos_s2c.as_slice())?;
|
||||
|
||||
let kex_algo = negotiate(KEY_EXCHANGE, kex_algos.as_slice())?;
|
||||
let srv_host_key_algo =
|
||||
negotiate(HOST_KEY, srv_host_key_algos.as_slice())?;
|
||||
let enc_algo = negotiate(ENCRYPTION, enc_algos_s2c.as_slice())?;
|
||||
let mac_algo = negotiate(MAC, mac_algos_s2c.as_slice())?;
|
||||
let comp_algo = negotiate(COMPRESSION, comp_algos_s2c.as_slice())?;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
// Save payload for hash generation
|
||||
self.hash_data.client_kexinit = Some(packet.payload());
|
||||
|
||||
use rand::{OsRng, Rng};
|
||||
let mut rng = OsRng::new()?;
|
||||
// Create a random 16 byte cookie
|
||||
use rand::{self, Rng};
|
||||
let mut rng = rand::thread_rng();
|
||||
let cookie: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
|
||||
|
||||
let mut packet = Packet::new(MessageType::KexInit);
|
||||
|
|
@ -162,7 +239,12 @@ impl<W: Write> Connection<W> {
|
|||
|
||||
self.state = ConnectionState::KeyExchange;
|
||||
self.key_exchange = Some(Box::new(key_exchange::Curve25519::new()));
|
||||
|
||||
packet.write_to(&mut self.stream)?;
|
||||
|
||||
// Save payload for hash generation
|
||||
self.hash_data.server_kexinit = Some(packet.payload());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub enum ConnectionError {
|
|||
ProtocolError,
|
||||
NegotiationError,
|
||||
KeyExchangeError,
|
||||
KeyGenerationError,
|
||||
}
|
||||
|
||||
impl fmt::Display for ConnectionError {
|
||||
|
|
@ -28,6 +29,7 @@ impl Error for ConnectionError {
|
|||
&ProtocolError => "protocol error",
|
||||
&NegotiationError => "negotiation error",
|
||||
&KeyExchangeError => "key exchange error",
|
||||
&KeyGenerationError => "key generation error",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,141 @@
|
|||
use crypto::curve25519::curve25519;
|
||||
use key_exchange::{KeyExchange, KeyExchangeResult};
|
||||
use connection::{Connection, ConnectionType};
|
||||
use crypto::curve25519;
|
||||
use crypto::digest::Digest;
|
||||
use crypto::sha2::Sha256;
|
||||
use key_exchange::{KexResult, KeyExchange};
|
||||
use message::MessageType;
|
||||
use num_bigint::{BigInt, Sign};
|
||||
use packet::{Packet, ReadPacketExt, WritePacketExt};
|
||||
use public_key::ED25519;
|
||||
use rand::{self, Rng};
|
||||
|
||||
const ECDH_KEX_INIT: u8 = 30;
|
||||
const ECDH_KEX_REPLY: u8 = 31;
|
||||
|
||||
pub struct Curve25519 {}
|
||||
pub struct Curve25519 {
|
||||
shared_secret: Option<[u8; 32]>,
|
||||
exchange_hash: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Curve25519 {
|
||||
pub fn new() -> Curve25519 {
|
||||
Curve25519 {}
|
||||
Curve25519 {
|
||||
shared_secret: None,
|
||||
exchange_hash: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyExchange for Curve25519 {
|
||||
fn process(&mut self, packet: &Packet) -> KeyExchangeResult {
|
||||
fn shared_secret<'a>(&'a self) -> Option<&'a [u8]> {
|
||||
self.shared_secret.as_ref().map(|x| x as &[u8])
|
||||
}
|
||||
|
||||
fn exchange_hash<'a>(&'a self) -> Option<&'a [u8]> {
|
||||
self.exchange_hash.as_ref().map(|x| x.as_slice())
|
||||
}
|
||||
|
||||
fn hash(&self, data: &[&[u8]]) -> Vec<u8> {
|
||||
let mut hash = [0; 32];
|
||||
let mut hasher = Sha256::new();
|
||||
|
||||
for item in data {
|
||||
hasher.input(item);
|
||||
}
|
||||
|
||||
hasher.result(&mut hash);
|
||||
hash.to_vec()
|
||||
}
|
||||
|
||||
fn process(&mut self, conn: &mut Connection, packet: Packet) -> KexResult {
|
||||
match packet.msg_type()
|
||||
{
|
||||
MessageType::KeyExchange(ECDH_KEX_INIT) => {
|
||||
let mut reader = packet.reader();
|
||||
let qc = reader.read_string().unwrap();
|
||||
let client_public = reader.read_string().unwrap();
|
||||
|
||||
let keypair = (ED25519.generate_key_pair)(None);
|
||||
let mut public_key = Vec::new();
|
||||
keypair.write_public(&mut public_key);
|
||||
let config = match &conn.conn_type
|
||||
{
|
||||
&ConnectionType::Server(ref config) => config.clone(),
|
||||
_ => return KexResult::Error,
|
||||
};
|
||||
|
||||
println!("Received qc: {:?}", qc);
|
||||
let public_key = {
|
||||
let mut key = Vec::new();
|
||||
config.as_ref().key.write_public(&mut key).unwrap();
|
||||
key
|
||||
};
|
||||
|
||||
println!("Received qc: {:?}", client_public);
|
||||
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(())
|
||||
});
|
||||
let server_secret = {
|
||||
let mut secret = [0; 32];
|
||||
let mut rng = rand::thread_rng();
|
||||
rng.fill_bytes(&mut secret);
|
||||
|
||||
KeyExchangeResult::Ok(Some(packet))
|
||||
secret[0] &= 248;
|
||||
secret[31] &= 127;
|
||||
secret[31] |= 64;
|
||||
|
||||
secret
|
||||
};
|
||||
|
||||
let server_public = curve25519::curve25519_base(&server_secret);
|
||||
let shared_secret =
|
||||
curve25519::curve25519(&server_secret, &client_public);
|
||||
|
||||
let hash_data = {
|
||||
let mut buf = Vec::new();
|
||||
let data = &conn.hash_data;
|
||||
|
||||
let items =
|
||||
[
|
||||
data.client_id.as_ref().unwrap().as_bytes(),
|
||||
data.server_id.as_ref().unwrap().as_bytes(),
|
||||
data.client_kexinit.as_ref().unwrap().as_slice(),
|
||||
data.server_kexinit.as_ref().unwrap().as_slice(),
|
||||
public_key.as_slice(),
|
||||
client_public.as_slice(),
|
||||
&server_public,
|
||||
];
|
||||
|
||||
for item in items.iter() {
|
||||
buf.write_bytes(item);
|
||||
}
|
||||
|
||||
buf.write_mpint(
|
||||
BigInt::from_bytes_be(Sign::Plus, &shared_secret),
|
||||
);
|
||||
|
||||
buf
|
||||
};
|
||||
|
||||
// Calculate hash
|
||||
let hash = self.hash(&[hash_data.as_slice()]);
|
||||
let signature = config.as_ref().key.sign(&hash).unwrap();
|
||||
|
||||
println!("Hash: {:?}", hash);
|
||||
println!("Public Key: {:?}", public_key);
|
||||
println!("Signature: {:?}", signature);
|
||||
|
||||
packet
|
||||
.with_writer(&|w| {
|
||||
w.write_bytes(public_key.as_slice())?;
|
||||
w.write_bytes(&server_public)?;
|
||||
w.write_bytes(signature.as_slice())?; // Signature
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
self.exchange_hash = Some(hash);
|
||||
self.shared_secret = Some(shared_secret);
|
||||
|
||||
KexResult::Done(packet)
|
||||
}
|
||||
_ => {
|
||||
debug!("Unhandled key exchange packet: {:?}", packet);
|
||||
KeyExchangeResult::Error(None)
|
||||
KexResult::Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use key_exchange::{KeyExchange, KeyExchangeResult};
|
||||
use connection::Connection;
|
||||
use key_exchange::{KexResult, KeyExchange};
|
||||
use message::MessageType;
|
||||
use num_bigint::{BigInt, RandBigInt, ToBigInt};
|
||||
use packet::{Packet, ReadPacketExt, WritePacketExt};
|
||||
|
|
@ -38,7 +39,19 @@ impl DhGroupSha1 {
|
|||
}
|
||||
|
||||
impl KeyExchange for DhGroupSha1 {
|
||||
fn process(&mut self, packet: &Packet) -> KeyExchangeResult {
|
||||
fn shared_secret<'a>(&'a self) -> Option<&'a [u8]> {
|
||||
Some(&[])
|
||||
}
|
||||
|
||||
fn exchange_hash<'a>(&'a self) -> Option<&'a [u8]> {
|
||||
Some(&[])
|
||||
}
|
||||
|
||||
fn hash(&self, data: &[&[u8]]) -> Vec<u8> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn process(&mut self, conn: &mut Connection, packet: Packet) -> KexResult {
|
||||
match packet.msg_type()
|
||||
{
|
||||
MessageType::KeyExchange(DH_GEX_REQUEST) => {
|
||||
|
|
@ -64,7 +77,7 @@ impl KeyExchange for DhGroupSha1 {
|
|||
self.g = Some(g);
|
||||
self.p = Some(p);
|
||||
|
||||
KeyExchangeResult::Ok(Some(packet))
|
||||
KexResult::Ok(packet)
|
||||
}
|
||||
MessageType::KeyExchange(DH_GEX_INIT) => {
|
||||
let mut reader = packet.reader();
|
||||
|
|
@ -83,11 +96,11 @@ impl KeyExchange for DhGroupSha1 {
|
|||
|
||||
self.e = Some(e);
|
||||
|
||||
KeyExchangeResult::Ok(Some(packet))
|
||||
KexResult::Done(packet)
|
||||
}
|
||||
_ => {
|
||||
debug!("Unhandled key exchange packet: {:?}", packet);
|
||||
KeyExchangeResult::Error(None)
|
||||
KexResult::Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,18 @@ mod dh_group_sha1;
|
|||
pub use self::curve25519::Curve25519;
|
||||
pub use self::dh_group_sha1::DhGroupSha1;
|
||||
|
||||
use connection::Connection;
|
||||
use packet::Packet;
|
||||
|
||||
pub enum KeyExchangeResult {
|
||||
Ok(Option<Packet>),
|
||||
Done(Option<Packet>),
|
||||
Error(Option<Packet>),
|
||||
pub enum KexResult {
|
||||
Ok(Packet),
|
||||
Done(Packet),
|
||||
Error,
|
||||
}
|
||||
|
||||
pub trait KeyExchange {
|
||||
fn process(&mut self, packet: &Packet) -> KeyExchangeResult;
|
||||
fn process(&mut self, conn: &mut Connection, packet: Packet) -> KexResult;
|
||||
fn shared_secret<'a>(&'a self) -> Option<&'a [u8]>;
|
||||
fn exchange_hash<'a>(&'a self) -> Option<&'a [u8]>;
|
||||
fn hash(&self, data: &[&[u8]]) -> Vec<u8>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ impl Packet {
|
|||
self.payload[0].into()
|
||||
}
|
||||
|
||||
pub fn payload(self) -> Vec<u8> {
|
||||
self.payload
|
||||
}
|
||||
|
||||
pub fn read_from<R: io::Read>(stream: &mut R) -> Result<Packet> {
|
||||
let mac_len = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -84,13 +84,28 @@ impl KeyPair for Ed25519KeyPair {
|
|||
}
|
||||
|
||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
Ok(ed25519::verify(data, &self.public, signature))
|
||||
use packet::ReadPacketExt;
|
||||
use std::io::Cursor;
|
||||
|
||||
let mut reader = Cursor::new(signature);
|
||||
let id = reader.read_string().unwrap_or(vec![]);
|
||||
|
||||
if id == b"ssh-ed25519" {
|
||||
if let Ok(sig) = reader.read_string() {
|
||||
return Ok(ed25519::verify(data, &self.public, sig.as_slice()));
|
||||
}
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
use packet::WritePacketExt;
|
||||
if let Some(private_key) = self.private {
|
||||
let signature = ed25519::signature(data, &private_key);
|
||||
Ok(signature.to_vec())
|
||||
let mut result = Vec::new();
|
||||
let sig = ed25519::signature(data, &private_key);
|
||||
result.write_string("ssh-ed25519").or(Err(()));
|
||||
result.write_bytes(&sig).or(Err(()));
|
||||
Ok(result)
|
||||
}
|
||||
else {
|
||||
Err(())
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::io;
|
||||
use std::net::TcpListener;
|
||||
use std::sync::Arc;
|
||||
|
||||
use connection::{Connection, ConnectionType};
|
||||
use public_key::KeyPair;
|
||||
|
|
@ -11,12 +12,12 @@ pub struct ServerConfig {
|
|||
}
|
||||
|
||||
pub struct Server {
|
||||
config: ServerConfig,
|
||||
config: Arc<ServerConfig>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn with_config(config: ServerConfig) -> Server {
|
||||
Server { config: config }
|
||||
Server { config: Arc::new(config) }
|
||||
}
|
||||
|
||||
pub fn run(&self) -> io::Result<()> {
|
||||
|
|
@ -24,8 +25,8 @@ impl Server {
|
|||
(&*self.config.host, self.config.port),
|
||||
).expect(&*format!(
|
||||
"sshd: failed to bind to {}:{}",
|
||||
self.config.host,
|
||||
self.config.port
|
||||
self.config.as_ref().host,
|
||||
self.config.as_ref().port
|
||||
));
|
||||
|
||||
loop {
|
||||
|
|
@ -36,8 +37,8 @@ impl Server {
|
|||
println!("Incoming connection from {}", addr);
|
||||
|
||||
let mut connection = Connection::new(
|
||||
ConnectionType::Server,
|
||||
stream.try_clone().unwrap(),
|
||||
ConnectionType::Server(self.config.clone()),
|
||||
Box::new(stream.try_clone().unwrap()),
|
||||
);
|
||||
|
||||
let result = connection.run(&mut stream);
|
||||
|
|
|
|||
Loading…
Reference in a new issue