DirSync::Resp work

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-05-17 10:26:39 +02:00
parent 7a129dbe90
commit a5f18ac533
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
5 changed files with 259 additions and 140 deletions

View File

@ -11,15 +11,16 @@
use super::{Error, HandshakeData}; use super::{Error, HandshakeData};
use crate::{ use crate::{
auth, auth,
connection::ID, connection::{ProtocolVersion, ID},
enc::{ enc::{
asym::{ExchangePubKey, KeyExchange, KeyID}, asym::{ExchangePubKey, KeyExchange, KeyID},
sym::{CipherKind, Secret}, sym::{CipherKind, HeadLen, Secret, TagLen},
}, },
}; };
use ::arrayref::array_mut_ref; use ::arrayref::array_mut_ref;
use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec}; use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec};
use trust_dns_client::rr::rdata::key::Protocol;
type Nonce = [u8; 16]; type Nonce = [u8; 16];
@ -42,10 +43,15 @@ impl DirSync {
} }
/// Serialize into raw bytes /// Serialize into raw bytes
/// NOTE: assumes that there is exactly asa much buffer as needed /// NOTE: assumes that there is exactly asa much buffer as needed
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
out: &mut [u8],
) {
match self { match self {
DirSync::Req(req) => req.serialize(out), DirSync::Req(req) => req.serialize(head_len, tag_len, out),
DirSync::Resp(resp) => resp.serialize(out), DirSync::Resp(resp) => resp.serialize(head_len, tag_len, out),
} }
} }
} }
@ -67,9 +73,21 @@ pub struct Req {
} }
impl Req { impl Req {
/// Set the cleartext data after it was parsed /// return the offset of the encrypted data
pub fn set_data(&mut self, data: ReqData) { /// NOTE: starts from the beginning of the fenrir packet
self.data = ReqInner::Data(data); pub fn encrypted_offset(&self) -> usize {
ProtocolVersion::len()
+ KeyID::len()
+ KeyExchange::len()
+ CipherKind::len()
+ self.exchange_key.len()
}
/// return the total length of the cleartext data
pub fn encrypted_length(&self) -> usize {
match &self.data {
ReqInner::ClearText(data) => data.len(),
_ => 0,
}
} }
/// actual length of the directory synchronized request /// actual length of the directory synchronized request
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
@ -81,7 +99,12 @@ impl Req {
} }
/// Serialize into raw bytes /// Serialize into raw bytes
/// NOTE: assumes that there is exactly as much buffer as needed /// NOTE: assumes that there is exactly as much buffer as needed
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
out: &mut [u8],
) {
//assert!(out.len() > , ": not enough buffer to serialize"); //assert!(out.len() > , ": not enough buffer to serialize");
todo!() todo!()
} }
@ -108,10 +131,7 @@ impl super::HandshakeParsing for Req {
Ok(exchange_key) => exchange_key, Ok(exchange_key) => exchange_key,
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
}; };
let mut vec = VecDeque::with_capacity(raw.len() - (4 + len)); let data = ReqInner::CipherText(raw.len() - (4 + len));
vec.extend(raw[(4 + len)..].iter().copied());
let _ = vec.make_contiguous();
let data = ReqInner::CipherText(vec);
Ok(HandshakeData::DirSync(DirSync::Req(Self { Ok(HandshakeData::DirSync(DirSync::Req(Self {
key_id, key_id,
exchange, exchange,
@ -125,40 +145,35 @@ impl super::HandshakeParsing for Req {
/// Quick way to avoid mixing cipher and clear text /// Quick way to avoid mixing cipher and clear text
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ReqInner { pub enum ReqInner {
/// Client data, still in ciphertext /// Data is still encrytped, we only keep the length
CipherText(VecDeque<u8>), CipherText(usize),
/// Client data, decrypted but unprocessed /// Client data, decrypted and parsed
ClearText(VecDeque<u8>), ClearText(ReqData),
/// Parsed client data
Data(ReqData),
} }
impl ReqInner { impl ReqInner {
/// The length of the data /// The length of the data
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { match self {
ReqInner::CipherText(c) => c.len(), ReqInner::CipherText(len) => *len,
ReqInner::ClearText(c) => c.len(), ReqInner::ClearText(data) => data.len(),
ReqInner::Data(d) => d.len(),
} }
} }
/// Get the ciptertext, or panic /// parse the cleartext
pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque<u8> { pub fn deserialize_as_cleartext(&mut self, raw: &[u8]) {
match self { let clear = match self {
ReqInner::CipherText(data) => data, ReqInner::CipherText(len) => {
_ => panic!(), assert!(
} *len == raw.len(),
} "DirSync::ReqInner::CipherText length mismatch"
/// switch from ciphertext to cleartext );
pub fn mark_as_cleartext(&mut self) { match ReqData::deserialize(raw) {
let mut newdata: VecDeque<u8>; Ok(clear) => clear,
match self { Err(_) => return,
ReqInner::CipherText(data) => { }
newdata = VecDeque::new();
::core::mem::swap(&mut newdata, data);
} }
_ => return, _ => return,
} };
*self = ReqInner::ClearText(newdata); *self = ReqInner::ClearText(clear);
} }
} }
@ -246,12 +261,7 @@ impl ReqData {
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;
/// Parse the cleartext raw data /// Parse the cleartext raw data
pub fn deserialize(raw: &ReqInner) -> Result<Self, Error> { pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
let raw = match raw {
// raw is VecDeque, assume everything is on the first slice
ReqInner::ClearText(raw) => raw.as_slices().0,
_ => return Err(Error::Parsing),
};
if raw.len() < Self::MIN_PKT_LEN { if raw.len() < Self::MIN_PKT_LEN {
return Err(Error::NotEnoughData); return Err(Error::NotEnoughData);
} }
@ -285,21 +295,19 @@ impl ReqData {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum RespInner { pub enum RespInner {
/// Server data, still in ciphertext /// Server data, still in ciphertext
CipherText(VecDeque<u8>), CipherText(usize),
/// Server data, decrypted but unprocessed /// Parsed, cleartext server data
ClearText(VecDeque<u8>), ClearText(RespData),
/// Parsed server data
Data(RespData),
} }
impl RespInner { impl RespInner {
/// The length of the data /// The length of the data
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { match self {
RespInner::CipherText(c) => c.len(), RespInner::CipherText(len) => *len,
RespInner::ClearText(c) => c.len(), RespInner::ClearText(d) => RespData::len(),
RespInner::Data(d) => RespData::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 {
@ -307,6 +315,25 @@ impl RespInner {
_ => panic!(), _ => panic!(),
} }
} }
*/
/// parse the cleartext
pub fn deserialize_as_cleartext(&mut self, raw: &[u8]) {
let clear = match self {
RespInner::CipherText(len) => {
assert!(
*len == raw.len(),
"DirSync::RespInner::CipherText length mismatch"
);
match RespData::deserialize(raw) {
Ok(clear) => clear,
Err(_) => return,
}
}
_ => return,
};
*self = RespInner::ClearText(clear);
}
/*
/// switch from ciphertext to cleartext /// switch from ciphertext to cleartext
pub fn mark_as_cleartext(&mut self) { pub fn mark_as_cleartext(&mut self) {
let mut newdata: VecDeque<u8>; let mut newdata: VecDeque<u8>;
@ -319,6 +346,7 @@ impl RespInner {
} }
*self = RespInner::ClearText(newdata); *self = RespInner::ClearText(newdata);
} }
*/
/// serialize, but only if ciphertext /// serialize, but only if ciphertext
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(&self, out: &mut [u8]) {
todo!() todo!()
@ -344,31 +372,48 @@ impl super::HandshakeParsing for Resp {
KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap())); KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap()));
Ok(HandshakeData::DirSync(DirSync::Resp(Self { Ok(HandshakeData::DirSync(DirSync::Resp(Self {
client_key_id, client_key_id,
data: RespInner::CipherText(raw[KeyID::len()..].to_vec().into()), data: RespInner::CipherText(raw[KeyID::len()..].len()),
}))) })))
} }
} }
impl Resp { impl Resp {
/// return the offset of the encrypted data
/// NOTE: starts from the beginning of the fenrir packet
pub fn encrypted_offset(&self) -> usize {
ProtocolVersion::len() + KeyID::len()
}
/// return the total length of the cleartext data
pub fn encrypted_length(&self) -> usize {
match &self.data {
RespInner::ClearText(_data) => RespData::len(),
_ => 0,
}
}
/// Total length of the response handshake /// Total length of the response handshake
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
KeyID::len() + self.data.len() KeyID::len() + self.data.len()
} }
/// Serialize into raw bytes /// Serialize into raw bytes
/// NOTE: assumes that there is exactly as much buffer as needed /// NOTE: assumes that there is exactly as much buffer as needed
/// NOTE: assumes that the data is encrypted /// NOTE: assumes that the data is *ClearText*
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
out: &mut [u8],
) {
assert!( assert!(
out.len() == KeyID::len() + self.data.len(), out.len() == KeyID::len() + self.data.len(),
"DirSync Resp: not enough buffer to serialize" "DirSync Resp: not enough buffer to serialize"
); );
self.client_key_id.serialize(array_mut_ref![out, 0, 2]); self.client_key_id.serialize(array_mut_ref![out, 0, 2]);
let end_data = 2 + self.data.len(); let end_data = (2 + self.data.len()) - tag_len.0;
self.data.serialize(&mut out[2..end_data]); self.data.serialize(&mut out[(2 + head_len.0)..end_data]);
} }
/// Set the cleartext data after it was parsed /// Set the cleartext data after it was parsed
pub fn set_data(&mut self, data: RespData) { pub fn set_data(&mut self, data: RespData) {
self.data = RespInner::Data(data); self.data = RespInner::ClearText(data);
} }
} }
@ -409,7 +454,7 @@ impl RespData {
out[start..end].copy_from_slice(self.service_key.as_ref()); out[start..end].copy_from_slice(self.service_key.as_ref());
} }
/// Parse the cleartext raw data /// Parse the cleartext raw data
pub fn deserialize(raw: &RespInner) -> Result<Self, Error> { pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
todo!(); todo!();
} }
} }

