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

Discard the usage of nom

This commit is contained in:
Thomas Gatzweiler 2017-07-14 12:19:19 +02:00
parent 587f810172
commit 6dd79b785d
16 changed files with 771 additions and 472 deletions

171
Cargo.lock generated
View file

@ -4,55 +4,29 @@ 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)",
"nom 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "coco"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "either"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "foreign-types"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.2.8"
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
@ -64,57 +38,6 @@ name = "log"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nom"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl"
version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pkg-config"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.15"
@ -123,75 +46,59 @@ dependencies = [
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon-core"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ring"
version = "0.11.0"
name = "rust-crypto"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scopeguard"
version = "0.3.2"
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "untrusted"
version = "0.5.0"
name = "time"
version = "0.1.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
"checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a"
"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a"
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
"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 memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
"checksum nom 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f609d6a10aad859fdfccb134ba1022bbdfac52dd759acc2ab75171874056237"
"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584"
"checksum openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "11ba043cb65fc9af71a431b8a36ffe8686cd4751cdf70a473ec1d01066ac7e41"
"checksum openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "236c718c2e2c2b58a546d86ffea5194400bb15dbe01ca85325ffd357b03cf66c"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a"
"checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493"
"checksum redox_syscall 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "9df6a71a1e67be2104410736b2389fb8e383c1d7e9e792d629ff13c02867147a"
"checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724"
"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918"
"checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673"
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View file

@ -18,8 +18,8 @@ path = "src/bin/sshd.rs"
[dependencies]
byteorder = "^1.0"
log = "^0.3"
nom = "^3.1"
ring = "^0.11.0"
rust-crypto = "^0.2"
rand = "^0.3"
[target.'cfg(target_os = "redox")'.dependencies]
redox_syscall = "0.1"

258
src/algorithm.rs Normal file
View file

@ -0,0 +1,258 @@
use std::str::FromStr;
use std::fmt;
/// Slice of implemented key exchange algorithms, ordered by preference
pub static KEY_EXCHANGE: &[KeyExchangeAlgorithm] = &[
KeyExchangeAlgorithm::CURVE25519_SHA256
];
/// Slice of implemented host key algorithms, ordered by preference
pub static HOST_KEY: &[PublicKeyAlgorithm] = &[
PublicKeyAlgorithm::SSH_ED25519
];
/// Slice of implemented encryption algorithms, ordered by preference
pub static ENCRYPTION: &[EncryptionAlgorithm] = &[
EncryptionAlgorithm::AES256_CTR
];
/// Slice of implemented MAC algorithms, ordered by preference
pub static MAC: &[MacAlgorithm] = &[
MacAlgorithm::HMAC_SHA2_512
];
/// Slice of implemented compression algorithms, ordered by preference
pub static COMPRESSION: &[CompressionAlgorithm] = &[
CompressionAlgorithm::None,
CompressionAlgorithm::Zlib
];
/// Find the best matching algorithm
pub fn negotiate<A: PartialEq + Copy>(server: &[A], client: &[A]) -> Option<A> {
for algorithm in client.iter() {
if server.iter().any(|a| a == algorithm) {
return Some(*algorithm);
}
}
None
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum KeyExchangeAlgorithm {
CURVE25519_SHA256,
ECDH_SHA2_NISTP256,
ECDH_SHA2_NISTP384,
ECDH_SHA2_NISTP521,
DH_GROUP_EXCHANGE_SHA256,
DH_GROUP_EXCHANGE_SHA1,
DH_GROUP16_SHA512,
DH_GROUP18_SHA512,
DH_GROUP14_SHA256,
DH_GROUP14_SHA1,
EXT_INFO_C,
}
impl FromStr for KeyExchangeAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<KeyExchangeAlgorithm, ()> {
use self::KeyExchangeAlgorithm::*;
match s {
"curve25519-sha256" => Ok(CURVE25519_SHA256),
"ecdh-sha2-nistp256" => Ok(ECDH_SHA2_NISTP256),
"ecdh-sha2-nistp384" => Ok(ECDH_SHA2_NISTP384),
"ecdh-sha2-nistp521" => Ok(ECDH_SHA2_NISTP521),
"diffie-hellman-group-exchange-sha256" => Ok(DH_GROUP_EXCHANGE_SHA256),
"diffie-hellman-group-exchange-sha1" => Ok(DH_GROUP_EXCHANGE_SHA1),
"diffie-hellman-group16-sha512" => Ok(DH_GROUP16_SHA512),
"diffie-hellman-group18-sha512" => Ok(DH_GROUP18_SHA512),
"diffie-hellman-group14-sha256" => Ok(DH_GROUP14_SHA256),
"diffie-hellman-group14-sha1" => Ok(DH_GROUP14_SHA1),
"ext-info-c" => Ok(EXT_INFO_C),
_ => {
debug!("Unknown kex algorithm: {}", s);
Err(())
}
}
}
}
impl fmt::Display for KeyExchangeAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::KeyExchangeAlgorithm::*;
f.write_str(match self {
&CURVE25519_SHA256 => "curve25519-sha256",
&ECDH_SHA2_NISTP256 => "ecdh-sha2-nistp256",
&ECDH_SHA2_NISTP384 => "ecdh-sha2-nistp384",
&ECDH_SHA2_NISTP521 => "ecdh-sha2-nistp521",
&DH_GROUP_EXCHANGE_SHA256 => "diffie-hellman-group-exchange-sha256",
&DH_GROUP_EXCHANGE_SHA1 => "diffie-hellman-group-exchange-sha1",
&DH_GROUP16_SHA512 => "diffie-hellman-group16-sha512",
&DH_GROUP18_SHA512 => "diffie-hellman-group18-sha512",
&DH_GROUP14_SHA256 => "diffie-hellman-group14-sha256",
&DH_GROUP14_SHA1 => "diffie-hellman-group14-sha1",
&EXT_INFO_C => "ext-info-c",
})
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[allow(non_camel_case_types)]
pub enum PublicKeyAlgorithm {
SSH_RSA,
RSA_SHA2_256,
RSA_SHA2_512,
ECDSA_SHA2_NISTP256,
ECDSA_SHA2_NISTP384,
ECDSA_SHA2_NISTP521,
SSH_ED25519,
}
impl FromStr for PublicKeyAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<PublicKeyAlgorithm, ()> {
use self::PublicKeyAlgorithm::*;
match s {
"ssh-rsa" => Ok(SSH_RSA),
"rsa-sha2-256" => Ok(RSA_SHA2_256),
"rsa-sha2-512" => Ok(RSA_SHA2_512),
"ecdsa-sha2-nistp256" => Ok(ECDSA_SHA2_NISTP256),
"ecdsa-sha2-nistp384" => Ok(ECDSA_SHA2_NISTP384),
"ecdsa-sha2-nistp521" => Ok(ECDSA_SHA2_NISTP521),
"ssh-ed25519" => Ok(SSH_ED25519),
_ => {
debug!("Unknown host key algorithm: {}", s);
Err(())
}
}
}
}
impl fmt::Display for PublicKeyAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::PublicKeyAlgorithm::*;
f.write_str(match self {
&SSH_RSA => "ssh-rsa",
&RSA_SHA2_256 => "rsa-sha2-256",
&RSA_SHA2_512 => "rsa-sha2-512",
&ECDSA_SHA2_NISTP256 => "ecdsa-sha2-nistp256",
&ECDSA_SHA2_NISTP384 => "ecdsa-sha2-nistp384",
&ECDSA_SHA2_NISTP521 => "ecdsa-sha2-nistp521",
&SSH_ED25519 => "ssh-ed25519",
})
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[allow(non_camel_case_types)]
pub enum EncryptionAlgorithm {
AES128_CTR,
AES128_CBC,
AES192_CTR,
AES192_CBC,
AES256_CTR,
AES256_CBC,
None,
}
impl FromStr for EncryptionAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<EncryptionAlgorithm, ()> {
use self::EncryptionAlgorithm::*;
match s {
"aes128-ctr" => Ok(AES128_CTR),
"aes128-cbc" => Ok(AES128_CBC),
"aes192-ctr" => Ok(AES192_CTR),
"aes192-cbc" => Ok(AES192_CBC),
"aes256-ctr" => Ok(AES256_CTR),
"aes256-cbc" => Ok(AES256_CBC),
"none" => Ok(EncryptionAlgorithm::None),
_ => {
println!("Unknown encryption algorithm: `{}`", s);
Err(())
}
}
}
}
impl fmt::Display for EncryptionAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::EncryptionAlgorithm::*;
f.write_str(match self {
&AES128_CTR => "aes128-ctr",
&AES128_CBC => "aes128-cbc",
&AES192_CTR => "aes192-ctr",
&AES192_CBC => "aes192-cbc",
&AES256_CTR => "aes256-ctr",
&AES256_CBC => "aes256-cbc",
&EncryptionAlgorithm::None => "none",
})
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[allow(non_camel_case_types)]
pub enum MacAlgorithm {
HMAC_SHA1,
HMAC_SHA2_256,
HMAC_SHA2_512,
None,
}
impl FromStr for MacAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<MacAlgorithm, ()> {
use self::MacAlgorithm::*;
match s {
"hmac-sha1" => Ok(MacAlgorithm::HMAC_SHA1),
"hmac-sha2-256" => Ok(MacAlgorithm::HMAC_SHA2_256),
"hmac-sha2-512" => Ok(MacAlgorithm::HMAC_SHA2_512),
_ => {
println!("Unknown mac algorithm: {}", s);
Err(())
}
}
}
}
impl fmt::Display for MacAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::MacAlgorithm::*;
f.write_str(match self {
&HMAC_SHA1 => "hmac-sha1",
&HMAC_SHA2_256 => "hmac-sha2-256",
&HMAC_SHA2_512 => "hmac-sha2-512",
&MacAlgorithm::None => "none"
})
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum CompressionAlgorithm {
Zlib,
None,
}
impl FromStr for CompressionAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<CompressionAlgorithm, ()> {
match s {
"zlib" => Ok(CompressionAlgorithm::Zlib),
"none" => Ok(CompressionAlgorithm::None),
_ => {
println!("Unknown compression algorithm: {}", s);
Err(())
}
}
}
}
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"
})
}
}

View file

@ -1,9 +0,0 @@
pub enum AuthMethod {
PublicKey, Password, HostBased, None
}
pub struct AuthRequest {
user: String,
service: String,
method: AuthMethod
}

View file

@ -1,10 +1,52 @@
#![cfg_attr(not(target_os = "redox"), feature(libc))]
extern crate ssh;
use std::io::{self, Write};
use std::str::FromStr;
use std::env;
use std::process;
use ssh::{Server, ServerConfig};
pub fn main() {
let config = ServerConfig { host: String::from("0.0.0.0:22222") };
let mut foreground = false;
let mut quiet = false;
let mut config = ServerConfig::default();
let mut args = env::args().skip(1);
while let Some(arg) = args.next() {
match arg.as_ref() {
"-f" => foreground = true,
"-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");
}
_ => ()
}
}
let server = Server::with_config(config);
server.start();
if !foreground && fork() != 0 {
process::exit(0);
}
if let Err(err) = server.run() {
writeln!(io::stderr(), "sshd: {}", err).unwrap();
process::exit(1);
}
}
#[cfg(target_os = "redox")]
fn fork() -> usize {
extern crate syscall;
unsafe { syscall::clone(0).unwrap() }
}
#[cfg(not(target_os = "redox"))]
fn fork() -> usize {
extern crate libc;
unsafe { libc::fork() as usize }
}

View file

@ -0,0 +1,3 @@
pub struct Curve25519 {
}

9
src/key_exchange/mod.rs Normal file
View file

@ -0,0 +1,9 @@
mod curve25519;
pub use self::curve25519::Curve25519;
use packet::Packet;
pub trait KeyExchange {
fn process(&self, packet: &Packet);
}

View file

@ -1,13 +1,15 @@
extern crate byteorder;
extern crate rand;
extern crate crypto;
#[macro_use]
extern crate log;
#[macro_use]
extern crate nom;
pub mod algorithm;
pub mod protocol;
pub mod server;
pub mod packet;
pub mod parser;
pub mod message;
pub mod session;
pub mod key_exchange;
pub use self::server::{Server, ServerConfig};

108
src/message.rs Normal file
View file

@ -0,0 +1,108 @@
use std::fmt::Debug;
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum MessageType {
Disconnect,
Ignore,
Unimplemented,
Debug,
ServiceRequest,
ServiceAccept,
KexInit,
NewKeys,
KeyExchange(u8),
UserAuthRequest,
UserAuthFailure,
UserAuthSuccess,
UserAuthBanner,
UserAuth(u8),
GlobalRequest,
RequestSuccess,
RequestFailure,
ChannelOpen,
ChannelOpenConfirmation,
ChannelOpenFailure,
ChannelWindowAdjust,
ChannelData,
ChannelExtendedData,
ChannelEOF,
ChannelClose,
ChannelRequest,
ChannelSuccess,
ChannelFailure,
Unknown
}
impl From<u8> for MessageType {
fn from(id: u8) -> Self {
use self::MessageType::*;
match id {
1 => Disconnect,
2 => Ignore,
3 => Unimplemented,
4 => Debug,
5 => ServiceRequest,
6 => ServiceAccept,
20 => KexInit,
21 => NewKeys,
30...49 => KeyExchange(id),
50 => UserAuthRequest,
51 => UserAuthFailure,
52 => UserAuthSuccess,
53 => UserAuthBanner,
60...79 => UserAuth(id),
80 => GlobalRequest,
81 => RequestSuccess,
82 => RequestFailure,
90 => ChannelOpen,
91 => ChannelOpenConfirmation,
92 => ChannelOpenFailure,
93 => ChannelWindowAdjust,
94 => ChannelData,
95 => ChannelExtendedData,
96 => ChannelEOF,
97 => ChannelClose,
98 => ChannelRequest,
99 => ChannelSuccess,
100 => ChannelFailure,
_ => Unknown
}
}
}
impl Into<u8> for MessageType {
fn into(self) -> u8 {
use self::MessageType::*;
match self {
Disconnect => 1,
Ignore => 2,
Unimplemented => 3,
Debug => 4,
ServiceRequest => 5,
ServiceAccept => 6,
KexInit => 20,
NewKeys => 21,
KeyExchange(id) => id,
UserAuthRequest => 50,
UserAuthFailure => 51,
UserAuthSuccess => 52,
UserAuthBanner => 53,
UserAuth(id) => id,
GlobalRequest => 80,
RequestSuccess => 81,
RequestFailure => 82,
ChannelOpen => 90,
ChannelOpenConfirmation => 91,
ChannelOpenFailure => 92,
ChannelWindowAdjust => 93,
ChannelData => 94,
ChannelExtendedData => 95,
ChannelEOF => 96,
ChannelClose => 97,
ChannelRequest => 98,
ChannelSuccess => 99,
ChannelFailure => 100,
Unknown => 255
}
}
}

View file

@ -1,163 +0,0 @@
use std::str::FromStr;
#[derive(Debug)]
pub struct KeyExchangeInit {
pub cookie: Vec<u8>,
pub kex_algorithms: Vec<KeyExchangeAlgorithm>,
pub server_host_key_algorithms: Vec<HostKeyAlgorithm>,
pub encryption_algorithms_client_to_server: Vec<EncryptionAlgorithm>,
pub encryption_algorithms_server_to_client: Vec<EncryptionAlgorithm>,
pub mac_algorithms_client_to_server: Vec<MacAlgorithm>,
pub mac_algorithms_server_to_client: Vec<MacAlgorithm>,
pub compression_algorithms_client_to_server: Vec<CompressionAlgorithm>,
pub compression_algorithms_server_to_client: Vec<CompressionAlgorithm>,
pub languages_client_to_server: Vec<Language>,
pub languages_server_to_client: Vec<Language>,
pub first_kex_packet_follows: bool
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum KeyExchangeAlgorithm {
CURVE25519_SHA256,
ECDH_SHA2_NISTP256,
ECDH_SHA2_NISTP384,
ECDH_SHA2_NISTP521,
DH_GROUP_EXCHANGE_SHA256,
DH_GROUP_EXCHANGE_SHA1,
DH_GROUP16_SHA512,
DH_GROUP18_SHA512,
DH_GROUP14_SHA256,
DH_GROUP14_SHA1,
EXT_INFO_C
}
impl FromStr for KeyExchangeAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<KeyExchangeAlgorithm, ()> {
match s {
"curve25519-sha256" =>
Ok(KeyExchangeAlgorithm::CURVE25519_SHA256),
"ecdh-sha2-nistp256" =>
Ok(KeyExchangeAlgorithm::ECDH_SHA2_NISTP256),
"ecdh-sha2-nistp384" =>
Ok(KeyExchangeAlgorithm::ECDH_SHA2_NISTP384),
"ecdh-sha2-nistp521" =>
Ok(KeyExchangeAlgorithm::ECDH_SHA2_NISTP521),
"diffie-hellman-group16-sha512" =>
Ok(KeyExchangeAlgorithm::DH_GROUP16_SHA512),
"diffie-hellman-group18-sha512" =>
Ok(KeyExchangeAlgorithm::DH_GROUP18_SHA512),
"diffie-hellman-group14-sha256" =>
Ok(KeyExchangeAlgorithm::DH_GROUP14_SHA256),
"diffie-hellman-group14-sha1" =>
Ok(KeyExchangeAlgorithm::DH_GROUP14_SHA1),
"diffie-hellman-group-exchange-sha256" =>
Ok(KeyExchangeAlgorithm::DH_GROUP_EXCHANGE_SHA256),
"diffie-hellman-group-exchange-sha1" =>
Ok(KeyExchangeAlgorithm::DH_GROUP_EXCHANGE_SHA1),
"ext-info-c" =>
Ok(KeyExchangeAlgorithm::EXT_INFO_C),
_ => { println!("Unknown kex algorithm: {}", s); Err(()) }
}
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum HostKeyAlgorithm {
SSH_RSA,
RSA_SHA2_256,
RSA_SHA2_512,
ECDSA_SHA2_NISTP256,
ECDSA_SHA2_NISTP384,
ECDSA_SHA2_NISTP521,
SSH_ED25519
}
impl FromStr for HostKeyAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<HostKeyAlgorithm, ()> {
match s {
"ssh-rsa" => Ok(HostKeyAlgorithm::SSH_RSA),
"rsa-sha2-256" => Ok(HostKeyAlgorithm::RSA_SHA2_256),
"rsa-sha2-512" => Ok(HostKeyAlgorithm::RSA_SHA2_512),
"ecdsa-sha2-nistp256" => Ok(HostKeyAlgorithm::ECDSA_SHA2_NISTP256),
"ecdsa-sha2-nistp384" => Ok(HostKeyAlgorithm::ECDSA_SHA2_NISTP384),
"ecdsa-sha2-nistp521" => Ok(HostKeyAlgorithm::ECDSA_SHA2_NISTP521),
"ssh-ed25519" => Ok(HostKeyAlgorithm::SSH_ED25519),
_ => { println!("Unknown host key algorithm: {}", s); Err(()) }
}
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum EncryptionAlgorithm {
AES128_CTR,
AES128_CBC,
AES192_CTR,
AES192_CBC,
AES256_CTR,
AES256_CBC,
None
}
impl FromStr for EncryptionAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<EncryptionAlgorithm, ()> {
match s {
"aes128-ctr" => Ok(EncryptionAlgorithm::AES128_CTR),
"aes128-cbc" => Ok(EncryptionAlgorithm::AES128_CBC),
"aes192-ctr" => Ok(EncryptionAlgorithm::AES192_CTR),
"aes192-cbc" => Ok(EncryptionAlgorithm::AES192_CBC),
"aes256-ctr" => Ok(EncryptionAlgorithm::AES256_CTR),
"aes256-cbc" => Ok(EncryptionAlgorithm::AES256_CBC),
"none" => Ok(EncryptionAlgorithm::None),
_ => { println!("Unknown encryption algorithm: `{}`", s); Err(()) }
}
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum MacAlgorithm {
HMAC_SHA1,
HMAC_SHA2_256,
HMAC_SHA2_512,
None
}
impl FromStr for MacAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<MacAlgorithm, ()> {
match s {
"hmac-sha1" => Ok(MacAlgorithm::HMAC_SHA1),
"hmac-sha2-256" => Ok(MacAlgorithm::HMAC_SHA2_256),
"hmac-sha2-512" => Ok(MacAlgorithm::HMAC_SHA2_512),
_ => { println!("Unknown mac algorithm: {}", s); Err(()) }
}
}
}
#[derive(Debug)]
pub enum CompressionAlgorithm {
Zlib,
None
}
impl FromStr for CompressionAlgorithm {
type Err = ();
fn from_str(s: &str) -> Result<CompressionAlgorithm, ()> {
match s {
"zlib" => Ok(CompressionAlgorithm::Zlib),
"none" => Ok(CompressionAlgorithm::None),
_ => { println!("Unknown compression algorithm: {}", s); Err(()) }
}
}
}
#[derive(Debug)]
pub struct Language(pub String);

View file

@ -1,33 +0,0 @@
pub mod kex;
#[derive(Debug)]
pub enum Message {
Disconnect,
Ignore,
Unimplemented,
Debug,
ServiceRequest,
ServiceAccept,
KexInit(kex::KeyExchangeInit),
NewKeys,
UserAuthRequest,
UserAuthFailure,
UserAuthSuccess,
UserAuthBanner,
GlobalRequest,
RequestSuccess,
RequestFailure,
ChannelOpen,
ChannelOpenConfirmation,
ChannelOpenFailure,
ChannelWindowAdjust,
ChannelData,
ChannelExtendedData,
ChannelEOF,
ChannelClose,
ChannelRequest,
ChannelSuccess,
ChannelFailure,
Unknown
}

View file

@ -1,21 +1,159 @@
use std::fmt;
use std::str;
use parser;
use std::str::{self, FromStr};
use std::string::ToString;
use std::io::{self, BufReader, Write, Read, Result};
use message::MessageType;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
pub struct Packet {
pub payload: Vec<u8>,
pub mac: Vec<u8>
payload: Vec<u8>
}
impl Packet {
pub fn parse(&self) {
let result = parser::parse_packet(&self.payload.as_slice());
println!("{:?}", result);
pub fn new(msg_type: MessageType) -> Packet {
Packet { payload: (&[msg_type.into()]).to_vec() }
}
pub fn msg_type(&self) -> MessageType {
self.payload[0].into()
}
pub fn read_from<R: io::Read>(stream: &mut R) -> Result<Packet> {
let mac_len = 0;
let packet_len = stream.read_u32::<BigEndian>()? as usize;
let padding_len = stream.read_u8()? as usize;
let payload_len = packet_len - padding_len - 1;
// TODO: Prevent packets that are too large
let mut payload = Vec::with_capacity(payload_len);
let mut padding = Vec::with_capacity(padding_len);
// let mut mac = Vec::with_capacity(mac_len);
stream.take(payload_len as u64).read_to_end(&mut payload)?;
stream.take(padding_len as u64).read_to_end(&mut padding)?;
// if mac_len > 0 {
// stream.take(mac_len as u64).read_to_end(&mut mac);
// }
Ok(Packet { payload: payload })
}
pub fn write_to<W: io::Write>(&self, stream: &mut W) -> Result<()> {
let padding_len = self.padding_len();
let packet_len = self.payload.len() + padding_len + 1;
stream.write_u32::<BigEndian>(packet_len as u32)?;
stream.write_u8(padding_len as u8)?;
stream.write(&self.payload)?;
stream.write(&[0u8;255][..padding_len])?;
Ok(())
}
pub fn writer<'a>(&'a mut self) -> &'a mut Write {
&mut self.payload
}
pub fn with_writer(&mut self, f: &Fn(&mut Write) -> ()) {
f(&mut self.payload);
}
pub fn reader<'a>(&'a self) -> BufReader<&'a [u8]> {
BufReader::new(self.payload.as_slice())
}
pub fn padding_len(&self) -> usize {
// Calculate the padding to reach a multiple of 8 bytes
let padding_len = 8 - ((self.payload.len() + 5) % 8);
// The padding has to be at least 4 bytes long
if padding_len < 4 { padding_len + 8 }
else { padding_len }
}
}
impl fmt::Debug for Packet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Packet({} bytes)", self.payload.len())
pub trait ReadPacketExt: ReadBytesExt {
fn read_msg_type(&mut self) -> Result<MessageType> {
Ok(self.read_u8()?.into())
}
fn read_string(&mut self) -> Result<Vec<u8>> {
let len = self.read_u32::<BigEndian>()?;
self.read_bytes(len as usize)
}
fn read_mpint(&mut self) -> Result<Vec<u8>> {
let len = self.read_u32::<BigEndian>()?;
self.read_bytes(len as usize)
}
fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>> {
let mut buffer = Vec::with_capacity(len);
self.take(len as u64).read_to_end(&mut buffer)?;
Ok(buffer)
}
fn read_utf8(&mut self) -> Result<String> {
Ok(str::from_utf8(self.read_string()?.as_slice()).unwrap_or("").to_owned())
}
fn read_bool(&mut self) -> Result<bool> {
self.read_u8().map(|i| i != 0)
}
fn read_enum_list<T: FromStr>(&mut self) -> Result<Vec<T>> {
let string = self.read_utf8()?;
Ok(string.split(",").filter_map(|l| T::from_str(&l).ok()).collect())
}
fn read_name_list(&mut self) -> Result<Vec<String>> {
let string = self.read_utf8()?;
Ok(string.split(",").map(|l| l.to_owned()).collect())
}
}
impl<R: ReadBytesExt> ReadPacketExt for R {}
pub trait WritePacketExt: WriteBytesExt {
fn write_msg_type(&mut self, msg_type: MessageType) -> Result<()> {
self.write_u8(msg_type.into())
}
fn write_string(&mut self, s: &str) -> Result<()> {
let bytes = s.as_bytes();
self.write_u32::<BigEndian>(bytes.len() as u32)?;
self.write_all(bytes)
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
self.write_all(bytes)
}
fn write_bool(&mut self, value: bool) -> Result<()> {
self.write_u8(if value { 1 } else { 0 })
}
fn write_list<T: ToString>(&mut self, list: &[T]) -> Result<()> {
let mut string = String::new();
let mut iter = list.iter();
while let Some(item) = iter.next() {
if !string.is_empty() {
string += ",";
}
string += &*item.to_string();
}
self.write_string(&*string)
}
}
impl<R: WriteBytesExt + ?Sized> WritePacketExt for R {}
impl fmt::Debug for Packet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Packet({:?}, {} bytes)", self.msg_type(), self.payload.len())
}
}

