diff --git a/Cargo.toml b/Cargo.toml index fe12dd1..07bb430 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ crate_type = [ "lib", "cdylib", "staticlib" ] # please keep these in alphabetical order arc-swap = { version = "1.6" } +arrayref = { version = "0.3" } async-channel = { version = "1.8" } # base85 repo has no tags, fix on a commit. v1.1.1 points to older, wrong version base85 = { git = "https://gitlab.com/darkwyrm/base85", rev = "d98efbfd171dd9ba48e30a5c88f94db92fc7b3c6" } diff --git a/src/connection/handshake/dirsync.rs b/src/connection/handshake/dirsync.rs index 780f468..9c0a299 100644 --- a/src/connection/handshake/dirsync.rs +++ b/src/connection/handshake/dirsync.rs @@ -17,6 +17,8 @@ use crate::{ sym::{CipherKind, Secret}, }, }; + +use ::arrayref::array_mut_ref; use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec}; type Nonce = [u8; 16]; @@ -30,6 +32,24 @@ pub enum DirSync { Resp(Resp), } +impl DirSync { + /// actual length of the dirsync handshake data + pub fn len(&self) -> usize { + match self { + DirSync::Req(req) => req.len(), + DirSync::Resp(resp) => resp.len(), + } + } + /// Serialize into raw bytes + /// NOTE: assumes that there is exactly asa much buffer as needed + pub fn serialize(&self, out: &mut [u8]) { + match self { + DirSync::Req(req) => req.serialize(out), + DirSync::Resp(resp) => resp.serialize(out), + } + } +} + /// Client request of a directory synchronized handshake #[derive(Debug, Clone)] pub struct Req { @@ -50,6 +70,20 @@ impl Req { pub fn set_data(&mut self, data: ReqData) { self.data = ReqInner::Data(data); } + /// actual length of the directory synchronized request + pub fn len(&self) -> usize { + KeyID::len() + + KeyExchange::len() + + CipherKind::len() + + self.exchange_key.len() + + self.data.len() + } + /// Serialize into raw bytes + /// NOTE: assumes that there is exactly asa much buffer as needed + pub fn serialize(&self, out: &mut [u8]) { + //assert!(out.len() > , ": not enough buffer to serialize"); + todo!() + } } impl super::HandshakeParsing for Req { @@ -76,7 +110,7 @@ impl super::HandshakeParsing for Req { let mut vec = VecDeque::with_capacity(raw.len() - (4 + len)); vec.extend(raw[(4 + len)..].iter().copied()); let _ = vec.make_contiguous(); - let data = ReqInner::Ciphertext(vec); + let data = ReqInner::CipherText(vec); Ok(HandshakeData::DirSync(DirSync::Req(Self { key_id, exchange, @@ -91,17 +125,25 @@ impl super::HandshakeParsing for Req { #[derive(Debug, Clone)] pub enum ReqInner { /// Client data, still in ciphertext - Ciphertext(VecDeque), + CipherText(VecDeque), /// Client data, decrypted but unprocessed - Cleartext(VecDeque), + ClearText(VecDeque), /// Parsed client data Data(ReqData), } impl ReqInner { + /// The length of the data + pub fn len(&self) -> usize { + match self { + ReqInner::CipherText(c) => c.len(), + ReqInner::ClearText(c) => c.len(), + ReqInner::Data(d) => d.len(), + } + } /// Get the ciptertext, or panic pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque { match self { - ReqInner::Ciphertext(data) => data, + ReqInner::CipherText(data) => data, _ => panic!(), } } @@ -109,13 +151,13 @@ impl ReqInner { pub fn mark_as_cleartext(&mut self) { let mut newdata: VecDeque; match self { - ReqInner::Ciphertext(data) => { + ReqInner::CipherText(data) => { newdata = VecDeque::new(); ::core::mem::swap(&mut newdata, data); } _ => return, } - *self = ReqInner::Cleartext(newdata); + *self = ReqInner::ClearText(newdata); } } @@ -195,6 +237,10 @@ pub struct ReqData { pub auth: AuthInfo, } impl ReqData { + /// actual length of the request data + pub fn len(&self) -> usize { + self.nonce.len() + KeyID::len() + ID::len() + self.auth.len() + } /// Minimum byte length of the request data pub const MIN_PKT_LEN: usize = 16 + KeyID::len() + ID::len() + AuthInfo::MIN_PKT_LEN; @@ -202,7 +248,7 @@ impl ReqData { pub fn deserialize(raw: &ReqInner) -> Result { let raw = match raw { // raw is VecDeque, assume everything is on the first slice - ReqInner::Cleartext(raw) => raw.as_slices().0, + ReqInner::ClearText(raw) => raw.as_slices().0, _ => return Err(Error::Parsing), }; if raw.len() < Self::MIN_PKT_LEN { @@ -249,6 +295,23 @@ impl super::HandshakeParsing for Resp { } } +impl Resp { + /// Total length of the response handshake + pub fn len(&self) -> usize { + KeyID::len() + self.enc.len() + } + /// Serialize into raw bytes + /// NOTE: assumes that there is exactly asa much buffer as needed + pub fn serialize(&self, out: &mut [u8]) { + assert!( + out.len() == KeyID::len() + self.enc.len(), + "DirSync Resp: not enough buffer to serialize" + ); + self.client_key_id.serialize(array_mut_ref![out, 0, 2]); + out[2..].copy_from_slice(&self.enc[..]); + } +} + /// Decrypted response data #[derive(Debug, Clone)] pub struct RespData { @@ -269,6 +332,7 @@ impl RespData { Self::NONCE_LEN + ID::len() + ID::len() + 32 } /// Serialize the data into a buffer + /// NOTE: assumes that there is exactly asa much buffer as needed pub fn serialize(&self, out: &mut [u8]) { assert!(out.len() == Self::len(), "wrong buffer size"); let mut start = 0; diff --git a/src/connection/handshake/mod.rs b/src/connection/handshake/mod.rs index ae8bf85..763191d 100644 --- a/src/connection/handshake/mod.rs +++ b/src/connection/handshake/mod.rs @@ -36,6 +36,22 @@ pub enum HandshakeData { DirSync(dirsync::DirSync), } +impl HandshakeData { + /// actual length of the handshake data + pub fn len(&self) -> usize { + match self { + HandshakeData::DirSync(d) => d.len(), + } + } + /// Serialize into raw bytes + /// NOTE: assumes that there is exactly asa much buffer as needed + pub fn serialize(&self, out: &mut [u8]) { + match self { + HandshakeData::DirSync(d) => d.serialize(out), + } + } +} + /// Kind of handshake #[derive(::num_derive::FromPrimitive, Debug, Clone, Copy)] #[repr(u8)] @@ -66,6 +82,17 @@ pub struct Handshake { } impl Handshake { + /// Build new handshake from the data + pub fn new(data: HandshakeData) -> Self { + Handshake { + fenrir_version: ProtocolVersion::V0, + data, + } + } + /// return the total length of the handshake + pub fn len(&self) -> usize { + ProtocolVersion::len() + self.data.len() + } const MIN_PKT_LEN: usize = 8; /// Parse the packet and return the parsed handshake pub fn deserialize(raw: &[u8]) -> Result { @@ -89,6 +116,14 @@ impl Handshake { data, }) } + /// serialize the handshake into bytes + /// NOTE: assumes that there is exactly asa much buffer as needed + pub fn serialize(&self, out: &mut [u8]) { + assert!(out.len() > 1, "Handshake: not enough buffer to serialize"); + self.fenrir_version.serialize(&mut out[0]); + self.data.serialize(&mut out[1..]); + } + pub(crate) fn work(&self, keys: &[HandshakeKey]) -> Result<(), Error> { todo!() } diff --git a/src/connection/mod.rs b/src/connection/mod.rs index 52e8828..22c5993 100644 --- a/src/connection/mod.rs +++ b/src/connection/mod.rs @@ -7,7 +7,7 @@ use ::std::vec::Vec; pub use handshake::Handshake; pub use packet::ConnectionID as ID; -pub use packet::Packet; +pub use packet::{Packet, PacketData}; /// Version of the fenrir protocol in use #[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)] @@ -16,3 +16,13 @@ pub enum ProtocolVersion { /// First Fenrir Protocol Version V0 = 0, } +impl ProtocolVersion { + /// actual length of the protocol version field + pub const fn len() -> usize { + 1 + } + /// Serialize into raw bytes + pub fn serialize(&self, out: &mut u8) { + *out = *self as u8; + } +} diff --git a/src/connection/packet.rs b/src/connection/packet.rs index 7fef6b2..d8c366e 100644 --- a/src/connection/packet.rs +++ b/src/connection/packet.rs @@ -13,6 +13,10 @@ pub enum ConnectionID { } impl ConnectionID { + /// Set the conenction id to handshake + pub fn new_handshake() -> Self { + Self::Handshake + } /// New random service ID pub fn new_rand(rand: &::ring::rand::SystemRandom) -> Self { use ::ring::rand::SecureRandom; @@ -67,9 +71,52 @@ impl From<[u8; 8]> for ConnectionID { } } +/// Enumerate the possible data in a fenrir packet +#[derive(Debug, Clone)] +pub enum PacketData { + /// A parsed handshake packet + Handshake(super::Handshake), +} + +impl PacketData { + /// total length of the data in bytes + pub fn len(&self) -> usize { + match self { + PacketData::Handshake(h) => h.len(), + } + } + /// serialize data into bytes + /// NOTE: assumes that there is exactly asa much buffer as needed + pub fn serialize(&self, out: &mut [u8]) { + assert!(self.len() == out.len(), "PacketData: wrong buffer length"); + match self { + PacketData::Handshake(h) => h.serialize(out), + } + } +} + /// Fenrir packet structure -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub struct Packet { /// Id of the Fenrir connection. - id: ConnectionID, + pub id: ConnectionID, + /// actual data inside the packet + pub data: PacketData, +} + +impl Packet { + /// get the total length of the packet + pub fn len(&self) -> usize { + ConnectionID::len() + self.data.len() + } + /// serialize packet into buffer + /// NOTE: assumes that there is exactly asa much buffer as needed + pub fn serialize(&self, out: &mut [u8]) { + assert!( + out.len() > ConnectionID::len(), + "Packet: not enough buffer to serialize" + ); + self.id.serialize(&mut out[0..ConnectionID::len()]); + self.data.serialize(&mut out[ConnectionID::len()..]); + } } diff --git a/src/enc/asym.rs b/src/enc/asym.rs index f7a79fa..c705a5f 100644 --- a/src/enc/asym.rs +++ b/src/enc/asym.rs @@ -15,6 +15,10 @@ impl KeyID { pub const fn len() -> usize { 2 } + /// Serialize into raw bytes + pub fn serialize(&self, out: &mut [u8; KeyID::len()]) { + out.copy_from_slice(&self.0.to_le_bytes()); + } } /// Kind of key used in the handshake @@ -40,6 +44,12 @@ pub enum KeyExchange { /// X25519 Public key X25519DiffieHellman = 0, } +impl KeyExchange { + /// The serialize length of the field + pub fn len() -> usize { + 1 + } +} /// Kind of key in the handshake #[derive(Clone)] @@ -96,12 +106,18 @@ pub enum ExchangePubKey { } impl ExchangePubKey { + /// length of the public key used for key exchange + pub fn len(&self) -> usize { + match self { + ExchangePubKey::X25519(_) => 32, + } + } /// Load public key used for key exchange from it raw bytes /// The riesult is "unparsed" since we don't verify /// the actual key pub fn from_slice(raw: &[u8]) -> Result<(Self, usize), Error> { // FIXME: get *real* minimum key size - const MIN_KEY_SIZE: usize = 8; + const MIN_KEY_SIZE: usize = 32; if raw.len() < 1 + MIN_KEY_SIZE { return Err(Error::NotEnoughData); } diff --git a/src/enc/sym.rs b/src/enc/sym.rs index f54cd0b..4e51f5e 100644 --- a/src/enc/sym.rs +++ b/src/enc/sym.rs @@ -54,6 +54,10 @@ pub enum CipherKind { } impl CipherKind { + /// length of the serialized id for the cipher kind field + pub fn len() -> usize { + 1 + } /// required length of the nonce pub fn nonce_len(&self) -> usize { // TODO: how the hell do I take this from ::chacha20poly1305? diff --git a/src/lib.rs b/src/lib.rs index 8961fc9..d8a6447 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -333,10 +333,7 @@ impl Fenrir { fn stop_sync(&mut self) { let _ = self.stop_working.send(true); let mut toempty_sockets = self.sockets.rm_all(); - let task = ::tokio::task::spawn(Self::stop_sockets(toempty_sockets)); - //let mut toempty_socket = Vec::new(); - //::std::mem::swap(&mut self.sockets, &mut toempty_socket); - //let task = ::tokio::task::spawn(Self::stop_sockets(toempty_socket)); + let task = ::tokio::task::spawn(toempty_sockets.stop_all()); let _ = ::futures::executor::block_on(task); self.dnssec = None; } @@ -345,15 +342,10 @@ impl Fenrir { pub async fn stop(&mut self) { let _ = self.stop_working.send(true); let mut toempty_sockets = self.sockets.rm_all(); - Self::stop_sockets(toempty_sockets).await; + toempty_sockets.stop_all().await; self.dnssec = None; } - /// actually do the work of stopping resolvers and listeners - async fn stop_sockets(sockets: SocketList) { - sockets.stop_all().await; - } - /// Enable some common socket options. This is just the unsafe part fn enable_sock_opt( fd: ::std::os::fd::RawFd, @@ -611,6 +603,17 @@ impl Fenrir { client_key_id: req_data.client_key_id, enc: data.get_raw(), }; + let resp_handshake = Handshake::new( + HandshakeData::DirSync(DirSync::Resp(resp)), + ); + use connection::{Packet, PacketData, ID}; + let packet = Packet { + id: ID::new_handshake(), + data: PacketData::Handshake(resp_handshake), + }; + let mut raw_out = + Vec::::with_capacity(packet.len()); + packet.serialize(&mut raw_out); todo!() } _ => {