More work on connect(), use our own Random

We use :💍:rand::SystemRandom, but we need to wrap it
for a couple of traits needed by ::x25519_dalek

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-05-30 10:52:54 +02:00
parent a3430f1813
commit c6a3bf0820
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
11 changed files with 173 additions and 37 deletions

View File

@ -39,6 +39,7 @@ hwloc2 = {version = "2.2" }
libc = { version = "0.2" } libc = { version = "0.2" }
num-traits = { version = "0.2" } num-traits = { version = "0.2" }
num-derive = { version = "0.3" } num-derive = { version = "0.3" }
rand_core = {version = "0.6" }
ring = { version = "0.16" } ring = { version = "0.16" }
bincode = { version = "1.3" } bincode = { version = "1.3" }
sha3 = { version = "0.10" } sha3 = { version = "0.10" }

View File

@ -1,6 +1,6 @@
//! Authentication related struct definitions //! Authentication related struct definitions
use ::ring::rand::SecureRandom; use crate::enc::Random;
use ::zeroize::Zeroize; use ::zeroize::Zeroize;
/// User identifier. 16 bytes for easy uuid conversion /// User identifier. 16 bytes for easy uuid conversion
@ -15,7 +15,7 @@ impl From<[u8; 16]> for UserID {
impl UserID { impl UserID {
/// New random user id /// New random user id
pub fn new(rand: &::ring::rand::SystemRandom) -> Self { pub fn new(rand: &Random) -> Self {
let mut ret = Self([0; 16]); let mut ret = Self([0; 16]);
rand.fill(&mut ret.0); rand.fill(&mut ret.0);
ret ret

View File

@ -39,6 +39,7 @@ pub(crate) struct HandshakeClient {
pub service_id: crate::auth::ServiceID, pub service_id: crate::auth::ServiceID,
pub service_conn_id: connection::IDRecv, pub service_conn_id: connection::IDRecv,
pub connection: Rc<crate::connection::Connection>, pub connection: Rc<crate::connection::Connection>,
pub timeout: Rc<u32>,
} }
/// Parsed handshake /// Parsed handshake

View File

@ -17,6 +17,7 @@ use crate::{
asym::PubKey, asym::PubKey,
hkdf::HkdfSha3, hkdf::HkdfSha3,
sym::{CipherKind, CipherRecv, CipherSend}, sym::{CipherKind, CipherRecv, CipherSend},
Random,
}, },
inner::ThreadTracker, inner::ThreadTracker,
}; };
@ -78,7 +79,7 @@ impl Connection {
hkdf: HkdfSha3, hkdf: HkdfSha3,
cipher: CipherKind, cipher: CipherKind,
role: Role, role: Role,
rand: &::ring::rand::SystemRandom, rand: &Random,
) -> Self { ) -> Self {
let (secret_recv, secret_send) = match role { let (secret_recv, secret_send) = match role {
Role::Server => { Role::Server => {

View File

@ -1,7 +1,10 @@
// //
//! Raw packet handling, encryption, decryption, parsing //! Raw packet handling, encryption, decryption, parsing
use crate::enc::sym::{HeadLen, TagLen}; use crate::enc::{
sym::{HeadLen, TagLen},
Random,
};
/// Fenrir Connection id /// Fenrir Connection id
/// 0 is special as it represents the handshake /// 0 is special as it represents the handshake
@ -33,8 +36,7 @@ impl ConnectionID {
} }
} }
/// New random service ID /// New random service ID
pub fn new_rand(rand: &::ring::rand::SystemRandom) -> Self { pub fn new_rand(rand: &Random) -> Self {
use ::ring::rand::SecureRandom;
let mut raw = [0; 8]; let mut raw = [0; 8];
let mut num = 0; let mut num = 0;
while num == 0 { while num == 0 {
@ -100,7 +102,7 @@ impl PacketData {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { match self {
PacketData::Handshake(h) => h.len(), PacketData::Handshake(h) => h.len(),
PacketData::Raw(len) => *len PacketData::Raw(len) => *len,
} }
} }
/// serialize data into bytes /// serialize data into bytes

View File

@ -32,7 +32,7 @@ use ::std::{net::IpAddr, vec::Vec};
*/ */
/// Public Key ID /// Public Key ID
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
pub struct PublicKeyID(u8); pub struct PublicKeyID(u8);
impl TryFrom<&str> for PublicKeyID { impl TryFrom<&str> for PublicKeyID {

View File

@ -3,7 +3,7 @@
use ::num_traits::FromPrimitive; use ::num_traits::FromPrimitive;
use super::Error; use super::Error;
use crate::enc::sym::Secret; use crate::enc::{sym::Secret, Random};
/// Public key ID /// Public key ID
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
@ -72,6 +72,7 @@ impl KeyKind {
/// Kind of key exchange /// Kind of key exchange
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
#[non_exhaustive]
#[repr(u8)] #[repr(u8)]
pub enum KeyExchange { pub enum KeyExchange {
/// X25519 Public key /// X25519 Public key
@ -82,6 +83,23 @@ impl KeyExchange {
pub fn len() -> usize { pub fn len() -> usize {
1 1
} }
/// Build a new keypair for key exchange
pub fn new_keypair(
&self,
rnd: &Random,
) -> Result<(ExchangePrivKey, ExchangePubKey), Error> {
match self {
KeyExchange::X25519DiffieHellman => {
let raw_priv = ::x25519_dalek::StaticSecret::new(rnd);
let pub_key = ExchangePubKey::X25519(
::x25519_dalek::PublicKey::from(&raw_priv),
);
let priv_key = ExchangePrivKey::X25519(raw_priv);
Ok((priv_key, pub_key))
}
_ => Err(Error::UnsupportedKeyExchange),
}
}
} }
/// Kind of public key in the handshake /// Kind of public key in the handshake
@ -162,6 +180,7 @@ pub enum PrivKey {
/// Keys to be used only in key exchanges, not for signing /// Keys to be used only in key exchanges, not for signing
Exchange(ExchangePrivKey), Exchange(ExchangePrivKey),
/// Keys to be used only for signing /// Keys to be used only for signing
// TODO: implement ed25519
Signing, Signing,
} }
@ -259,3 +278,8 @@ impl ExchangePubKey {
} }
} }
} }
/// Build a new pair of private/public key pair
pub fn new_keypair(kind: KeyKind, rnd: &Random) -> (PrivKey, PubKey) {
todo!()
}

View File

@ -6,3 +6,69 @@ pub mod hkdf;
pub mod sym; pub mod sym;
pub use errors::Error; pub use errors::Error;
use ::ring::rand::SecureRandom;
/// wrapper where we implement whatever random traint stuff each library needs
pub struct Random {
/// actual source of randomness
rnd: ::ring::rand::SystemRandom,
}
impl Random {
/// Build a nre Random source
pub fn new() -> Self {
Self {
rnd: ::ring::rand::SystemRandom::new(),
}
}
/// Fill a buffer with randomness
pub fn fill(&self, out: &mut [u8]) {
self.rnd.fill(out);
}
}
// Fake debug implementation to avoid leaking secrets
impl ::core::fmt::Debug for Random {
fn fmt(
&self,
f: &mut core::fmt::Formatter<'_>,
) -> Result<(), ::std::fmt::Error> {
::core::fmt::Debug::fmt("[hidden randomness]", f)
}
}
// ::rand_core::{RngCore, CryptoRng} needed for ::x25519::dalek
impl ::rand_core::RngCore for &Random {
fn next_u32(&mut self) -> u32 {
use ::core::mem::MaybeUninit;
let mut out: MaybeUninit<[u8; 4]> = MaybeUninit::uninit();
#[allow(unsafe_code)]
unsafe {
let _ = self.rnd.fill(out.assume_init_mut());
u32::from_le_bytes(out.assume_init())
}
}
fn next_u64(&mut self) -> u64 {
use ::core::mem::MaybeUninit;
let mut out: MaybeUninit<[u8; 8]> = MaybeUninit::uninit();
#[allow(unsafe_code)]
unsafe {
let _ = self.rnd.fill(out.assume_init_mut());
u64::from_le_bytes(out.assume_init())
}
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
let _ = self.rnd.fill(dest);
}
fn try_fill_bytes(
&mut self,
dest: &mut [u8],
) -> Result<(), ::rand_core::Error> {
match self.rnd.fill(dest) {
Ok(()) => Ok(()),
Err(e) => Err(::rand_core::Error::new(e)),
}
}
}
impl ::rand_core::CryptoRng for &Random {}

View File

@ -1,6 +1,7 @@
//! Symmetric cypher stuff //! Symmetric cypher stuff
use super::Error; use super::Error;
use crate::enc::Random;
use ::zeroize::Zeroize; use ::zeroize::Zeroize;
/// Secret, used for keys. /// Secret, used for keys.
@ -20,8 +21,7 @@ impl ::core::fmt::Debug for Secret {
impl Secret { impl Secret {
/// New randomly generated secret /// New randomly generated secret
pub fn new_rand(rand: &::ring::rand::SystemRandom) -> Self { pub fn new_rand(rand: &Random) -> Self {
use ::ring::rand::SecureRandom;
let mut ret = Self([0; 32]); let mut ret = Self([0; 32]);
rand.fill(&mut ret.0); rand.fill(&mut ret.0);
ret ret
@ -265,11 +265,7 @@ impl ::core::fmt::Debug for CipherSend {
impl CipherSend { impl CipherSend {
/// Build a new Cipher /// Build a new Cipher
pub fn new( pub fn new(kind: CipherKind, secret: Secret, rand: &Random) -> Self {
kind: CipherKind,
secret: Secret,
rand: &::ring::rand::SystemRandom,
) -> Self {
Self { Self {
nonce: NonceSync::new(rand), nonce: NonceSync::new(rand),
cipher: Cipher::new(kind, secret), cipher: Cipher::new(kind, secret),
@ -335,8 +331,7 @@ impl ::core::fmt::Debug for Nonce {
impl Nonce { impl Nonce {
/// Generate a new random Nonce /// Generate a new random Nonce
pub fn new(rand: &::ring::rand::SystemRandom) -> Self { pub fn new(rand: &Random) -> Self {
use ring::rand::SecureRandom;
let mut raw = [0; 12]; let mut raw = [0; 12];
rand.fill(&mut raw); rand.fill(&mut raw);
Self { raw } Self { raw }
@ -376,7 +371,7 @@ pub struct NonceSync {
} }
impl NonceSync { impl NonceSync {
/// Create a new thread safe nonce /// Create a new thread safe nonce
pub fn new(rand: &::ring::rand::SystemRandom) -> Self { pub fn new(rand: &Random) -> Self {
Self { Self {
nonce: ::std::sync::Mutex::new(Nonce::new(rand)), nonce: ::std::sync::Mutex::new(Nonce::new(rand)),
} }

View File

@ -11,7 +11,7 @@ use crate::{
ConnList, Connection, IDSend, Packet, ConnList, Connection, IDSend, Packet,
}, },
dnssec, dnssec,
enc::{asym::PubKey, hkdf::HkdfSha3, sym::Secret}, enc::{asym::PubKey, hkdf::HkdfSha3, sym::Secret, Random},
inner::{HandshakeAction, HandshakeTracker, ThreadTracker}, inner::{HandshakeAction, HandshakeTracker, ThreadTracker},
}; };
use ::std::{rc::Rc, sync::Arc, vec::Vec}; use ::std::{rc::Rc, sync::Arc, vec::Vec};
@ -29,16 +29,17 @@ pub(crate) struct RawUdp {
pub packet: Packet, pub packet: Packet,
} }
pub(crate) enum ConnectionResult {
Failed(crate::Error),
Established((PubKey, IDSend)),
}
pub(crate) enum Work { pub(crate) enum Work {
/// ask the thread to report to the main thread the total number of /// ask the thread to report to the main thread the total number of
/// connections present /// connections present
CountConnections(oneshot::Sender<usize>), CountConnections(oneshot::Sender<usize>),
Connect((oneshot::Sender<ConnectionResult>, dnssec::Record, ServiceID)), Connect(
(
oneshot::Sender<Result<(PubKey, IDSend), crate::Error>>,
dnssec::Record,
ServiceID,
),
),
Recv(RawUdp), Recv(RawUdp),
} }
pub(crate) enum WorkAnswer { pub(crate) enum WorkAnswer {
@ -49,7 +50,7 @@ pub(crate) enum WorkAnswer {
pub(crate) struct Worker { pub(crate) struct Worker {
thread_id: ThreadTracker, thread_id: ThreadTracker,
// PERF: rand uses syscalls. how to do that async? // PERF: rand uses syscalls. how to do that async?
rand: ::ring::rand::SystemRandom, rand: Random,
stop_working: ::tokio::sync::broadcast::Receiver<bool>, stop_working: ::tokio::sync::broadcast::Receiver<bool>,
token_check: Option<Arc<Mutex<TokenChecker>>>, token_check: Option<Arc<Mutex<TokenChecker>>>,
sockets: Vec<UdpSocket>, sockets: Vec<UdpSocket>,
@ -121,7 +122,7 @@ impl Worker {
Ok(Self { Ok(Self {
thread_id, thread_id,
rand: ::ring::rand::SystemRandom::new(), rand: Random::new(),
stop_working, stop_working,
token_check, token_check,
sockets, sockets,
@ -132,7 +133,7 @@ impl Worker {
}) })
} }
pub(crate) async fn work_loop(&mut self) { pub(crate) async fn work_loop(&mut self) {
loop { 'mainloop: loop {
let work = ::tokio::select! { let work = ::tokio::select! {
_done = self.stop_working.recv() => { _done = self.stop_working.recv() => {
break; break;
@ -149,7 +150,51 @@ impl Worker {
let conn_num = self.connections.len(); let conn_num = self.connections.len();
let _ = sender.send(conn_num); let _ = sender.send(conn_num);
} }
Work::Connect((send_res, dnssec_record, service_id)) => { Work::Connect((send_res, dnssec_record, _service_id)) => {
let destination =
dnssec_record.addresses.iter().find_map(|addr| {
let maybe_key =
dnssec_record.public_keys.iter().find(
|(id, _)| addr.public_key_ids.contains(id),
);
match maybe_key {
Some(key) => Some((addr, key)),
None => None,
}
});
let (addr, key) = match destination {
Some((addr, key)) => (addr, key),
None => {
let _ =
send_res.send(Err(crate::Error::Resolution(
"No selectable address and key combination"
.to_owned(),
)));
continue 'mainloop;
}
};
use crate::enc::asym;
let exchange = asym::KeyExchange::X25519DiffieHellman;
let (priv_key, pub_key) =
match exchange.new_keypair(&self.rand) {
Ok(pair) => pair,
Err(_) => todo!(),
};
// build request
/*
let req = dirsync::Req {
key_id: key.0,
exchange: exchange,
cipher: 42,
exchange_key: client_pub_key,
data: 42,
};
*/
// start timeout
// send packet
todo!() todo!()
} }
//TODO: reconf message to add channels //TODO: reconf message to add channels

View File

@ -59,6 +59,9 @@ pub enum Error {
/// Key error /// Key error
#[error("key: {0:?}")] #[error("key: {0:?}")]
Key(#[from] crate::enc::Error), Key(#[from] crate::enc::Error),
/// Resolution problems. wrong or incomplete DNSSEC data
#[error("DNSSEC resolution: {0}")]
Resolution(String),
} }
/// Instance of a fenrir endpoint /// Instance of a fenrir endpoint
@ -199,7 +202,7 @@ impl Fenrir {
// we very likely have multiple threads, pinned to different cpus. // we very likely have multiple threads, pinned to different cpus.
// use the ConnectionID to send the same connection // use the ConnectionID to send the same connection
// to the same thread. // to the same thread.
// Handshakes have conenction ID 0, so we use the sender's UDP port // Handshakes have connection ID 0, so we use the sender's UDP port
let packet = match Packet::deserialize_id(&data) { let packet = match Packet::deserialize_id(&data) {
Ok(packet) => packet, Ok(packet) => packet,
@ -266,7 +269,7 @@ impl Fenrir {
continue; continue;
} }
Reservation::Reserved => break, Reservation::Reserved => break,
Reservation::Present(id_send) => { Reservation::Present(_id_send) => {
//TODO: reuse connection //TODO: reuse connection
todo!() todo!()
} }
@ -275,7 +278,6 @@ impl Fenrir {
// Spot reserved for the connection // Spot reserved for the connection
// find the thread with less connections // find the thread with less connections
let th_num = self._thread_work.len(); let th_num = self._thread_work.len();
let mut conn_count = Vec::<usize>::with_capacity(th_num); let mut conn_count = Vec::<usize>::with_capacity(th_num);
let mut wait_res = let mut wait_res =
@ -313,15 +315,14 @@ impl Fenrir {
match recv.await { match recv.await {
Ok(res) => { Ok(res) => {
use crate::inner::worker::ConnectionResult;
match res { match res {
ConnectionResult::Failed(e) => { Err(e) => {
let mut conn_auth_lock = let mut conn_auth_lock =
self.conn_auth_srv.lock().await; self.conn_auth_srv.lock().await;
conn_auth_lock.remove_reserved(&resolved); conn_auth_lock.remove_reserved(&resolved);
Err(e) Err(e)
} }
ConnectionResult::Established((pubkey, id_send)) => { Ok((pubkey, id_send)) => {
let mut conn_auth_lock = let mut conn_auth_lock =
self.conn_auth_srv.lock().await; self.conn_auth_srv.lock().await;
conn_auth_lock.add(&pubkey, id_send, &resolved); conn_auth_lock.add(&pubkey, id_send, &resolved);