libFenrir/src/connection/handshake/dirsync.rs
Luca Fulchir a39767d32b
More work on ciphers and hkdf
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
2023-02-17 14:59:02 +01:00

118 lines
3.3 KiB
Rust

//! 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 super::{Error, HandshakeData};
use crate::{
connection::ID,
enc::{
asym::{ExchangePubKey, KeyExchange, KeyID},
sym::CipherKind,
},
};
use ::std::vec::Vec;
/// Parsed handshake
#[derive(Debug, Clone)]
pub enum DirSync {
/// Directory synchronized handshake: client request
Req(Req),
/// Directory synchronized handshake: server response
Resp(Resp),
}
/// Client request of a directory synchronized handshake
#[derive(Debug, Clone)]
pub struct Req {
/// Id of the server key used for the key exchange
pub key_id: KeyID,
/// Selected key exchange
pub exchange: KeyExchange,
/// Selected cipher
pub cipher: CipherKind,
/// Client ephemeral public key used for key exchanges
pub exchange_key: ExchangePubKey,
/// encrypted data
pub enc: Vec<u8>,
}
impl super::HandshakeParsing for Req {
fn parse(raw: &[u8]) -> Result<HandshakeData, Error> {
const MIN_PKT_LEN: usize = 10;
if raw.len() < MIN_PKT_LEN {
return Err(Error::NotEnoughData);
}
let key_id: KeyID =
KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap()));
use ::num_traits::FromPrimitive;
let exchange: KeyExchange = match KeyExchange::from_u8(raw[2]) {
Some(exchange) => exchange,
None => return Err(Error::Parsing),
};
let cipher: CipherKind = match CipherKind::from_u8(raw[3]) {
Some(cipher) => cipher,
None => return Err(Error::Parsing),
};
let (exchange_key, len) = match ExchangePubKey::from_slice(&raw[4..]) {
Ok(exchange_key) => exchange_key,
Err(e) => return Err(e.into()),
};
let enc = raw[(4 + len)..].to_vec();
Ok(HandshakeData::DirSync(DirSync::Req(Self {
key_id,
exchange,
cipher,
exchange_key,
enc,
})))
}
}
/// Decrypted request data
#[derive(Debug, Clone, Copy)]
pub struct ReqData {
/// Random nonce, the client can use this to track multiple key exchanges
pub nonce: [u8; 16],
/// Client key id so the client can use and rotate keys
pub client_key_id: KeyID,
/// Authentication token
pub token: [u8; 32],
/// Receiving connection id for the client
pub id: ID,
// TODO: service info
}
/// Server response in a directory synchronized handshake
#[derive(Debug, Clone)]
pub struct Resp {
/// Tells the client with which key the exchange was done
pub client_key_id: KeyID,
/// encrypted data
pub enc: Vec<u8>,
}
impl super::HandshakeParsing for Resp {
fn parse(raw: &[u8]) -> Result<HandshakeData, Error> {
todo!()
}
}
/// Decrypted response data
#[derive(Debug, Clone, Copy)]
pub struct RespData {
/// Client nonce, copied from the request
client_nonce: [u8; 16],
/// Server Connection ID
id: ID,
/// Service Connection ID
service_id: ID,
/// Service encryption key
service_key: [u8; 32],
}