View file

@ -1,81 +0,0 @@
use std::str;
use std::str::FromStr;
use nom::{IResult, Endianness};
use message::*;
macro_rules! enum_list (
($i:expr, $name:ty) => (
parse_enum_list::<$name>($i)
);
);
named!(pub parse_packet<Message>,
map!(parse_keyx_init, |m| Message::KexInit(m))
);
named!(parse_keyx_init<&[u8], kex::KeyExchangeInit>, do_parse!(tag!(&[20]) >>
cookie: take!(16) >>
kex_algos: enum_list!(kex::KeyExchangeAlgorithm) >>
server_host_key_algos: enum_list!(kex::HostKeyAlgorithm) >>
enc_algos_c2s: enum_list!(kex::EncryptionAlgorithm) >>
enc_algos_s2c: enum_list!(kex::EncryptionAlgorithm) >>
mac_algos_c2s: enum_list!(kex::MacAlgorithm) >>
mac_algos_s2c: enum_list!(kex::MacAlgorithm) >>
comp_algos_c2s: enum_list!(kex::CompressionAlgorithm) >>
comp_algos_s2c: enum_list!(kex::CompressionAlgorithm) >>
langs_c2s: parse_name_list >>
langs_s2c: parse_name_list >>
first_kex_packet_follows: parse_bool >>
reserved: u32!(Endianness::Big) >>
(kex::KeyExchangeInit {
cookie: cookie.to_vec(),
kex_algorithms: kex_algos,
server_host_key_algorithms: server_host_key_algos,
encryption_algorithms_client_to_server: enc_algos_c2s,
encryption_algorithms_server_to_client: enc_algos_s2c,
mac_algorithms_client_to_server: mac_algos_c2s,
mac_algorithms_server_to_client: mac_algos_s2c,
compression_algorithms_client_to_server: comp_algos_c2s,
compression_algorithms_server_to_client: comp_algos_s2c,
languages_client_to_server:
langs_c2s
.iter()
.filter(|s| !s.is_empty())
.map(|lang| kex::Language(lang.to_string()))
.collect(),
languages_server_to_client:
langs_c2s
.iter()
.filter(|s| !s.is_empty())
.map(|lang| kex::Language(lang.to_string()))
.collect(),
first_kex_packet_follows: first_kex_packet_follows
})
));
named!(parse_bool<&[u8], bool>,
map!(take!(1), |i: &[u8]| i[0] != 0)
);
named!(parse_string<&[u8], &[u8]>,
do_parse!(len: u32!(Endianness::Big) >>
data: take!(len) >>
(data)
)
);
named!(parse_name_list<&[u8], Vec<&str>>,
map_res!(parse_string, |s| str::from_utf8(s).map(|s| s.split(",").collect()))
);
pub fn parse_enum_list<T: FromStr>(i: &[u8]) -> IResult<&[u8], Vec<T>> {
match parse_name_list(i) {
IResult::Done(i, list) => IResult::Done(i,
list.iter()
.filter_map(|l| T::from_str(&l).ok())
.collect()
),
IResult::Error(e) => IResult::Error(e),
IResult::Incomplete(n) => IResult::Incomplete(n)
}
}

