Test (de)serialization of DirSync::Resp
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
a32dfe098f
commit
faaf8762c7
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue