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" }
num-traits = { version = "0.2" }
num-derive = { version = "0.3" }
rand_core = {version = "0.6" }
ring = { version = "0.16" }
bincode = { version = "1.3" }
sha3 = { version = "0.10" }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
use ::num_traits::FromPrimitive;
use super::Error;
use crate::enc::sym::Secret;
use crate::enc::{sym::Secret, Random};
/// Public key ID
#[derive(Debug, Copy, Clone, PartialEq)]
@ -72,6 +72,7 @@ impl KeyKind {
/// Kind of key exchange
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum KeyExchange {
/// X25519 Public key
@ -82,6 +83,23 @@ impl KeyExchange {
pub fn len() -> usize {
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
@ -162,6 +180,7 @@ pub enum PrivKey {
/// Keys to be used only in key exchanges, not for signing
Exchange(ExchangePrivKey),
/// Keys to be used only for signing
// TODO: implement ed25519
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 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
use super::Error;
use crate::enc::Random;
use ::zeroize::Zeroize;
/// Secret, used for keys.
@ -20,8 +21,7 @@ impl ::core::fmt::Debug for Secret {
impl Secret {
/// New randomly generated secret
pub fn new_rand(rand: &::ring::rand::SystemRandom) -> Self {
use ::ring::rand::SecureRandom;
pub fn new_rand(rand: &Random) -> Self {
let mut ret = Self([0; 32]);
rand.fill(&mut ret.0);
ret
@ -265,11 +265,7 @@ impl ::core::fmt::Debug for CipherSend {
impl CipherSend {
/// Build a new Cipher
pub fn new(
kind: CipherKind,
secret: Secret,
rand: &::ring::rand::SystemRandom,
) -> Self {
pub fn new(kind: CipherKind, secret: Secret, rand: &Random) -> Self {
Self {
nonce: NonceSync::new(rand),
cipher: Cipher::new(kind, secret),
@ -335,8 +331,7 @@ impl ::core::fmt::Debug for Nonce {
impl Nonce {
/// Generate a new random Nonce
pub fn new(rand: &::ring::rand::SystemRandom) -> Self {
use ring::rand::SecureRandom;
pub fn new(rand: &Random) -> Self {
let mut raw = [0; 12];
rand.fill(&mut raw);
Self { raw }
@ -376,7 +371,7 @@ pub struct NonceSync {
}
impl NonceSync {
/// Create a new thread safe nonce
pub fn new(rand: &::ring::rand::SystemRandom) -> Self {
pub fn new(rand: &Random) -> Self {
Self {
nonce: ::std::sync::Mutex::new(Nonce::new(rand)),
}

View File

@ -11,7 +11,7 @@ use crate::{
ConnList, Connection, IDSend, Packet,
},
dnssec,
enc::{asym::PubKey, hkdf::HkdfSha3, sym::Secret},
enc::{asym::PubKey, hkdf::HkdfSha3, sym::Secret, Random},
inner::{HandshakeAction, HandshakeTracker, ThreadTracker},
};
use ::std::{rc::Rc, sync::Arc, vec::Vec};
@ -29,16 +29,17 @@ pub(crate) struct RawUdp {
pub packet: Packet,
}
pub(crate) enum ConnectionResult {
Failed(crate::Error),
Established((PubKey, IDSend)),
}
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<ConnectionResult>, dnssec::Record, ServiceID)),
Connect(
(
oneshot::Sender<Result<(PubKey, IDSend), crate::Error>>,
dnssec::Record,
ServiceID,
),
),
Recv(RawUdp),
}
pub(crate) enum WorkAnswer {
@ -49,7 +50,7 @@ pub(crate) enum WorkAnswer {
pub(crate) struct Worker {
thread_id: ThreadTracker,
// PERF: rand uses syscalls. how to do that async?
rand: ::ring::rand::SystemRandom,
rand: Random,
stop_working: ::tokio::sync::broadcast::Receiver<bool>,
token_check: Option<Arc<Mutex<TokenChecker>>>,
sockets: Vec<UdpSocket>,
@ -121,7 +122,7 @@ impl Worker {
Ok(Self {
thread_id,
rand: ::ring::rand::SystemRandom::new(),
rand: Random::new(),
stop_working,
token_check,
sockets,
@ -132,7 +133,7 @@ impl Worker {
})
}
pub(crate) async fn work_loop(&mut self) {
loop {
'mainloop: loop {
let work = ::tokio::select! {
_done = self.stop_working.recv() => {
break;
@ -149,7 +150,51 @@ impl Worker {
let conn_num = self.connections.len();
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: reconf message to add channels

View File

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