Handhsake DirSync RespInner

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-05-11 11:28:30 +02:00
parent d1e1006143
commit 7a129dbe90
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
5 changed files with 195 additions and 37 deletions

View File

@ -1,12 +1,15 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1676283394,
"narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
@ -16,12 +19,15 @@
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
@ -32,11 +38,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1677624842,
"narHash": "sha256-4DF9DbDuK4/+KYx0L6XcPBeDHUFVCtzok2fWtwXtb5w=",
"lastModified": 1683478192,
"narHash": "sha256-7f7RR71w0jRABDgBwjq3vE1yY3nrVJyXk8hDzu5kl1E=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "d70f5cd5c3bef45f7f52698f39e7cc7a89daa7f0",
"rev": "c568239bcc990050b7aedadb7387832440ad8fb1",
"type": "github"
},
"original": {
@ -48,11 +54,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1677407201,
"narHash": "sha256-3blwdI9o1BAprkvlByHvtEm5HAIRn/XPjtcfiunpY7s=",
"lastModified": 1683408522,
"narHash": "sha256-9kcPh6Uxo17a3kK3XCHhcWiV1Yu1kYj22RHiymUhMkU=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "7f5639fa3b68054ca0b062866dc62b22c3f11505",
"rev": "897876e4c484f1e8f92009fd11b7d988a121a4e7",
"type": "github"
},
"original": {
@ -64,11 +70,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1665296151,
"narHash": "sha256-uOB0oxqxN9K7XGF1hcnY+PQnlQJ+3bP2vCn/+Ru/bbc=",
"lastModified": 1681358109,
"narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "14ccaaedd95a488dd7ae142757884d8e125b3363",
"rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9",
"type": "github"
},
"original": {
@ -92,11 +98,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1677638104,
"narHash": "sha256-vbdOoDYnQ1QYSchMb3fYGCLYeta3XwmGvMrlXchST5s=",
"lastModified": 1683512408,
"narHash": "sha256-QMJGp/37En+d5YocJuSU89GL14bBYkIJQ6mqhRfqkkc=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "f388187efb41ce4195b2f4de0b6bb463d3cd0a76",
"rev": "75b07756c3feb22cf230e75fb064c1b4c725b9bc",
"type": "github"
},
"original": {
@ -104,6 +110,36 @@
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View File

@ -15,6 +15,9 @@
pkgs = import nixpkgs {
inherit system overlays;
};
pkgs-unstable = import nixpkgs-unstable {
inherit system overlays;
};
in
{
devShells.default = pkgs.mkShell {
@ -36,7 +39,7 @@
cargo-watch
cargo-license
lld
rust-bin.stable.latest.default
rust-bin.stable."1.69.0".default
rustfmt
rust-analyzer
];

View File

@ -63,6 +63,7 @@ pub struct Req {
pub exchange_key: ExchangePubKey,
/// encrypted data
pub data: ReqInner,
// Security: Add padding to min: 1200 bytes to avoid amplification attaks
}
impl Req {
@ -79,7 +80,7 @@ impl Req {
+ self.data.len()
}
/// Serialize into raw bytes
/// NOTE: assumes that there is exactly asa much buffer as needed
/// NOTE: assumes that there is exactly as much buffer as needed
pub fn serialize(&self, out: &mut [u8]) {
//assert!(out.len() > , ": not enough buffer to serialize");
todo!()
@ -280,35 +281,94 @@ impl ReqData {
}
}
/// Quick way to avoid mixing cipher and clear text
#[derive(Debug, Clone)]
pub enum RespInner {
/// Server data, still in ciphertext
CipherText(VecDeque<u8>),
/// Server data, decrypted but unprocessed
ClearText(VecDeque<u8>),
/// Parsed server data
Data(RespData),
}
impl RespInner {
/// The length of the data
pub fn len(&self) -> usize {
match self {
RespInner::CipherText(c) => c.len(),
RespInner::ClearText(c) => c.len(),
RespInner::Data(d) => RespData::len(),
}
}
/// Get the ciptertext, or panic
pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque<u8> {
match self {
RespInner::CipherText(data) => data,
_ => panic!(),
}
}
/// switch from ciphertext to cleartext
pub fn mark_as_cleartext(&mut self) {
let mut newdata: VecDeque<u8>;
match self {
RespInner::CipherText(data) => {
newdata = VecDeque::new();
::core::mem::swap(&mut newdata, data);
}
_ => return,
}
*self = RespInner::ClearText(newdata);
}
/// serialize, but only if ciphertext
pub fn serialize(&self, out: &mut [u8]) {
todo!()
}
}
/// 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>,
/// actual response data, might be encrypted
pub data: RespInner,
}
impl super::HandshakeParsing for Resp {
fn deserialize(raw: &[u8]) -> Result<HandshakeData, Error> {
todo!()
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..1].try_into().unwrap()));
Ok(HandshakeData::DirSync(DirSync::Resp(Self {
client_key_id,
data: RespInner::CipherText(raw[KeyID::len()..].to_vec().into()),
})))
}
}
impl Resp {
/// Total length of the response handshake
pub fn len(&self) -> usize {
KeyID::len() + self.enc.len()
KeyID::len() + self.data.len()
}
/// Serialize into raw bytes
/// NOTE: assumes that there is exactly asa much buffer as needed
/// NOTE: assumes that there is exactly as much buffer as needed
/// NOTE: assumes that the data is encrypted
pub fn serialize(&self, out: &mut [u8]) {
assert!(
out.len() == KeyID::len() + self.enc.len(),
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]);
out[2..].copy_from_slice(&self.enc[..]);
let end_data = 2 + self.data.len();
self.data.serialize(&mut out[2..end_data]);
}
/// Set the cleartext data after it was parsed
pub fn set_data(&mut self, data: RespData) {
self.data = RespInner::Data(data);
}
}
@ -348,4 +408,8 @@ impl RespData {
end = end + Self::NONCE_LEN;
out[start..end].copy_from_slice(self.service_key.as_ref());
}
/// Parse the cleartext raw data
pub fn deserialize(raw: &RespInner) -> Result<Self, Error> {
todo!();
}
}

View File

@ -24,11 +24,19 @@ pub enum Error {
NotEnoughData,
}
pub(crate) struct HandshakeKey {
pub(crate) struct HandshakeServer {
pub id: crate::enc::asym::KeyID,
pub key: crate::enc::asym::PrivKey,
}
#[derive(Clone)]
pub(crate) struct HandshakeClient {
pub id: crate::enc::asym::KeyID,
pub key: crate::enc::asym::PrivKey,
pub hkdf: crate::enc::hkdf::HkdfSha3,
pub cipher: crate::enc::sym::CipherKind,
}
/// Parsed handshake
#[derive(Debug, Clone)]
pub enum HandshakeData {
@ -117,14 +125,14 @@ impl Handshake {
})
}
/// serialize the handshake into bytes
/// NOTE: assumes that there is exactly asa much buffer as needed
/// NOTE: assumes that there is exactly as much buffer as needed
pub fn serialize(&self, out: &mut [u8]) {
assert!(out.len() > 1, "Handshake: not enough buffer to serialize");
self.fenrir_version.serialize(&mut out[0]);
self.data.serialize(&mut out[1..]);
}
pub(crate) fn work(&self, keys: &[HandshakeKey]) -> Result<(), Error> {
pub(crate) fn work(&self, keys: &[HandshakeServer]) -> Result<(), Error> {
todo!()
}
}

View File

@ -32,7 +32,7 @@ use crate::enc::{
};
pub use config::Config;
use connection::{
handshake::{self, Handshake, HandshakeKey},
handshake::{self, Handshake, HandshakeClient, HandshakeServer},
Connection,
};
@ -79,7 +79,10 @@ pub enum HandshakeAction {
struct FenrirInner {
key_exchanges: ArcSwapAny<Arc<Vec<(asym::Key, asym::KeyExchange)>>>,
ciphers: ArcSwapAny<Arc<Vec<CipherKind>>>,
keys: ArcSwapAny<Arc<Vec<HandshakeKey>>>,
/// ephemeral keys used server side in key exchange
keys_srv: ArcSwapAny<Arc<Vec<HandshakeServer>>>,
/// ephemeral keys used client side in key exchange
hshake_cli: ArcSwapAny<Arc<Vec<HandshakeClient>>>,
}
#[allow(unsafe_code)]
@ -102,8 +105,8 @@ impl FenrirInner {
DirSync::Req(ref mut req) => {
let ephemeral_key = {
// Keep this block short to avoid contention
// on self.keys
let keys = self.keys.load();
// on self.keys_srv
let keys = self.keys_srv.load();
if let Some(h_k) =
keys.iter().find(|k| k.id == req.key_id)
{
@ -120,7 +123,10 @@ impl FenrirInner {
}
};
if ephemeral_key.is_none() {
::tracing::debug!("No such key id: {:?}", req.key_id);
::tracing::debug!(
"No such server key id: {:?}",
req.key_id
);
return Err(handshake::Error::UnknownKeyID.into());
}
let ephemeral_key = ephemeral_key.unwrap();
@ -170,6 +176,40 @@ impl FenrirInner {
}));
}
DirSync::Resp(resp) => {
let hshake = {
// Keep this block short to avoid contention
// on self.hshake_cli
let hshake_cli_lock = self.hshake_cli.load();
match hshake_cli_lock
.iter()
.find(|h| h.id == resp.client_key_id)
{
Some(h) => Some(h.clone()),
None => None,
}
};
if hshake.is_none() {
::tracing::debug!(
"No such client key id: {:?}",
resp.client_key_id
);
return Err(handshake::Error::UnknownKeyID.into());
}
let hshake = hshake.unwrap();
let secret_recv = hshake.hkdf.get_secret(b"to_client");
let cipher_recv =
CipherRecv::new(hshake.cipher, secret_recv);
use crate::enc::sym::AAD;
let aad = AAD(&mut []); // no aad for now
match cipher_recv.decrypt(aad, &mut resp.data.ciphertext())
{
Ok(()) => resp.data.mark_as_cleartext(),
Err(e) => {
return Err(handshake::Error::Key(e).into());
}
}
resp.set_data(dirsync::RespData::deserialize(&resp.data)?);
todo!();
}
},
@ -391,7 +431,8 @@ impl Fenrir {
_inner: Arc::new(FenrirInner {
ciphers: ArcSwapAny::new(Arc::new(Vec::new())),
key_exchanges: ArcSwapAny::new(Arc::new(Vec::new())),
keys: ArcSwapAny::new(Arc::new(Vec::new())),
keys_srv: ArcSwapAny::new(Arc::new(Vec::new())),
hshake_cli: ArcSwapAny::new(Arc::new(Vec::new())),
}),
token_check: Arc::new(ArcSwapOption::from(None)),
work_send: Arc::new(work_send),
@ -692,9 +733,12 @@ impl Fenrir {
::tracing::error!("can't encrypt: {:?}", e);
return;
}
use dirsync::RespInner;
let resp = dirsync::Resp {
client_key_id: req_data.client_key_id,
enc: data.get_raw(),
data: RespInner::CipherText(
data.get_raw().into(),
),
};
let resp_handshake = Handshake::new(
HandshakeData::DirSync(DirSync::Resp(resp)),
@ -710,6 +754,9 @@ impl Fenrir {
self.send_packet(raw_out, udp.src, udp.dst)
.await;
}
DirSync::Resp(resp) => {
todo!()
}
_ => {
todo!()
}