More work on handshake. obviously unfinished

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-02-16 19:11:45 +01:00
parent e3af78eaba
commit 238a0a5516
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
10 changed files with 422 additions and 98 deletions

View File

@ -26,6 +26,7 @@ crate_type = [ "lib", "cdylib", "staticlib" ]
[dependencies] [dependencies]
# please keep these in alphabetical order # please keep these in alphabetical order
arc-swap = { version = "^1.6" }
# base85 repo has no tags, fix on a commit. v1.1.1 points to older, wrong version # base85 repo has no tags, fix on a commit. v1.1.1 points to older, wrong version
base85 = { git = "https://gitlab.com/darkwyrm/base85", rev = "d98efbfd171dd9ba48e30a5c88f94db92fc7b3c6" } base85 = { git = "https://gitlab.com/darkwyrm/base85", rev = "d98efbfd171dd9ba48e30a5c88f94db92fc7b3c6" }
futures = { version = "^0.3" } futures = { version = "^0.3" }
@ -33,6 +34,7 @@ libc = { version = "^0.2" }
num-traits = { version = "^0.2" } num-traits = { version = "^0.2" }
num-derive = { version = "^0.3" } num-derive = { version = "^0.3" }
ring = { version = "^0.16" } ring = { version = "^0.16" }
bincode = { version = "^1.3" }
strum = { version = "^0.24" } strum = { version = "^0.24" }
strum_macros = { version = "^0.24" } strum_macros = { version = "^0.24" }
thiserror = { version = "^1.0" } thiserror = { version = "^1.0" }
@ -43,6 +45,7 @@ tracing = { version = "^0.1" }
trust-dns-resolver = { version = "^0.22", features = [ "dnssec-ring" ] } trust-dns-resolver = { version = "^0.22", features = [ "dnssec-ring" ] }
trust-dns-client = { version = "^0.22", features = [ "dnssec" ] } trust-dns-client = { version = "^0.22", features = [ "dnssec" ] }
trust-dns-proto = { version = "^0.22" } trust-dns-proto = { version = "^0.22" }
x25519-dalek = { version = "^1.2", features = [ "serde" ] }
[profile.dev] [profile.dev]

View File

@ -9,7 +9,10 @@
//! change the DNSSEC public/private keys //! change the DNSSEC public/private keys
use super::{Error, HandshakeData}; use super::{Error, HandshakeData};
use crate::connection::{KeyID, UnparsedExchangePubKey, ID}; use crate::{
connection::ID,
enc::asym::{ExchangePubKey, KeyID},
};
use ::std::vec::Vec; use ::std::vec::Vec;
/// Parsed handshake /// Parsed handshake
@ -25,11 +28,11 @@ pub enum DirSync {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Req { pub struct Req {
/// Id of the server key used for the key exchange /// Id of the server key used for the key exchange
key_id: KeyID, pub key_id: KeyID,
/// Client ephemeral public key used for key exchanges /// Client ephemeral public key used for key exchanges
exchange_key: UnparsedExchangePubKey, pub exchange_key: ExchangePubKey,
/// encrypted data /// encrypted data
enc: Vec<u8>, pub enc: Vec<u8>,
} }
impl super::HandshakeParsing for Req { impl super::HandshakeParsing for Req {
@ -40,11 +43,10 @@ impl super::HandshakeParsing for Req {
} }
let key_id: KeyID = let key_id: KeyID =
KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap())); KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap()));
let (exchange_key, len) = let (exchange_key, len) = match ExchangePubKey::from_slice(&raw[2..]) {
match UnparsedExchangePubKey::from_raw(&raw[2..]) { Ok(exchange_key) => exchange_key,
Ok(exchange_key) => exchange_key, Err(e) => return Err(e.into()),
Err(e) => return Err(e), };
};
let enc = raw[(2 + len)..].to_vec(); let enc = raw[(2 + len)..].to_vec();
Ok(HandshakeData::DirSync(DirSync::Req(Self { Ok(HandshakeData::DirSync(DirSync::Req(Self {
key_id, key_id,
@ -58,13 +60,13 @@ impl super::HandshakeParsing for Req {
#[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
nonce: [u8; 16], pub nonce: [u8; 16],
/// Client key id so the client can use and rotate keys /// Client key id so the client can use and rotate keys
client_key_id: KeyID, pub client_key_id: KeyID,
/// Authentication token /// Authentication token
token: [u8; 32], pub token: [u8; 32],
/// Receiving connection id for the client /// Receiving connection id for the client
id: ID, pub id: ID,
// TODO: service info // TODO: service info
} }
@ -72,9 +74,9 @@ pub struct ReqData {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Resp { pub struct Resp {
/// Tells the client with which key the exchange was done /// Tells the client with which key the exchange was done
client_key_id: KeyID, pub client_key_id: KeyID,
/// encrypted data /// encrypted data
enc: Vec<u8>, pub enc: Vec<u8>,
} }
impl super::HandshakeParsing for Resp { impl super::HandshakeParsing for Resp {

View File

@ -4,7 +4,7 @@ pub mod dirsync;
use ::num_traits::FromPrimitive; use ::num_traits::FromPrimitive;
use crate::connection::ProtocolVersion; use crate::connection::{self, ProtocolVersion};
/// Handshake errors /// Handshake errors
#[derive(::thiserror::Error, Debug, Copy, Clone)] #[derive(::thiserror::Error, Debug, Copy, Clone)]
@ -13,11 +13,22 @@ pub enum Error {
/// TODO: more detailed parsing errors /// TODO: more detailed parsing errors
#[error("not an handshake packet")] #[error("not an handshake packet")]
Parsing, Parsing,
/// No such Key ID
#[error("unknown key id")]
UnknownKeyID,
/// Key error
#[error("key: {0:?}")]
Key(#[from] crate::enc::Error),
/// Not enough data /// Not enough data
#[error("not enough data")] #[error("not enough data")]
NotEnoughData, NotEnoughData,
} }
pub(crate) struct HandshakeKey {
pub id: crate::enc::asym::KeyID,
pub key: crate::enc::asym::PrivKey,
}
/// Parsed handshake /// Parsed handshake
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum HandshakeData { pub enum HandshakeData {
@ -49,9 +60,9 @@ pub enum Kind {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Handshake { pub struct Handshake {
/// Fenrir Protocol version /// Fenrir Protocol version
fenrir_version: ProtocolVersion, pub fenrir_version: ProtocolVersion,
/// enum for the parsed data /// enum for the parsed data
data: HandshakeData, pub data: HandshakeData,
} }
impl Handshake { impl Handshake {
@ -69,11 +80,16 @@ impl Handshake {
Some(handshake_kind) => handshake_kind, Some(handshake_kind) => handshake_kind,
None => return Err(Error::Parsing), None => return Err(Error::Parsing),
}; };
let parsed = match handshake_kind { let data = match handshake_kind {
Kind::DirSyncReq => dirsync::Req::parse(&raw[2..])?, Kind::DirSyncReq => dirsync::Req::parse(&raw[2..])?,
Kind::DirSyncResp => dirsync::Resp::parse(&raw[2..])?, Kind::DirSyncResp => dirsync::Resp::parse(&raw[2..])?,
}; };
Ok(Self {
fenrir_version,
data,
})
}
pub(crate) fn work(&self, keys: &[HandshakeKey]) -> Result<(), Error> {
todo!() todo!()
} }
} }

View File

@ -10,10 +10,6 @@ pub use handshake::Handshake;
pub use packet::ConnectionID as ID; pub use packet::ConnectionID as ID;
pub use packet::Packet; pub use packet::Packet;
/// Public key ID
#[derive(Debug, Copy, Clone)]
pub struct KeyID(u16);
/// Version of the fenrir protocol in use /// Version of the fenrir protocol in use
#[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)] #[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)]
#[repr(u8)] #[repr(u8)]
@ -21,54 +17,3 @@ pub enum ProtocolVersion {
/// First Fenrir Protocol Version /// First Fenrir Protocol Version
V0 = 0, V0 = 0,
} }
/// Kind of key in the key exchange
#[derive(Debug, Copy, Clone, ::num_derive::FromPrimitive)]
#[repr(u8)]
pub enum ExchangePubKeyKind {
/// X25519 Public key
X25519 = 0,
}
/// all Ephemeral Public key types
#[derive(Debug, Clone)]
pub enum ExchangePubKey {
/// X25519(Curve25519) used for key exchange
X25519(Vec<u8>),
}
/// Mark the Ephemeral key as yet unparsed, meaning it could be
/// maliciously currupted data
#[derive(Debug, Clone)]
pub struct UnparsedExchangePubKey(ExchangePubKey);
impl UnparsedExchangePubKey {
/// Load public key used for key exchange from it raw bytes
/// The riesult is "unparsed" since we don't verify
/// the actual key
pub fn from_raw(raw: &[u8]) -> Result<(Self, usize), handshake::Error> {
// FIXME: get *real* minimum key size
const MIN_KEY_SIZE: usize = 8;
if raw.len() < 1 + MIN_KEY_SIZE {
return Err(handshake::Error::NotEnoughData);
}
match ExchangePubKeyKind::from_u8(raw[0]) {
Some(kind) => match kind {
ExchangePubKeyKind::X25519 => {
// FIXME: is this really the
const len: usize =
1 + ::ring::signature::ED25519_PUBLIC_KEY_LEN;
Ok((
UnparsedExchangePubKey(ExchangePubKey::X25519(
raw[1..len].to_vec(),
)),
len,
))
}
},
None => {
return Err(handshake::Error::Parsing);
}
}
}
}

View File

@ -33,13 +33,13 @@ use ::std::{net::IpAddr, vec::Vec};
/// Public Key ID /// Public Key ID
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct PublicKeyId(u8); pub struct PublicKeyID(u8);
impl TryFrom<&str> for PublicKeyId { impl TryFrom<&str> for PublicKeyID {
type Error = ::std::io::Error; type Error = ::std::io::Error;
fn try_from(raw: &str) -> Result<Self, Self::Error> { fn try_from(raw: &str) -> Result<Self, Self::Error> {
if let Ok(id_u8) = raw.parse::<u8>() { if let Ok(id_u8) = raw.parse::<u8>() {
return Ok(PublicKeyId(id_u8)); return Ok(PublicKeyID(id_u8));
} }
return Err(::std::io::Error::new( return Err(::std::io::Error::new(
::std::io::ErrorKind::InvalidData, ::std::io::ErrorKind::InvalidData,
@ -95,7 +95,7 @@ pub struct PublicKey {
/// type of public key /// type of public key
pub kind: PublicKeyType, pub kind: PublicKeyType,
/// id of public key /// id of public key
pub id: PublicKeyId, pub id: PublicKeyID,
} }
impl PublicKey { impl PublicKey {
@ -114,7 +114,7 @@ impl PublicKey {
} }
let kind = PublicKeyType::from_u8(raw[0]).unwrap(); let kind = PublicKeyType::from_u8(raw[0]).unwrap();
let id = PublicKeyId(raw[1]); let id = PublicKeyID(raw[1]);
if raw.len() < 2 + kind.key_len() { if raw.len() < 2 + kind.key_len() {
return Err(Error::NotEnoughData(2)); return Err(Error::NotEnoughData(2));
} }
@ -230,12 +230,45 @@ impl TryFrom<&str> for AddressWeight {
} }
} }
/// List of possible handshakes
#[derive(::num_derive::FromPrimitive, Debug, Clone, Copy)]
#[repr(u8)]
pub enum HandshakeID {
/// 1-RTT Directory synchronized handshake. Fast, no forward secrecy
DirectorySynchronized = 0,
/// 2-RTT Stateful exchange. Little DDos protection
Stateful,
/// 3-RTT stateless exchange. Forward secrecy and ddos protection
Stateless,
}
impl TryFrom<&str> for HandshakeID {
type Error = ::std::io::Error;
// TODO: from actual names, not only numeric
fn try_from(raw: &str) -> Result<Self, Self::Error> {
if let Ok(handshake_u8) = raw.parse::<u8>() {
if handshake_u8 >= 1 {
if let Some(handshake) = HandshakeID::from_u8(handshake_u8 - 1)
{
return Ok(handshake);
}
}
}
return Err(::std::io::Error::new(
::std::io::ErrorKind::InvalidData,
"Unknown handshake ID",
));
}
}
/// Authentication server address information: /// Authentication server address information:
/// * ip /// * ip
/// * udp port /// * udp port
/// * priority /// * priority
/// * weight within priority /// * weight within priority
#[derive(Debug, Clone, Copy)] /// * list of supported handshakes IDs
/// * list of public keys IDs
#[derive(Debug, Clone)]
pub struct Address { pub struct Address {
/// Ip address of server, v4 or v6 /// Ip address of server, v4 or v6
pub ip: IpAddr, pub ip: IpAddr,
@ -246,14 +279,18 @@ pub struct Address {
pub priority: AddressPriority, pub priority: AddressPriority,
/// Weight of this address in the priority group /// Weight of this address in the priority group
pub weight: AddressWeight, pub weight: AddressWeight,
/// List of supported handshakes
pub handshake_ids: Vec<HandshakeID>,
/// Public key IDs used by this address /// Public key IDs used by this address
pub public_key_id: PublicKeyId, pub public_key_ids: Vec<PublicKeyID>,
} }
impl Address { impl Address {
fn raw_len(&self) -> usize { fn raw_len(&self) -> usize {
let size = 4; // UDP port + Priority + Weight // UDP port + Priority + Weight + pubkey_len + handshake_len
match self.ip { let mut size = 6;
size = size + self.public_key_ids.len() + self.handshake_ids.len();
size + match self.ip {
IpAddr::V4(_) => size + 4, IpAddr::V4(_) => size + 4,
IpAddr::V6(_) => size + 16, IpAddr::V6(_) => size + 16,
} }
@ -270,7 +307,6 @@ impl Address {
raw.push(bitfield); raw.push(bitfield);
raw.push(self.public_key_id.0);
raw.extend_from_slice( raw.extend_from_slice(
&(match self.port { &(match self.port {
Some(port) => port.get().to_le_bytes(), Some(port) => port.get().to_le_bytes(),
@ -278,6 +314,11 @@ impl Address {
}), }),
); );
raw.push(self.public_key_ids.len() as u8);
for id in self.public_key_ids.iter() {
raw.push(id.0);
}
match self.ip { match self.ip {
IpAddr::V4(ip) => { IpAddr::V4(ip) => {
let raw_ip = ip.octets(); let raw_ip = ip.octets();
@ -290,7 +331,7 @@ impl Address {
}; };
} }
fn decode_raw(raw: &[u8]) -> Result<(Self, usize), Error> { fn decode_raw(raw: &[u8]) -> Result<(Self, usize), Error> {
if raw.len() < 8 { if raw.len() < 10 {
return Err(Error::NotEnoughData(0)); return Err(Error::NotEnoughData(0));
} }
let ip_type = raw[0] >> 6; let ip_type = raw[0] >> 6;
@ -315,19 +356,60 @@ impl Address {
let priority = AddressPriority::from_u8(raw_priority).unwrap(); let priority = AddressPriority::from_u8(raw_priority).unwrap();
let weight = AddressWeight::from_u8(raw_weight).unwrap(); let weight = AddressWeight::from_u8(raw_weight).unwrap();
let public_key_id = PublicKeyId(raw[1]); let raw_port = u16::from_le_bytes([raw[1], raw[2]]);
// Add publi key ids
let num_pubkey_ids = raw[3] as usize;
if raw.len() < 3 + num_pubkey_ids {
return Err(Error::NotEnoughData(3));
}
let mut public_key_ids = Vec::with_capacity(num_pubkey_ids);
for raw_pubkey_id in raw[4..num_pubkey_ids].iter() {
public_key_ids.push(PublicKeyID(*raw_pubkey_id));
}
// add handshake ids
let next_ptr = 3 + num_pubkey_ids;
let num_handshake_ids = raw[next_ptr] as usize;
if raw.len() < next_ptr + num_handshake_ids {
return Err(Error::NotEnoughData(next_ptr));
}
let mut handshake_ids = Vec::with_capacity(num_handshake_ids);
for raw_handshake_id in
raw[next_ptr..(next_ptr + num_pubkey_ids)].iter()
{
match HandshakeID::from_u8(*raw_handshake_id) {
Some(h_id) => handshake_ids.push(h_id),
None => {
::tracing::warn!(
"Unsupported handshake {}. Upgrade?",
*raw_handshake_id
);
// ignore unsupported handshakes
}
}
}
let next_ptr = next_ptr + num_pubkey_ids;
let raw_port = u16::from_le_bytes([raw[2], raw[3]]);
let port = if raw_port == 0 { let port = if raw_port == 0 {
None None
} else { } else {
Some(NonZeroU16::new(raw_port).unwrap()) Some(NonZeroU16::new(raw_port).unwrap())
}; };
let ip = if is_ipv6 { let ip = if is_ipv6 {
let raw_ip: [u8; 16] = raw[4..20].try_into().unwrap(); let ip_end = next_ptr + 16;
if raw.len() < ip_end {
return Err(Error::NotEnoughData(next_ptr));
}
let raw_ip: [u8; 16] = raw[next_ptr..ip_end].try_into().unwrap();
IpAddr::from(raw_ip) IpAddr::from(raw_ip)
} else { } else {
let raw_ip: [u8; 4] = raw[4..8].try_into().unwrap(); let ip_end = next_ptr + 4;
if raw.len() < ip_end {
return Err(Error::NotEnoughData(next_ptr));
}
let raw_ip: [u8; 4] = raw[next_ptr..ip_end].try_into().unwrap();
IpAddr::from(raw_ip) IpAddr::from(raw_ip)
}; };
@ -337,7 +419,8 @@ impl Address {
port, port,
priority, priority,
weight, weight,
public_key_id, public_key_ids,
handshake_ids,
}, },
total_length, total_length,
)) ))

92
src/enc/asym.rs Normal file
View File

@ -0,0 +1,92 @@
//! Asymmetric key handling and wrappers
use ::num_traits::FromPrimitive;
use ::std::vec::Vec;
use super::Error;
/// Public key ID
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct KeyID(pub u16);
/// Kind of key in the handshake
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub enum PrivKey {
/// Keys to be used only in key exchanges, not for signing
Exchange(ExchangePrivKey),
/// Keys to be used only for signing
Signing,
}
/// Ephemeral private keys
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub enum ExchangePrivKey {
/// X25519(Curve25519) used for key exchange
X25519(::x25519_dalek::StaticSecret),
}
impl ExchangePrivKey {
/// Run the key exchange between two keys of the same kind
pub fn key_exchange(
&self,
pub_key: ExchangePubKey,
) -> Result<[u8; 32], Error> {
todo!();
}
}
/// Kind of key in the key exchange
#[derive(Debug, Copy, Clone, ::num_derive::FromPrimitive)]
#[repr(u8)]
pub enum ExchangePubKeyKind {
/// X25519 Public key
X25519 = 0,
}
impl ExchangePubKeyKind {
fn len(&self) -> usize {
match self {
// FIXME: 99% wrong size
ExchangePubKeyKind::X25519 => {
::ring::signature::ED25519_PUBLIC_KEY_LEN
}
}
}
}
/// all Ephemeral Public keys
#[derive(Debug, Copy, Clone)]
pub enum ExchangePubKey {
/// X25519(Curve25519) used for key exchange
X25519(::x25519_dalek::PublicKey),
}
impl ExchangePubKey {
/// Load public key used for key exchange from it raw bytes
/// The riesult is "unparsed" since we don't verify
/// the actual key
pub fn from_slice(raw: &[u8]) -> Result<(Self, usize), Error> {
// FIXME: get *real* minimum key size
const MIN_KEY_SIZE: usize = 8;
if raw.len() < 1 + MIN_KEY_SIZE {
return Err(Error::NotEnoughData);
}
match ExchangePubKeyKind::from_u8(raw[0]) {
Some(kind) => match kind {
ExchangePubKeyKind::X25519 => {
let pub_key: ::x25519_dalek::PublicKey =
match ::bincode::deserialize(&raw[1..(1 + kind.len())])
{
Ok(pub_key) => pub_key,
Err(_) => return Err(Error::Parsing),
};
Ok((ExchangePubKey::X25519(pub_key), kind.len()))
}
},
None => {
return Err(Error::Parsing);
}
}
}
}

16
src/enc/errors.rs Normal file
View File

@ -0,0 +1,16 @@
//! Common errors when handling cryptographic functions
/// Crypto errors
#[derive(::thiserror::Error, Debug, Copy, Clone)]
pub enum Error {
/// Error while parsing key material
#[error("can't parse key")]
Parsing,
/// Not enough data
#[error("not enough data")]
NotEnoughData,
/// Wrong Key type found.
/// You might have passed rsa keys where x25519 was expected
#[error("wrong key type")]
WrongKey,
}

7
src/enc/mod.rs Normal file
View File

@ -0,0 +1,7 @@
//! Public or symmetric key wrappers, nonces and all that magic stuff
pub mod asym;
mod errors;
pub mod sym;
pub use errors::Error;

75
src/enc/sym.rs Normal file
View File

@ -0,0 +1,75 @@
//! Symmetric cypher stuff
#[derive(Debug, Copy, Clone)]
#[repr(C)]
#[allow(missing_debug_implementations)]
struct NonceNum {
high: u32,
low: u64,
}
/// Nonce with sequence for chach20_apoly1305
#[repr(C)]
pub union Nonce {
num: NonceNum,
raw: ::core::mem::ManuallyDrop<::ring::aead::Nonce>,
easy_from: [u8; 12],
}
impl ::core::fmt::Debug for Nonce {
fn fmt(
&self,
f: &mut core::fmt::Formatter<'_>,
) -> Result<(), ::std::fmt::Error> {
// use the Debug from NonceNum
#[allow(unsafe_code)]
unsafe {
core::fmt::Debug::fmt(&self.num, f)
}
}
}
impl Nonce {
// FIXME: nonces should be random!
/// Generate a new random Nonce
pub fn new() -> Self {
#[allow(unsafe_code)]
unsafe {
Self {
num: NonceNum { high: 42, low: 69 },
}
}
}
/// Create Nonce from array
pub fn from_slice(raw: [u8; 12]) -> Self {
#[allow(unsafe_code)]
unsafe {
Self { easy_from: raw }
}
}
}
//impl Copy for Nonce {}
impl Clone for Nonce {
fn clone(&self) -> Self {
#[allow(unsafe_code)]
unsafe {
Self { num: self.num }
}
}
}
impl ::ring::aead::NonceSequence for Nonce {
fn advance(
&mut self,
) -> Result<::ring::aead::Nonce, ::ring::error::Unspecified> {
#[allow(unsafe_code)]
unsafe {
let old_low = self.num.low;
self.num.low = self.num.low + 1;
if self.num.low < old_low {
self.num.high = self.num.high;
}
Ok(::core::mem::ManuallyDrop::take(&mut self.raw))
}
}
}

View File

@ -13,13 +13,17 @@
//! //!
//! libFenrir is the official rust library implementing the Fenrir protocol //! libFenrir is the official rust library implementing the Fenrir protocol
mod config;
pub mod connection;
pub mod dnssec;
pub mod enc;
use ::arc_swap::{ArcSwap, ArcSwapAny};
use ::std::{net::SocketAddr, sync::Arc}; use ::std::{net::SocketAddr, sync::Arc};
use ::tokio::{net::UdpSocket, task::JoinHandle}; use ::tokio::{net::UdpSocket, task::JoinHandle};
mod config;
pub use config::Config; pub use config::Config;
pub mod connection; use connection::handshake::{self, Handshake, HandshakeKey};
pub mod dnssec;
/// Main fenrir library errors /// Main fenrir library errors
#[derive(::thiserror::Error, Debug)] #[derive(::thiserror::Error, Debug)]
@ -35,7 +39,66 @@ pub enum Error {
Dnssec(#[from] dnssec::Error), Dnssec(#[from] dnssec::Error),
/// Handshake errors /// Handshake errors
#[error("Handshake: {0:?}")] #[error("Handshake: {0:?}")]
Handshake(#[from] connection::handshake::Error), Handshake(#[from] handshake::Error),
}
struct FenrirInner {
keys: ArcSwapAny<Arc<Vec<HandshakeKey>>>,
}
impl FenrirInner {
fn recv_handshake(&self, handshake: Handshake) -> Result<(), Error> {
use connection::handshake::{dirsync::DirSync, HandshakeData};
match handshake.data {
HandshakeData::DirSync(ds) => match ds {
DirSync::Req(req) => {
let ephemeral_key = {
// Keep this block short to avoid contention
// on self.keys
let keys = self.keys.load();
if let Some(h_k) =
keys.iter().find(|k| k.id == req.key_id)
{
use enc::asym::PrivKey;
// Directory synchronized can only used keys
// for key exchange, not signing keys
if let PrivKey::Exchange(k) = &h_k.key {
Some(k.clone())
} else {
None
}
} else {
None
}
};
if ephemeral_key.is_none() {
::tracing::debug!("No such key id: {:?}", req.key_id);
return Err(handshake::Error::UnknownKeyID.into());
}
let ephemeral_key = ephemeral_key.unwrap();
let shared_key = match ephemeral_key
.key_exchange(req.exchange_key)
{
Ok(shared_key) => shared_key,
Err(e) => return Err(handshake::Error::Key(e).into()),
};
use crate::enc::sym::Nonce;
use ::ring::aead::{self, BoundKey};
let alg = aead::UnboundKey::new(
&aead::CHACHA20_POLY1305,
&shared_key,
)
.unwrap();
let nonce = Nonce::new();
let chacha = aead::OpeningKey::new(alg, nonce);
todo!();
}
DirSync::Resp(resp) => {
todo!();
}
},
}
}
} }
/// Instance of a fenrir endpoint /// Instance of a fenrir endpoint
@ -49,6 +112,8 @@ pub struct Fenrir {
dnssec: Option<dnssec::Dnssec>, dnssec: Option<dnssec::Dnssec>,
/// Broadcast channel to tell workers to stop working /// Broadcast channel to tell workers to stop working
stop_working: ::tokio::sync::broadcast::Sender<bool>, stop_working: ::tokio::sync::broadcast::Sender<bool>,
/// Private keys used in the handshake
_inner: Arc<FenrirInner>,
} }
// TODO: graceful vs immediate stop // TODO: graceful vs immediate stop
@ -69,6 +134,9 @@ impl Fenrir {
sockets: Vec::with_capacity(listen_num), sockets: Vec::with_capacity(listen_num),
dnssec: None, dnssec: None,
stop_working: sender, stop_working: sender,
_inner: Arc::new(FenrirInner {
keys: ArcSwapAny::new(Arc::new(Vec::new())),
}),
}; };
Ok(endpoint) Ok(endpoint)
} }
@ -162,6 +230,7 @@ impl Fenrir {
/// Run a dedicated loop to read packets on the listening socket /// Run a dedicated loop to read packets on the listening socket
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>,
socket: Arc<UdpSocket>, socket: Arc<UdpSocket>,
) -> ::std::io::Result<()> { ) -> ::std::io::Result<()> {
// jumbo frames are 9K max // jumbo frames are 9K max
@ -175,7 +244,7 @@ impl Fenrir {
result? result?
} }
}; };
Self::recv(&buffer[0..bytes], sock_from).await; Self::recv(fenrir.clone(), &buffer[0..bytes], sock_from).await;
} }
Ok(()) Ok(())
} }
@ -195,6 +264,7 @@ impl Fenrir {
let stop_working = self.stop_working.subscribe(); let stop_working = self.stop_working.subscribe();
let join = ::tokio::spawn(Self::listen_udp( let join = ::tokio::spawn(Self::listen_udp(
stop_working, stop_working,
self._inner.clone(),
s.clone(), s.clone(),
)); ));
self.sockets.push((s, join)); self.sockets.push((s, join));
@ -223,14 +293,29 @@ impl Fenrir {
const MIN_PACKET_BYTES: usize = 8; const MIN_PACKET_BYTES: usize = 8;
/// Read and do stuff with the udp packet /// Read and do stuff with the udp packet
async fn recv(buffer: &[u8], _sock_from: SocketAddr) { async fn recv(
fenrir: Arc<FenrirInner>,
buffer: &[u8],
_sock_from: SocketAddr,
) {
if buffer.len() < Self::MIN_PACKET_BYTES { if buffer.len() < Self::MIN_PACKET_BYTES {
return; return;
} }
use connection::ID; use connection::ID;
let raw_id: [u8; 8] = buffer.try_into().expect("unreachable"); let raw_id: [u8; 8] = buffer.try_into().expect("unreachable");
if ID::from(raw_id).is_handshake() { if ID::from(raw_id).is_handshake() {
todo!(); use connection::handshake::Handshake;
let handshake = match Handshake::parse(&buffer[8..]) {
Ok(handshake) => handshake,
Err(e) => {
::tracing::warn!("Handshake parsing: {}", e);
return;
}
};
if let Err(err) = fenrir.recv_handshake(handshake) {
::tracing::debug!("Handshake recv error {}", err);
return;
}
} }
// copy packet, spawn // copy packet, spawn
todo!(); todo!();