More work on key exhcnage negotiation

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-06-01 11:41:10 +02:00
parent 1bae4c9953
commit ac213a6528
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
9 changed files with 350 additions and 108 deletions

View File

@ -1,6 +1,10 @@
//!
//! Configuration to initialize the Fenrir networking library
use crate::{
connection::handshake::HandshakeID,
enc::{asym::KeyExchange, hkdf::HkdfKind, sym::CipherKind},
};
use ::std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
num::NonZeroUsize,
@ -18,6 +22,14 @@ pub struct Config {
pub listen: Vec<SocketAddr>,
/// List of DNS resolvers to use
pub resolvers: Vec<SocketAddr>,
/// Supported handshakes
pub handshakes: Vec<HandshakeID>,
/// Supported key exchanges
pub key_exchanges: Vec<KeyExchange>,
/// Supported Hkdfs
pub hkdfs: Vec<HkdfKind>,
/// Supported Ciphers
pub ciphers: Vec<CipherKind>,
}
impl Default for Config {
@ -34,6 +46,10 @@ impl Default for Config {
),
],
resolvers: Vec::new(),
handshakes: [HandshakeID::DirectorySynchronized].to_vec(),
key_exchanges: [KeyExchange::X25519DiffieHellman].to_vec(),
hkdfs: [HkdfKind::Sha3].to_vec(),
ciphers: [CipherKind::XChaCha20Poly1305].to_vec(),
}
}
}

View File

@ -14,13 +14,41 @@ use crate::{
connection::{ProtocolVersion, ID},
enc::{
asym::{ExchangePubKey, KeyExchange, KeyID},
hkdf::HkdfKind,
sym::{CipherKind, HeadLen, Secret, TagLen},
Random,
},
};
use ::arrayref::array_mut_ref;
type Nonce = [u8; 16];
// TODO: merge with crate::enc::sym::Nonce
/// random nonce
#[derive(Debug, Clone, Copy)]
pub struct Nonce([u8; 16]);
impl Nonce {
/// Create a new random Nonce
pub fn new(rnd: &Random) -> Self {
use ::core::mem::MaybeUninit;
let mut out: MaybeUninit<[u8; 16]>;
#[allow(unsafe_code)]
unsafe {
out = MaybeUninit::uninit();
let _ = rnd.fill(out.assume_init_mut());
Self(out.assume_init())
}
}
/// Length of the serialized Nonce
pub const fn len() -> usize {
16
}
}
impl From<&[u8; 16]> for Nonce {
fn from(raw: &[u8; 16]) -> Self {
Self(raw.clone())
}
}
/// Parsed handshake
#[derive(Debug, Clone)]
@ -61,6 +89,8 @@ pub struct Req {
pub key_id: KeyID,
/// Selected key exchange
pub exchange: KeyExchange,
/// Selected hkdf
pub hkdf: HkdfKind,
/// Selected cipher
pub cipher: CipherKind,
/// Client ephemeral public key used for key exchanges
@ -77,6 +107,7 @@ impl Req {
ProtocolVersion::len()
+ KeyID::len()
+ KeyExchange::len()
+ HkdfKind::len()
+ CipherKind::len()
+ self.exchange_key.kind().pub_len()
}
@ -91,6 +122,7 @@ impl Req {
pub fn len(&self) -> usize {
KeyID::len()
+ KeyExchange::len()
+ HkdfKind::len()
+ CipherKind::len()
+ self.exchange_key.kind().pub_len()
+ self.data.len()
@ -121,18 +153,23 @@ impl super::HandshakeParsing for Req {
Some(exchange) => exchange,
None => return Err(Error::Parsing),
};
let cipher: CipherKind = match CipherKind::from_u8(raw[3]) {
let hkdf: HkdfKind = match HkdfKind::from_u8(raw[3]) {
Some(exchange) => exchange,
None => return Err(Error::Parsing),
};
let cipher: CipherKind = match CipherKind::from_u8(raw[4]) {
Some(cipher) => cipher,
None => return Err(Error::Parsing),
};
let (exchange_key, len) = match ExchangePubKey::from_slice(&raw[4..]) {
let (exchange_key, len) = match ExchangePubKey::from_slice(&raw[5..]) {
Ok(exchange_key) => exchange_key,
Err(e) => return Err(e.into()),
};
let data = ReqInner::CipherText(raw.len() - (4 + len));
let data = ReqInner::CipherText(raw.len() - (5 + len));
Ok(HandshakeData::DirSync(DirSync::Req(Self {
key_id,
exchange,
hkdf,
cipher,
exchange_key,
data,
@ -253,7 +290,7 @@ pub struct ReqData {
impl ReqData {
/// actual length of the request data
pub fn len(&self) -> usize {
self.nonce.len() + KeyID::len() + ID::len() + self.auth.len()
Nonce::len() + KeyID::len() + ID::len() + self.auth.len()
}
/// Minimum byte length of the request data
pub const MIN_PKT_LEN: usize =
@ -265,7 +302,8 @@ impl ReqData {
}
let mut start = 0;
let mut end = 16;
let nonce: Nonce = raw[start..end].try_into().unwrap();
let raw_sized: &[u8; 16] = raw[start..end].try_into().unwrap();
let nonce: Nonce = raw_sized.into();
start = end;
end = end + KeyID::len();
let client_key_id =
@ -440,7 +478,7 @@ impl RespData {
assert!(out.len() == Self::len(), "wrong buffer size");
let mut start = 0;
let mut end = Self::NONCE_LEN;
out[start..end].copy_from_slice(&self.client_nonce);
out[start..end].copy_from_slice(&self.client_nonce.0);
start = end;
end = end + Self::NONCE_LEN;
self.id.serialize(&mut out[start..end]);

View File

@ -27,6 +27,37 @@ pub enum Error {
NotEnoughData,
}
/// List of possible handshakes
#[derive(::num_derive::FromPrimitive, Debug, Clone, Copy, PartialEq)]
#[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",
));
}
}
pub(crate) struct HandshakeServer {
pub id: crate::enc::asym::KeyID,
pub key: crate::enc::asym::PrivKey,

View File

@ -19,15 +19,15 @@
//! * 2..4 priority (for failover)
//! * 5..7 weight between priority
//! * 1 byte: divided in half:
//! * half: num of public key ids
//! * half: num of handhskae ids
//! * half: num of public key indexes
//! * half: num of handshake ids
//! * 2 bytes: UDP port
//! * [ 1 byte per public key id ]
//! * [ HALF byte per public key idx ] (index on the list of public keys)
//! * [ 1 byte per handshake id ]
//! * X bytes: IP
//! ]
//! [ # list of pubkeys
//! * 1 byte: pubkey id
//! [ # list of pubkeys (max: 16)
//! * 2 byte: pubkey id
//! * 1 byte: pubkey length
//! * 1 byte: pubkey type
//! * Y bytes: pubkey
@ -42,11 +42,14 @@
//! * 1 byte for each cipher
//! ]
use crate::enc::{
use crate::{
connection::handshake::HandshakeID,
enc::{
self,
asym::{KeyExchange, PubKey},
asym::{KeyExchange, KeyID, PubKey},
hkdf::HkdfKind,
sym::CipherKind,
},
};
use ::core::num::NonZeroU16;
use ::num_traits::FromPrimitive;
@ -55,22 +58,12 @@ use ::std::{net::IpAddr, vec::Vec};
* Public key data
*/
/// Public Key ID
/// Public Key Index.
/// this points to the index of the public key in the array of public keys.
/// needed to have one byte less in the list of public keys
/// supported by and address
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PublicKeyID(u8);
impl TryFrom<&str> for PublicKeyID {
type Error = ::std::io::Error;
fn try_from(raw: &str) -> Result<Self, Self::Error> {
if let Ok(id_u8) = raw.parse::<u8>() {
return Ok(PublicKeyID(id_u8));
}
return Err(::std::io::Error::new(
::std::io::ErrorKind::InvalidData,
"Public Key ID must be between 0 and 256",
));
}
}
pub struct PubKeyIdx(pub u8);
/*
* Address data
@ -168,37 +161,6 @@ 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:
/// * ip
/// * udp port
@ -220,14 +182,16 @@ pub struct Address {
/// List of supported handshakes
pub handshake_ids: Vec<HandshakeID>,
/// Public key IDs used by this address
pub public_key_ids: Vec<PublicKeyID>,
pub public_key_idx: Vec<PubKeyIdx>,
}
impl Address {
fn raw_len(&self) -> usize {
// UDP port + Priority + Weight + pubkey_len + handshake_len
let mut size = 6;
size = size + self.public_key_ids.len() + self.handshake_ids.len();
let num_pubkey_idx = self.public_key_idx.len();
let idx_bytes = (num_pubkey_idx / 2) + (num_pubkey_idx % 2);
size = size + idx_bytes + self.handshake_ids.len();
size + match self.ip {
IpAddr::V4(_) => size + 4,
IpAddr::V6(_) => size + 16,
@ -244,7 +208,7 @@ impl Address {
bitfield |= self.weight as u8;
raw.push(bitfield);
let len_combined: u8 = self.public_key_ids.len() as u8;
let len_combined: u8 = self.public_key_idx.len() as u8;
let len_combined = len_combined << 4;
let len_combined = len_combined | self.handshake_ids.len() as u8;
raw.push(len_combined);
@ -256,8 +220,18 @@ impl Address {
}),
);
for id in self.public_key_ids.iter() {
raw.push(id.0);
// pair every idx, since the max is 16
for chunk in self.public_key_idx.chunks(2) {
let second = {
if chunk.len() == 2 {
chunk[1].0
} else {
0
}
};
let tmp = chunk[0].0 << 4;
let tmp = tmp | second;
raw.push(tmp);
}
for id in self.handshake_ids.iter() {
raw.push(*id as u8);
@ -301,21 +275,29 @@ impl Address {
};
// Add publickey ids
let num_pubkey_ids = (raw[3] >> 4) as usize;
let num_pubkey_idx = (raw[3] >> 4) as usize;
let num_handshake_ids = (raw[3] & 0x0F) as usize;
if raw.len() <= 3 + num_pubkey_ids + num_handshake_ids {
if raw.len() <= 3 + num_pubkey_idx + num_handshake_ids {
return Err(Error::NotEnoughData(3));
}
let mut bytes_parsed = 4;
let mut public_key_ids = Vec::with_capacity(num_pubkey_ids);
for raw_pubkey_id in
raw[bytes_parsed..(bytes_parsed + num_pubkey_ids)].iter()
let mut public_key_idx = Vec::with_capacity(num_pubkey_idx);
let idx_bytes = (num_pubkey_idx / 2) + (num_pubkey_idx % 2);
let mut idx_added = 0;
for raw_pubkey_idx_pair in
raw[bytes_parsed..(bytes_parsed + idx_bytes)].iter()
{
public_key_ids.push(PublicKeyID(*raw_pubkey_id));
let first = PubKeyIdx(raw_pubkey_idx_pair >> 4);
let second = PubKeyIdx(raw_pubkey_idx_pair & 0x0F);
public_key_idx.push(first);
if num_pubkey_idx - idx_added >= 2 {
public_key_idx.push(second);
}
idx_added = idx_added + 2;
}
// add handshake ids
bytes_parsed = bytes_parsed + num_pubkey_ids;
bytes_parsed = bytes_parsed + idx_bytes;
let mut handshake_ids = Vec::with_capacity(num_handshake_ids);
for raw_handshake_id in
raw[bytes_parsed..(bytes_parsed + num_handshake_ids)].iter()
@ -358,7 +340,7 @@ impl Address {
port,
priority,
weight,
public_key_ids,
public_key_idx,
handshake_ids,
},
bytes_parsed,
@ -374,7 +356,7 @@ impl Address {
#[derive(Debug, Clone)]
pub struct Record {
/// Public keys used by any authentication server
pub public_keys: Vec<(PublicKeyID, PubKey)>,
pub public_keys: Vec<(KeyID, PubKey)>,
/// List of all authentication servers' addresses.
/// Multiple ones can point to the same authentication server
pub addresses: Vec<Address>,
@ -443,7 +425,8 @@ impl Record {
address.encode_into(&mut raw);
}
for (public_key_id, public_key) in self.public_keys.iter() {
raw.push(public_key_id.0);
let key_id_bytes = public_key_id.0.to_le_bytes();
raw.extend_from_slice(&key_id_bytes);
raw.push(public_key.kind().pub_len() as u8);
raw.push(public_key.kind() as u8);
public_key.serialize_into(&mut raw);
@ -462,8 +445,8 @@ impl Record {
}
/// Decode from base85 to the actual object
pub fn decode(raw: &[u8]) -> Result<Self, Error> {
// bare minimum for 1 address, 1 key, 1 key exchange and 1 cipher
const MIN_RAW_LENGTH: usize = 1 + 1 + 1 + 8 + 9 + 1 + 1;
// bare minimum for lengths, (1 address), (1 key), cipher negotiation
const MIN_RAW_LENGTH: usize = 3 + (6 + 4) + (4 + 32) + 1 + 1 + 1;
if raw.len() <= MIN_RAW_LENGTH {
return Err(Error::NotEnoughData(0));
}
@ -499,11 +482,14 @@ impl Record {
num_addresses = num_addresses - 1;
}
while num_public_keys > 0 {
if bytes_parsed + 2 >= raw.len() {
if bytes_parsed + 3 >= raw.len() {
return Err(Error::NotEnoughData(bytes_parsed));
}
let id = PublicKeyID(raw[bytes_parsed]);
bytes_parsed = bytes_parsed + 1;
let raw_key_id =
u16::from_le_bytes([raw[bytes_parsed], raw[bytes_parsed + 1]]);
let id = KeyID(raw_key_id);
bytes_parsed = bytes_parsed + 2;
let pubkey_length = raw[bytes_parsed] as usize;
bytes_parsed = bytes_parsed + 1;
if pubkey_length + bytes_parsed >= raw.len() {
@ -590,6 +576,13 @@ impl Record {
result.ciphers.push(cipher);
num_ciphers = num_ciphers - 1;
}
for addr in result.addresses.iter() {
for idx in addr.public_key_idx.iter() {
if idx.0 as usize >= result.public_keys.len() {
return Err(Error::Max16PublicKeys);
}
}
}
if bytes_parsed != raw.len() {
Err(Error::UnknownData(bytes_parsed))
} else {

View File

@ -3,7 +3,10 @@
use ::num_traits::FromPrimitive;
use super::Error;
use crate::enc::{sym::Secret, Random};
use crate::{
config::Config,
enc::{sym::Secret, Random},
};
/// Public key ID
#[derive(Debug, Copy, Clone, PartialEq)]
@ -68,8 +71,19 @@ impl KeyKind {
KeyKind::X25519 => KeyCapabilities::Exchange,
}
}
/// Returns the key exchanges supported by this key
pub fn key_exchanges(&self) -> &'static [KeyExchange] {
const EMPTY: [KeyExchange; 0] = [];
const X25519_KEY_EXCHANGES: [KeyExchange; 1] =
[KeyExchange::X25519DiffieHellman];
match self {
KeyKind::Ed25519 => &EMPTY,
KeyKind::X25519 => &X25519_KEY_EXCHANGES,
}
}
}
// FIXME: rename in KeyExchangeKind
/// Kind of key exchange
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
#[non_exhaustive]
@ -279,7 +293,28 @@ impl ExchangePubKey {
}
}
/// Build a new pair of private/public key pair
pub fn new_keypair(kind: KeyKind, rnd: &Random) -> (PrivKey, PubKey) {
todo!()
/// Select the best key exchange from our supported list
/// and the other endpoint supported list.
/// Give priority to our list
pub fn server_select_key_exchange(
cfg: &Config,
client_supported: &Vec<KeyExchange>,
) -> Option<KeyExchange> {
cfg.key_exchanges
.iter()
.find(|k| client_supported.contains(k))
.copied()
}
/// Select the best key exchange from our supported list
/// and the other endpoint supported list.
/// Give priority to the server list
/// This is used only in the Directory Synchronized handshake
pub fn client_select_key_exchange(
cfg: &Config,
server_supported: &Vec<KeyExchange>,
) -> Option<KeyExchange> {
server_supported
.iter()
.find(|k| cfg.key_exchanges.contains(k))
.copied()
}

View File

@ -4,7 +4,7 @@
use ::sha3::Sha3_256;
use ::zeroize::Zeroize;
use crate::enc::sym::Secret;
use crate::{config::Config, enc::sym::Secret};
/// Kind of HKDF
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
@ -14,6 +14,12 @@ pub enum HkdfKind {
/// Sha3
Sha3 = 0,
}
impl HkdfKind {
/// Length of the serialized type
pub const fn len() -> usize {
1
}
}
/// Generic wrapper on Hkdfs
#[derive(Clone)]
@ -52,6 +58,8 @@ impl Hkdf {
// we can't use #[derive(Zeroing)] either.
// So we craete a union with a Zeroing object, and drop both manually.
// TODO: move this to Hkdf instead of Sha3
#[derive(Zeroize)]
#[zeroize(drop)]
struct Zeroable([u8; ::core::mem::size_of::<::hkdf::Hkdf<Sha3_256>>()]);
@ -89,7 +97,7 @@ pub struct HkdfSha3 {
impl HkdfSha3 {
/// Instantiate a new HKDF with Sha3-256
pub fn new(salt: &[u8], key: Secret) -> Self {
pub(crate) fn new(salt: &[u8], key: Secret) -> Self {
let hkdf = ::hkdf::Hkdf::<Sha3_256>::new(Some(salt), key.as_ref());
Self {
inner: HkdfInner {
@ -98,7 +106,7 @@ impl HkdfSha3 {
}
}
/// Get a secret generated from the key and a given context
pub fn get_secret(&self, context: &[u8]) -> Secret {
pub(crate) fn get_secret(&self, context: &[u8]) -> Secret {
let mut out: [u8; 32] = [0; 32];
#[allow(unsafe_code)]
unsafe {
@ -117,3 +125,29 @@ impl ::core::fmt::Debug for HkdfSha3 {
::core::fmt::Debug::fmt("[hidden hkdf]", f)
}
}
/// Select the best hkdf from our supported list
/// and the other endpoint supported list.
/// Give priority to our list
pub fn server_select_hkdf(
cfg: &Config,
client_supported: &Vec<HkdfKind>,
) -> Option<HkdfKind> {
cfg.hkdfs
.iter()
.find(|h| client_supported.contains(h))
.copied()
}
/// Select the best hkdf from our supported list
/// and the other endpoint supported list.
/// Give priority to the server list
/// this is used only in the directory synchronized handshake
pub fn client_select_hkdf(
cfg: &Config,
server_supported: &Vec<HkdfKind>,
) -> Option<HkdfKind> {
server_supported
.iter()
.find(|h| cfg.hkdfs.contains(h))
.copied()
}

View File

@ -1,7 +1,7 @@
//! Symmetric cypher stuff
use super::Error;
use crate::enc::Random;
use crate::{config::Config, enc::Random};
use ::zeroize::Zeroize;
/// Secret, used for keys.
@ -299,7 +299,7 @@ impl XChaCha20Poly1305 {
}
//
// TODO: For efficiency "Nonce" should become a reference.
// TODO: Merge crate::{enc::sym::Nonce, connection::handshake::dirsync::Nonce}
//
#[derive(Debug, Copy, Clone)]
@ -387,3 +387,28 @@ impl NonceSync {
old_nonce
}
}
/// Select the best cipher from our supported list
/// and the other endpoint supported list.
/// Give priority to our list
pub fn server_select_cipher(
cfg: &Config,
client_supported: &Vec<CipherKind>,
) -> Option<CipherKind> {
cfg.ciphers
.iter()
.find(|c| client_supported.contains(c))
.copied()
}
/// Select the best cipher from our supported list
/// and the other endpoint supported list.
/// Give priority to the server list
/// This is used only in the Directory synchronized handshake
pub fn client_select_cipher(
cfg: &Config,
server_supported: &Vec<CipherKind>,
) -> Option<CipherKind> {
server_supported
.iter()
.find(|c| cfg.ciphers.contains(c))
.copied()
}

View File

@ -1,6 +1,7 @@
//! Worker thread implementation
use crate::{
auth::{ServiceID, TokenChecker},
config::Config,
connection::{
self,
handshake::{
@ -12,9 +13,9 @@ use crate::{
},
dnssec,
enc::{
asym::PubKey,
hkdf::{Hkdf, HkdfKind},
sym::Secret,
asym::{self, PubKey},
hkdf::{self, Hkdf, HkdfKind},
sym::{self, Secret},
Random,
},
inner::{HandshakeAction, HandshakeTracker, ThreadTracker},
@ -53,6 +54,7 @@ pub(crate) enum WorkAnswer {
/// Actual worker implementation.
pub(crate) struct Worker {
cfg: Config,
thread_id: ThreadTracker,
// PERF: rand uses syscalls. how to do that async?
rand: Random,
@ -67,6 +69,7 @@ pub(crate) struct Worker {
impl Worker {
pub(crate) async fn new_and_loop(
cfg: Config,
thread_id: ThreadTracker,
stop_working: ::tokio::sync::broadcast::Receiver<bool>,
token_check: Option<Arc<Mutex<TokenChecker>>>,
@ -75,6 +78,7 @@ impl Worker {
) -> ::std::io::Result<()> {
// TODO: get a channel to send back information, and send the error
let mut worker = Self::new(
cfg,
thread_id,
stop_working,
token_check,
@ -86,6 +90,7 @@ impl Worker {
Ok(())
}
pub(crate) async fn new(
cfg: Config,
thread_id: ThreadTracker,
stop_working: ::tokio::sync::broadcast::Receiver<bool>,
token_check: Option<Arc<Mutex<TokenChecker>>>,
@ -126,6 +131,7 @@ impl Worker {
};
Ok(Self {
cfg,
thread_id,
rand: Random::new(),
stop_working,
@ -156,19 +162,52 @@ impl Worker {
let _ = sender.send(conn_num);
}
Work::Connect((send_res, dnssec_record, _service_id)) => {
// PERF: geolocation
// Find the first destination with a coherent
// pubkey/key exchange
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,
if addr
.handshake_ids
.iter()
.find(|h_srv| {
self.cfg.handshakes.contains(h_srv)
})
.is_none()
{
// skip servers with no corresponding
// handshake types
return None;
}
for idx in addr.public_key_idx.iter() {
let key_supported_k_x =
dnssec_record.public_keys[idx.0 as usize]
.1
.kind()
.key_exchanges();
match self
.cfg
.key_exchanges
.iter()
.find(|x| key_supported_k_x.contains(x))
{
Some(exchange) => {
return Some((
addr,
dnssec_record.public_keys
[idx.0 as usize],
exchange,
))
}
None => return None,
}
}
return None;
});
let (addr, key) = match destination {
Some((addr, key)) => (addr, key),
let (addr, key, exchange) = match destination {
Some((addr, key, exchange)) => (addr, key, exchange),
None => {
let _ =
send_res.send(Err(crate::Error::Resolution(
@ -178,8 +217,29 @@ impl Worker {
continue 'mainloop;
}
};
use crate::enc::asym;
let exchange = asym::KeyExchange::X25519DiffieHellman;
let hkdf = match hkdf::client_select_hkdf(
&self.cfg,
&dnssec_record.hkdfs,
) {
Some(hkdf) => hkdf,
None => {
let _ = send_res
.send(Err(crate::Error::HandshakeNegotiation));
continue 'mainloop;
}
};
let cipher = match sym::client_select_cipher(
&self.cfg,
&dnssec_record.ciphers,
) {
Some(cipher) => cipher,
None => {
let _ = send_res
.send(Err(crate::Error::HandshakeNegotiation));
continue 'mainloop;
}
};
let (priv_key, pub_key) =
match exchange.new_keypair(&self.rand) {
Ok(pair) => pair,
@ -187,10 +247,15 @@ impl Worker {
};
// build request
/*
let req_data = dirsync::ReqData {
nonce: dirsync::Nonce::new(&self.rand),
client_key_id:
};
let req = dirsync::Req {
key_id: key.0,
exchange: exchange,
cipher: 42,
exchange,
hkdf,
cipher,
exchange_key: client_pub_key,
data: 42,
};

View File

@ -62,6 +62,9 @@ pub enum Error {
/// Resolution problems. wrong or incomplete DNSSEC data
#[error("DNSSEC resolution: {0}")]
Resolution(String),
/// No common cryptographic primitives
#[error("No common cryptographic primitives")]
HandshakeNegotiation,
}
/// Instance of a fenrir endpoint
@ -381,6 +384,7 @@ impl Fenrir {
::tracing::debug!("Spawning thread {}", core);
let th_topology = hw_topology.clone();
let th_tokio_rt = tokio_rt.clone();
let th_config = self.cfg.clone();
let (work_send, work_recv) = ::async_channel::unbounded::<Work>();
let th_stop_working = self.stop_working.subscribe();
let th_token_check = self.token_check.clone();
@ -417,6 +421,7 @@ impl Fenrir {
let _ = tk_local.block_on(
&th_tokio_rt,
Worker::new_and_loop(
th_config,
thread_id,
th_stop_working,
th_token_check,