Commit 587f8101 authored by Thomas Gatzweiler's avatar Thomas Gatzweiler
Browse files

Initial commit

parents
/target/
**/*.rs.bk
[root]
name = "redox-ssh"
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)",
"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)",
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
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"
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 = "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"
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)",
]
[[package]]
name = "scopeguard"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "untrusted"
version = "0.5.0"
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 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"
[package]
name = "redox-ssh"
version = "0.1.0"
authors = ["Thomas Gatzweiler <mail@thomasgatzweiler.com>"]
[lib]
name = "ssh"
path = "src/lib.rs"
[[bin]]
name = "ssh"
path = "src/bin/ssh.rs"
[[bin]]
name = "sshd"
path = "src/bin/sshd.rs"
[dependencies]
byteorder = "^1.0"
log = "^0.3"
nom = "^3.1"
ring = "^0.11.0"
[target.'cfg(target_os = "redox")'.dependencies]
redox_syscall = "0.1"
This diff is collapsed.
# redox-ssh
A ssh client and server written entirely on rust, primarily targeted at (http://redox-os.org).
## Features
Currently implemented features, ordered by priority:
[ ] SSH Server
[ ] SSH Client
[ ] Encryption
[ ] Public key authentication
[ ] Port forwarding
[ ] SCP File Transfers
## License
Redox SSH
Copyright (C) 2017 Thomas Gatzweiler
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
pub enum AuthMethod {
PublicKey, Password, HostBased, None
}
pub struct AuthRequest {
user: String,
service: String,
method: AuthMethod
}
pub fn main() {
println!("Hello from ssh!");
}
extern crate ssh;
use std::env;
use ssh::{Server, ServerConfig};
pub fn main() {
let config = ServerConfig { host: String::from("0.0.0.0:22222") };
let server = Server::with_config(config);
server.start();
}
extern crate byteorder;
#[macro_use]
extern crate log;
#[macro_use]
extern crate nom;
pub mod protocol;
pub mod server;
pub mod packet;
pub mod parser;
pub mod message;
pub use self::server::{Server, ServerConfig};
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);
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
}
use std::fmt;
use std::str;
use parser;
pub struct Packet {
pub payload: Vec<u8>,
pub mac: Vec<u8>
}
impl Packet {
pub fn parse(&self) {
let result = parser::parse_packet(&self.payload.as_slice());
println!("{:?}", result);
}
}
impl fmt::Debug for Packet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Packet({} bytes)", self.payload.len())
}
}
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)
}
}
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"));
stream.write(id.as_bytes())
}
pub fn read_identification<R: Read>(stream: &mut R) -> io::Result<String> {
// The identification string has a maximum length of 255 bytes
// TODO: Make sure that we stop reading when the client sends more than that
let mut reader = BufReader::new(stream);
let mut id = String::new();
while !id.starts_with("SSH-") {
reader.read_line(&mut id)?;
}
Ok(id.trim_right().to_owned())
}