View File

@ -4,7 +4,10 @@ pub mod dirsync;
use ::num_traits::FromPrimitive; use ::num_traits::FromPrimitive;
use crate::connection::{self, ProtocolVersion}; use crate::{
connection::{self, ProtocolVersion},
enc::sym::{HeadLen, TagLen},
};
/// Handshake errors /// Handshake errors
#[derive(::thiserror::Error, Debug, Copy, Clone)] #[derive(::thiserror::Error, Debug, Copy, Clone)]
@ -53,9 +56,14 @@ impl HandshakeData {
} }
/// Serialize into raw bytes /// Serialize into raw bytes
/// NOTE: assumes that there is exactly asa much buffer as needed /// NOTE: assumes that there is exactly asa much buffer as needed
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
out: &mut [u8],
) {
match self { match self {
HandshakeData::DirSync(d) => d.serialize(out), HandshakeData::DirSync(d) => d.serialize(head_len, tag_len, out),
} }
} }
} }
@ -126,10 +134,15 @@ impl Handshake {
} }
/// serialize the handshake into bytes /// serialize the handshake into bytes
/// NOTE: assumes that there is exactly as much buffer as needed /// NOTE: assumes that there is exactly as much buffer as needed
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
out: &mut [u8],
) {
assert!(out.len() > 1, "Handshake: not enough buffer to serialize"); assert!(out.len() > 1, "Handshake: not enough buffer to serialize");
self.fenrir_version.serialize(&mut out[0]); self.fenrir_version.serialize(&mut out[0]);
self.data.serialize(&mut out[1..]); self.data.serialize(head_len, tag_len, &mut out[1..]);
} }
pub(crate) fn work(&self, keys: &[HandshakeServer]) -> Result<(), Error> { pub(crate) fn work(&self, keys: &[HandshakeServer]) -> Result<(), Error> {

View File

@ -1,6 +1,8 @@
// //
//! Raw packet handling, encryption, decryption, parsing //! Raw packet handling, encryption, decryption, parsing
use crate::enc::sym::{HeadLen, TagLen};
/// Fenrir Connection id /// Fenrir Connection id
/// 0 is special as it represents the handshake /// 0 is special as it represents the handshake
/// Connection IDs are to be considered u64 little endian /// Connection IDs are to be considered u64 little endian
@ -100,10 +102,15 @@ impl PacketData {
} }
/// serialize data into bytes /// serialize data into bytes
/// NOTE: assumes that there is exactly asa much buffer as needed /// NOTE: assumes that there is exactly asa much buffer as needed
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
out: &mut [u8],
) {
assert!(self.len() == out.len(), "PacketData: wrong buffer length"); assert!(self.len() == out.len(), "PacketData: wrong buffer length");
match self { match self {
PacketData::Handshake(h) => h.serialize(out), PacketData::Handshake(h) => h.serialize(head_len, tag_len, out),
} }
} }
} }
@ -124,12 +131,18 @@ impl Packet {
} }
/// serialize packet into buffer /// serialize packet into buffer
/// NOTE: assumes that there is exactly asa much buffer as needed /// NOTE: assumes that there is exactly asa much buffer as needed
pub fn serialize(&self, out: &mut [u8]) { pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
out: &mut [u8],
) {
assert!( assert!(
out.len() > ConnectionID::len(), out.len() > ConnectionID::len(),
"Packet: not enough buffer to serialize" "Packet: not enough buffer to serialize"
); );
self.id.serialize(&mut out[0..ConnectionID::len()]); self.id.serialize(&mut out[0..ConnectionID::len()]);
self.data.serialize(&mut out[ConnectionID::len()..]); self.data
.serialize(head_len, tag_len, &mut out[ConnectionID::len()..]);
} }
} }

View File

@ -59,9 +59,9 @@ impl CipherKind {
1 1
} }
/// required length of the nonce /// required length of the nonce
pub fn nonce_len(&self) -> usize { pub fn nonce_len(&self) -> HeadLen {
// TODO: how the hell do I take this from ::chacha20poly1305? // TODO: how the hell do I take this from ::chacha20poly1305?
Nonce::len() HeadLen(Nonce::len())
} }
/// required length of the key /// required length of the key
pub fn key_len(&self) -> usize { pub fn key_len(&self) -> usize {
@ -69,9 +69,9 @@ impl CipherKind {
XChaCha20Poly1305::key_size() XChaCha20Poly1305::key_size()
} }
/// Length of the authentication tag /// Length of the authentication tag
pub fn tag_len(&self) -> usize { pub fn tag_len(&self) -> TagLen {
// TODO: how the hell do I take this from ::chacha20poly1305? // TODO: how the hell do I take this from ::chacha20poly1305?
::ring::aead::CHACHA20_POLY1305.tag_len() TagLen(::ring::aead::CHACHA20_POLY1305.tag_len())
} }
} }
@ -90,6 +90,16 @@ pub enum CipherDirection {
Send, Send,
} }
/// strong typedef for header length
/// aka: nonce length in the encrypted data)
#[derive(Debug, Copy, Clone)]
pub struct HeadLen(pub usize);
/// strong typedef for the Tag length
/// aka: cryptographic authentication tag length at the end
/// of the encrypted data
#[derive(Debug, Copy, Clone)]
pub struct TagLen(pub usize);
/// actual ciphers /// actual ciphers
enum Cipher { enum Cipher {
/// Cipher XChaha20_Poly1305 /// Cipher XChaha20_Poly1305
@ -105,31 +115,33 @@ impl Cipher {
} }
} }
} }
fn nonce_len(&self) -> usize { fn nonce_len(&self) -> HeadLen {
match self { match self {
Cipher::XChaCha20Poly1305(_) => { Cipher::XChaCha20Poly1305(_) => {
// TODO: how the hell do I take this from ::chacha20poly1305? // TODO: how the hell do I take this from ::chacha20poly1305?
::ring::aead::CHACHA20_POLY1305.nonce_len() HeadLen(::ring::aead::CHACHA20_POLY1305.nonce_len())
} }
} }
} }
fn tag_len(&self) -> usize { fn tag_len(&self) -> TagLen {
match self { match self {
Cipher::XChaCha20Poly1305(_) => { Cipher::XChaCha20Poly1305(_) => {
// TODO: how the hell do I take this from ::chacha20poly1305? // TODO: how the hell do I take this from ::chacha20poly1305?
::ring::aead::CHACHA20_POLY1305.tag_len() TagLen(::ring::aead::CHACHA20_POLY1305.tag_len())
} }
} }
} }
fn decrypt(&self, aad: AAD, data: &mut VecDeque<u8>) -> Result<(), Error> { fn decrypt<'a>(
&self,
aad: AAD,
raw_data: &'a mut [u8],
) -> Result<&'a [u8], Error> {
match self { match self {
Cipher::XChaCha20Poly1305(cipher) => { Cipher::XChaCha20Poly1305(cipher) => {
use ::chacha20poly1305::{ use ::chacha20poly1305::{
aead::generic_array::GenericArray, AeadInPlace, aead::generic_array::GenericArray, AeadInPlace,
}; };
let final_len: usize; let final_len: usize = {
{
let raw_data = data.as_mut_slices().0;
// FIXME: check min data length // FIXME: check min data length
let (nonce_bytes, data_and_tag) = raw_data.split_at_mut(13); let (nonce_bytes, data_and_tag) = raw_data.split_at_mut(13);
let (data_notag, tag_bytes) = data_and_tag.split_at_mut( let (data_notag, tag_bytes) = data_and_tag.split_at_mut(
@ -147,11 +159,11 @@ impl Cipher {
if maybe.is_err() { if maybe.is_err() {
return Err(Error::Decrypt); return Err(Error::Decrypt);
} }
final_len = data_notag.len(); data_notag.len()
} };
data.drain(..Nonce::len()); //data.drain(..Nonce::len());
data.truncate(final_len); //data.truncate(final_len);
Ok(()) Ok(&raw_data[Nonce::len()..Nonce::len() + final_len])
} }
} }
} }
@ -159,7 +171,7 @@ impl Cipher {
match self { match self {
Cipher::XChaCha20Poly1305(cipher) => { Cipher::XChaCha20Poly1305(cipher) => {
let cipher = CipherKind::XChaCha20Poly1305; let cipher = CipherKind::XChaCha20Poly1305;
cipher.nonce_len() + cipher.tag_len() cipher.nonce_len().0 + cipher.tag_len().0
} }
} }
} }
@ -167,28 +179,30 @@ impl Cipher {
&self, &self,
nonce: &Nonce, nonce: &Nonce,
aad: AAD, aad: AAD,
data: &mut Data, data: &mut [u8],
) -> Result<(), Error> { ) -> Result<(), Error> {
// No need to check for minimum buffer size since `Data` assures we // FIXME: check minimum buffer size
// already went through that
match self { match self {
Cipher::XChaCha20Poly1305(cipher) => { Cipher::XChaCha20Poly1305(cipher) => {
use ::chacha20poly1305::{ use ::chacha20poly1305::{
aead::generic_array::GenericArray, AeadInPlace, aead::generic_array::GenericArray, AeadInPlace,
}; };
let tag_len: usize = ::ring::aead::CHACHA20_POLY1305.tag_len();
let data_len_notag = data.len() - tag_len;
// write nonce // write nonce
data.get_slice_full()[..Nonce::len()] data[..Nonce::len()].copy_from_slice(nonce.as_bytes());
.copy_from_slice(nonce.as_bytes());
// encrypt data // encrypt data
match cipher.cipher.encrypt_in_place_detached( match cipher.cipher.encrypt_in_place_detached(
nonce.as_bytes().into(), nonce.as_bytes().into(),
aad.0, aad.0,
data.get_slice(), &mut data[Nonce::len()..data_len_notag],
) { ) {
Ok(tag) => { Ok(tag) => {
// add tag data[data_len_notag..]
data.get_tag_slice().copy_from_slice(tag.as_slice()); // add tag
//data.get_tag_slice()
.copy_from_slice(tag.as_slice());
Ok(()) Ok(())
} }
Err(_) => Err(Error::Encrypt), Err(_) => Err(Error::Encrypt),
@ -216,7 +230,7 @@ impl CipherRecv {
Self(Cipher::new(kind, secret)) Self(Cipher::new(kind, secret))
} }
/// Get the length of the nonce for this cipher /// Get the length of the nonce for this cipher
pub fn nonce_len(&self) -> usize { pub fn nonce_len(&self) -> HeadLen {
self.0.nonce_len() self.0.nonce_len()
} }
/// Decrypt a paket. Nonce and Tag are taken from the packet, /// Decrypt a paket. Nonce and Tag are taken from the packet,
@ -224,8 +238,8 @@ impl CipherRecv {
pub fn decrypt<'a>( pub fn decrypt<'a>(
&self, &self,
aad: AAD, aad: AAD,
data: &mut VecDeque<u8>, data: &'a mut [u8],
) -> Result<(), Error> { ) -> Result<&'a [u8], Error> {
self.0.decrypt(aad, data) self.0.decrypt(aad, data)
} }
} }
@ -289,12 +303,12 @@ impl CipherSend {
pub fn make_data(&self, length: usize) -> Data { pub fn make_data(&self, length: usize) -> Data {
Data { Data {
data: Vec::with_capacity(length + self.cipher.overhead()), data: Vec::with_capacity(length + self.cipher.overhead()),
skip_start: self.cipher.nonce_len(), skip_start: self.cipher.nonce_len().0,
skip_end: self.cipher.tag_len(), skip_end: self.cipher.tag_len().0,
} }
} }
/// Encrypt the given data /// Encrypt the given data
pub fn encrypt(&self, aad: AAD, data: &mut Data) -> Result<(), Error> { pub fn encrypt(&self, aad: AAD, data: &mut [u8]) -> Result<(), Error> {
let old_nonce = self.nonce.advance(); let old_nonce = self.nonce.advance();
self.cipher.encrypt(&old_nonce, aad, data)?; self.cipher.encrypt(&old_nonce, aad, data)?;
Ok(()) Ok(())

View File

@ -28,7 +28,7 @@ use ::tokio::{
use crate::enc::{ use crate::enc::{
asym, asym,
hkdf::HkdfSha3, hkdf::HkdfSha3,
sym::{CipherKind, CipherRecv, CipherSend}, sym::{CipherKind, CipherRecv, CipherSend, HeadLen, TagLen},
}; };
pub use config::Config; pub use config::Config;
use connection::{ use connection::{
@ -67,13 +67,26 @@ pub struct AuthNeededInfo {
pub cipher: CipherKind, pub cipher: CipherKind,
} }
/// Client information needed to fully establish the conenction
#[derive(Debug)]
pub struct ClientConnectInfo {
/// Parsed handshake
pub handshake: Handshake,
/// hkdf generated from the handshake
pub hkdf: HkdfSha3,
/// cipher to be used in both directions
pub cipher_recv: CipherRecv,
}
/// Intermediate actions to be taken while parsing the handshake /// Intermediate actions to be taken while parsing the handshake
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum HandshakeAction { pub enum HandshakeAction {
/// Parsing finished, all ok, nothing to do /// Parsing finished, all ok, nothing to do
None, None,
/// Packet parsed, now go perform authentication /// Packet parsed, now go perform authentication
AuthNeeded(AuthNeededInfo), AuthNeeded(AuthNeededInfo),
/// the client can fully establish a connection with this info
ClientConnect(ClientConnectInfo),
} }
// No async here // No async here
struct FenrirInner { struct FenrirInner {
@ -95,6 +108,7 @@ impl FenrirInner {
fn recv_handshake( fn recv_handshake(
&self, &self,
mut handshake: Handshake, mut handshake: Handshake,
handshake_raw: &mut [u8],
) -> Result<HandshakeAction, Error> { ) -> Result<HandshakeAction, Error> {
use connection::handshake::{ use connection::handshake::{
dirsync::{self, DirSync}, dirsync::{self, DirSync},
@ -159,13 +173,17 @@ impl FenrirInner {
let cipher_recv = CipherRecv::new(req.cipher, secret_recv); let cipher_recv = CipherRecv::new(req.cipher, secret_recv);
use crate::enc::sym::AAD; use crate::enc::sym::AAD;
let aad = AAD(&mut []); // no aad for now let aad = AAD(&mut []); // no aad for now
match cipher_recv.decrypt(aad, &mut req.data.ciphertext()) { match cipher_recv.decrypt(
Ok(()) => req.data.mark_as_cleartext(), aad,
&mut handshake_raw[req.encrypted_offset()..],
) {
Ok(cleartext) => {
req.data.deserialize_as_cleartext(cleartext)
}
Err(e) => { Err(e) => {
return Err(handshake::Error::Key(e).into()); return Err(handshake::Error::Key(e).into());
} }
} }
req.set_data(dirsync::ReqData::deserialize(&req.data)?);
let cipher = req.cipher; let cipher = req.cipher;
@ -200,17 +218,26 @@ impl FenrirInner {
let cipher_recv = let cipher_recv =
CipherRecv::new(hshake.cipher, secret_recv); CipherRecv::new(hshake.cipher, secret_recv);
use crate::enc::sym::AAD; use crate::enc::sym::AAD;
let aad = AAD(&mut []); // no aad for now // no aad for now
match cipher_recv.decrypt(aad, &mut resp.data.ciphertext()) let aad = AAD(&mut []);
{ let mut raw_data = &mut handshake_raw[resp
Ok(()) => resp.data.mark_as_cleartext(), .encrypted_offset()
..(resp.encrypted_offset() + resp.encrypted_length())];
match cipher_recv.decrypt(aad, &mut raw_data) {
Ok(cleartext) => {
resp.data.deserialize_as_cleartext(&cleartext)
}
Err(e) => { Err(e) => {
return Err(handshake::Error::Key(e).into()); return Err(handshake::Error::Key(e).into());
} }
} }
resp.set_data(dirsync::RespData::deserialize(&resp.data)?); return Ok(HandshakeAction::ClientConnect(
ClientConnectInfo {
todo!(); handshake,
hkdf: hshake.hkdf,
cipher_recv,
},
));
} }
}, },
} }
@ -615,7 +642,7 @@ impl Fenrir {
const MIN_PACKET_BYTES: usize = 8; const MIN_PACKET_BYTES: usize = 8;
/// Read and do stuff with the raw udp packet /// Read and do stuff with the raw udp packet
async fn recv(&self, udp: RawUdp) { async fn recv(&self, mut udp: RawUdp) {
if udp.data.len() < Self::MIN_PACKET_BYTES { if udp.data.len() < Self::MIN_PACKET_BYTES {
return; return;
} }
@ -630,13 +657,15 @@ impl Fenrir {
return; return;
} }
}; };
let action = match self._inner.recv_handshake(handshake) { let action =
Ok(action) => action, match self._inner.recv_handshake(handshake, &mut udp.data[8..])
Err(err) => { {
::tracing::debug!("Handshake recv error {}", err); Ok(action) => action,
return; Err(err) => {
} ::tracing::debug!("Handshake recv error {}", err);
}; return;
}
};
match action { match action {
HandshakeAction::AuthNeeded(authinfo) => { HandshakeAction::AuthNeeded(authinfo) => {
let tk_check = match self.token_check.load_full() { let tk_check = match self.token_check.load_full() {
@ -657,10 +686,10 @@ impl Fenrir {
DirSync::Req(req) => { DirSync::Req(req) => {
use dirsync::ReqInner; use dirsync::ReqInner;
let req_data = match req.data { let req_data = match req.data {
ReqInner::Data(req_data) => req_data, ReqInner::ClearText(req_data) => req_data,
_ => { _ => {
::tracing::error!( ::tracing::error!(
"token_check: expected Data" "token_check: expected ClearText"
); );
return; return;
} }
@ -697,6 +726,8 @@ impl Fenrir {
connection::ID::new_rand(&self.rand); connection::ID::new_rand(&self.rand);
let srv_secret = let srv_secret =
enc::sym::Secret::new_rand(&self.rand); enc::sym::Secret::new_rand(&self.rand);
let head_len = req.cipher.nonce_len();
let tag_len = req.cipher.tag_len();
let raw_conn = Connection::new( let raw_conn = Connection::new(
authinfo.hkdf, authinfo.hkdf,
@ -711,9 +742,6 @@ impl Fenrir {
lock.reserve_first(raw_conn) lock.reserve_first(raw_conn)
}; };
// TODO: move all the next bits into
// dirsync::Req::respond(...)
let resp_data = dirsync::RespData { let resp_data = dirsync::RespData {
client_nonce: req_data.nonce, client_nonce: req_data.nonce,
id: auth_conn.id, id: auth_conn.id,
@ -721,25 +749,18 @@ impl Fenrir {
service_key: srv_secret, service_key: srv_secret,
}; };
use crate::enc::sym::AAD; use crate::enc::sym::AAD;
let aad = AAD(&mut []); // no aad for now // no aad for now
let mut data = auth_conn let aad = AAD(&mut []);
.cipher_send
.make_data(dirsync::RespData::len());
if let Err(e) = auth_conn
.cipher_send
.encrypt(aad, &mut data)
{
::tracing::error!("can't encrypt: {:?}", e);
return;
}
use dirsync::RespInner; use dirsync::RespInner;
let resp = dirsync::Resp { let resp = dirsync::Resp {
client_key_id: req_data.client_key_id, client_key_id: req_data.client_key_id,
data: RespInner::CipherText( data: RespInner::ClearText(resp_data),
data.get_raw().into(),
),
}; };
let offset_to_encrypt = resp.encrypted_offset();
let encrypt_until = offset_to_encrypt
+ resp.encrypted_length()
+ tag_len.0;
let resp_handshake = Handshake::new( let resp_handshake = Handshake::new(
HandshakeData::DirSync(DirSync::Resp(resp)), HandshakeData::DirSync(DirSync::Resp(resp)),
); );
@ -750,7 +771,20 @@ impl Fenrir {
}; };
let mut raw_out = let mut raw_out =
Vec::<u8>::with_capacity(packet.len()); Vec::<u8>::with_capacity(packet.len());
packet.serialize(&mut raw_out); packet.serialize(
head_len,
tag_len,
&mut raw_out,
);
if let Err(e) = auth_conn.cipher_send.encrypt(
aad,
&mut raw_out
[offset_to_encrypt..encrypt_until],
) {
::tracing::error!("can't encrypt: {:?}", e);
return;
}
self.send_packet(raw_out, udp.src, udp.dst) self.send_packet(raw_out, udp.src, udp.dst)
.await; .await;
} }