Helpers for dnssec

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-06-06 22:37:34 +02:00
parent 3e09b9cee0
commit 6da5464c68
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
8 changed files with 149 additions and 30 deletions

View File

@ -106,8 +106,10 @@ impl Domain {
} }
} }
/// Reserve the first service ID for the authentication service
pub const SERVICEID_AUTH: ServiceID = ServiceID([0; 16]);
/// The Service ID is a UUID associated with the service. /// The Service ID is a UUID associated with the service.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
pub struct ServiceID([u8; 16]); pub struct ServiceID([u8; 16]);
impl From<[u8; 16]> for ServiceID { impl From<[u8; 16]> for ServiceID {

View File

@ -185,7 +185,7 @@ impl ConnList {
self.connections[id_in_thread] = Some(conn); self.connections[id_in_thread] = Some(conn);
Ok(()) Ok(())
} }
pub(crate) fn delete(&mut self, id: IDRecv) { pub(crate) fn remove(&mut self, id: IDRecv) {
if let IDRecv(ID::ID(raw_id)) = id { if let IDRecv(ID::ID(raw_id)) = id {
let id_in_thread: usize = let id_in_thread: usize =
(raw_id.get() / (self.thread_id.total as u64)) as usize; (raw_id.get() / (self.thread_id.total as u64)) as usize;

View File

@ -25,6 +25,24 @@ impl KeyID {
} }
} }
impl TryFrom<&str> for KeyID {
type Error = ::std::io::Error;
fn try_from(raw: &str) -> Result<Self, Self::Error> {
if let Ok(id_u16) = raw.parse::<u16>() {
return Ok(KeyID(id_u16));
}
return Err(::std::io::Error::new(
::std::io::ErrorKind::InvalidData,
"KeyID must be between 0 and 65535",
));
}
}
impl ::std::fmt::Display for KeyID {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{}", self.0)
}
}
/// Capabilities of each key /// Capabilities of each key
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum KeyCapabilities { pub enum KeyCapabilities {
@ -56,13 +74,23 @@ impl KeyCapabilities {
} }
/// Kind of key used in the handshake /// Kind of key used in the handshake
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)] #[derive(
Debug,
Copy,
Clone,
PartialEq,
::num_derive::FromPrimitive,
::strum_macros::EnumString,
::strum_macros::IntoStaticStr,
)]
#[non_exhaustive] #[non_exhaustive]
#[repr(u8)] #[repr(u8)]
pub enum KeyKind { pub enum KeyKind {
/// Ed25519 Public key (sign only) /// Ed25519 Public key (sign only)
#[strum(serialize = "ed25519")]
Ed25519 = 0, Ed25519 = 0,
/// X25519 Public key (key exchange) /// X25519 Public key (key exchange)
#[strum(serialize = "x25519")]
X25519, X25519,
} }
// FIXME: actually check this // FIXME: actually check this
@ -73,8 +101,7 @@ impl KeyKind {
match self { match self {
// FIXME: 99% wrong size // FIXME: 99% wrong size
KeyKind::Ed25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN, KeyKind::Ed25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN,
// FIXME: 99% wrong size KeyKind::X25519 => 32,
KeyKind::X25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN,
} }
} }
/// Get the capabilities of this key type /// Get the capabilities of this key type
@ -94,15 +121,30 @@ impl KeyKind {
KeyKind::X25519 => &X25519_KEY_EXCHANGES, KeyKind::X25519 => &X25519_KEY_EXCHANGES,
} }
} }
/// generate new keypair
pub fn new_keypair(
&self,
rnd: &Random,
) -> Result<(PrivKey, PubKey), Error> {
PubKey::new_keypair(*self, rnd)
}
} }
// FIXME: rename in KeyExchangeKind
/// Kind of key exchange /// Kind of key exchange
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)] #[derive(
Debug,
Copy,
Clone,
PartialEq,
::num_derive::FromPrimitive,
::strum_macros::EnumString,
::strum_macros::IntoStaticStr,
)]
#[non_exhaustive] #[non_exhaustive]
#[repr(u8)] #[repr(u8)]
pub enum KeyExchangeKind { pub enum KeyExchangeKind {
/// X25519 Public key /// X25519 Public key
#[strum(serialize = "x25519diffiehellman")]
X25519DiffieHellman = 0, X25519DiffieHellman = 0,
} }
impl KeyExchangeKind { impl KeyExchangeKind {
@ -141,6 +183,13 @@ pub enum PubKey {
} }
impl PubKey { impl PubKey {
/// Get the serialized key length
pub fn len(&self) -> usize {
match self {
PubKey::Exchange(ex) => ex.len(),
PubKey::Signing => todo!(),
}
}
/// return the kind of public key /// return the kind of public key
pub fn kind(&self) -> KeyKind { pub fn kind(&self) -> KeyKind {
match self { match self {
@ -149,6 +198,20 @@ impl PubKey {
PubKey::Exchange(ex) => ex.kind(), PubKey::Exchange(ex) => ex.kind(),
} }
} }
/// generate new keypair
fn new_keypair(
kind: KeyKind,
rnd: &Random,
) -> Result<(PrivKey, PubKey), Error> {
match kind {
KeyKind::Ed25519 => todo!(),
KeyKind::X25519 => {
let (priv_key, pub_key) =
KeyExchangeKind::X25519DiffieHellman.new_keypair(rnd)?;
Ok((PrivKey::Exchange(priv_key), PubKey::Exchange(pub_key)))
}
}
}
/// serialize the key into the buffer /// serialize the key into the buffer
/// NOTE: Assumes there is enough space /// NOTE: Assumes there is enough space
pub fn serialize_into(&self, out: &mut [u8]) { pub fn serialize_into(&self, out: &mut [u8]) {
@ -211,6 +274,24 @@ pub enum PrivKey {
Signing, Signing,
} }
impl PrivKey {
/// Get the serialized key length
pub fn len(&self) -> usize {
match self {
PrivKey::Exchange(ex) => ex.len(),
PrivKey::Signing => todo!(),
}
}
/// serialize the key into the buffer
/// NOTE: Assumes there is enough space
pub fn serialize_into(&self, out: &mut [u8]) {
match self {
PrivKey::Exchange(ex) => ex.serialize_into(out),
PrivKey::Signing => todo!(),
}
}
}
/// Ephemeral private keys /// Ephemeral private keys
#[derive(Clone)] #[derive(Clone)]
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@ -221,6 +302,12 @@ pub enum ExchangePrivKey {
} }
impl ExchangePrivKey { impl ExchangePrivKey {
/// Get the serialized key length
pub fn len(&self) -> usize {
match self {
ExchangePrivKey::X25519(_) => KeyKind::X25519.pub_len(),
}
}
/// Get the kind of key /// Get the kind of key
pub fn kind(&self) -> KeyKind { pub fn kind(&self) -> KeyKind {
match self { match self {
@ -238,12 +325,18 @@ impl ExchangePrivKey {
if exchange != KeyExchangeKind::X25519DiffieHellman { if exchange != KeyExchangeKind::X25519DiffieHellman {
return Err(Error::UnsupportedKeyExchange); return Err(Error::UnsupportedKeyExchange);
} }
if let ExchangePubKey::X25519(inner_pub_key) = pub_key { let ExchangePubKey::X25519(inner_pub_key) = pub_key;
let shared_secret = priv_key.diffie_hellman(&inner_pub_key); let shared_secret = priv_key.diffie_hellman(&inner_pub_key);
Ok(shared_secret.into()) Ok(shared_secret.into())
} else { }
Err(Error::UnsupportedKeyExchange) }
} }
/// serialize the key into the buffer
/// NOTE: Assumes there is enough space
pub fn serialize_into(&self, out: &mut [u8]) {
match self {
ExchangePrivKey::X25519(key) => {
out[..32].copy_from_slice(&key.to_bytes());
} }
} }
} }
@ -258,6 +351,12 @@ pub enum ExchangePubKey {
} }
impl ExchangePubKey { impl ExchangePubKey {
/// Get the serialized key length
pub fn len(&self) -> usize {
match self {
ExchangePubKey::X25519(_) => KeyKind::X25519.pub_len(),
}
}
/// Get the kind of key /// Get the kind of key
pub fn kind(&self) -> KeyKind { pub fn kind(&self) -> KeyKind {
match self { match self {

View File

@ -7,11 +7,20 @@ use ::zeroize::Zeroize;
use crate::{config::Config, enc::Secret}; use crate::{config::Config, enc::Secret};
/// Kind of HKDF /// Kind of HKDF
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)] #[derive(
Debug,
Copy,
Clone,
PartialEq,
::num_derive::FromPrimitive,
::strum_macros::EnumString,
::strum_macros::IntoStaticStr,
)]
#[non_exhaustive] #[non_exhaustive]
#[repr(u8)] #[repr(u8)]
pub enum HkdfKind { pub enum HkdfKind {
/// Sha3 /// Sha3
#[strum(serialize = "sha3")]
Sha3 = 0, Sha3 = 0,
} }
impl HkdfKind { impl HkdfKind {

View File

@ -27,6 +27,10 @@ impl Random {
pub fn fill(&self, out: &mut [u8]) { pub fn fill(&self, out: &mut [u8]) {
self.rnd.fill(out); self.rnd.fill(out);
} }
/// return the underlying ring SystemRandom
pub fn ring_rnd(&self) -> &::ring::rand::SystemRandom {
&self.rnd
}
} }
// Fake debug implementation to avoid leaking secrets // Fake debug implementation to avoid leaking secrets

View File

@ -8,10 +8,19 @@ use crate::{
use ::zeroize::Zeroize; use ::zeroize::Zeroize;
/// List of possible Ciphers /// List of possible Ciphers
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)] #[derive(
Debug,
Copy,
Clone,
PartialEq,
::num_derive::FromPrimitive,
::strum_macros::EnumString,
::strum_macros::IntoStaticStr,
)]
#[repr(u8)] #[repr(u8)]
pub enum CipherKind { pub enum CipherKind {
/// XChaCha20_Poly1305 /// XChaCha20_Poly1305
#[strum(serialize = "xchacha20poly1305")]
XChaCha20Poly1305 = 0, XChaCha20Poly1305 = 0,
} }

View File

@ -51,7 +51,7 @@ pub(crate) struct ClientConnectInfo {
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum HandshakeAction { pub(crate) enum HandshakeAction {
/// Parsing finished, all ok, nothing to do /// Parsing finished, all ok, nothing to do
None, Nonthing,
/// Packet parsed, now go perform authentication /// Packet parsed, now go perform authentication
AuthNeeded(AuthNeededInfo), AuthNeeded(AuthNeededInfo),
/// the client can fully establish a connection with this info /// the client can fully establish a connection with this info
@ -227,6 +227,9 @@ impl HandshakeTracker {
} }
let hshake = let hshake =
self.hshake_cli.remove(resp.client_key_id).unwrap(); self.hshake_cli.remove(resp.client_key_id).unwrap();
if let Some(timeout) = hshake.timeout {
timeout.abort();
}
return Ok(HandshakeAction::ClientConnect( return Ok(HandshakeAction::ClientConnect(
ClientConnectInfo { ClientConnectInfo {
service_id: hshake.service_id, service_id: hshake.service_id,

View File

@ -1,6 +1,6 @@
//! Worker thread implementation //! Worker thread implementation
use crate::{ use crate::{
auth::{Domain, ServiceID, Token, TokenChecker, UserID}, auth::{self, Domain, ServiceID, Token, TokenChecker, UserID},
config::Config, config::Config,
connection::{ connection::{
self, self,
@ -390,13 +390,10 @@ impl Worker {
self.handshakes.timeout_client(key_id) self.handshakes.timeout_client(key_id)
{ {
for conn_id in connections.into_iter() { for conn_id in connections.into_iter() {
if !conn_id.0.is_handshake() { self.connections.remove(conn_id);
self.connections.delete(conn_id);
}
} }
}; };
} }
//TODO: reconf message to add channels
Work::Recv(pkt) => { Work::Recv(pkt) => {
self.recv(pkt).await; self.recv(pkt).await;
} }
@ -545,7 +542,6 @@ impl Worker {
return; return;
} }
self.send_packet(raw_out, udp.src, udp.dst).await; self.send_packet(raw_out, udp.src, udp.dst).await;
return;
} }
HandshakeAction::ClientConnect(cci) => { HandshakeAction::ClientConnect(cci) => {
let ds_resp; let ds_resp;
@ -573,19 +569,19 @@ impl Worker {
let id_recv = conn.id_recv; let id_recv = conn.id_recv;
let cipher = conn.cipher_recv.kind(); let cipher = conn.cipher_recv.kind();
// track the connection to the authentication server // track the connection to the authentication server
if self.connections.track(Rc::new(conn)).is_err() { if self.connections.track(conn.into()).is_err() {
::tracing::error!("Could not track new connection"); ::tracing::error!("Could not track new connection");
self.connections.delete(id_recv); self.connections.remove(id_recv);
return; return;
} }
if id_recv.0 == resp_data.service_connection_id { if cci.service_id == auth::SERVICEID_AUTH {
// the user asked a single connection // the user asked a single connection
// to the authentication server, without any additional // to the authentication server, without any additional
// service. No more connections to setup // service. No more connections to setup
return; return;
} }
// create and track the connection to the service // create and track the connection to the service
// SECURITY: // SECURITY: xor with secrets
//FIXME: the Secret should be XORed with the client stored //FIXME: the Secret should be XORed with the client stored
// secret (if any) // secret (if any)
let hkdf = Hkdf::new( let hkdf = Hkdf::new(
@ -603,13 +599,10 @@ impl Worker {
service_connection.id_send = service_connection.id_send =
IDSend(resp_data.service_connection_id); IDSend(resp_data.service_connection_id);
let _ = self.connections.track(service_connection.into()); let _ = self.connections.track(service_connection.into());
return;
} }
_ => {} HandshakeAction::Nonthing => {}
}; };
} }
// copy packet, spawn
todo!();
} }
async fn send_packet( async fn send_packet(
&self, &self,