View file

@ -1,8 +1,5 @@
use std::io::{Read, Write, BufReader, BufRead};
use std::io;
use byteorder::{ReadBytesExt, BigEndian};
use packet::Packet;
pub fn send_identification<W: Write>(stream: &mut W) -> io::Result<usize> {
let id = format!("SSH-2.0-RedoxSSH_{}\r\n", env!("CARGO_PKG_VERSION"));
@ -22,24 +19,3 @@ pub fn read_identification<R: Read>(stream: &mut R) -> io::Result<String> {
Ok(id.trim_right().to_owned())
}
pub fn read_packet<R: Read>(stream: &mut R, mac_len: usize) -> io::Result<Packet> {
let packet_len = stream.read_u32::<BigEndian>()? as usize;
let padding_len = stream.read_u8()? as usize;
let payload_len = packet_len - padding_len - 1;
// TODO: Prevent packets that are too large
let mut payload = Vec::with_capacity(payload_len);
let mut padding = Vec::with_capacity(padding_len);
let mut mac = Vec::with_capacity(mac_len);
stream.take(payload_len as u64).read_to_end(&mut payload)?;
stream.take(padding_len as u64).read_to_end(&mut padding)?;
if mac_len > 0 {
stream.take(mac_len as u64).read_to_end(&mut mac);
}
Ok(Packet { payload: payload, mac: mac })
}

View file

@ -1,14 +1,26 @@
use std::net::TcpListener;
use std::io;
use std::io::{self, Write};
use session::{Session, SessionType};
use packet::Packet;
use protocol;
pub struct ServerConfig {
pub host: String
pub host: String,
pub port: u16,
}
impl Default for ServerConfig {
fn default() -> ServerConfig {
ServerConfig {
host: "0.0.0.0".to_owned(),
port: 22,
}
}
}
pub struct Server {
config: ServerConfig
config: ServerConfig,
}
impl Server {
@ -16,25 +28,56 @@ impl Server {
Server { config: config }
}
pub fn start(&self) -> io::Result<()> {
let listener = TcpListener::bind(&*self.config.host)
.expect(&*format!("Failed to bind to {}.", self.config.host));
let (mut stream, addr) = listener.accept()
.expect(&*format!("Failed to establish incomin connection."));
pub fn run(&self) -> io::Result<()> {
let listener = TcpListener::bind((&*self.config.host, self.config.port)).expect(&*format!(
"sshd: failed to bind to {}:{}",
self.config.host,
self.config.port
));
let (mut stream, addr) = listener.accept().expect(&*format!(
"sshd: failed to establish incoming connection"
));
println!("Connection established!");
println!("Incoming connection from {}", addr);
let id = protocol::read_identification(&mut stream)?;
println!("Incoming connection from {}", id);
println!("{} identifies as {}", addr, id);
protocol::send_identification(&mut stream)?;
let mut session = Session::new(SessionType::Server, stream.try_clone().unwrap());
loop {
let packet = protocol::read_packet(&mut stream, 0)?;
let message = packet.parse();
let packet = Packet::read_from(&mut stream).unwrap();
println!("packet: {:?}", packet);
session.process(&packet);
use rand::{OsRng, Rng};
let mut rng = OsRng::new()?;
println!("{:?}", message);
/*
if message.msg_type() == MessageType::KexInit {
xs let cookie: Vec<u8> = rng.gen_iter::<u8>().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(())
}

99
src/session.rs Normal file
View file

@ -0,0 +1,99 @@
use key_exchange::KeyExchange;
use message::MessageType;
use packet::{Packet, ReadPacketExt, WritePacketExt};
use std::io::Write;
#[derive(PartialEq)]
enum SessionState {
Initial,
KeyExchange,
Established
}
#[derive(PartialEq)]
pub enum SessionType {
Server,
Client
}
pub struct Session<'a, W: Write> {
stype: SessionType,
state: SessionState,
key_exchange: Option<&'a KeyExchange>,
stream: W
}
impl<'a, W: Write> Session<'a, W> {
pub fn new(stype: SessionType, stream: W) -> Session<'a, W> {
Session {
stype: stype,
state: SessionState::Initial,
key_exchange: None,
stream: stream
}
}
pub fn process(&mut self, packet: &Packet) {
match packet.msg_type() {
MessageType::KexInit => {
println!("Starting Key Exchange!");
self.kex_init(packet);
}
_ => {
println!("Unhandled packet: {:?}", packet);
}
}
}
pub fn kex_init(&mut self, packet: &Packet) {
use algorithm::*;
let mut reader = packet.reader();
reader.read_msg_type();
let cookie = reader.read_bytes(16);
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.unwrap().as_slice());
let srv_host_key_algo = negotiate(HOST_KEY, srv_host_key_algos.unwrap().as_slice());
let enc_algo = negotiate(ENCRYPTION, enc_algos_s2c.unwrap().as_slice());
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);
use rand::{OsRng, Rng};
let mut rng = OsRng::new().unwrap();
let cookie: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
let mut packet = Packet::new(MessageType::KexInit);
packet.with_writer(&|w| {
w.write_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]);
});
self.state = SessionState::KeyExchange;
packet.write_to(&mut self.stream);
}
}