namespace #4
|
@ -0,0 +1,77 @@
|
|||
//! Directory synchronized handshake
|
||||
//! 1-RTT connection
|
||||
//!
|
||||
//! The simplest, fastest handshake supported by Fenrir
|
||||
//! Downside: It does not offer protection from DDos,
|
||||
//! no perfect forward secrecy
|
||||
//!
|
||||
//! To grant a form of perfect forward secrecy, the server should periodically
|
||||
//! change the DNSSEC public/private keys
|
||||
|
||||
use crate::enc::{
|
||||
sym::{NonceLen, TagLen},
|
||||
Random,
|
||||
};
|
||||
|
||||
pub mod req;
|
||||
pub mod resp;
|
||||
|
||||
// TODO: merge with crate::enc::sym::Nonce
|
||||
/// random nonce
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Nonce(pub(crate) [u8; 16]);
|
||||
|
||||
impl Nonce {
|
||||
/// Create a new random Nonce
|
||||
pub fn new(rnd: &Random) -> Self {
|
||||
use ::core::mem::MaybeUninit;
|
||||
let mut out: MaybeUninit<[u8; 16]>;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
out = MaybeUninit::uninit();
|
||||
let _ = rnd.fill(out.assume_init_mut());
|
||||
Self(out.assume_init())
|
||||
}
|
||||
}
|
||||
/// Length of the serialized Nonce
|
||||
pub const fn len() -> usize {
|
||||
16
|
||||
}
|
||||
}
|
||||
impl From<&[u8; 16]> for Nonce {
|
||||
fn from(raw: &[u8; 16]) -> Self {
|
||||
Self(raw.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsed handshake
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum DirSync {
|
||||
/// Directory synchronized handshake: client request
|
||||
Req(req::Req),
|
||||
/// Directory synchronized handshake: server response
|
||||
Resp(resp::Resp),
|
||||
}
|
||||
|
||||
impl DirSync {
|
||||
/// actual length of the dirsync handshake data
|
||||
pub fn len(&self, head_len: NonceLen, tag_len: TagLen) -> usize {
|
||||
match self {
|
||||
DirSync::Req(req) => req.len(),
|
||||
DirSync::Resp(resp) => resp.len(head_len, tag_len),
|
||||
}
|
||||
}
|
||||
/// Serialize into raw bytes
|
||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: NonceLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
match self {
|
||||
DirSync::Req(req) => req.serialize(head_len, tag_len, out),
|
||||
DirSync::Resp(resp) => resp.serialize(head_len, tag_len, out),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +1,22 @@
|
|||
//! Directory synchronized handshake
|
||||
//! 1-RTT connection
|
||||
//!
|
||||
//! The simplest, fastest handshake supported by Fenrir
|
||||
//! Downside: It does not offer protection from DDos,
|
||||
//! no perfect forward secrecy
|
||||
//!
|
||||
//! To grant a form of perfect forward secrecy, the server should periodically
|
||||
//! change the DNSSEC public/private keys
|
||||
//! Directory synchronized handshake, Request parsing
|
||||
|
||||
use super::Error;
|
||||
use crate::{
|
||||
auth,
|
||||
connection::{handshake, ProtocolVersion, ID},
|
||||
connection::{
|
||||
handshake::{
|
||||
self,
|
||||
dirsync::{DirSync, Nonce},
|
||||
Error,
|
||||
},
|
||||
ProtocolVersion, ID,
|
||||
},
|
||||
enc::{
|
||||
asym::{ExchangePubKey, KeyExchangeKind, KeyID},
|
||||
hkdf,
|
||||
sym::{self, NonceLen, TagLen},
|
||||
Random, Secret,
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: merge with crate::enc::sym::Nonce
|
||||
/// random nonce
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Nonce(pub(crate) [u8; 16]);
|
||||
|
||||
impl Nonce {
|
||||
/// Create a new random Nonce
|
||||
pub fn new(rnd: &Random) -> Self {
|
||||
use ::core::mem::MaybeUninit;
|
||||
let mut out: MaybeUninit<[u8; 16]>;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
out = MaybeUninit::uninit();
|
||||
let _ = rnd.fill(out.assume_init_mut());
|
||||
Self(out.assume_init())
|
||||
}
|
||||
}
|
||||
/// Length of the serialized Nonce
|
||||
pub const fn len() -> usize {
|
||||
16
|
||||
}
|
||||
}
|
||||
impl From<&[u8; 16]> for Nonce {
|
||||
fn from(raw: &[u8; 16]) -> Self {
|
||||
Self(raw.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsed handshake
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum DirSync {
|
||||
/// Directory synchronized handshake: client request
|
||||
Req(Req),
|
||||
/// Directory synchronized handshake: server response
|
||||
Resp(Resp),
|
||||
}
|
||||
|
||||
impl DirSync {
|
||||
/// actual length of the dirsync handshake data
|
||||
pub fn len(&self, head_len: NonceLen, tag_len: TagLen) -> usize {
|
||||
match self {
|
||||
DirSync::Req(req) => req.len(),
|
||||
DirSync::Resp(resp) => resp.len(head_len, tag_len),
|
||||
}
|
||||
}
|
||||
/// Serialize into raw bytes
|
||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: NonceLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
match self {
|
||||
DirSync::Req(req) => req.serialize(head_len, tag_len, out),
|
||||
DirSync::Resp(resp) => resp.serialize(head_len, tag_len, out),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Client request of a directory synchronized handshake
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Req {
|
||||
|
@ -94,7 +31,7 @@ pub struct Req {
|
|||
/// Client ephemeral public key used for key exchanges
|
||||
pub exchange_key: ExchangePubKey,
|
||||
/// encrypted data
|
||||
pub data: ReqState,
|
||||
pub data: State,
|
||||
// SECURITY: TODO: Add padding to min: 1200 bytes
|
||||
// to avoid amplification attaks
|
||||
// also: 1200 < 1280 to allow better vpn compatibility
|
||||
|
@ -119,8 +56,8 @@ impl Req {
|
|||
tag_len: TagLen,
|
||||
) -> usize {
|
||||
match &self.data {
|
||||
ReqState::ClearText(data) => data.len() + head_len.0 + tag_len.0,
|
||||
ReqState::CipherText(length) => *length,
|
||||
State::ClearText(data) => data.len() + head_len.0 + tag_len.0,
|
||||
State::CipherText(length) => *length,
|
||||
}
|
||||
}
|
||||
/// actual length of the directory synchronized request
|
||||
|
@ -150,7 +87,7 @@ impl Req {
|
|||
let written_next = 5 + key_len;
|
||||
self.exchange_key.serialize_into(&mut out[5..written_next]);
|
||||
let written = written_next;
|
||||
if let ReqState::ClearText(data) = &self.data {
|
||||
if let State::ClearText(data) = &self.data {
|
||||
let from = written + head_len.0;
|
||||
let to = out.len() - tag_len.0;
|
||||
data.serialize(&mut out[from..to]);
|
||||
|
@ -190,7 +127,7 @@ impl handshake::Parsing for Req {
|
|||
Ok(exchange_key) => exchange_key,
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
let data = ReqState::CipherText(raw.len() - (CURR_SIZE + len));
|
||||
let data = State::CipherText(raw.len() - (CURR_SIZE + len));
|
||||
Ok(handshake::Data::DirSync(DirSync::Req(Self {
|
||||
key_id,
|
||||
exchange,
|
||||
|
@ -204,18 +141,18 @@ impl handshake::Parsing for Req {
|
|||
|
||||
/// Quick way to avoid mixing cipher and clear text
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ReqState {
|
||||
pub enum State {
|
||||
/// Data is still encrytped, we only keep the length
|
||||
CipherText(usize),
|
||||
/// Client data, decrypted and parsed
|
||||
ClearText(ReqData),
|
||||
ClearText(Data),
|
||||
}
|
||||
impl ReqState {
|
||||
impl State {
|
||||
/// The length of the data
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
ReqState::CipherText(len) => *len,
|
||||
ReqState::ClearText(data) => data.len(),
|
||||
State::CipherText(len) => *len,
|
||||
State::ClearText(data) => data.len(),
|
||||
}
|
||||
}
|
||||
/// parse the cleartext
|
||||
|
@ -224,19 +161,19 @@ impl ReqState {
|
|||
raw: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
let clear = match self {
|
||||
ReqState::CipherText(len) => {
|
||||
State::CipherText(len) => {
|
||||
assert!(
|
||||
*len > raw.len(),
|
||||
"DirSync::ReqState::CipherText length mismatch"
|
||||
"DirSync::State::CipherText length mismatch"
|
||||
);
|
||||
match ReqData::deserialize(raw) {
|
||||
match Data::deserialize(raw) {
|
||||
Ok(clear) => clear,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::Parsing),
|
||||
};
|
||||
*self = ReqState::ClearText(clear);
|
||||
*self = State::ClearText(clear);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +258,7 @@ impl AuthInfo {
|
|||
|
||||
/// Decrypted request data
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ReqData {
|
||||
pub struct Data {
|
||||
/// Random nonce, the client can use this to track multiple key exchanges
|
||||
pub nonce: Nonce,
|
||||
/// Client key id so the client can use and rotate keys
|
||||
|
@ -331,7 +268,7 @@ pub struct ReqData {
|
|||
/// Authentication data
|
||||
pub auth: AuthInfo,
|
||||
}
|
||||
impl ReqData {
|
||||
impl Data {
|
||||
/// actual length of the request data
|
||||
pub fn len(&self) -> usize {
|
||||
Nonce::len() + KeyID::len() + ID::len() + self.auth.len()
|
||||
|
@ -383,177 +320,3 @@ impl ReqData {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Quick way to avoid mixing cipher and clear text
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum RespState {
|
||||
/// Server data, still in ciphertext
|
||||
CipherText(usize),
|
||||
/// Parsed, cleartext server data
|
||||
ClearText(RespData),
|
||||
}
|
||||
impl RespState {
|
||||
/// The length of the data
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
RespState::CipherText(len) => *len,
|
||||
RespState::ClearText(_) => RespData::len(),
|
||||
}
|
||||
}
|
||||
/// parse the cleartext
|
||||
pub fn deserialize_as_cleartext(
|
||||
&mut self,
|
||||
raw: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
let clear = match self {
|
||||
RespState::CipherText(len) => {
|
||||
assert!(
|
||||
*len > raw.len(),
|
||||
"DirSync::RespState::CipherText length mismatch"
|
||||
);
|
||||
match RespData::deserialize(raw) {
|
||||
Ok(clear) => clear,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::Parsing),
|
||||
};
|
||||
*self = RespState::ClearText(clear);
|
||||
Ok(())
|
||||
}
|
||||
/// Serialize the still cleartext data
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
if let RespState::ClearText(clear) = &self {
|
||||
clear.serialize(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Server response in a directory synchronized handshake
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Resp {
|
||||
/// Tells the client with which key the exchange was done
|
||||
pub client_key_id: KeyID,
|
||||
/// actual response data, might be encrypted
|
||||
pub data: RespState,
|
||||
}
|
||||
|
||||
impl handshake::Parsing for Resp {
|
||||
fn deserialize(raw: &[u8]) -> Result<handshake::Data, Error> {
|
||||
const MIN_PKT_LEN: usize = 68;
|
||||
if raw.len() < MIN_PKT_LEN {
|
||||
return Err(Error::NotEnoughData);
|
||||
}
|
||||
let client_key_id: KeyID =
|
||||
KeyID(u16::from_le_bytes(raw[0..KeyID::len()].try_into().unwrap()));
|
||||
Ok(handshake::Data::DirSync(DirSync::Resp(Self {
|
||||
client_key_id,
|
||||
data: RespState::CipherText(raw[KeyID::len()..].len()),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
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() + handshake::ID::len() + KeyID::len()
|
||||
}
|
||||
/// return the total length of the cleartext data
|
||||
pub fn encrypted_length(
|
||||
&self,
|
||||
head_len: NonceLen,
|
||||
tag_len: TagLen,
|
||||
) -> usize {
|
||||
match &self.data {
|
||||
RespState::ClearText(_data) => {
|
||||
RespData::len() + head_len.0 + tag_len.0
|
||||
}
|
||||
RespState::CipherText(len) => *len,
|
||||
}
|
||||
}
|
||||
/// Total length of the response handshake
|
||||
pub fn len(&self, head_len: NonceLen, 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
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: NonceLen,
|
||||
_tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
out[0..KeyID::len()]
|
||||
.copy_from_slice(&self.client_key_id.0.to_le_bytes());
|
||||
let start_data = KeyID::len() + head_len.0;
|
||||
let end_data = start_data + self.data.len();
|
||||
self.data.serialize(&mut out[start_data..end_data]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypted response data
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RespData {
|
||||
/// Client nonce, copied from the request
|
||||
pub client_nonce: Nonce,
|
||||
/// Server Connection ID
|
||||
pub id: ID,
|
||||
/// Service Connection ID
|
||||
pub service_connection_id: ID,
|
||||
/// Service encryption key
|
||||
pub service_key: Secret,
|
||||
}
|
||||
|
||||
impl RespData {
|
||||
/// Return the expected length for buffer allocation
|
||||
pub fn len() -> usize {
|
||||
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]) {
|
||||
let mut start = 0;
|
||||
let mut end = Nonce::len();
|
||||
out[start..end].copy_from_slice(&self.client_nonce.0);
|
||||
start = end;
|
||||
end = end + ID::len();
|
||||
self.id.serialize(&mut out[start..end]);
|
||||
start = end;
|
||||
end = end + ID::len();
|
||||
self.service_connection_id.serialize(&mut out[start..end]);
|
||||
start = end;
|
||||
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> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
//! Directory synchronized handshake, Response parsing
|
||||
|
||||
use crate::{
|
||||
connection::{
|
||||
handshake::{
|
||||
self,
|
||||
dirsync::{DirSync, Nonce},
|
||||
Error,
|
||||
},
|
||||
ProtocolVersion, ID,
|
||||
},
|
||||
enc::{
|
||||
asym::KeyID,
|
||||
sym::{NonceLen, TagLen},
|
||||
Secret,
|
||||
},
|
||||
};
|
||||
|
||||
/// Server response in a directory synchronized handshake
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Resp {
|
||||
/// Tells the client with which key the exchange was done
|
||||
pub client_key_id: KeyID,
|
||||
/// actual response data, might be encrypted
|
||||
pub data: State,
|
||||
}
|
||||
|
||||
impl handshake::Parsing for Resp {
|
||||
fn deserialize(raw: &[u8]) -> Result<handshake::Data, Error> {
|
||||
const MIN_PKT_LEN: usize = 68;
|
||||
if raw.len() < MIN_PKT_LEN {
|
||||
return Err(Error::NotEnoughData);
|
||||
}
|
||||
let client_key_id: KeyID =
|
||||
KeyID(u16::from_le_bytes(raw[0..KeyID::len()].try_into().unwrap()));
|
||||
Ok(handshake::Data::DirSync(DirSync::Resp(Self {
|
||||
client_key_id,
|
||||
data: State::CipherText(raw[KeyID::len()..].len()),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
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() + handshake::ID::len() + KeyID::len()
|
||||
}
|
||||
/// return the total length of the cleartext data
|
||||
pub fn encrypted_length(
|
||||
&self,
|
||||
head_len: NonceLen,
|
||||
tag_len: TagLen,
|
||||
) -> usize {
|
||||
match &self.data {
|
||||
State::ClearText(_data) => Data::len() + head_len.0 + tag_len.0,
|
||||
State::CipherText(len) => *len,
|
||||
}
|
||||
}
|
||||
/// Total length of the response handshake
|
||||
pub fn len(&self, head_len: NonceLen, 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
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: NonceLen,
|
||||
_tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
out[0..KeyID::len()]
|
||||
.copy_from_slice(&self.client_key_id.0.to_le_bytes());
|
||||
let start_data = KeyID::len() + head_len.0;
|
||||
let end_data = start_data + self.data.len();
|
||||
self.data.serialize(&mut out[start_data..end_data]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Quick way to avoid mixing cipher and clear text
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum State {
|
||||
/// Server data, still in ciphertext
|
||||
CipherText(usize),
|
||||
/// Parsed, cleartext server data
|
||||
ClearText(Data),
|
||||
}
|
||||
impl State {
|
||||
/// The length of the data
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
State::CipherText(len) => *len,
|
||||
State::ClearText(_) => Data::len(),
|
||||
}
|
||||
}
|
||||
/// parse the cleartext
|
||||
pub fn deserialize_as_cleartext(
|
||||
&mut self,
|
||||
raw: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
let clear = match self {
|
||||
State::CipherText(len) => {
|
||||
assert!(
|
||||
*len > raw.len(),
|
||||
"DirSync::State::CipherText length mismatch"
|
||||
);
|
||||
match Data::deserialize(raw) {
|
||||
Ok(clear) => clear,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::Parsing),
|
||||
};
|
||||
*self = State::ClearText(clear);
|
||||
Ok(())
|
||||
}
|
||||
/// Serialize the still cleartext data
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
if let State::ClearText(clear) = &self {
|
||||
clear.serialize(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypted response data
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Data {
|
||||
/// Client nonce, copied from the request
|
||||
pub client_nonce: Nonce,
|
||||
/// Server Connection ID
|
||||
pub id: ID,
|
||||
/// Service Connection ID
|
||||
pub service_connection_id: ID,
|
||||
/// Service encryption key
|
||||
pub service_key: Secret,
|
||||
}
|
||||
|
||||
impl Data {
|
||||
/// Return the expected length for buffer allocation
|
||||
pub fn len() -> usize {
|
||||
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]) {
|
||||
let mut start = 0;
|
||||
let mut end = Nonce::len();
|
||||
out[start..end].copy_from_slice(&self.client_nonce.0);
|
||||
start = end;
|
||||
end = end + ID::len();
|
||||
self.id.serialize(&mut out[start..end]);
|
||||
start = end;
|
||||
end = end + ID::len();
|
||||
self.service_connection_id.serialize(&mut out[start..end]);
|
||||
start = end;
|
||||
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> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -166,9 +166,11 @@ impl Handshake {
|
|||
None => return Err(Error::Parsing),
|
||||
};
|
||||
let data = match handshake_kind {
|
||||
HandshakeKind::DirSyncReq => dirsync::Req::deserialize(&raw[2..])?,
|
||||
HandshakeKind::DirSyncReq => {
|
||||
dirsync::req::Req::deserialize(&raw[2..])?
|
||||
}
|
||||
HandshakeKind::DirSyncResp => {
|
||||
dirsync::Resp::deserialize(&raw[2..])?
|
||||
dirsync::resp::Resp::deserialize(&raw[2..])?
|
||||
}
|
||||
};
|
||||
Ok(Self {
|
||||
|
|
|
@ -22,11 +22,11 @@ fn test_handshake_dirsync_req() {
|
|||
}
|
||||
};
|
||||
|
||||
let data = dirsync::ReqState::ClearText(dirsync::ReqData {
|
||||
let data = dirsync::req::State::ClearText(dirsync::req::Data {
|
||||
nonce: dirsync::Nonce::new(&rand),
|
||||
client_key_id: KeyID(2424),
|
||||
id: ID::ID(::core::num::NonZeroU64::new(424242).unwrap()),
|
||||
auth: dirsync::AuthInfo {
|
||||
auth: dirsync::req::AuthInfo {
|
||||
user: auth::UserID::new(&rand),
|
||||
token: auth::Token::new_anonymous(&rand),
|
||||
service_id: auth::SERVICEID_AUTH,
|
||||
|
@ -35,7 +35,7 @@ fn test_handshake_dirsync_req() {
|
|||
});
|
||||
|
||||
let h_req = Handshake::new(handshake::Data::DirSync(
|
||||
dirsync::DirSync::Req(dirsync::Req {
|
||||
dirsync::DirSync::Req(dirsync::req::Req {
|
||||
key_id: KeyID(4224),
|
||||
exchange: enc::asym::KeyExchangeKind::X25519DiffieHellman,
|
||||
hkdf: enc::hkdf::Kind::Sha3,
|
||||
|
@ -81,7 +81,7 @@ fn test_handshake_dirsync_reqsp() {
|
|||
|
||||
let service_key = enc::Secret::new_rand(&rand);
|
||||
|
||||
let data = dirsync::RespState::ClearText(dirsync::RespData {
|
||||
let data = dirsync::resp::State::ClearText(dirsync::resp::Data {
|
||||
client_nonce: dirsync::Nonce::new(&rand),
|
||||
id: ID::ID(::core::num::NonZeroU64::new(424242).unwrap()),
|
||||
service_connection_id: ID::ID(
|
||||
|
@ -91,7 +91,7 @@ fn test_handshake_dirsync_reqsp() {
|
|||
});
|
||||
|
||||
let h_resp = Handshake::new(handshake::Data::DirSync(
|
||||
dirsync::DirSync::Resp(dirsync::Resp {
|
||||
dirsync::DirSync::Resp(dirsync::resp::Resp {
|
||||
client_key_id: KeyID(4444),
|
||||
data,
|
||||
}),
|
||||
|
|
|
@ -53,7 +53,7 @@ fn test_encrypt_decrypt() {
|
|||
|
||||
let service_key = enc::Secret::new_rand(&rand);
|
||||
|
||||
let data = dirsync::RespState::ClearText(dirsync::RespData {
|
||||
let data = dirsync::resp::State::ClearText(dirsync::resp::Data {
|
||||
client_nonce: dirsync::Nonce::new(&rand),
|
||||
id: ID::ID(::core::num::NonZeroU64::new(424242).unwrap()),
|
||||
service_connection_id: ID::ID(
|
||||
|
@ -62,7 +62,7 @@ fn test_encrypt_decrypt() {
|
|||
service_key,
|
||||
});
|
||||
|
||||
let resp = dirsync::Resp {
|
||||
let resp = dirsync::resp::Resp {
|
||||
client_key_id: KeyID(4444),
|
||||
data,
|
||||
};
|
||||
|
|
|
@ -326,25 +326,25 @@ impl Worker {
|
|||
};
|
||||
|
||||
// build request
|
||||
let auth_info = dirsync::AuthInfo {
|
||||
let auth_info = dirsync::req::AuthInfo {
|
||||
user: UserID::new_anonymous(),
|
||||
token: Token::new_anonymous(&self.rand),
|
||||
service_id: conn_info.service_id,
|
||||
domain: conn_info.domain,
|
||||
};
|
||||
let req_data = dirsync::ReqData {
|
||||
let req_data = dirsync::req::Data {
|
||||
nonce: dirsync::Nonce::new(&self.rand),
|
||||
client_key_id,
|
||||
id: auth_recv_id.0, //FIXME: is zero
|
||||
auth: auth_info,
|
||||
};
|
||||
let req = dirsync::Req {
|
||||
let req = dirsync::req::Req {
|
||||
key_id: key.0,
|
||||
exchange,
|
||||
hkdf: hkdf_selected,
|
||||
cipher: cipher_selected,
|
||||
exchange_key: pub_key,
|
||||
data: dirsync::ReqState::ClearText(req_data),
|
||||
data: dirsync::req::State::ClearText(req_data),
|
||||
};
|
||||
let encrypt_start =
|
||||
connection::ID::len() + req.encrypted_offset();
|
||||
|
@ -459,9 +459,8 @@ impl Worker {
|
|||
::tracing::error!("AuthInfo on non DS::Req");
|
||||
return;
|
||||
}
|
||||
use dirsync::ReqState;
|
||||
let req_data = match req.data {
|
||||
ReqState::ClearText(req_data) => req_data,
|
||||
dirsync::req::State::ClearText(req_data) => req_data,
|
||||
_ => {
|
||||
::tracing::error!("AuthNeeded: expected ClearText");
|
||||
assert!(false, "AuthNeeded: unreachable");
|
||||
|
@ -527,7 +526,7 @@ impl Worker {
|
|||
let auth_id_recv = self.connections.reserve_first();
|
||||
auth_conn.id_recv = auth_id_recv;
|
||||
|
||||
let resp_data = dirsync::RespData {
|
||||
let resp_data = dirsync::resp::Data {
|
||||
client_nonce: req_data.nonce,
|
||||
id: auth_conn.id_recv.0,
|
||||
service_connection_id: srv_conn_id,
|
||||
|
@ -537,10 +536,9 @@ impl Worker {
|
|||
// no aad for now
|
||||
let aad = AAD(&mut []);
|
||||
|
||||
use dirsync::RespState;
|
||||
let resp = dirsync::Resp {
|
||||
let resp = dirsync::resp::Resp {
|
||||
client_key_id: req_data.client_key_id,
|
||||
data: RespState::ClearText(resp_data),
|
||||
data: dirsync::resp::State::ClearText(resp_data),
|
||||
};
|
||||
let encrypt_from =
|
||||
connection::ID::len() + resp.encrypted_offset();
|
||||
|
@ -579,7 +577,8 @@ impl Worker {
|
|||
}
|
||||
// track connection
|
||||
let resp_data;
|
||||
if let dirsync::RespState::ClearText(r_data) = ds_resp.data
|
||||
if let dirsync::resp::State::ClearText(r_data) =
|
||||
ds_resp.data
|
||||
{
|
||||
resp_data = r_data;
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue