More work on Dirsync request sending
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
9634fbba31
commit
289c6c318e
@ -16,9 +16,17 @@ impl From<[u8; 16]> for UserID {
|
||||
impl UserID {
|
||||
/// New random user id
|
||||
pub fn new(rand: &Random) -> Self {
|
||||
let mut ret = Self([0; 16]);
|
||||
rand.fill(&mut ret.0);
|
||||
ret
|
||||
use ::core::mem::MaybeUninit;
|
||||
let mut out: MaybeUninit<[u8; 16]> = MaybeUninit::uninit();
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
let _ = rand.fill(out.assume_init_mut());
|
||||
Self(out.assume_init())
|
||||
}
|
||||
}
|
||||
/// Anonymous user id
|
||||
pub fn new_anonymous() -> Self {
|
||||
UserID([0; 16])
|
||||
}
|
||||
/// length of the User ID in bytes
|
||||
pub const fn len() -> usize {
|
||||
@ -31,6 +39,16 @@ impl UserID {
|
||||
pub struct Token([u8; 32]);
|
||||
|
||||
impl Token {
|
||||
/// New random token, anonymous should not check this anyway
|
||||
pub fn new_anonymous(rand: &Random) -> Self {
|
||||
use ::core::mem::MaybeUninit;
|
||||
let mut out: MaybeUninit<[u8; 32]> = MaybeUninit::uninit();
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
let _ = rand.fill(out.assume_init_mut());
|
||||
Self(out.assume_init())
|
||||
}
|
||||
}
|
||||
/// length of the token in bytes
|
||||
pub const fn len() -> usize {
|
||||
32
|
||||
@ -68,7 +86,7 @@ pub type TokenChecker =
|
||||
/// further limit to a "safe" subset of utf8
|
||||
// SECURITY: TODO: limit to a subset of utf8
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Domain(String);
|
||||
pub struct Domain(pub String);
|
||||
|
||||
impl TryFrom<&[u8]> for Domain {
|
||||
type Error = ();
|
||||
|
@ -3,11 +3,15 @@
|
||||
pub mod dirsync;
|
||||
|
||||
use crate::{
|
||||
connection::{self, ProtocolVersion},
|
||||
enc::sym::{HeadLen, TagLen},
|
||||
auth::ServiceID,
|
||||
connection::{self, Connection, IDRecv, ProtocolVersion},
|
||||
enc::{
|
||||
asym::{KeyID, PrivKey, PubKey},
|
||||
sym::{HeadLen, TagLen},
|
||||
},
|
||||
};
|
||||
use ::num_traits::FromPrimitive;
|
||||
use ::std::rc::Rc;
|
||||
use ::std::{collections::VecDeque, rc::Rc};
|
||||
|
||||
/// Handshake errors
|
||||
#[derive(::thiserror::Error, Debug, Copy, Clone)]
|
||||
@ -32,6 +36,9 @@ pub enum Error {
|
||||
/// Could not generate Keys
|
||||
#[error("Key generation failed")]
|
||||
KeyGeneration,
|
||||
/// Too many client handshakes currently running
|
||||
#[error("Too many client handshakes")]
|
||||
TooManyClientHandshakes,
|
||||
}
|
||||
|
||||
/// List of possible handshakes
|
||||
@ -66,20 +73,108 @@ impl TryFrom<&str> for HandshakeID {
|
||||
}
|
||||
|
||||
pub(crate) struct HandshakeServer {
|
||||
pub id: crate::enc::asym::KeyID,
|
||||
pub key: crate::enc::asym::PrivKey,
|
||||
pub id: KeyID,
|
||||
pub key: PrivKey,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct HandshakeClient {
|
||||
pub id: crate::enc::asym::KeyID,
|
||||
pub key: crate::enc::asym::PrivKey,
|
||||
pub service_id: crate::auth::ServiceID,
|
||||
pub service_conn_id: connection::IDRecv,
|
||||
pub connection: Rc<crate::connection::Connection>,
|
||||
pub id: KeyID,
|
||||
pub key: PrivKey,
|
||||
pub service_id: ServiceID,
|
||||
pub service_conn_id: IDRecv,
|
||||
pub connection: Connection,
|
||||
pub timeout: Rc<u32>,
|
||||
}
|
||||
|
||||
/// Tracks the keys used by the client and the handshake
|
||||
/// they are associated with
|
||||
pub(crate) struct HandshakeClientList {
|
||||
used: Vec<::bitmaps::Bitmap<1024>>, // index = KeyID
|
||||
keys: Vec<Option<(PrivKey, PubKey)>>,
|
||||
list: Vec<Option<HandshakeClient>>,
|
||||
}
|
||||
|
||||
impl HandshakeClientList {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
used: [::bitmaps::Bitmap::<1024>::new()].to_vec(),
|
||||
keys: Vec::with_capacity(16),
|
||||
list: Vec::with_capacity(16),
|
||||
}
|
||||
}
|
||||
pub(crate) fn get(&self, id: KeyID) -> Option<&HandshakeClient> {
|
||||
if id.0 as usize >= self.list.len() {
|
||||
return None;
|
||||
}
|
||||
self.list[id.0 as usize].as_ref()
|
||||
}
|
||||
pub(crate) fn remove(&mut self, id: KeyID) -> Option<HandshakeClient> {
|
||||
if id.0 as usize >= self.list.len() {
|
||||
return None;
|
||||
}
|
||||
let used_vec_idx = id.0 as usize / 1024;
|
||||
let used_bitmap_idx = id.0 as usize % 1024;
|
||||
let used_iter = match self.used.get_mut(used_vec_idx) {
|
||||
Some(used_iter) => used_iter,
|
||||
None => return None,
|
||||
};
|
||||
used_iter.set(used_bitmap_idx, false);
|
||||
self.keys[id.0 as usize] = None;
|
||||
let mut owned = None;
|
||||
::core::mem::swap(&mut self.list[id.0 as usize], &mut owned);
|
||||
owned
|
||||
}
|
||||
pub(crate) fn add(
|
||||
&mut self,
|
||||
priv_key: PrivKey,
|
||||
pub_key: PubKey,
|
||||
service_id: ServiceID,
|
||||
service_conn_id: IDRecv,
|
||||
connection: Connection,
|
||||
) -> Result<(KeyID, &HandshakeClient), ()> {
|
||||
let maybe_free_key_idx =
|
||||
self.used.iter().enumerate().find_map(|(idx, bmap)| {
|
||||
match bmap.first_false_index() {
|
||||
Some(false_idx) => Some(((idx * 1024), false_idx)),
|
||||
None => None,
|
||||
}
|
||||
});
|
||||
let free_key_idx = match maybe_free_key_idx {
|
||||
Some((idx, false_idx)) => {
|
||||
let free_key_idx = idx * 1024 + false_idx;
|
||||
if free_key_idx > KeyID::MAX as usize {
|
||||
return Err(());
|
||||
}
|
||||
self.used[idx].set(false_idx, true);
|
||||
free_key_idx
|
||||
}
|
||||
None => {
|
||||
let mut bmap = ::bitmaps::Bitmap::<1024>::new();
|
||||
bmap.set(0, true);
|
||||
self.used.push(bmap);
|
||||
self.used.len() * 1024
|
||||
}
|
||||
};
|
||||
if self.keys.len() >= free_key_idx {
|
||||
self.keys.push(None);
|
||||
self.list.push(None);
|
||||
}
|
||||
self.keys[free_key_idx] = Some((priv_key.clone(), pub_key));
|
||||
self.list[free_key_idx] = Some(HandshakeClient {
|
||||
id: KeyID(free_key_idx as u16),
|
||||
key: priv_key,
|
||||
service_id,
|
||||
service_conn_id,
|
||||
connection,
|
||||
timeout: Rc::new(0),
|
||||
});
|
||||
Ok((
|
||||
KeyID(free_key_idx as u16),
|
||||
self.list[free_key_idx].as_ref().unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsed handshake
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HandshakeData {
|
||||
|
@ -132,10 +132,7 @@ impl ConnList {
|
||||
}
|
||||
/// Only *Reserve* a connection,
|
||||
/// without actually tracking it in self.connections
|
||||
pub(crate) fn reserve_first(
|
||||
&mut self,
|
||||
mut conn: Connection,
|
||||
) -> Rc<Connection> {
|
||||
pub(crate) fn reserve_first(&mut self) -> IDRecv {
|
||||
// uhm... bad things are going on here:
|
||||
// * id must be initialized, but only because:
|
||||
// * rust does not understand that after the `!found` id is always
|
||||
@ -173,9 +170,7 @@ impl ConnList {
|
||||
let actual_id = ((id_in_thread as u64) * (self.thread_id.total as u64))
|
||||
+ (self.thread_id.id as u64);
|
||||
let new_id = IDRecv(ID::new_u64(actual_id));
|
||||
conn.id_recv = new_id;
|
||||
// Return the new connection without tracking it
|
||||
Rc::new(conn)
|
||||
new_id
|
||||
}
|
||||
/// NOTE: does NOT check if the connection has been previously reserved!
|
||||
pub(crate) fn track(&mut self, conn: Rc<Connection>) -> Result<(), ()> {
|
||||
|
@ -7,6 +7,8 @@ use ::trust_dns_resolver::TokioAsyncResolver;
|
||||
pub mod record;
|
||||
pub use record::Record;
|
||||
|
||||
use crate::auth::Domain;
|
||||
|
||||
/// Common errors for Dnssec setup and usage
|
||||
#[derive(::thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
@ -88,10 +90,10 @@ impl Dnssec {
|
||||
}
|
||||
const TXT_RECORD_START: &str = "v=Fenrir1 ";
|
||||
/// Get the fenrir data for a domain
|
||||
pub async fn resolv(&self, domain: &str) -> ::std::io::Result<String> {
|
||||
pub async fn resolv(&self, domain: &Domain) -> ::std::io::Result<String> {
|
||||
use ::trust_dns_client::rr::Name;
|
||||
|
||||
let fqdn_str = "_fenrir.".to_owned() + domain;
|
||||
let fqdn_str = "_fenrir.".to_owned() + &domain.0;
|
||||
::tracing::debug!("Resolving: {}", fqdn_str);
|
||||
let fqdn = Name::from_utf8(&fqdn_str)?;
|
||||
let answers = self.resolver.txt_lookup(fqdn).await?;
|
||||
|
@ -17,6 +17,8 @@ impl KeyID {
|
||||
pub const fn len() -> usize {
|
||||
2
|
||||
}
|
||||
/// Maximum possible KeyID
|
||||
pub const MAX: u16 = u16::MAX;
|
||||
/// Serialize into raw bytes
|
||||
pub fn serialize(&self, out: &mut [u8; KeyID::len()]) {
|
||||
out.copy_from_slice(&self.0.to_le_bytes());
|
||||
|
@ -51,6 +51,12 @@ impl Hkdf {
|
||||
Hkdf::Sha3(sha3) => sha3.get_secret(context),
|
||||
}
|
||||
}
|
||||
/// get the kind of this Hkdf
|
||||
pub fn kind(&self) -> HkdfKind {
|
||||
match self {
|
||||
Hkdf::Sha3(_) => HkdfKind::Sha3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hack & tricks:
|
||||
|
@ -39,7 +39,7 @@ impl CipherKind {
|
||||
|
||||
/// Additional Authenticated Data
|
||||
#[derive(Debug)]
|
||||
pub struct AAD<'a>(pub &'a mut [u8]);
|
||||
pub struct AAD<'a>(pub &'a [u8]);
|
||||
|
||||
/// Cipher direction, to make sure we don't reuse the same cipher
|
||||
/// for both decrypting and encrypting
|
||||
|
@ -5,20 +5,24 @@
|
||||
pub(crate) mod worker;
|
||||
|
||||
use crate::{
|
||||
auth,
|
||||
auth::ServiceID,
|
||||
connection::{
|
||||
self,
|
||||
handshake::{self, Handshake, HandshakeClient, HandshakeServer},
|
||||
Connection,
|
||||
handshake::{
|
||||
self, Handshake, HandshakeClient, HandshakeClientList,
|
||||
HandshakeServer,
|
||||
},
|
||||
Connection, IDRecv,
|
||||
},
|
||||
enc::{
|
||||
self, asym,
|
||||
self,
|
||||
asym::{self, KeyID, PrivKey, PubKey},
|
||||
hkdf::{Hkdf, HkdfKind},
|
||||
sym::{CipherKind, CipherRecv},
|
||||
},
|
||||
Error,
|
||||
};
|
||||
use ::std::{rc::Rc, vec::Vec};
|
||||
use ::std::vec::Vec;
|
||||
|
||||
/// Information needed to reply after the key exchange
|
||||
#[derive(Debug, Clone)]
|
||||
@ -35,13 +39,13 @@ pub(crate) struct AuthNeededInfo {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ClientConnectInfo {
|
||||
/// The service ID that we are connecting to
|
||||
pub service_id: auth::ServiceID,
|
||||
pub service_id: ServiceID,
|
||||
/// The service ID that we are connecting to
|
||||
pub service_connection_id: connection::IDRecv,
|
||||
pub service_connection_id: IDRecv,
|
||||
/// Parsed handshake packet
|
||||
pub handshake: Handshake,
|
||||
/// Connection
|
||||
pub connection: Rc<Connection>,
|
||||
pub connection: Connection,
|
||||
}
|
||||
/// Intermediate actions to be taken while parsing the handshake
|
||||
#[derive(Debug)]
|
||||
@ -63,11 +67,11 @@ pub(crate) struct ThreadTracker {
|
||||
pub id: u16,
|
||||
}
|
||||
|
||||
/// Async free but thread safe tracking of handhsakes and conenctions
|
||||
/// Tracking of handhsakes and conenctions
|
||||
/// Note that we have multiple Handshake trackers, pinned to different cores
|
||||
/// Each of them will handle a subset of all handshakes.
|
||||
/// Each handshake is routed to a different tracker with:
|
||||
/// (udp_src_sender_port % total_threads) - 1
|
||||
/// Each handshake is routed to a different tracker by checking
|
||||
/// core = (udp_src_sender_port % total_threads) - 1
|
||||
pub(crate) struct HandshakeTracker {
|
||||
thread_id: ThreadTracker,
|
||||
key_exchanges: Vec<(asym::KeyKind, asym::KeyExchangeKind)>,
|
||||
@ -75,12 +79,8 @@ pub(crate) struct HandshakeTracker {
|
||||
/// ephemeral keys used server side in key exchange
|
||||
keys_srv: Vec<HandshakeServer>,
|
||||
/// ephemeral keys used client side in key exchange
|
||||
hshake_cli: Vec<HandshakeClient>,
|
||||
hshake_cli: HandshakeClientList,
|
||||
}
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl Send for HandshakeTracker {}
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl Sync for HandshakeTracker {}
|
||||
|
||||
impl HandshakeTracker {
|
||||
pub(crate) fn new(thread_id: ThreadTracker) -> Self {
|
||||
@ -89,9 +89,25 @@ impl HandshakeTracker {
|
||||
ciphers: Vec::new(),
|
||||
key_exchanges: Vec::new(),
|
||||
keys_srv: Vec::new(),
|
||||
hshake_cli: Vec::new(),
|
||||
hshake_cli: HandshakeClientList::new(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn new_client(
|
||||
&mut self,
|
||||
priv_key: PrivKey,
|
||||
pub_key: PubKey,
|
||||
service_id: ServiceID,
|
||||
service_conn_id: IDRecv,
|
||||
connection: Connection,
|
||||
) -> Result<(KeyID, &HandshakeClient), ()> {
|
||||
self.hshake_cli.add(
|
||||
priv_key,
|
||||
pub_key,
|
||||
service_id,
|
||||
service_conn_id,
|
||||
connection,
|
||||
)
|
||||
}
|
||||
pub(crate) fn recv_handshake(
|
||||
&mut self,
|
||||
mut handshake: Handshake,
|
||||
@ -105,7 +121,6 @@ impl HandshakeTracker {
|
||||
if let Some(h_k) =
|
||||
self.keys_srv.iter().find(|k| k.id == req.key_id)
|
||||
{
|
||||
use enc::asym::PrivKey;
|
||||
// Directory synchronized can only use keys
|
||||
// for key exchange, not signing keys
|
||||
if let PrivKey::Exchange(k) = &h_k.key {
|
||||
@ -175,20 +190,9 @@ impl HandshakeTracker {
|
||||
}));
|
||||
}
|
||||
DirSync::Resp(resp) => {
|
||||
let hshake_idx = {
|
||||
match self
|
||||
.hshake_cli
|
||||
.iter()
|
||||
.position(|h| h.id == resp.client_key_id)
|
||||
{
|
||||
Some(h) => Some(h.clone()),
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
let hshake_idx = {
|
||||
if let Some(real_idx) = hshake_idx {
|
||||
real_idx
|
||||
} else {
|
||||
let hshake = match self.hshake_cli.get(resp.client_key_id) {
|
||||
Some(hshake) => hshake,
|
||||
None => {
|
||||
::tracing::debug!(
|
||||
"No such client key id: {:?}",
|
||||
resp.client_key_id
|
||||
@ -196,7 +200,6 @@ impl HandshakeTracker {
|
||||
return Err(handshake::Error::UnknownKeyID.into());
|
||||
}
|
||||
};
|
||||
let hshake = &self.hshake_cli[hshake_idx];
|
||||
let cipher_recv = &hshake.connection.cipher_recv;
|
||||
use crate::enc::sym::AAD;
|
||||
// no aad for now
|
||||
@ -212,14 +215,8 @@ impl HandshakeTracker {
|
||||
return Err(handshake::Error::Key(e).into());
|
||||
}
|
||||
}
|
||||
// we can remove the handshake from the list
|
||||
let hshake: HandshakeClient = {
|
||||
let len = self.hshake_cli.len();
|
||||
if (hshake_idx + 1) != len {
|
||||
self.hshake_cli.swap(hshake_idx, len - 1);
|
||||
}
|
||||
self.hshake_cli.pop().unwrap()
|
||||
};
|
||||
let hshake =
|
||||
self.hshake_cli.remove(resp.client_key_id).unwrap();
|
||||
return Ok(HandshakeAction::ClientConnect(
|
||||
ClientConnectInfo {
|
||||
service_id: hshake.service_id,
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Worker thread implementation
|
||||
use crate::{
|
||||
auth::{ServiceID, TokenChecker},
|
||||
auth::{Domain, ServiceID, Token, TokenChecker, UserID},
|
||||
config::Config,
|
||||
connection::{
|
||||
self,
|
||||
@ -14,10 +14,9 @@ use crate::{
|
||||
},
|
||||
dnssec,
|
||||
enc::{
|
||||
asym::{self, PrivKey, PubKey},
|
||||
asym::{PrivKey, PubKey},
|
||||
hkdf::{self, Hkdf, HkdfKind},
|
||||
sym::{self},
|
||||
Random, Secret,
|
||||
sym, Random, Secret,
|
||||
},
|
||||
inner::{HandshakeAction, HandshakeTracker, ThreadTracker},
|
||||
};
|
||||
@ -36,17 +35,19 @@ pub(crate) struct RawUdp {
|
||||
pub packet: Packet,
|
||||
}
|
||||
|
||||
pub(crate) struct ConnectInfo {
|
||||
pub answer: oneshot::Sender<Result<(PubKey, IDSend), crate::Error>>,
|
||||
pub resolved: dnssec::Record,
|
||||
pub service_id: ServiceID,
|
||||
pub domain: Domain,
|
||||
// TODO: UserID, Token information
|
||||
}
|
||||
|
||||
pub(crate) enum Work {
|
||||
/// ask the thread to report to the main thread the total number of
|
||||
/// connections present
|
||||
CountConnections(oneshot::Sender<usize>),
|
||||
Connect(
|
||||
(
|
||||
oneshot::Sender<Result<(PubKey, IDSend), crate::Error>>,
|
||||
dnssec::Record,
|
||||
ServiceID,
|
||||
),
|
||||
),
|
||||
Connect(ConnectInfo),
|
||||
Recv(RawUdp),
|
||||
}
|
||||
pub(crate) enum WorkAnswer {
|
||||
@ -162,13 +163,13 @@ impl Worker {
|
||||
let conn_num = self.connections.len();
|
||||
let _ = sender.send(conn_num);
|
||||
}
|
||||
Work::Connect((send_res, dnssec_record, _service_id)) => {
|
||||
Work::Connect(conn_info) => {
|
||||
// PERF: geolocation
|
||||
|
||||
// Find the first destination with a coherent
|
||||
// pubkey/key exchange
|
||||
let destination =
|
||||
dnssec_record.addresses.iter().find_map(|addr| {
|
||||
conn_info.resolved.addresses.iter().find_map(|addr| {
|
||||
if addr
|
||||
.handshake_ids
|
||||
.iter()
|
||||
@ -187,7 +188,8 @@ impl Worker {
|
||||
// *we* support
|
||||
for idx in addr.public_key_idx.iter() {
|
||||
let key_supported_k_x =
|
||||
dnssec_record.public_keys[idx.0 as usize]
|
||||
conn_info.resolved.public_keys
|
||||
[idx.0 as usize]
|
||||
.1
|
||||
.kind()
|
||||
.key_exchanges();
|
||||
@ -200,7 +202,7 @@ impl Worker {
|
||||
Some(exchange) => {
|
||||
return Some((
|
||||
addr,
|
||||
dnssec_record.public_keys
|
||||
conn_info.resolved.public_keys
|
||||
[idx.0 as usize],
|
||||
exchange.clone(),
|
||||
))
|
||||
@ -214,7 +216,9 @@ impl Worker {
|
||||
Some((addr, key, exchange)) => (addr, key, exchange),
|
||||
None => {
|
||||
let _ =
|
||||
send_res.send(Err(crate::Error::Resolution(
|
||||
conn_info
|
||||
.answer
|
||||
.send(Err(crate::Error::Resolution(
|
||||
"No selectable address and key combination"
|
||||
.to_owned(),
|
||||
)));
|
||||
@ -223,11 +227,11 @@ impl Worker {
|
||||
};
|
||||
let hkdf_selected = match hkdf::client_select_hkdf(
|
||||
&self.cfg,
|
||||
&dnssec_record.hkdfs,
|
||||
&conn_info.resolved.hkdfs,
|
||||
) {
|
||||
Some(hkdf_selected) => hkdf_selected,
|
||||
None => {
|
||||
let _ = send_res.send(Err(
|
||||
let _ = conn_info.answer.send(Err(
|
||||
handshake::Error::Negotiation.into(),
|
||||
));
|
||||
continue 'mainloop;
|
||||
@ -235,23 +239,24 @@ impl Worker {
|
||||
};
|
||||
let cipher_selected = match sym::client_select_cipher(
|
||||
&self.cfg,
|
||||
&dnssec_record.ciphers,
|
||||
&conn_info.resolved.ciphers,
|
||||
) {
|
||||
Some(cipher_selected) => cipher_selected,
|
||||
None => {
|
||||
let _ = send_res.send(Err(
|
||||
let _ = conn_info.answer.send(Err(
|
||||
handshake::Error::Negotiation.into(),
|
||||
));
|
||||
continue 'mainloop;
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: save KeyID
|
||||
let (priv_key, pub_key) =
|
||||
match exchange.new_keypair(&self.rand) {
|
||||
Ok(pair) => pair,
|
||||
Err(_) => {
|
||||
::tracing::error!("Failed to generate keys");
|
||||
let _ = send_res.send(Err(
|
||||
let _ = conn_info.answer.send(Err(
|
||||
handshake::Error::KeyGeneration.into(),
|
||||
));
|
||||
continue 'mainloop;
|
||||
@ -266,7 +271,7 @@ impl Worker {
|
||||
::tracing::warn!(
|
||||
"Could not run the key exchange"
|
||||
);
|
||||
let _ = send_res.send(Err(
|
||||
let _ = conn_info.answer.send(Err(
|
||||
handshake::Error::Negotiation.into(),
|
||||
));
|
||||
continue 'mainloop;
|
||||
@ -279,25 +284,79 @@ impl Worker {
|
||||
// are PubKey::Exchange
|
||||
unreachable!()
|
||||
}
|
||||
let mut conn = Connection::new(
|
||||
hkdf,
|
||||
cipher_selected,
|
||||
connection::Role::Client,
|
||||
&self.rand,
|
||||
);
|
||||
|
||||
let auth_recv_id = self.connections.reserve_first();
|
||||
let service_conn_id = self.connections.reserve_first();
|
||||
conn.id_recv = auth_recv_id;
|
||||
let (client_key_id, hshake) = match self
|
||||
.handshakes
|
||||
.new_client(
|
||||
PrivKey::Exchange(priv_key),
|
||||
PubKey::Exchange(pub_key),
|
||||
conn_info.service_id,
|
||||
service_conn_id,
|
||||
conn,
|
||||
) {
|
||||
Ok((client_key_id, hshake)) => (client_key_id, hshake),
|
||||
Err(_) => {
|
||||
::tracing::warn!("Too many client handshakes");
|
||||
let _ = conn_info.answer.send(Err(
|
||||
handshake::Error::TooManyClientHandshakes
|
||||
.into(),
|
||||
));
|
||||
continue 'mainloop;
|
||||
}
|
||||
};
|
||||
|
||||
// build request
|
||||
/*
|
||||
let auth_info = dirsync::AuthInfo {
|
||||
user: UserID::new_anonymous(),
|
||||
token: Token::new_anonymous(&self.rand),
|
||||
service_id: conn_info.service_id,
|
||||
domain: conn_info.domain,
|
||||
};
|
||||
let req_data = dirsync::ReqData {
|
||||
nonce: dirsync::Nonce::new(&self.rand),
|
||||
client_key_id:
|
||||
client_key_id,
|
||||
id: auth_recv_id.0,
|
||||
auth: auth_info,
|
||||
};
|
||||
let req = dirsync::Req {
|
||||
key_id: key.0,
|
||||
exchange,
|
||||
hkdf,
|
||||
cipher,
|
||||
exchange_key: client_pub_key,
|
||||
data: 42,
|
||||
hkdf: hkdf_selected,
|
||||
cipher: cipher_selected,
|
||||
exchange_key: pub_key,
|
||||
data: dirsync::ReqInner::ClearText(req_data),
|
||||
};
|
||||
*/
|
||||
let mut raw = Vec::<u8>::with_capacity(req.len());
|
||||
req.serialize(
|
||||
cipher_selected.nonce_len(),
|
||||
cipher_selected.tag_len(),
|
||||
&mut raw[..],
|
||||
);
|
||||
// encrypt
|
||||
let encrypt_start = req.encrypted_offset();
|
||||
let encrypt_end = encrypt_start + req.encrypted_length();
|
||||
if let Err(e) = hshake.connection.cipher_send.encrypt(
|
||||
sym::AAD(&[]),
|
||||
&mut raw[encrypt_start..encrypt_end],
|
||||
) {
|
||||
::tracing::error!("Can't encrypt DirSync Request");
|
||||
let _ = conn_info.answer.send(Err(e.into()));
|
||||
continue 'mainloop;
|
||||
}
|
||||
|
||||
// start timeout
|
||||
|
||||
// send packet
|
||||
// send packeti
|
||||
//self.send_packet(raw,
|
||||
|
||||
todo!()
|
||||
}
|
||||
@ -395,15 +454,16 @@ impl Worker {
|
||||
let head_len = req.cipher.nonce_len();
|
||||
let tag_len = req.cipher.tag_len();
|
||||
|
||||
let mut raw_conn = Connection::new(
|
||||
let mut auth_conn = Connection::new(
|
||||
authinfo.hkdf,
|
||||
req.cipher,
|
||||
connection::Role::Server,
|
||||
&self.rand,
|
||||
);
|
||||
raw_conn.id_send = IDSend(req_data.id);
|
||||
auth_conn.id_send = IDSend(req_data.id);
|
||||
// track connection
|
||||
let auth_conn = self.connections.reserve_first(raw_conn);
|
||||
let auth_id_recv = self.connections.reserve_first();
|
||||
auth_conn.id_recv = auth_id_recv;
|
||||
|
||||
let resp_data = dirsync::RespData {
|
||||
client_nonce: req_data.nonce,
|
||||
@ -444,7 +504,7 @@ impl Worker {
|
||||
self.send_packet(raw_out, udp.src, udp.dst).await;
|
||||
return;
|
||||
}
|
||||
HandshakeAction::ClientConnect(mut cci) => {
|
||||
HandshakeAction::ClientConnect(cci) => {
|
||||
let ds_resp;
|
||||
if let HandshakeData::DirSync(DirSync::Resp(resp)) =
|
||||
cci.handshake.data
|
||||
@ -465,17 +525,17 @@ impl Worker {
|
||||
);
|
||||
return;
|
||||
}
|
||||
{
|
||||
let conn = Rc::get_mut(&mut cci.connection).unwrap();
|
||||
conn.id_send = IDSend(resp_data.id);
|
||||
}
|
||||
let mut conn = cci.connection;
|
||||
conn.id_send = IDSend(resp_data.id);
|
||||
let id_recv = conn.id_recv;
|
||||
let cipher = conn.cipher_recv.kind();
|
||||
// track the connection to the authentication server
|
||||
if self.connections.track(cci.connection.clone()).is_err() {
|
||||
self.connections.delete(cci.connection.id_recv);
|
||||
if self.connections.track(Rc::new(conn)).is_err() {
|
||||
::tracing::error!("Could not track new connection");
|
||||
self.connections.delete(id_recv);
|
||||
return;
|
||||
}
|
||||
if cci.connection.id_recv.0
|
||||
== resp_data.service_connection_id
|
||||
{
|
||||
if id_recv.0 == resp_data.service_connection_id {
|
||||
// the user asked a single connection
|
||||
// to the authentication server, without any additional
|
||||
// service. No more connections to setup
|
||||
@ -492,7 +552,7 @@ impl Worker {
|
||||
);
|
||||
let mut service_connection = Connection::new(
|
||||
hkdf,
|
||||
cci.connection.cipher_recv.kind(),
|
||||
cipher,
|
||||
connection::Role::Client,
|
||||
&self.rand,
|
||||
);
|
||||
|
24
src/lib.rs
24
src/lib.rs
@ -22,17 +22,16 @@ mod inner;
|
||||
|
||||
use ::std::{sync::Arc, vec::Vec};
|
||||
use ::tokio::{net::UdpSocket, sync::Mutex};
|
||||
use auth::ServiceID;
|
||||
|
||||
use crate::{
|
||||
auth::TokenChecker,
|
||||
auth::{Domain, ServiceID, TokenChecker},
|
||||
connection::{
|
||||
handshake,
|
||||
socket::{SocketList, UdpClient, UdpServer},
|
||||
AuthServerConnections, Packet,
|
||||
},
|
||||
inner::{
|
||||
worker::{RawUdp, Work, Worker},
|
||||
worker::{ConnectInfo, RawUdp, Work, Worker},
|
||||
ThreadTracker,
|
||||
},
|
||||
};
|
||||
@ -62,6 +61,9 @@ pub enum Error {
|
||||
/// Resolution problems. wrong or incomplete DNSSEC data
|
||||
#[error("DNSSEC resolution: {0}")]
|
||||
Resolution(String),
|
||||
/// Wrapper on encryption errors
|
||||
#[error("Encrypt: {0}")]
|
||||
Encrypt(enc::Error),
|
||||
}
|
||||
|
||||
/// Instance of a fenrir endpoint
|
||||
@ -232,7 +234,7 @@ impl Fenrir {
|
||||
Ok(())
|
||||
}
|
||||
/// Get the raw TXT record of a Fenrir domain
|
||||
pub async fn resolv_txt(&self, domain: &str) -> Result<String, Error> {
|
||||
pub async fn resolv_txt(&self, domain: &Domain) -> Result<String, Error> {
|
||||
match &self.dnssec {
|
||||
Some(dnssec) => Ok(dnssec.resolv(domain).await?),
|
||||
None => Err(Error::NotInitialized),
|
||||
@ -240,7 +242,10 @@ impl Fenrir {
|
||||
}
|
||||
|
||||
/// Get the raw TXT record of a Fenrir domain
|
||||
pub async fn resolv(&self, domain: &str) -> Result<dnssec::Record, Error> {
|
||||
pub async fn resolv(
|
||||
&self,
|
||||
domain: &Domain,
|
||||
) -> Result<dnssec::Record, Error> {
|
||||
let record_str = self.resolv_txt(domain).await?;
|
||||
Ok(dnssec::Dnssec::parse_txt_record(&record_str)?)
|
||||
}
|
||||
@ -248,7 +253,7 @@ impl Fenrir {
|
||||
/// Connect to a service
|
||||
pub async fn connect(
|
||||
&self,
|
||||
domain: &str,
|
||||
domain: &Domain,
|
||||
service: ServiceID,
|
||||
) -> Result<(), Error> {
|
||||
let resolved = self.resolv(domain).await?;
|
||||
@ -310,7 +315,12 @@ impl Fenrir {
|
||||
// and tell that thread to connect somewhere
|
||||
let (send, recv) = ::tokio::sync::oneshot::channel();
|
||||
let _ = self._thread_work[thread_idx]
|
||||
.send(Work::Connect((send, resolved.clone(), service)))
|
||||
.send(Work::Connect(ConnectInfo {
|
||||
answer: send,
|
||||
resolved: resolved.clone(),
|
||||
service_id: service,
|
||||
domain: domain.clone(),
|
||||
}))
|
||||
.await;
|
||||
|
||||
match recv.await {
|
||||
|
Loading…
Reference in New Issue
Block a user