diff --git a/async/Cargo.toml b/async/Cargo.toml index eb07034dfd65766a7a2797f7330c55394f936430..d4116423b2953dc688c1ef0eeb3389a088cd8329 100644 --- a/async/Cargo.toml +++ b/async/Cargo.toml @@ -22,6 +22,7 @@ argh = "0.1" # "net" for AsyncFd on unix tokio = { version = "1.19", features = ["sync", "net"] } # require alpha for https://github.com/rust-lang/futures-rs/pull/2571 +# need later than 0.3.21 futures = { git = "https://github.com/rust-lang/futures-rs", revision = "8b0f812f53ada0d0aeb74abc32be22ab9dafae05" } async-trait = "0.1" moro = "0.4" diff --git a/async/src/async_channel.rs b/async/src/async_channel.rs index 0adc4c773bb59817153980dc885d21337cd27da0..ad745f4743732f51549a8b52338bf199057e408a 100644 --- a/async/src/async_channel.rs +++ b/async/src/async_channel.rs @@ -1,3 +1,4 @@ +//! Presents SSH channels as async #[allow(unused_imports)] use log::{debug, error, info, log, trace, warn}; diff --git a/async/src/fdio.rs b/async/src/fdio.rs index 814b60c8ab7a7c2ef6a72f1f6556e0ca103bc839..f2572439cdbfe63ababa2ca2fbd78bb44163b4fd 100644 --- a/async/src/fdio.rs +++ b/async/src/fdio.rs @@ -1,3 +1,4 @@ +//! Helpers for async file descriptor IO #[allow(unused_imports)] use log::{debug, error, info, log, trace, warn}; diff --git a/async/src/pty.rs b/async/src/pty.rs index ec2f413a9aca2567d6eb6f6f7f440c140d6653e5..4876d3580b7f1abce077a0133aed6e394773cd57 100644 --- a/async/src/pty.rs +++ b/async/src/pty.rs @@ -1,3 +1,4 @@ +//! Code to manipulate PTYs #[allow(unused_imports)] use log::{debug, error, info, log, trace, warn}; diff --git a/docs/design.md b/docs/design.md index f5395462ac4e331329da5658f057581e8880c2dc..cba75bace2e4a4767eba48e93e715d39d855d1a6 100644 --- a/docs/design.md +++ b/docs/design.md @@ -69,5 +69,5 @@ between async and non-async traits, hiding that from the main code. Eventually ` ## Async -The majority of packet dispatch handling isn't async, it just returns Ready straight away. Becaues of that we just have a Tokio `Mutex` which occassionally +The majority of packet dispatch handling isn't async, it just returns Ready straight away. Because of that we just have a Tokio `Mutex` which occassionally holds the mutex across the `.await` boundary - it should seldom be contended. diff --git a/sshproto/src/async_behaviour.rs b/sshproto/src/async_behaviour.rs index e6ef03816f5c99fa15d2ebeebb7d0b9b28a3465f..558b98fecf2b75a694f7acaada836668f9b153fa 100644 --- a/sshproto/src/async_behaviour.rs +++ b/sshproto/src/async_behaviour.rs @@ -100,4 +100,5 @@ pub trait AsyncCliBehaviour: Sync+Send { // #[async_trait(?Send)] #[async_trait] pub trait AsyncServBehaviour: Sync+Send { + async fn hostkeys(&self) -> BhResult<&[&sign::SignKey]>; } diff --git a/sshproto/src/behaviour.rs b/sshproto/src/behaviour.rs index b96417700a888ef98419ebd114a9934dd03cfb3b..914148e16aa08491dfc3e2d02d054e78b2223e47 100644 --- a/sshproto/src/behaviour.rs +++ b/sshproto/src/behaviour.rs @@ -112,7 +112,6 @@ pub struct CliBehaviour<'a> { pub inner: &'a mut (dyn async_behaviour::AsyncCliBehaviour + Send), #[cfg(not(feature = "std"))] pub inner: &'a mut dyn block_behaviour::BlockCliBehaviour, - // pub phantom: core::marker::PhantomData<&'a ()>, } // wraps everything in AsyncCliBehaviour @@ -190,8 +189,18 @@ pub struct ServBehaviour<'a> { #[cfg(feature = "std")] impl<'a> ServBehaviour<'a> { + pub(crate) async fn hostkeys(&self) -> BhResult<&[&sign::SignKey]> { + self.inner.hostkeys().await + } +} +#[cfg(not(feature = "std"))] +impl<'a> ServBehaviour<'a> { + pub(crate) async fn hostkeys(&self) -> BhResult<&[&sign::SignKey]> { + self.inner.hostkeys() + } } + /// A stack-allocated string to store responses for usernames or passwords. // 100 bytes is an arbitrary size. pub type ResponseString = heapless::String<100>; diff --git a/sshproto/src/block_behaviour.rs b/sshproto/src/block_behaviour.rs index 16e2b0cb8b857e3c54d7a1ef7e73751702e7b76f..b63ab13b0517455a007fbec66bdad156ffc75df6 100644 --- a/sshproto/src/block_behaviour.rs +++ b/sshproto/src/block_behaviour.rs @@ -86,4 +86,5 @@ pub trait BlockCliBehaviour { } pub trait BlockServBehaviour { + fn hostkeys(&self) -> BhResult<&[&sign::SignKey]>; } diff --git a/sshproto/src/kex.rs b/sshproto/src/kex.rs index cee9f13e83ab6d8ea0fe4a1cd96c33ab12f0e6f6..ef3b8e444a9056e792aad1f744c2e4a59c1837f3 100644 --- a/sshproto/src/kex.rs +++ b/sshproto/src/kex.rs @@ -27,7 +27,6 @@ use behaviour::{CliBehaviour, Behaviour, ServBehaviour}; const MAX_SESSID: usize = 32; pub type SessId = heapless::Vec<u8, MAX_SESSID>; -// #[cfg(test)] use pretty_hex::PrettyHex; const EMPTY_LOCALNAMES: LocalNames = LocalNames(&[]); @@ -404,7 +403,6 @@ impl SharedSecret { fn make_kexdhinit(&self) -> Result<Packet> { let q_c = self.pubkey(); - trace!("pubkey ours {:?}", self.pubkey().hex_dump()); let q_c = BinString(q_c); Ok(packets::KexDHInit { q_c }.into()) } diff --git a/sshproto/src/packets.rs b/sshproto/src/packets.rs index 6d63ae427b5fbd899502c898181062264f0b20c2..586704dc052f840bfaa2d5cb0293141797c5d06c 100644 --- a/sshproto/src/packets.rs +++ b/sshproto/src/packets.rs @@ -1,6 +1,6 @@ //! SSH protocol packets. A [`Packet`] can be encoded/decoded to the //! SSH Binary Packet Protocol using [`crate::sshwire`]. -//! + use core::borrow::BorrowMut; use core::cell::Cell; use core::fmt; @@ -592,7 +592,7 @@ impl ParseContext { } } -// we have repeated `match` statements for the various packet types, use a macro +/// We have repeated `match` statements for the various packet types, use a macro macro_rules! messagetypes { ( $( ( $message_num:literal, $SpecificPacketVariant:ident, $SpecificPacketType:ty, $SSH_MESSAGE_NAME:ident ), )* diff --git a/sshproto/src/sshwire.rs b/sshproto/src/sshwire.rs index dbc0a744f69d7bb038e76d0c693718219b367025..1196d98333c6e5f549aee2f69e6e4c15255fd93b 100644 --- a/sshproto/src/sshwire.rs +++ b/sshproto/src/sshwire.rs @@ -1,3 +1,7 @@ +//! SSH wire format reading/writing. +//! Used in conjunction with [`sshwire_derive`] and the [`packet`](crate::packets) format +//! definitions. + #[allow(unused_imports)] use { crate::error::{Error, Result, TrapBug}, @@ -15,7 +19,7 @@ use ascii::{AsAsciiStr, AsciiChar, AsciiStr}; use crate::*; use packets::{Packet, ParseContext}; - +/// A generic destination for serializing, used similarly to `serde::Serializer` pub trait SSHSink { fn push(&mut self, v: &[u8]) -> WireResult<()>; fn ctx(&self) -> Option<&ParseContext> { @@ -23,12 +27,14 @@ pub trait SSHSink { } } +/// A generic source for a packet, used similarly to `serde::Deserializer` pub trait SSHSource<'de> { fn take(&mut self, len: usize) -> WireResult<&'de [u8]>; fn pos(&self) -> usize; fn ctx(&self) -> &ParseContext; } +/// Encodes the type in SSH wire format pub trait SSHEncode { fn enc<S>(&self, s: &mut S) -> WireResult<()> where S: SSHSink; } @@ -117,6 +123,7 @@ where Ok(s.pos) } +/// Hashes the SSH wire format representation of `value`, with a `u32` length prefix. pub fn hash_ser_length<T>(hash_ctx: &mut impl digest::DynDigest, value: &T) -> Result<()> where @@ -127,6 +134,7 @@ where hash_ser(hash_ctx, None, value) } +/// Hashes the SSH wire format representation of `value` pub fn hash_ser<T>(hash_ctx: &mut impl digest::DynDigest, parse_ctx: Option<&ParseContext>, value: &T) -> Result<()> @@ -331,7 +339,7 @@ impl<'de> SSHDecode<'de> for TextString<'de> { } } -/// A wrapper for a u32 prefixed data structure `B`, such as a public key blob +/// A wrapper for a `u32` length prefixed data structure `B`, such as a public key blob pub struct Blob<B>(pub B); impl<B> AsRef<B> for Blob<B> { @@ -372,6 +380,7 @@ impl<'de, B: SSHDecode<'de>> SSHDecode<'de> for Blob<B> { let pos1 = s.pos(); let inner = SSHDecode::dec(s)?; let pos2 = s.pos(); + // Sanity check the length matched if (pos2 - pos1) == len as usize { Ok(Blob(inner)) } else { diff --git a/sshwire_derive/src/lib.rs b/sshwire_derive/src/lib.rs index 73d72491df67e6d8600ad4de8b680a9bc96887d4..4b354ff6b27c4a3074da9ebc93485bf3129dbf93 100644 --- a/sshwire_derive/src/lib.rs +++ b/sshwire_derive/src/lib.rs @@ -1,3 +1,5 @@ +//! Used in conjunction with `sshwire.rs` and `packets.rs` + use std::collections::HashSet; use proc_macro::Delimiter;