Preparation work to write/encrypt response

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-02-22 21:10:00 +01:00
parent 9e1312b149
commit c3aff3e8df
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
5 changed files with 116 additions and 23 deletions

View File

@ -14,7 +14,7 @@ use crate::{
connection::ID, connection::ID,
enc::{ enc::{
asym::{ExchangePubKey, KeyExchange, KeyID}, asym::{ExchangePubKey, KeyExchange, KeyID},
sym::CipherKind, sym::{CipherKind, Secret},
}, },
}; };
use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec}; use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec};
@ -250,16 +250,16 @@ impl super::HandshakeParsing for Resp {
} }
/// Decrypted response data /// Decrypted response data
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
pub struct RespData { pub struct RespData {
/// Client nonce, copied from the request /// Client nonce, copied from the request
client_nonce: Nonce, pub client_nonce: Nonce,
/// Server Connection ID /// Server Connection ID
id: ID, pub id: ID,
/// Service Connection ID /// Service Connection ID
service_id: ID, pub service_id: ID,
/// Service encryption key /// Service encryption key
service_key: [u8; 32], pub service_key: Secret,
} }
impl RespData { impl RespData {
@ -282,6 +282,6 @@ impl RespData {
self.service_id.serialize(&mut out[start..end]); self.service_id.serialize(&mut out[start..end]);
start = end; start = end;
end = end + Self::NONCE_LEN; end = end + Self::NONCE_LEN;
out[start..end].copy_from_slice(&self.service_key); out[start..end].copy_from_slice(self.service_key.as_ref());
} }
} }

View File

@ -9,6 +9,9 @@ pub enum Error {
/// Not enough data /// Not enough data
#[error("not enough data")] #[error("not enough data")]
NotEnoughData, NotEnoughData,
/// buffer too small
#[error("buffer too small")]
InsufficientBuffer,
/// Wrong Key type found. /// Wrong Key type found.
/// You might have passed rsa keys where x25519 was expected /// You might have passed rsa keys where x25519 was expected
#[error("wrong key type")] #[error("wrong key type")]

View File

@ -30,9 +30,19 @@ impl Drop for HkdfInner {
} }
} }
} }
impl Clone for HkdfInner {
fn clone(&self) -> Self {
#[allow(unsafe_code)]
unsafe {
Self {
hkdf: self.hkdf.clone(),
}
}
}
}
/// Sha3 based HKDF /// Sha3 based HKDF
#[allow(missing_debug_implementations)] #[derive(Clone)]
pub struct HkdfSha3 { pub struct HkdfSha3 {
inner: HkdfInner, inner: HkdfInner,
} }
@ -60,3 +70,13 @@ impl HkdfSha3 {
out.into() out.into()
} }
} }
// Fake debug implementation to avoid leaking secrets
impl ::core::fmt::Debug for HkdfSha3 {
fn fmt(
&self,
f: &mut core::fmt::Formatter<'_>,
) -> Result<(), ::std::fmt::Error> {
::core::fmt::Debug::fmt("[hidden hkdf]", f)
}
}

View File

@ -6,10 +6,18 @@ use ::zeroize::Zeroize;
/// Secret, used for keys. /// Secret, used for keys.
/// Grants that on drop() we will zero out memory /// Grants that on drop() we will zero out memory
#[derive(Zeroize)] #[derive(Zeroize, Clone)]
#[zeroize(drop)] #[zeroize(drop)]
#[allow(missing_debug_implementations)]
pub struct Secret([u8; 32]); pub struct Secret([u8; 32]);
// Fake debug implementation to avoid leaking secrets
impl ::core::fmt::Debug for Secret {
fn fmt(
&self,
f: &mut core::fmt::Formatter<'_>,
) -> Result<(), ::std::fmt::Error> {
::core::fmt::Debug::fmt("[hidden secret]", f)
}
}
impl Secret { impl Secret {
/// New randomly generated secret /// New randomly generated secret
@ -49,12 +57,12 @@ impl CipherKind {
/// required length of the nonce /// required length of the nonce
pub fn nonce_len(&self) -> usize { pub fn nonce_len(&self) -> usize {
// TODO: how the hell do I take this from ::chacha20poly1305? // TODO: how the hell do I take this from ::chacha20poly1305?
::ring::aead::CHACHA20_POLY1305.nonce_len() Nonce::len()
} }
/// required length of the key /// required length of the key
pub fn key_len(&self) -> usize { pub fn key_len(&self) -> usize {
use ::chacha20poly1305::KeySizeUser; use ::chacha20poly1305::{KeySizeUser, XChaCha20Poly1305};
::chacha20poly1305::XChaCha20Poly1305::key_size() XChaCha20Poly1305::key_size()
} }
/// Length of the authentication tag /// Length of the authentication tag
pub fn tag_len(&self) -> usize { pub fn tag_len(&self) -> usize {
@ -109,11 +117,7 @@ impl Cipher {
} }
} }
} }
fn decrypt<'a>( fn decrypt(&self, aad: AAD, data: &mut VecDeque<u8>) -> Result<(), Error> {
&self,
aad: AAD,
data: &mut VecDeque<u8>,
) -> Result<(), Error> {
match self { match self {
Cipher::XChaCha20Poly1305(cipher) => { Cipher::XChaCha20Poly1305(cipher) => {
use ::chacha20poly1305::{ use ::chacha20poly1305::{
@ -147,6 +151,32 @@ impl Cipher {
} }
} }
} }
fn encrypt(
&self,
aad: AAD,
nonce: Nonce,
data: &mut [u8],
) -> Result<(), Error> {
match self {
Cipher::XChaCha20Poly1305(cipher) => {
use ::chacha20poly1305::{
aead::generic_array::GenericArray, AeadInPlace,
};
let min_len: usize = CipherKind::XChaCha20Poly1305.nonce_len()
+ CipherKind::XChaCha20Poly1305.tag_len()
+ 1;
if data.len() < min_len {
return Err(Error::InsufficientBuffer);
}
// write Nonce, then advance it
// encrypt data
// add tag
}
}
todo!()
}
} }
/// Receive only cipher /// Receive only cipher
@ -254,7 +284,7 @@ impl Nonce {
} }
} }
/// Length of this nonce in bytes /// Length of this nonce in bytes
pub fn len() -> usize { pub const fn len() -> usize {
return 12; return 12;
} }
/// Get reference to the nonce bytes /// Get reference to the nonce bytes

