Test (de)serialization of DirSync::Resp

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-06-09 21:58:33 +02:00
parent a32dfe098f
commit faaf8762c7
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
7 changed files with 142 additions and 57 deletions

View File

@ -20,8 +20,6 @@ use crate::{
},
};
use ::arrayref::array_mut_ref;
// TODO: merge with crate::enc::sym::Nonce
/// random nonce
#[derive(Debug, Clone, Copy, PartialEq)]
@ -61,10 +59,10 @@ pub enum DirSync {
impl DirSync {
/// actual length of the dirsync handshake data
pub fn len(&self) -> usize {
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
match self {
DirSync::Req(req) => req.len(),
DirSync::Resp(resp) => resp.len(),
DirSync::Resp(resp) => resp.len(head_len, tag_len),
}
}
/// Serialize into raw bytes
@ -394,25 +392,31 @@ impl RespInner {
}
}
/// parse the cleartext
pub fn deserialize_as_cleartext(&mut self, raw: &[u8]) {
pub fn deserialize_as_cleartext(
&mut self,
raw: &[u8],
) -> Result<(), Error> {
let clear = match self {
RespInner::CipherText(len) => {
assert!(
*len == raw.len(),
*len > raw.len(),
"DirSync::RespInner::CipherText length mismatch"
);
match RespData::deserialize(raw) {
Ok(clear) => clear,
Err(_) => return,
Err(e) => return Err(e),
}
}
_ => return,
_ => return Err(Error::Parsing),
};
*self = RespInner::ClearText(clear);
Ok(())
}
/// serialize, but only if ciphertext
/// Serialize the still cleartext data
pub fn serialize(&self, out: &mut [u8]) {
todo!()
if let RespInner::ClearText(clear) = &self {
clear.serialize(out);
}
}
}
@ -432,7 +436,7 @@ impl super::HandshakeParsing for Resp {
return Err(Error::NotEnoughData);
}
let client_key_id: KeyID =
KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap()));
KeyID(u16::from_le_bytes(raw[0..2].try_into().unwrap()));
Ok(HandshakeData::DirSync(DirSync::Resp(Self {
client_key_id,
data: RespInner::CipherText(raw[KeyID::len()..].len()),
@ -444,7 +448,9 @@ 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()
ProtocolVersion::len()
+ crate::connection::handshake::HandshakeID::len()
+ KeyID::len()
}
/// return the total length of the cleartext data
pub fn encrypted_length(&self) -> usize {
@ -454,29 +460,21 @@ impl Resp {
}
}
/// Total length of the response handshake
pub fn len(&self) -> usize {
KeyID::len() + self.data.len()
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
KeyID::len() + head_len.0 + self.data.len() + tag_len.0
}
/// Serialize into raw bytes
/// NOTE: assumes that there is exactly as much buffer as needed
/// NOTE: assumes that the data is *ClearText*
pub fn serialize(
&self,
head_len: HeadLen,
tag_len: TagLen,
_tag_len: TagLen,
out: &mut [u8],
) {
assert!(
out.len() == KeyID::len() + self.data.len(),
"DirSync Resp: not enough buffer to serialize"
);
self.client_key_id.serialize(array_mut_ref![out, 0, 2]);
let end_data = (2 + self.data.len()) - tag_len.0;
self.data.serialize(&mut out[(2 + head_len.0)..end_data]);
}
/// Set the cleartext data after it was parsed
pub fn set_data(&mut self, data: RespData) {
self.data = RespInner::ClearText(data);
out[0..2].copy_from_slice(&self.client_key_id.0.to_le_bytes());
let start_data = 2 + head_len.0;
let end_data = start_data + self.data.len();
self.data.serialize(&mut out[start_data..end_data]);
}
}
@ -494,30 +492,54 @@ pub struct RespData {
}
impl RespData {
const NONCE_LEN: usize = ::core::mem::size_of::<Nonce>();
/// Return the expected length for buffer allocation
pub fn len() -> usize {
Self::NONCE_LEN + ID::len() + ID::len() + 32
Nonce::len() + ID::len() + ID::len() + Secret::len()
}
/// 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;
let mut end = Self::NONCE_LEN;
let mut end = Nonce::len();
out[start..end].copy_from_slice(&self.client_nonce.0);
start = end;
end = end + Self::NONCE_LEN;
end = end + ID::len();
self.id.serialize(&mut out[start..end]);
start = end;
end = end + Self::NONCE_LEN;
end = end + ID::len();
self.service_connection_id.serialize(&mut out[start..end]);
start = end;
end = end + Self::NONCE_LEN;
end = end + Secret::len();
out[start..end].copy_from_slice(self.service_key.as_ref());
}
/// Parse the cleartext raw data
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
todo!();
let raw_sized: &[u8; 16] = raw[..Nonce::len()].try_into().unwrap();
let client_nonce: Nonce = raw_sized.into();
let end = Nonce::len() + ID::len();
let id: ID =
u64::from_le_bytes(raw[Nonce::len()..end].try_into().unwrap())
.into();
if id.is_handshake() {
return Err(Error::Parsing);
}
let parsed = end;
let end = parsed + ID::len();
let service_connection_id: ID =
u64::from_le_bytes(raw[parsed..end].try_into().unwrap()).into();
if service_connection_id.is_handshake() {
return Err(Error::Parsing);
}
let parsed = end;
let end = parsed + Secret::len();
let raw_secret: &[u8; 32] = raw[parsed..end].try_into().unwrap();
let service_key = raw_secret.into();
Ok(Self {
client_nonce,
id,
service_connection_id,
service_key,
})
}
}

