DirSync response serialization

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-02-25 15:36:14 +01:00
parent 59394959bd
commit 4157c207a3
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
8 changed files with 201 additions and 21 deletions

View File

@ -27,6 +27,7 @@ crate_type = [ "lib", "cdylib", "staticlib" ]
# please keep these in alphabetical order # please keep these in alphabetical order
arc-swap = { version = "1.6" } arc-swap = { version = "1.6" }
arrayref = { version = "0.3" }
async-channel = { version = "1.8" } async-channel = { version = "1.8" }
# base85 repo has no tags, fix on a commit. v1.1.1 points to older, wrong version # 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" } base85 = { git = "https://gitlab.com/darkwyrm/base85", rev = "d98efbfd171dd9ba48e30a5c88f94db92fc7b3c6" }

View File

@ -17,6 +17,8 @@ use crate::{
sym::{CipherKind, Secret}, sym::{CipherKind, Secret},
}, },
}; };
use ::arrayref::array_mut_ref;
use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec}; use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec};
type Nonce = [u8; 16]; type Nonce = [u8; 16];
@ -30,6 +32,24 @@ pub enum DirSync {
Resp(Resp), 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 /// Client request of a directory synchronized handshake
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Req { pub struct Req {
@ -50,6 +70,20 @@ impl Req {
pub fn set_data(&mut self, data: ReqData) { pub fn set_data(&mut self, data: ReqData) {
self.data = ReqInner::Data(data); 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 { impl super::HandshakeParsing for Req {
@ -76,7 +110,7 @@ impl super::HandshakeParsing for Req {
let mut vec = VecDeque::with_capacity(raw.len() - (4 + len)); let mut vec = VecDeque::with_capacity(raw.len() - (4 + len));
vec.extend(raw[(4 + len)..].iter().copied()); vec.extend(raw[(4 + len)..].iter().copied());
let _ = vec.make_contiguous(); let _ = vec.make_contiguous();
let data = ReqInner::Ciphertext(vec); let data = ReqInner::CipherText(vec);
Ok(HandshakeData::DirSync(DirSync::Req(Self { Ok(HandshakeData::DirSync(DirSync::Req(Self {
key_id, key_id,
exchange, exchange,
@ -91,17 +125,25 @@ impl super::HandshakeParsing for Req {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ReqInner { pub enum ReqInner {
/// Client data, still in ciphertext /// Client data, still in ciphertext
Ciphertext(VecDeque<u8>), CipherText(VecDeque<u8>),
/// Client data, decrypted but unprocessed /// Client data, decrypted but unprocessed
Cleartext(VecDeque<u8>), ClearText(VecDeque<u8>),
/// Parsed client data /// Parsed client data
Data(ReqData), Data(ReqData),
} }
impl ReqInner { 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 /// Get the ciptertext, or panic
pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque<u8> { pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque<u8> {
match self { match self {
ReqInner::Ciphertext(data) => data, ReqInner::CipherText(data) => data,
_ => panic!(), _ => panic!(),
} }
} }
@ -109,13 +151,13 @@ impl ReqInner {
pub fn mark_as_cleartext(&mut self) { pub fn mark_as_cleartext(&mut self) {
let mut newdata: VecDeque<u8>; let mut newdata: VecDeque<u8>;
match self { match self {
ReqInner::Ciphertext(data) => { ReqInner::CipherText(data) => {
newdata = VecDeque::new(); newdata = VecDeque::new();
::core::mem::swap(&mut newdata, data); ::core::mem::swap(&mut newdata, data);
} }
_ => return, _ => return,
} }
*self = ReqInner::Cleartext(newdata); *self = ReqInner::ClearText(newdata);
} }
} }
@ -195,6 +237,10 @@ pub struct ReqData {
pub auth: AuthInfo, pub auth: AuthInfo,
} }
impl ReqData { 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 /// Minimum byte length of the request data
pub const MIN_PKT_LEN: usize = pub const MIN_PKT_LEN: usize =
16 + KeyID::len() + ID::len() + AuthInfo::MIN_PKT_LEN; 16 + KeyID::len() + ID::len() + AuthInfo::MIN_PKT_LEN;
@ -202,7 +248,7 @@ impl ReqData {
pub fn deserialize(raw: &ReqInner) -> Result<Self, Error> { pub fn deserialize(raw: &ReqInner) -> Result<Self, Error> {
let raw = match raw { let raw = match raw {
// raw is VecDeque, assume everything is on the first slice // 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), _ => return Err(Error::Parsing),
}; };
if raw.len() < Self::MIN_PKT_LEN { 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 /// Decrypted response data
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RespData { pub struct RespData {
@ -269,6 +332,7 @@ impl RespData {
Self::NONCE_LEN + ID::len() + ID::len() + 32 Self::NONCE_LEN + ID::len() + ID::len() + 32
} }
/// Serialize the data into a buffer /// Serialize the data into a buffer
/// NOTE: assumes that there is exactly asa much buffer as needed
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(&self, out: &mut [u8]) {
assert!(out.len() == Self::len(), "wrong buffer size"); assert!(out.len() == Self::len(), "wrong buffer size");
let mut start = 0; let mut start = 0;

View File

@ -36,6 +36,22 @@ pub enum HandshakeData {
DirSync(dirsync::DirSync), 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 /// Kind of handshake
#[derive(::num_derive::FromPrimitive, Debug, Clone, Copy)] #[derive(::num_derive::FromPrimitive, Debug, Clone, Copy)]
#[repr(u8)] #[repr(u8)]
@ -66,6 +82,17 @@ pub struct Handshake {
} }
impl 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; const MIN_PKT_LEN: usize = 8;
/// Parse the packet and return the parsed handshake /// Parse the packet and return the parsed handshake
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> { pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
@ -89,6 +116,14 @@ impl Handshake {
data, 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> { pub(crate) fn work(&self, keys: &[HandshakeKey]) -> Result<(), Error> {
todo!() todo!()
} }

View File

@ -7,7 +7,7 @@ use ::std::vec::Vec;
pub use handshake::Handshake; pub use handshake::Handshake;
pub use packet::ConnectionID as ID; pub use packet::ConnectionID as ID;
pub use packet::Packet; pub use packet::{Packet, PacketData};
/// Version of the fenrir protocol in use /// Version of the fenrir protocol in use
#[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)] #[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)]
@ -16,3 +16,13 @@ pub enum ProtocolVersion {
/// First Fenrir Protocol Version /// First Fenrir Protocol Version
V0 = 0, 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;
}
}

View File

@ -13,6 +13,10 @@ pub enum ConnectionID {
} }
impl ConnectionID { impl ConnectionID {
/// Set the conenction id to handshake
pub fn new_handshake() -> Self {
Self::Handshake
}
/// New random service ID /// New random service ID
pub fn new_rand(rand: &::ring::rand::SystemRandom) -> Self { pub fn new_rand(rand: &::ring::rand::SystemRandom) -> Self {
use ::ring::rand::SecureRandom; 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 /// Fenrir packet structure
#[derive(Debug, Copy, Clone)] #[derive(Debug, Clone)]
pub struct Packet { pub struct Packet {
/// Id of the Fenrir connection. /// 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()..]);
}
} }

View File

@ -15,6 +15,10 @@ impl KeyID {
pub const fn len() -> usize { pub const fn len() -> usize {
2 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 /// Kind of key used in the handshake
@ -40,6 +44,12 @@ pub enum KeyExchange {
/// X25519 Public key /// X25519 Public key
X25519DiffieHellman = 0, X25519DiffieHellman = 0,
} }
impl KeyExchange {
/// The serialize length of the field
pub fn len() -> usize {
1
}
}
/// Kind of key in the handshake /// Kind of key in the handshake
#[derive(Clone)] #[derive(Clone)]
@ -96,12 +106,18 @@ pub enum ExchangePubKey {
} }
impl 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 /// Load public key used for key exchange from it raw bytes
/// The riesult is "unparsed" since we don't verify /// The riesult is "unparsed" since we don't verify
/// the actual key /// the actual key
pub fn from_slice(raw: &[u8]) -> Result<(Self, usize), Error> { pub fn from_slice(raw: &[u8]) -> Result<(Self, usize), Error> {
// FIXME: get *real* minimum key size // 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 { if raw.len() < 1 + MIN_KEY_SIZE {
return Err(Error::NotEnoughData); return Err(Error::NotEnoughData);
} }

View File

@ -54,6 +54,10 @@ pub enum CipherKind {
} }
impl CipherKind { impl CipherKind {
/// length of the serialized id for the cipher kind field
pub fn len() -> usize {
1
}
/// required length of the nonce /// required length of the nonce
pub fn nonce_len(&self) -> usize { pub fn nonce_len(&self) -> usize {
// TODO: how the hell do I take this from ::chacha20poly1305? // TODO: how the hell do I take this from ::chacha20poly1305?

View File

@ -333,10 +333,7 @@ impl Fenrir {
fn stop_sync(&mut self) { fn stop_sync(&mut self) {
let _ = self.stop_working.send(true); let _ = self.stop_working.send(true);
let mut toempty_sockets = self.sockets.rm_all(); let mut toempty_sockets = self.sockets.rm_all();
let task = ::tokio::task::spawn(Self::stop_sockets(toempty_sockets)); let task = ::tokio::task::spawn(toempty_sockets.stop_all());
//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 _ = ::futures::executor::block_on(task); let _ = ::futures::executor::block_on(task);
self.dnssec = None; self.dnssec = None;
} }
@ -345,15 +342,10 @@ impl Fenrir {
pub async fn stop(&mut self) { pub async fn stop(&mut self) {
let _ = self.stop_working.send(true); let _ = self.stop_working.send(true);
let mut toempty_sockets = self.sockets.rm_all(); let mut toempty_sockets = self.sockets.rm_all();
Self::stop_sockets(toempty_sockets).await; toempty_sockets.stop_all().await;
self.dnssec = None; 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 /// Enable some common socket options. This is just the unsafe part
fn enable_sock_opt( fn enable_sock_opt(
fd: ::std::os::fd::RawFd, fd: ::std::os::fd::RawFd,
@ -611,6 +603,17 @@ impl Fenrir {
client_key_id: req_data.client_key_id, client_key_id: req_data.client_key_id,
enc: data.get_raw(), 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::<u8>::with_capacity(packet.len());
packet.serialize(&mut raw_out);
todo!() todo!()
} }
_ => { _ => {