token check function stubs
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
bb348f392e
commit
f5a605867e
14
flake.nix
14
flake.nix
|
@ -28,15 +28,17 @@
|
||||||
fd
|
fd
|
||||||
#(rust-bin.stable.latest.default.override {
|
#(rust-bin.stable.latest.default.override {
|
||||||
# go with nightly to have async fn in traits
|
# go with nightly to have async fn in traits
|
||||||
(rust-bin.nightly."2023-02-01".default.override {
|
#(rust-bin.nightly."2023-02-01".default.override {
|
||||||
#extensions = [ "rust-src" ];
|
# #extensions = [ "rust-src" ];
|
||||||
#targets = [ "arm-unknown-linux-gnueabihf" ];
|
# #targets = [ "arm-unknown-linux-gnueabihf" ];
|
||||||
})
|
#})
|
||||||
clippy
|
clippy
|
||||||
lld
|
|
||||||
cargo-watch
|
cargo-watch
|
||||||
rustfmt
|
|
||||||
cargo-license
|
cargo-license
|
||||||
|
lld
|
||||||
|
rust-bin.stable.latest.default
|
||||||
|
rustfmt
|
||||||
|
rust-analyzer
|
||||||
];
|
];
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
# use zsh or other custom shell
|
# use zsh or other custom shell
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
//! Authentication reslated struct definitions
|
||||||
|
|
||||||
|
/// User identifier. 16 bytes for easy uuid conversion
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct UserID([u8; 16]);
|
||||||
|
|
||||||
|
impl From<[u8; 16]> for UserID {
|
||||||
|
fn from(raw: [u8; 16]) -> Self {
|
||||||
|
UserID(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserID {
|
||||||
|
/// length of the User ID in bytes
|
||||||
|
pub const fn len() -> usize {
|
||||||
|
16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Authentication Token, basically just 32 random bytes
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Token([u8; 32]);
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
/// length of the token in bytes
|
||||||
|
pub const fn len() -> usize {
|
||||||
|
32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; 32]> for Token {
|
||||||
|
fn from(raw: [u8; 32]) -> Self {
|
||||||
|
Token(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake debug implementation to avoid leaking tokens
|
||||||
|
impl ::core::fmt::Debug for Token {
|
||||||
|
fn fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> Result<(), ::std::fmt::Error> {
|
||||||
|
::core::fmt::Debug::fmt("[hidden token]", f)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,13 +10,16 @@
|
||||||
|
|
||||||
use super::{Error, HandshakeData};
|
use super::{Error, HandshakeData};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
auth,
|
||||||
connection::ID,
|
connection::ID,
|
||||||
enc::{
|
enc::{
|
||||||
asym::{ExchangePubKey, KeyExchange, KeyID},
|
asym::{ExchangePubKey, KeyExchange, KeyID},
|
||||||
sym::CipherKind,
|
sym::CipherKind,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use ::std::vec::Vec;
|
use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec};
|
||||||
|
|
||||||
|
type Nonce = [u8; 16];
|
||||||
|
|
||||||
/// Parsed handshake
|
/// Parsed handshake
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -39,7 +42,14 @@ pub struct Req {
|
||||||
/// Client ephemeral public key used for key exchanges
|
/// Client ephemeral public key used for key exchanges
|
||||||
pub exchange_key: ExchangePubKey,
|
pub exchange_key: ExchangePubKey,
|
||||||
/// encrypted data
|
/// encrypted data
|
||||||
pub enc: Vec<u8>,
|
pub data: ReqInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Req {
|
||||||
|
/// Set the cleartext data after it was parsed
|
||||||
|
pub fn set_data(&mut self, data: ReqData) {
|
||||||
|
self.data = ReqInner::Data(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::HandshakeParsing for Req {
|
impl super::HandshakeParsing for Req {
|
||||||
|
@ -63,30 +73,102 @@ impl super::HandshakeParsing for Req {
|
||||||
Ok(exchange_key) => exchange_key,
|
Ok(exchange_key) => exchange_key,
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
};
|
};
|
||||||
let enc = raw[(4 + len)..].to_vec();
|
let mut vec = VecDeque::with_capacity(raw.len() - (4 + len));
|
||||||
|
vec.extend(raw[(4 + len)..].iter().copied());
|
||||||
|
let _ = vec.make_contiguous();
|
||||||
|
let data = ReqInner::Ciphertext(vec);
|
||||||
Ok(HandshakeData::DirSync(DirSync::Req(Self {
|
Ok(HandshakeData::DirSync(DirSync::Req(Self {
|
||||||
key_id,
|
key_id,
|
||||||
exchange,
|
exchange,
|
||||||
cipher,
|
cipher,
|
||||||
exchange_key,
|
exchange_key,
|
||||||
enc,
|
data,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Quick way to avoid mixing cipher and clear text
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ReqInner {
|
||||||
|
/// Client data, still in ciphertext
|
||||||
|
Ciphertext(VecDeque<u8>),
|
||||||
|
/// Client data, decrypted but unprocessed
|
||||||
|
Cleartext(VecDeque<u8>),
|
||||||
|
/// Parsed client data
|
||||||
|
Data(ReqData),
|
||||||
|
}
|
||||||
|
impl ReqInner {
|
||||||
|
/// Get the ciptertext, or panic
|
||||||
|
pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque<u8> {
|
||||||
|
match self {
|
||||||
|
ReqInner::Ciphertext(data) => data,
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// switch from ciphertext to cleartext
|
||||||
|
pub fn mark_as_cleartext(&mut self) {
|
||||||
|
let mut newdata: VecDeque<u8>;
|
||||||
|
match self {
|
||||||
|
ReqInner::Ciphertext(data) => {
|
||||||
|
newdata = VecDeque::new();
|
||||||
|
::core::mem::swap(&mut newdata, data);
|
||||||
|
}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
*self = ReqInner::Cleartext(newdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Decrypted request data
|
/// Decrypted request data
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct ReqData {
|
pub struct ReqData {
|
||||||
/// Random nonce, the client can use this to track multiple key exchanges
|
/// Random nonce, the client can use this to track multiple key exchanges
|
||||||
pub nonce: [u8; 16],
|
pub nonce: Nonce,
|
||||||
/// Client key id so the client can use and rotate keys
|
/// Client key id so the client can use and rotate keys
|
||||||
pub client_key_id: KeyID,
|
pub client_key_id: KeyID,
|
||||||
|
/// User of the domain
|
||||||
|
pub user: auth::UserID,
|
||||||
/// Authentication token
|
/// Authentication token
|
||||||
pub token: [u8; 32],
|
pub token: auth::Token,
|
||||||
/// Receiving connection id for the client
|
/// Receiving connection id for the client
|
||||||
pub id: ID,
|
pub id: ID,
|
||||||
// TODO: service info
|
// TODO: service info
|
||||||
}
|
}
|
||||||
|
impl ReqData {
|
||||||
|
/// Parse the cleartext raw data
|
||||||
|
pub fn parse(raw: &ReqInner) -> Result<Self, Error> {
|
||||||
|
const MIN_PKT_LEN: usize = 16
|
||||||
|
+ KeyID::len()
|
||||||
|
+ auth::UserID::len()
|
||||||
|
+ auth::Token::len()
|
||||||
|
+ ID::len();
|
||||||
|
let raw = match raw {
|
||||||
|
ReqInner::Cleartext(raw) => raw.as_slices().0,
|
||||||
|
_ => return Err(Error::Parsing),
|
||||||
|
};
|
||||||
|
if raw.len() < MIN_PKT_LEN {
|
||||||
|
return Err(Error::NotEnoughData);
|
||||||
|
}
|
||||||
|
let nonce: Nonce = raw.try_into().unwrap();
|
||||||
|
let client_key_id =
|
||||||
|
KeyID(u16::from_le_bytes(raw[16..17].try_into().unwrap()));
|
||||||
|
let raw_user: [u8; 16] = raw[18..34].try_into().unwrap();
|
||||||
|
let user: auth::UserID = raw_user.into();
|
||||||
|
let raw_token: [u8; 32] = raw[34..66].try_into().unwrap();
|
||||||
|
let token: auth::Token = raw_token.into();
|
||||||
|
let id: ID = u64::from_le_bytes(raw[66..74].try_into().unwrap()).into();
|
||||||
|
if id.is_handshake() {
|
||||||
|
return Err(Error::Parsing);
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
nonce,
|
||||||
|
client_key_id,
|
||||||
|
user,
|
||||||
|
token,
|
||||||
|
id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Server response in a directory synchronized handshake
|
/// Server response in a directory synchronized handshake
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -107,7 +189,7 @@ impl super::HandshakeParsing for Resp {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct RespData {
|
pub struct RespData {
|
||||||
/// Client nonce, copied from the request
|
/// Client nonce, copied from the request
|
||||||
client_nonce: [u8; 16],
|
client_nonce: Nonce,
|
||||||
/// Server Connection ID
|
/// Server Connection ID
|
||||||
id: ID,
|
id: ID,
|
||||||
/// Service Connection ID
|
/// Service Connection ID
|
||||||
|
@ -115,3 +197,27 @@ pub struct RespData {
|
||||||
/// Service encryption key
|
/// Service encryption key
|
||||||
service_key: [u8; 32],
|
service_key: [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RespData {
|
||||||
|
const NONCE_LEN: usize = ::core::mem::size_of::<Nonce>();
|
||||||
|
/// Return the expected length for buffer allocation
|
||||||
|
pub fn len() -> usize {
|
||||||
|
Self::NONCE_LEN + ID::len() + ID::len() + 32
|
||||||
|
}
|
||||||
|
/// Serialize the data into a buffer
|
||||||
|
pub fn serialize(&self, out: &mut [u8]) {
|
||||||
|
assert!(out.len() == Self::len(), "wrong buffer size");
|
||||||
|
let mut start = 0;
|
||||||
|
let mut end = Self::NONCE_LEN;
|
||||||
|
out[start..end].copy_from_slice(&self.client_nonce);
|
||||||
|
start = end;
|
||||||
|
end = end + Self::NONCE_LEN;
|
||||||
|
self.id.serialize(&mut out[start..end]);
|
||||||
|
start = end;
|
||||||
|
end = end + Self::NONCE_LEN;
|
||||||
|
self.service_id.serialize(&mut out[start..end]);
|
||||||
|
start = end;
|
||||||
|
end = end + Self::NONCE_LEN;
|
||||||
|
out[start..end].copy_from_slice(&self.service_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,20 @@ impl ConnectionID {
|
||||||
pub fn is_handshake(&self) -> bool {
|
pub fn is_handshake(&self) -> bool {
|
||||||
*self == ConnectionID::Handshake
|
*self == ConnectionID::Handshake
|
||||||
}
|
}
|
||||||
|
/// length if the connection ID in bytes
|
||||||
|
pub const fn len() -> usize {
|
||||||
|
8
|
||||||
|
}
|
||||||
|
/// write the ID to a buffer
|
||||||
|
pub fn serialize(&self, out: &mut [u8]) {
|
||||||
|
assert!(out.len() == 8, "Insufficient buffer");
|
||||||
|
match self {
|
||||||
|
ConnectionID::Handshake => out[..].copy_from_slice(&[0; 8]),
|
||||||
|
ConnectionID::ID(id) => {
|
||||||
|
out[..].copy_from_slice(&id.get().to_le_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u64> for ConnectionID {
|
impl From<u64> for ConnectionID {
|
||||||
|
|
|
@ -10,6 +10,13 @@ use crate::enc::sym::Secret;
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct KeyID(pub u16);
|
pub struct KeyID(pub u16);
|
||||||
|
|
||||||
|
impl KeyID {
|
||||||
|
/// Length of the Key ID in bytes
|
||||||
|
pub const fn len() -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Kind of key used in the handshake
|
/// Kind of key used in the handshake
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
|
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
|
|
@ -19,4 +19,7 @@ pub enum Error {
|
||||||
/// Unsupported cipher
|
/// Unsupported cipher
|
||||||
#[error("unsupported cipher")]
|
#[error("unsupported cipher")]
|
||||||
UnsupportedCipher,
|
UnsupportedCipher,
|
||||||
|
/// Can not decrypt. Either corrupted or malicious data
|
||||||
|
#[error("decrypt: corrupted data")]
|
||||||
|
Decrypt,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! Symmetric cypher stuff
|
//! Symmetric cypher stuff
|
||||||
|
|
||||||
|
use super::Error;
|
||||||
|
use ::std::collections::VecDeque;
|
||||||
use ::zeroize::Zeroize;
|
use ::zeroize::Zeroize;
|
||||||
|
|
||||||
/// Secret, used for keys.
|
/// Secret, used for keys.
|
||||||
|
@ -106,31 +108,41 @@ impl Cipher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn decrypt(&self, aad: AAD, data: &mut [u8]) -> Result<(), ()> {
|
fn decrypt<'a>(
|
||||||
|
&self,
|
||||||
|
aad: AAD,
|
||||||
|
data: &mut VecDeque<u8>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
match self {
|
match self {
|
||||||
Cipher::XChaCha20Poly1305(cipher) => {
|
Cipher::XChaCha20Poly1305(cipher) => {
|
||||||
use ::chacha20poly1305::{
|
use ::chacha20poly1305::{
|
||||||
aead::generic_array::GenericArray, AeadInPlace,
|
aead::generic_array::GenericArray, AeadInPlace,
|
||||||
};
|
};
|
||||||
// FIXME: check min data length
|
let final_len: usize;
|
||||||
let (nonce_bytes, data_and_tag) = data.split_at_mut(13);
|
{
|
||||||
let (data_notag, tag_bytes) = data_and_tag.split_at_mut(
|
let raw_data = data.as_mut_slices().0;
|
||||||
data_and_tag.len() + 1
|
// FIXME: check min data length
|
||||||
- ::ring::aead::CHACHA20_POLY1305.tag_len(),
|
let (nonce_bytes, data_and_tag) = raw_data.split_at_mut(13);
|
||||||
);
|
let (data_notag, tag_bytes) = data_and_tag.split_at_mut(
|
||||||
let nonce = GenericArray::from_slice(nonce_bytes);
|
data_and_tag.len() + 1
|
||||||
let tag = GenericArray::from_slice(tag_bytes);
|
- ::ring::aead::CHACHA20_POLY1305.tag_len(),
|
||||||
let maybe = cipher.cipher.decrypt_in_place_detached(
|
);
|
||||||
nonce.into(),
|
let nonce = GenericArray::from_slice(nonce_bytes);
|
||||||
aad.0,
|
let tag = GenericArray::from_slice(tag_bytes);
|
||||||
data_notag,
|
let maybe = cipher.cipher.decrypt_in_place_detached(
|
||||||
tag,
|
nonce.into(),
|
||||||
);
|
aad.0,
|
||||||
if maybe.is_err() {
|
data_notag,
|
||||||
Err(())
|
tag,
|
||||||
} else {
|
);
|
||||||
Ok(())
|
if maybe.is_err() {
|
||||||
|
return Err(Error::Decrypt);
|
||||||
|
}
|
||||||
|
final_len = data_notag.len();
|
||||||
}
|
}
|
||||||
|
data.drain(..Nonce::len());
|
||||||
|
data.truncate(final_len);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +163,11 @@ impl CipherRecv {
|
||||||
}
|
}
|
||||||
/// Decrypt a paket. Nonce and Tag are taken from the packet,
|
/// Decrypt a paket. Nonce and Tag are taken from the packet,
|
||||||
/// while you need to provide AAD (Additional Authenticated Data)
|
/// while you need to provide AAD (Additional Authenticated Data)
|
||||||
pub fn decrypt(&self, aad: AAD, data: &mut [u8]) -> Result<(), ()> {
|
pub fn decrypt<'a>(
|
||||||
|
&self,
|
||||||
|
aad: AAD,
|
||||||
|
data: &mut VecDeque<u8>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
self.0.decrypt(aad, data)
|
self.0.decrypt(aad, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +252,10 @@ impl Nonce {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Length of this nonce in bytes
|
||||||
|
pub fn len() -> usize {
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
/// Get reference to the nonce bytes
|
/// Get reference to the nonce bytes
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
|
113
src/lib.rs
113
src/lib.rs
|
@ -13,13 +13,15 @@
|
||||||
//!
|
//!
|
||||||
//! libFenrir is the official rust library implementing the Fenrir protocol
|
//! libFenrir is the official rust library implementing the Fenrir protocol
|
||||||
|
|
||||||
|
pub mod auth;
|
||||||
mod config;
|
mod config;
|
||||||
pub mod connection;
|
pub mod connection;
|
||||||
pub mod dnssec;
|
pub mod dnssec;
|
||||||
pub mod enc;
|
pub mod enc;
|
||||||
|
|
||||||
use ::arc_swap::{ArcSwap, ArcSwapAny};
|
use ::arc_swap::{ArcSwap, ArcSwapAny, ArcSwapOption};
|
||||||
use ::std::{net::SocketAddr, sync::Arc};
|
use ::std::{net::SocketAddr, pin::Pin, sync::Arc};
|
||||||
|
use ::tokio::macros::support::Future;
|
||||||
use ::tokio::{net::UdpSocket, task::JoinHandle};
|
use ::tokio::{net::UdpSocket, task::JoinHandle};
|
||||||
|
|
||||||
use crate::enc::{
|
use crate::enc::{
|
||||||
|
@ -50,18 +52,35 @@ pub enum Error {
|
||||||
Key(#[from] crate::enc::Error),
|
Key(#[from] crate::enc::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No async here
|
||||||
struct FenrirInner {
|
struct FenrirInner {
|
||||||
key_exchanges: ArcSwapAny<Arc<Vec<(asym::Key, asym::KeyExchange)>>>,
|
key_exchanges: ArcSwapAny<Arc<Vec<(asym::Key, asym::KeyExchange)>>>,
|
||||||
ciphers: ArcSwapAny<Arc<Vec<CipherKind>>>,
|
ciphers: ArcSwapAny<Arc<Vec<CipherKind>>>,
|
||||||
keys: ArcSwapAny<Arc<Vec<HandshakeKey>>>,
|
keys: ArcSwapAny<Arc<Vec<HandshakeKey>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Intermediate actions to be taken while parsing the handshake
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum HandshakeAction {
|
||||||
|
/// Parsing finished, all ok, nothing to do
|
||||||
|
None,
|
||||||
|
/// Packet parsed, now go perform authentication
|
||||||
|
AuthNeeded(Handshake),
|
||||||
|
}
|
||||||
|
|
||||||
|
// No async here
|
||||||
impl FenrirInner {
|
impl FenrirInner {
|
||||||
fn recv_handshake(&self, handshake: Handshake) -> Result<(), Error> {
|
fn recv_handshake(
|
||||||
use connection::handshake::{dirsync::DirSync, HandshakeData};
|
&self,
|
||||||
|
mut handshake: Handshake,
|
||||||
|
) -> Result<HandshakeAction, Error> {
|
||||||
|
use connection::handshake::{
|
||||||
|
dirsync::{self, DirSync},
|
||||||
|
HandshakeData,
|
||||||
|
};
|
||||||
match handshake.data {
|
match handshake.data {
|
||||||
HandshakeData::DirSync(ds) => match ds {
|
HandshakeData::DirSync(ref mut ds) => match ds {
|
||||||
DirSync::Req(mut req) => {
|
DirSync::Req(ref mut req) => {
|
||||||
let ephemeral_key = {
|
let ephemeral_key = {
|
||||||
// Keep this block short to avoid contention
|
// Keep this block short to avoid contention
|
||||||
// on self.keys
|
// on self.keys
|
||||||
|
@ -70,7 +89,7 @@ impl FenrirInner {
|
||||||
keys.iter().find(|k| k.id == req.key_id)
|
keys.iter().find(|k| k.id == req.key_id)
|
||||||
{
|
{
|
||||||
use enc::asym::PrivKey;
|
use enc::asym::PrivKey;
|
||||||
// Directory synchronized can only used keys
|
// Directory synchronized can only use keys
|
||||||
// for key exchange, not signing keys
|
// for key exchange, not signing keys
|
||||||
if let PrivKey::Exchange(k) = &h_k.key {
|
if let PrivKey::Exchange(k) = &h_k.key {
|
||||||
Some(k.clone())
|
Some(k.clone())
|
||||||
|
@ -115,9 +134,15 @@ impl FenrirInner {
|
||||||
let cipher_recv = CipherRecv::new(req.cipher, secret_recv);
|
let cipher_recv = CipherRecv::new(req.cipher, secret_recv);
|
||||||
use crate::enc::sym::AAD;
|
use crate::enc::sym::AAD;
|
||||||
let aad = AAD(&mut []); // no aad for now
|
let aad = AAD(&mut []); // no aad for now
|
||||||
let _ = cipher_recv.decrypt(aad, &mut req.enc);
|
match cipher_recv.decrypt(aad, &mut req.data.ciphertext()) {
|
||||||
|
Ok(()) => req.data.mark_as_cleartext(),
|
||||||
|
Err(e) => {
|
||||||
|
return Err(handshake::Error::Key(e).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.set_data(dirsync::ReqData::parse(&req.data)?);
|
||||||
|
|
||||||
todo!();
|
return Ok(HandshakeAction::AuthNeeded(handshake));
|
||||||
}
|
}
|
||||||
DirSync::Resp(resp) => {
|
DirSync::Resp(resp) => {
|
||||||
todo!();
|
todo!();
|
||||||
|
@ -127,6 +152,12 @@ impl FenrirInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TokenChecker =
|
||||||
|
fn(
|
||||||
|
user: auth::UserID,
|
||||||
|
token: auth::Token,
|
||||||
|
) -> ::futures::future::BoxFuture<'static, Result<bool, ()>>;
|
||||||
|
|
||||||
/// Instance of a fenrir endpoint
|
/// Instance of a fenrir endpoint
|
||||||
#[allow(missing_copy_implementations, missing_debug_implementations)]
|
#[allow(missing_copy_implementations, missing_debug_implementations)]
|
||||||
pub struct Fenrir {
|
pub struct Fenrir {
|
||||||
|
@ -140,6 +171,8 @@ pub struct Fenrir {
|
||||||
stop_working: ::tokio::sync::broadcast::Sender<bool>,
|
stop_working: ::tokio::sync::broadcast::Sender<bool>,
|
||||||
/// Private keys used in the handshake
|
/// Private keys used in the handshake
|
||||||
_inner: Arc<FenrirInner>,
|
_inner: Arc<FenrirInner>,
|
||||||
|
/// where to ask for token check
|
||||||
|
token_check: Arc<ArcSwapOption<TokenChecker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: graceful vs immediate stop
|
// TODO: graceful vs immediate stop
|
||||||
|
@ -165,6 +198,7 @@ impl Fenrir {
|
||||||
key_exchanges: ArcSwapAny::new(Arc::new(Vec::new())),
|
key_exchanges: ArcSwapAny::new(Arc::new(Vec::new())),
|
||||||
keys: ArcSwapAny::new(Arc::new(Vec::new())),
|
keys: ArcSwapAny::new(Arc::new(Vec::new())),
|
||||||
}),
|
}),
|
||||||
|
token_check: Arc::new(ArcSwapOption::from(None)),
|
||||||
};
|
};
|
||||||
Ok(endpoint)
|
Ok(endpoint)
|
||||||
}
|
}
|
||||||
|
@ -259,6 +293,7 @@ impl Fenrir {
|
||||||
async fn listen_udp(
|
async fn listen_udp(
|
||||||
mut stop_working: ::tokio::sync::broadcast::Receiver<bool>,
|
mut stop_working: ::tokio::sync::broadcast::Receiver<bool>,
|
||||||
fenrir: Arc<FenrirInner>,
|
fenrir: Arc<FenrirInner>,
|
||||||
|
token_check: Arc<ArcSwapOption<TokenChecker>>,
|
||||||
socket: Arc<UdpSocket>,
|
socket: Arc<UdpSocket>,
|
||||||
) -> ::std::io::Result<()> {
|
) -> ::std::io::Result<()> {
|
||||||
// jumbo frames are 9K max
|
// jumbo frames are 9K max
|
||||||
|
@ -272,7 +307,13 @@ impl Fenrir {
|
||||||
result?
|
result?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Self::recv(fenrir.clone(), &buffer[0..bytes], sock_from).await;
|
Self::recv(
|
||||||
|
fenrir.clone(),
|
||||||
|
token_check.clone(),
|
||||||
|
&buffer[0..bytes],
|
||||||
|
sock_from,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -293,6 +334,7 @@ impl Fenrir {
|
||||||
let join = ::tokio::spawn(Self::listen_udp(
|
let join = ::tokio::spawn(Self::listen_udp(
|
||||||
stop_working,
|
stop_working,
|
||||||
self._inner.clone(),
|
self._inner.clone(),
|
||||||
|
self.token_check.clone(),
|
||||||
s.clone(),
|
s.clone(),
|
||||||
));
|
));
|
||||||
self.sockets.push((s, join));
|
self.sockets.push((s, join));
|
||||||
|
@ -323,6 +365,7 @@ impl Fenrir {
|
||||||
/// Read and do stuff with the udp packet
|
/// Read and do stuff with the udp packet
|
||||||
async fn recv(
|
async fn recv(
|
||||||
fenrir: Arc<FenrirInner>,
|
fenrir: Arc<FenrirInner>,
|
||||||
|
token_check: Arc<ArcSwapOption<TokenChecker>>,
|
||||||
buffer: &[u8],
|
buffer: &[u8],
|
||||||
_sock_from: SocketAddr,
|
_sock_from: SocketAddr,
|
||||||
) {
|
) {
|
||||||
|
@ -340,10 +383,52 @@ impl Fenrir {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(err) = fenrir.recv_handshake(handshake) {
|
let action = match fenrir.recv_handshake(handshake) {
|
||||||
::tracing::debug!("Handshake recv error {}", err);
|
Ok(action) => action,
|
||||||
return;
|
Err(err) => {
|
||||||
}
|
::tracing::debug!("Handshake recv error {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match action {
|
||||||
|
HandshakeAction::AuthNeeded(hshake) => {
|
||||||
|
let tk_check = match token_check.load_full() {
|
||||||
|
Some(tokenchecker) => tokenchecker,
|
||||||
|
None => {
|
||||||
|
::tracing::error!(
|
||||||
|
"Handshake received, but no tocken_checker"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
use handshake::{
|
||||||
|
dirsync::{self, DirSync},
|
||||||
|
HandshakeData,
|
||||||
|
};
|
||||||
|
match hshake.data {
|
||||||
|
HandshakeData::DirSync(ds) => match ds {
|
||||||
|
DirSync::Req(req) => {
|
||||||
|
use dirsync::ReqInner;
|
||||||
|
let req_data = match req.data {
|
||||||
|
ReqInner::Data(req_data) => req_data,
|
||||||
|
_ => {
|
||||||
|
::tracing::error!(
|
||||||
|
"token_check: expected Data"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tk_check(req_data.user, req_data.token).await;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
// copy packet, spawn
|
// copy packet, spawn
|
||||||
todo!();
|
todo!();
|
||||||
|
|
Loading…
Reference in New Issue