View File

@ -61,13 +61,24 @@ struct FenrirInner {
keys: ArcSwapAny<Arc<Vec<HandshakeKey>>>, keys: ArcSwapAny<Arc<Vec<HandshakeKey>>>,
} }
/// Information needed to reply after the key exchange
#[derive(Debug, Clone)]
pub struct AuthNeededInfo {
/// Parsed handshake
pub handshake: Handshake,
/// hkdf generated from the handshake
pub hkdf: HkdfSha3,
/// cipher to be used in both directions
pub cipher: CipherKind,
}
/// Intermediate actions to be taken while parsing the handshake /// Intermediate actions to be taken while parsing the handshake
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum HandshakeAction { pub enum HandshakeAction {
/// Parsing finished, all ok, nothing to do /// Parsing finished, all ok, nothing to do
None, None,
/// Packet parsed, now go perform authentication /// Packet parsed, now go perform authentication
AuthNeeded(Handshake), AuthNeeded(AuthNeededInfo),
} }
// No async here // No async here
@ -144,7 +155,13 @@ impl FenrirInner {
} }
req.set_data(dirsync::ReqData::deserialize(&req.data)?); req.set_data(dirsync::ReqData::deserialize(&req.data)?);
return Ok(HandshakeAction::AuthNeeded(handshake)); let cipher = req.cipher;
return Ok(HandshakeAction::AuthNeeded(AuthNeededInfo {
handshake,
hkdf,
cipher,
}));
} }
DirSync::Resp(resp) => { DirSync::Resp(resp) => {
todo!(); todo!();
@ -396,7 +413,7 @@ impl Fenrir {
} }
}; };
match action { match action {
HandshakeAction::AuthNeeded(hshake) => { HandshakeAction::AuthNeeded(authinfo) => {
let tk_check = match token_check.load_full() { let tk_check = match token_check.load_full() {
Some(tk_check) => tk_check, Some(tk_check) => tk_check,
None => { None => {
@ -410,7 +427,7 @@ impl Fenrir {
dirsync::{self, DirSync}, dirsync::{self, DirSync},
HandshakeData, HandshakeData,
}; };
match hshake.data { match authinfo.handshake.data {
HandshakeData::DirSync(ds) => match ds { HandshakeData::DirSync(ds) => match ds {
DirSync::Req(req) => { DirSync::Req(req) => {
use dirsync::ReqInner; use dirsync::ReqInner;
@ -458,6 +475,29 @@ impl Fenrir {
let srv_secret = let srv_secret =
enc::sym::Secret::new_rand(&fenrir.rand); enc::sym::Secret::new_rand(&fenrir.rand);
let resp_data = dirsync::RespData {
client_nonce: req_data.nonce,
id: auth_conn_id,
service_id: srv_conn_id,
service_key: srv_secret,
};
// build response
let secret_send =
authinfo.hkdf.get_secret(b"to_client");
let cipher_send = CipherRecv::new(
authinfo.cipher,
secret_send,
);
use crate::enc::sym::AAD;
let aad = AAD(&mut []); // no aad for now
/*
match cipher_send.encrypt(aad, &mut req.data.ciphertext()) {
Ok(()) => req.data.mark_as_cleartext(),
Err(e) => {
return Err(handshake::Error::Key(e).into());
}
}
*/
todo!() todo!()
} }
_ => { _ => {