View File

@ -179,9 +179,9 @@ pub enum HandshakeData {
impl HandshakeData {
/// actual length of the handshake data
pub fn len(&self) -> usize {
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
match self {
HandshakeData::DirSync(d) => d.len(),
HandshakeData::DirSync(d) => d.len(head_len, tag_len),
}
}
/// Serialize into raw bytes
@ -242,8 +242,10 @@ impl Handshake {
}
}
/// return the total length of the handshake
pub fn len(&self) -> usize {
ProtocolVersion::len() + HandshakeKind::len() + self.data.len()
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
ProtocolVersion::len()
+ HandshakeKind::len()
+ self.data.len(head_len, tag_len)
}
const MIN_PKT_LEN: usize = 8;
/// Parse the packet and return the parsed handshake

View File

@ -7,7 +7,6 @@ use crate::{
#[test]
fn test_handshake_dirsync_req() {
let rand = enc::Random::new();
let secret = enc::Secret::new_rand(&rand);
let cipher = enc::sym::CipherKind::XChaCha20Poly1305;
let (_, exchange_key) =
@ -43,8 +42,10 @@ fn test_handshake_dirsync_req() {
},
)));
let mut bytes = Vec::<u8>::with_capacity(h_req.len());
bytes.resize(h_req.len(), 0);
let mut bytes = Vec::<u8>::with_capacity(
h_req.len(cipher.nonce_len(), cipher.tag_len()),
);
bytes.resize(h_req.len(cipher.nonce_len(), cipher.tag_len()), 0);
h_req.serialize(cipher.nonce_len(), cipher.tag_len(), &mut bytes);
let mut deserialized = match Handshake::deserialize(&bytes) {
@ -70,3 +71,55 @@ fn test_handshake_dirsync_req() {
"DirSync Req (de)serialization not working",
);
}
#[test]
fn test_handshake_dirsync_reqsp() {
let rand = enc::Random::new();
let cipher = enc::sym::CipherKind::XChaCha20Poly1305;
let service_key = enc::Secret::new_rand(&rand);
let data = dirsync::RespInner::ClearText(dirsync::RespData {
client_nonce: dirsync::Nonce::new(&rand),
id: ID::ID(::core::num::NonZeroU64::new(424242).unwrap()),
service_connection_id: ID::ID(
::core::num::NonZeroU64::new(434343).unwrap(),
),
service_key,
});
let h_resp = Handshake::new(HandshakeData::DirSync(
dirsync::DirSync::Resp(dirsync::Resp {
client_key_id: KeyID(4444),
data,
}),
));
let mut bytes = Vec::<u8>::with_capacity(
h_resp.len(cipher.nonce_len(), cipher.tag_len()),
);
bytes.resize(h_resp.len(cipher.nonce_len(), cipher.tag_len()), 0);
h_resp.serialize(cipher.nonce_len(), cipher.tag_len(), &mut bytes);
let mut deserialized = match Handshake::deserialize(&bytes) {
Ok(deserialized) => deserialized,
Err(e) => {
assert!(false, "{}", e.to_string());
return;
}
};
if let HandshakeData::DirSync(dirsync::DirSync::Resp(r_a)) =
&mut deserialized.data
{
let enc_start = r_a.encrypted_offset() + cipher.nonce_len().0;
if let Err(e) = r_a.data.deserialize_as_cleartext(
&bytes[enc_start..(bytes.len() - cipher.tag_len().0)],
) {
assert!(false, "DirSync Resp Inner serialize: {}", e.to_string());
}
};
assert!(
deserialized == h_resp,
"DirSync Resp (de)serialization not working",
);
}

View File

@ -58,11 +58,10 @@ impl ConnectionID {
}
/// write the ID to a buffer
pub fn serialize(&self, out: &mut [u8]) {
assert!(out.len() == 8, "out buffer must be 8 bytes");
match self {
ConnectionID::Handshake => out[..].copy_from_slice(&[0; 8]),
ConnectionID::Handshake => out[..8].copy_from_slice(&[0; 8]),
ConnectionID::ID(id) => {
out[..].copy_from_slice(&id.get().to_le_bytes())
out[..8].copy_from_slice(&id.get().to_le_bytes())
}
}
}
@ -99,9 +98,9 @@ pub enum PacketData {
impl PacketData {
/// total length of the data in bytes
pub fn len(&self) -> usize {
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
match self {
PacketData::Handshake(h) => h.len(),
PacketData::Handshake(h) => h.len(head_len, tag_len),
PacketData::Raw(len) => *len,
}
}
@ -113,7 +112,10 @@ impl PacketData {
tag_len: TagLen,
out: &mut [u8],
) {
assert!(self.len() == out.len(), "PacketData: wrong buffer length");
assert!(
self.len(head_len, tag_len) == out.len(),
"PacketData: wrong buffer length"
);
match self {
PacketData::Handshake(h) => h.serialize(head_len, tag_len, out),
PacketData::Raw(_) => {
@ -148,8 +150,8 @@ impl Packet {
})
}
/// get the total length of the packet
pub fn len(&self) -> usize {
ConnectionID::len() + self.data.len()
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
ConnectionID::len() + self.data.len(head_len, tag_len)
}
/// serialize packet into buffer
/// NOTE: assumes that there is exactly asa much buffer as needed

View File

@ -94,6 +94,10 @@ impl ::core::fmt::Debug for Secret {
}
impl Secret {
/// return the length of the serialized secret
pub const fn len() -> usize {
32
}
/// New randomly generated secret
pub fn new_rand(rand: &Random) -> Self {
let mut ret = Self([0; 32]);
@ -110,6 +114,11 @@ impl From<[u8; 32]> for Secret {
Self(shared_secret)
}
}
impl From<&[u8; 32]> for Secret {
fn from(shared_secret: &[u8; 32]) -> Self {
Self(*shared_secret)
}
}
impl From<::x25519_dalek::SharedSecret> for Secret {
fn from(shared_secret: ::x25519_dalek::SharedSecret) -> Self {

View File

@ -184,11 +184,7 @@ impl HandshakeTracker {
&mut handshake_raw[req.encrypted_offset()..],
) {
Ok(cleartext) => {
if let Err(e) =
req.data.deserialize_as_cleartext(cleartext)
{
return Err(e.into());
}
req.data.deserialize_as_cleartext(cleartext)?;
}
Err(e) => {
return Err(handshake::Error::Key(e).into());
@ -223,7 +219,7 @@ impl HandshakeTracker {
..(resp.encrypted_offset() + resp.encrypted_length())];
match cipher_recv.decrypt(aad, &mut raw_data) {
Ok(cleartext) => {
resp.data.deserialize_as_cleartext(&cleartext)
resp.data.deserialize_as_cleartext(&cleartext)?;
}
Err(e) => {
return Err(handshake::Error::Key(e).into());

View File

@ -546,7 +546,8 @@ impl Worker {
id: ID::new_handshake(),
data: PacketData::Handshake(resp_handshake),
};
let mut raw_out = Vec::<u8>::with_capacity(packet.len());
let mut raw_out =
Vec::<u8>::with_capacity(packet.len(head_len, tag_len));
packet.serialize(head_len, tag_len, &mut raw_out);
if let Err(e) = auth_conn.cipher_send.encrypt(