//! Handhsake handling pub mod dirsync; use ::num_traits::FromPrimitive; use crate::{ connection::{self, ProtocolVersion}, enc::sym::{HeadLen, TagLen}, }; /// Handshake errors #[derive(::thiserror::Error, Debug, Copy, Clone)] pub enum Error { /// Error while parsing the handshake packet /// TODO: more detailed parsing errors #[error("not an handshake packet")] Parsing, /// No such Key ID #[error("unknown key id")] UnknownKeyID, /// Key error #[error("key: {0:?}")] Key(#[from] crate::enc::Error), /// Not enough data #[error("not enough data")] NotEnoughData, } pub(crate) struct HandshakeServer { pub id: crate::enc::asym::KeyID, pub key: crate::enc::asym::PrivKey, } #[derive(Clone)] pub(crate) struct HandshakeClient { pub id: crate::enc::asym::KeyID, pub key: crate::enc::asym::PrivKey, pub hkdf: crate::enc::hkdf::HkdfSha3, pub cipher: crate::enc::sym::CipherKind, } /// Parsed handshake #[derive(Debug, Clone)] pub enum HandshakeData { /// Directory synchronized handhsake 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, head_len: HeadLen, tag_len: TagLen, out: &mut [u8], ) { match self { HandshakeData::DirSync(d) => d.serialize(head_len, tag_len, out), } } } /// Kind of handshake #[derive(::num_derive::FromPrimitive, Debug, Clone, Copy)] #[repr(u8)] pub enum Kind { /// 1-RTT, Directory synchronized handshake /// Request DirSyncReq = 0, /// 1-RTT, Directory synchronized handshake /// Response DirSyncResp, /* /// 2-RTT, Stateful connection Stateful, ... /// 3 RTT, Stateless connection Stateless, .... */ } /// Parsed handshake #[derive(Debug, Clone)] pub struct Handshake { /// Fenrir Protocol version pub fenrir_version: ProtocolVersion, /// enum for the parsed data pub data: HandshakeData, } 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 { if raw.len() < Self::MIN_PKT_LEN { return Err(Error::NotEnoughData); } let fenrir_version = match ProtocolVersion::from_u8(raw[0]) { Some(fenrir_version) => fenrir_version, None => return Err(Error::Parsing), }; let handshake_kind = match Kind::from_u8(raw[1]) { Some(handshake_kind) => handshake_kind, None => return Err(Error::Parsing), }; let data = match handshake_kind { Kind::DirSyncReq => dirsync::Req::deserialize(&raw[2..])?, Kind::DirSyncResp => dirsync::Resp::deserialize(&raw[2..])?, }; Ok(Self { fenrir_version, data, }) } /// serialize the handshake into bytes /// NOTE: assumes that there is exactly as much buffer as needed pub fn serialize( &self, head_len: HeadLen, tag_len: TagLen, out: &mut [u8], ) { assert!(out.len() > 1, "Handshake: not enough buffer to serialize"); self.fenrir_version.serialize(&mut out[0]); self.data.serialize(head_len, tag_len, &mut out[1..]); } pub(crate) fn work(&self, keys: &[HandshakeServer]) -> Result<(), Error> { todo!() } } trait HandshakeParsing { fn deserialize(raw: &[u8]) -> Result; }