Handhsake DirSync RespInner
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
d1e1006143
commit
7a129dbe90
72
flake.lock
72
flake.lock
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
];
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
61
src/lib.rs
61
src/lib.rs
|
@ -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!()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue