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.
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ServiceID([u8; 16]);
impl From<[u8; 16]> for ServiceID {

View File

@ -185,7 +185,7 @@ impl ConnList {
self.connections[id_in_thread] = Some(conn);
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 {
let id_in_thread: 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
#[derive(Debug, Clone, Copy)]
pub enum KeyCapabilities {
@ -56,13 +74,23 @@ impl KeyCapabilities {
}
/// 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]
#[repr(u8)]
pub enum KeyKind {
/// Ed25519 Public key (sign only)
#[strum(serialize = "ed25519")]
Ed25519 = 0,
/// X25519 Public key (key exchange)
#[strum(serialize = "x25519")]
X25519,
}
// FIXME: actually check this
@ -73,8 +101,7 @@ impl KeyKind {
match self {
// FIXME: 99% wrong size
KeyKind::Ed25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN,
// FIXME: 99% wrong size
KeyKind::X25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN,
KeyKind::X25519 => 32,
}
}
/// Get the capabilities of this key type
@ -94,15 +121,30 @@ impl KeyKind {
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
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
#[derive(
Debug,
Copy,
Clone,
PartialEq,
::num_derive::FromPrimitive,
::strum_macros::EnumString,
::strum_macros::IntoStaticStr,
)]
#[non_exhaustive]
#[repr(u8)]
pub enum KeyExchangeKind {
/// X25519 Public key
#[strum(serialize = "x25519diffiehellman")]
X25519DiffieHellman = 0,
}
impl KeyExchangeKind {
@ -141,6 +183,13 @@ pub enum 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
pub fn kind(&self) -> KeyKind {
match self {
@ -149,6 +198,20 @@ impl PubKey {
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
/// NOTE: Assumes there is enough space
pub fn serialize_into(&self, out: &mut [u8]) {
@ -211,6 +274,24 @@ pub enum PrivKey {
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
#[derive(Clone)]
#[allow(missing_debug_implementations)]
@ -221,6 +302,12 @@ pub enum 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
pub fn kind(&self) -> KeyKind {
match self {
@ -238,14 +325,20 @@ impl ExchangePrivKey {
if exchange != KeyExchangeKind::X25519DiffieHellman {
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);
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 {
/// Get the serialized key length
pub fn len(&self) -> usize {
match self {
ExchangePubKey::X25519(_) => KeyKind::X25519.pub_len(),
}
}
/// Get the kind of key
pub fn kind(&self) -> KeyKind {
match self {

View File

@ -7,11 +7,20 @@ use ::zeroize::Zeroize;
use crate::{config::Config, enc::Secret};
/// 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]
#[repr(u8)]
pub enum HkdfKind {
/// Sha3
#[strum(serialize = "sha3")]
Sha3 = 0,
}
impl HkdfKind {

View File

@ -27,6 +27,10 @@ impl Random {
pub fn fill(&self, out: &mut [u8]) {
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

View File

@ -8,10 +8,19 @@ use crate::{
use ::zeroize::Zeroize;
/// 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)]
pub enum CipherKind {
/// XChaCha20_Poly1305
#[strum(serialize = "xchacha20poly1305")]
XChaCha20Poly1305 = 0,
}

View File

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

View File

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