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
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" }

View File

@ -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<u8>),
CipherText(VecDeque<u8>),
/// Client data, decrypted but unprocessed
Cleartext(VecDeque<u8>),
ClearText(VecDeque<u8>),
/// 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<u8> {
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<u8>;
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<Self, Error> {
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;

View File

@ -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<Self, Error> {
@ -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!()
}

View File

@ -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;
}
}

View File

@ -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()..]);
}
}

View File

@ -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);
}

View File

@ -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?

View File

@ -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::<u8>::with_capacity(packet.len());
packet.serialize(&mut raw_out);
todo!()
}
_ => {