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
|
// TODO: merge with crate::enc::sym::Nonce
|
||||||
/// random nonce
|
/// random nonce
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
@ -61,10 +59,10 @@ pub enum DirSync {
|
||||||
|
|
||||||
impl DirSync {
|
impl DirSync {
|
||||||
/// actual length of the dirsync handshake data
|
/// 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 {
|
match self {
|
||||||
DirSync::Req(req) => req.len(),
|
DirSync::Req(req) => req.len(),
|
||||||
DirSync::Resp(resp) => resp.len(),
|
DirSync::Resp(resp) => resp.len(head_len, tag_len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Serialize into raw bytes
|
/// Serialize into raw bytes
|
||||||
|
@ -394,25 +392,31 @@ impl RespInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// parse the cleartext
|
/// 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 {
|
let clear = match self {
|
||||||
RespInner::CipherText(len) => {
|
RespInner::CipherText(len) => {
|
||||||
assert!(
|
assert!(
|
||||||
*len == raw.len(),
|
*len > raw.len(),
|
||||||
"DirSync::RespInner::CipherText length mismatch"
|
"DirSync::RespInner::CipherText length mismatch"
|
||||||
);
|
);
|
||||||
match RespData::deserialize(raw) {
|
match RespData::deserialize(raw) {
|
||||||
Ok(clear) => clear,
|
Ok(clear) => clear,
|
||||||
Err(_) => return,
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return Err(Error::Parsing),
|
||||||
};
|
};
|
||||||
*self = RespInner::ClearText(clear);
|
*self = RespInner::ClearText(clear);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
/// serialize, but only if ciphertext
|
/// Serialize the still cleartext data
|
||||||
pub fn serialize(&self, out: &mut [u8]) {
|
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);
|
return Err(Error::NotEnoughData);
|
||||||
}
|
}
|
||||||
let client_key_id: KeyID =
|
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 {
|
Ok(HandshakeData::DirSync(DirSync::Resp(Self {
|
||||||
client_key_id,
|
client_key_id,
|
||||||
data: RespInner::CipherText(raw[KeyID::len()..].len()),
|
data: RespInner::CipherText(raw[KeyID::len()..].len()),
|
||||||
|
@ -444,7 +448,9 @@ impl Resp {
|
||||||
/// return the offset of the encrypted data
|
/// return the offset of the encrypted data
|
||||||
/// NOTE: starts from the beginning of the fenrir packet
|
/// NOTE: starts from the beginning of the fenrir packet
|
||||||
pub fn encrypted_offset(&self) -> usize {
|
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
|
/// return the total length of the cleartext data
|
||||||
pub fn encrypted_length(&self) -> usize {
|
pub fn encrypted_length(&self) -> usize {
|
||||||
|
@ -454,29 +460,21 @@ impl Resp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Total length of the response handshake
|
/// Total length of the response handshake
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
||||||
KeyID::len() + self.data.len()
|
KeyID::len() + head_len.0 + self.data.len() + tag_len.0
|
||||||
}
|
}
|
||||||
/// 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 *ClearText*
|
|
||||||
pub fn serialize(
|
pub fn serialize(
|
||||||
&self,
|
&self,
|
||||||
head_len: HeadLen,
|
head_len: HeadLen,
|
||||||
tag_len: TagLen,
|
_tag_len: TagLen,
|
||||||
out: &mut [u8],
|
out: &mut [u8],
|
||||||
) {
|
) {
|
||||||
assert!(
|
out[0..2].copy_from_slice(&self.client_key_id.0.to_le_bytes());
|
||||||
out.len() == KeyID::len() + self.data.len(),
|
let start_data = 2 + head_len.0;
|
||||||
"DirSync Resp: not enough buffer to serialize"
|
let end_data = start_data + self.data.len();
|
||||||
);
|
self.data.serialize(&mut out[start_data..end_data]);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,30 +492,54 @@ pub struct RespData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RespData {
|
impl RespData {
|
||||||
const NONCE_LEN: usize = ::core::mem::size_of::<Nonce>();
|
|
||||||
/// Return the expected length for buffer allocation
|
/// Return the expected length for buffer allocation
|
||||||
pub fn len() -> usize {
|
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
|
/// Serialize the data into a 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, out: &mut [u8]) {
|
||||||
assert!(out.len() == Self::len(), "wrong buffer size");
|
|
||||||
let mut start = 0;
|
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);
|
out[start..end].copy_from_slice(&self.client_nonce.0);
|
||||||
start = end;
|
start = end;
|
||||||
end = end + Self::NONCE_LEN;
|
end = end + ID::len();
|
||||||
self.id.serialize(&mut out[start..end]);
|
self.id.serialize(&mut out[start..end]);
|
||||||
start = end;
|
start = end;
|
||||||
end = end + Self::NONCE_LEN;
|
end = end + ID::len();
|
||||||
self.service_connection_id.serialize(&mut out[start..end]);
|
self.service_connection_id.serialize(&mut out[start..end]);
|
||||||
start = end;
|
start = end;
|
||||||
end = end + Self::NONCE_LEN;
|
end = end + Secret::len();
|
||||||
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: &[u8]) -> Result<Self, Error> {
|
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 {
|
impl HandshakeData {
|
||||||
/// actual length of the handshake data
|
/// actual length of the handshake data
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
||||||
match self {
|
match self {
|
||||||
HandshakeData::DirSync(d) => d.len(),
|
HandshakeData::DirSync(d) => d.len(head_len, tag_len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Serialize into raw bytes
|
/// Serialize into raw bytes
|
||||||
|
@ -242,8 +242,10 @@ impl Handshake {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// return the total length of the handshake
|
/// return the total length of the handshake
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
||||||
ProtocolVersion::len() + HandshakeKind::len() + self.data.len()
|
ProtocolVersion::len()
|
||||||
|
+ HandshakeKind::len()
|
||||||
|
+ self.data.len(head_len, tag_len)
|
||||||
}
|
}
|
||||||
const MIN_PKT_LEN: usize = 8;
|
const MIN_PKT_LEN: usize = 8;
|
||||||
/// Parse the packet and return the parsed handshake
|
/// Parse the packet and return the parsed handshake
|
||||||
|
|
|
@ -7,7 +7,6 @@ use crate::{
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handshake_dirsync_req() {
|
fn test_handshake_dirsync_req() {
|
||||||
let rand = enc::Random::new();
|
let rand = enc::Random::new();
|
||||||
let secret = enc::Secret::new_rand(&rand);
|
|
||||||
let cipher = enc::sym::CipherKind::XChaCha20Poly1305;
|
let cipher = enc::sym::CipherKind::XChaCha20Poly1305;
|
||||||
|
|
||||||
let (_, exchange_key) =
|
let (_, exchange_key) =
|
||||||
|
@ -43,8 +42,10 @@ fn test_handshake_dirsync_req() {
|
||||||
},
|
},
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let mut bytes = Vec::<u8>::with_capacity(h_req.len());
|
let mut bytes = Vec::<u8>::with_capacity(
|
||||||
bytes.resize(h_req.len(), 0);
|
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);
|
h_req.serialize(cipher.nonce_len(), cipher.tag_len(), &mut bytes);
|
||||||
|
|
||||||
let mut deserialized = match Handshake::deserialize(&bytes) {
|
let mut deserialized = match Handshake::deserialize(&bytes) {
|
||||||
|
@ -70,3 +71,55 @@ fn test_handshake_dirsync_req() {
|
||||||
"DirSync Req (de)serialization not working",
|
"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
|
/// write the ID to a buffer
|
||||||
pub fn serialize(&self, out: &mut [u8]) {
|
pub fn serialize(&self, out: &mut [u8]) {
|
||||||
assert!(out.len() == 8, "out buffer must be 8 bytes");
|
|
||||||
match self {
|
match self {
|
||||||
ConnectionID::Handshake => out[..].copy_from_slice(&[0; 8]),
|
ConnectionID::Handshake => out[..8].copy_from_slice(&[0; 8]),
|
||||||
ConnectionID::ID(id) => {
|
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 {
|
impl PacketData {
|
||||||
/// total length of the data in bytes
|
/// 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 {
|
match self {
|
||||||
PacketData::Handshake(h) => h.len(),
|
PacketData::Handshake(h) => h.len(head_len, tag_len),
|
||||||
PacketData::Raw(len) => *len,
|
PacketData::Raw(len) => *len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +112,10 @@ impl PacketData {
|
||||||
tag_len: TagLen,
|
tag_len: TagLen,
|
||||||
out: &mut [u8],
|
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 {
|
match self {
|
||||||
PacketData::Handshake(h) => h.serialize(head_len, tag_len, out),
|
PacketData::Handshake(h) => h.serialize(head_len, tag_len, out),
|
||||||
PacketData::Raw(_) => {
|
PacketData::Raw(_) => {
|
||||||
|
@ -148,8 +150,8 @@ impl Packet {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// get the total length of the packet
|
/// get the total length of the packet
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
||||||
ConnectionID::len() + self.data.len()
|
ConnectionID::len() + self.data.len(head_len, tag_len)
|
||||||
}
|
}
|
||||||
/// 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
|
||||||
|
|
|
@ -94,6 +94,10 @@ impl ::core::fmt::Debug for Secret {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Secret {
|
impl Secret {
|
||||||
|
/// return the length of the serialized secret
|
||||||
|
pub const fn len() -> usize {
|
||||||
|
32
|
||||||
|
}
|
||||||
/// New randomly generated secret
|
/// New randomly generated secret
|
||||||
pub fn new_rand(rand: &Random) -> Self {
|
pub fn new_rand(rand: &Random) -> Self {
|
||||||
let mut ret = Self([0; 32]);
|
let mut ret = Self([0; 32]);
|
||||||
|
@ -110,6 +114,11 @@ impl From<[u8; 32]> for Secret {
|
||||||
Self(shared_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 {
|
impl From<::x25519_dalek::SharedSecret> for Secret {
|
||||||
fn from(shared_secret: ::x25519_dalek::SharedSecret) -> Self {
|
fn from(shared_secret: ::x25519_dalek::SharedSecret) -> Self {
|
||||||
|
|
|
@ -184,11 +184,7 @@ impl HandshakeTracker {
|
||||||
&mut handshake_raw[req.encrypted_offset()..],
|
&mut handshake_raw[req.encrypted_offset()..],
|
||||||
) {
|
) {
|
||||||
Ok(cleartext) => {
|
Ok(cleartext) => {
|
||||||
if let Err(e) =
|
req.data.deserialize_as_cleartext(cleartext)?;
|
||||||
req.data.deserialize_as_cleartext(cleartext)
|
|
||||||
{
|
|
||||||
return Err(e.into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(handshake::Error::Key(e).into());
|
return Err(handshake::Error::Key(e).into());
|
||||||
|
@ -223,7 +219,7 @@ impl HandshakeTracker {
|
||||||
..(resp.encrypted_offset() + resp.encrypted_length())];
|
..(resp.encrypted_offset() + resp.encrypted_length())];
|
||||||
match cipher_recv.decrypt(aad, &mut raw_data) {
|
match cipher_recv.decrypt(aad, &mut raw_data) {
|
||||||
Ok(cleartext) => {
|
Ok(cleartext) => {
|
||||||
resp.data.deserialize_as_cleartext(&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());
|
||||||
|
|
|
@ -546,7 +546,8 @@ impl Worker {
|
||||||
id: ID::new_handshake(),
|
id: ID::new_handshake(),
|
||||||
data: PacketData::Handshake(resp_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);
|
packet.serialize(head_len, tag_len, &mut raw_out);
|
||||||
|
|
||||||
if let Err(e) = auth_conn.cipher_send.encrypt(
|
if let Err(e) = auth_conn.cipher_send.encrypt(
|
||||||
|
|
Loading…
Reference in New Issue