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:
parent
a3430f1813
commit
c6a3bf0820
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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
|
||||
|
@ -134,7 +136,7 @@ pub struct Packet {
|
|||
|
||||
impl Packet {
|
||||
/// New recevied packet, yet unparsed
|
||||
pub fn deserialize_id(raw: &[u8]) -> Result<Self,()> {
|
||||
pub fn deserialize_id(raw: &[u8]) -> Result<Self, ()> {
|
||||
// TODO: proper min_packet length. 16 is too conservative.
|
||||
if raw.len() < MIN_PACKET_BYTES {
|
||||
return Err(());
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue