diff --git a/src/connection/handshake/dirsync.rs b/src/connection/handshake/dirsync.rs index c5ef626..775f301 100644 --- a/src/connection/handshake/dirsync.rs +++ b/src/connection/handshake/dirsync.rs @@ -78,7 +78,7 @@ impl Req { + KeyID::len() + KeyExchange::len() + CipherKind::len() - + self.exchange_key.len() + + self.exchange_key.kind().pub_len() } /// return the total length of the cleartext data pub fn encrypted_length(&self) -> usize { @@ -92,7 +92,7 @@ impl Req { KeyID::len() + KeyExchange::len() + CipherKind::len() - + self.exchange_key.len() + + self.exchange_key.kind().pub_len() + self.data.len() } /// Serialize into raw bytes diff --git a/src/connection/mod.rs b/src/connection/mod.rs index 9d8a4cb..e264cf7 100644 --- a/src/connection/mod.rs +++ b/src/connection/mod.rs @@ -200,3 +200,12 @@ impl ConnList { } } } + +/* +use ::std::collections::HashMap; + +pub(crate) struct AuthServerConnections { + conn_map : HashMap< + pub id: IDSend, +} +*/ diff --git a/src/dnssec/record.rs b/src/dnssec/record.rs index 5f5e09f..b4e9bb9 100644 --- a/src/dnssec/record.rs +++ b/src/dnssec/record.rs @@ -23,10 +23,10 @@ //! * Y bytes: pubkey //! ] +use crate::enc::{self, asym::PubKey}; use ::core::num::NonZeroU16; use ::num_traits::FromPrimitive; use ::std::{net::IpAddr, vec::Vec}; - /* * Public key data */ @@ -48,92 +48,6 @@ impl TryFrom<&str> for PublicKeyID { } } -/// Public Key Type -#[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)] -// public enum: use non_exhaustive to force users to add a default case -// so in the future we can expand this easily -#[non_exhaustive] -#[repr(u8)] -pub enum PublicKeyType { - /// ed25519 asymmetric key - Ed25519 = 0, - /// Ephemeral X25519 (Curve25519) key. - /// Used in the directory synchronized handshake - X25519, -} - -impl PublicKeyType { - /// Get the size of a public key of this kind - pub fn key_len(&self) -> usize { - match &self { - PublicKeyType::Ed25519 => 32, - PublicKeyType::X25519 => 32, // FIXME: hopefully... - } - } -} - -impl TryFrom<&str> for PublicKeyType { - type Error = ::std::io::Error; - fn try_from(raw: &str) -> Result { - if let Ok(type_u8) = raw.parse::() { - if let Some(kind) = PublicKeyType::from_u8(type_u8) { - return Ok(kind); - } - } - return Err(::std::io::Error::new( - ::std::io::ErrorKind::InvalidData, - "Public Key Type 0 is the only one supported", - )); - } -} - -/// Public Key, with its type and id -#[derive(Debug, Clone)] -pub struct PublicKey { - /// public key raw data - pub raw: Vec, - /// type of public key - pub kind: PublicKeyType, - /// id of public key - pub id: PublicKeyID, -} - -impl PublicKey { - fn raw_len(&self) -> usize { - let size = 2; // Public Key Type + ID - size + self.raw.len() - } - fn encode_into(&self, raw: &mut Vec) { - raw.push(self.kind as u8); - raw.push(self.id.0); - raw.extend_from_slice(&self.raw); - } - fn decode_raw(raw: &[u8]) -> Result<(Self, usize), Error> { - if raw.len() < 4 { - return Err(Error::NotEnoughData(0)); - } - - let kind = PublicKeyType::from_u8(raw[0]).unwrap(); - let id = PublicKeyID(raw[1]); - if raw.len() < 2 + kind.key_len() { - return Err(Error::NotEnoughData(2)); - } - - let mut raw_key = Vec::with_capacity(kind.key_len()); - let total_length = 2 + kind.key_len(); - raw_key.extend_from_slice(&raw[2..total_length]); - - Ok(( - Self { - raw: raw_key, - kind, - id, - }, - total_length, - )) - } -} - /* * Address data */ @@ -358,7 +272,7 @@ impl Address { let raw_port = u16::from_le_bytes([raw[1], raw[2]]); - // Add publi key ids + // Add publickey ids let num_pubkey_ids = raw[3] as usize; if raw.len() < 3 + num_pubkey_ids { return Err(Error::NotEnoughData(3)); @@ -428,14 +342,14 @@ impl Address { } /* - * Actual record puuting it all toghether + * Actual record putting it all toghether */ /// All informations found in the DNSSEC record #[derive(Debug, Clone)] pub struct Record { /// Public keys used by any authentication server - pub public_keys: Vec, + pub public_keys: Vec<(PublicKeyID, PubKey)>, /// List of all authentication servers' addresses. /// Multiple ones can point to the same authentication server pub addresses: Vec
, @@ -461,7 +375,11 @@ impl Record { let total_size: usize = 1 + self.addresses.iter().map(|a| a.raw_len()).sum::() - + self.public_keys.iter().map(|a| a.raw_len()).sum::(); + + self + .public_keys + .iter() + .map(|(_, key)| 1 + key.kind().pub_len()) + .sum::(); let mut raw = Vec::with_capacity(total_size); @@ -475,8 +393,9 @@ impl Record { for address in self.addresses.iter() { address.encode_into(&mut raw); } - for public_key in self.public_keys.iter() { - public_key.encode_into(&mut raw); + for (public_key_id, public_key) in self.public_keys.iter() { + raw.push(public_key_id.0); + public_key.serialize_into(&mut raw); } Ok(::base85::encode(&raw)) @@ -514,19 +433,21 @@ impl Record { num_addresses = num_addresses - 1; } while num_public_keys > 0 { + let id = PublicKeyID(raw[bytes_parsed]); + bytes_parsed = bytes_parsed + 1; let (public_key, bytes) = - match PublicKey::decode_raw(&raw[bytes_parsed..]) { + match PubKey::deserialize(&raw[bytes_parsed..]) { Ok(public_key) => public_key, - Err(Error::UnsupportedData(b)) => { + Err(enc::Error::UnsupportedKey(b)) => { return Err(Error::UnsupportedData(bytes_parsed + b)) } - Err(Error::NotEnoughData(b)) => { + Err(enc::Error::NotEnoughData(b)) => { return Err(Error::NotEnoughData(bytes_parsed + b)) } - Err(e) => return Err(e), + _ => return Err(Error::UnknownData(bytes_parsed)), }; bytes_parsed = bytes_parsed + bytes; - result.public_keys.push(public_key); + result.public_keys.push((id, public_key)); num_public_keys = num_public_keys - 1; } if bytes_parsed != raw.len() { diff --git a/src/enc/asym.rs b/src/enc/asym.rs index 56027df..160ee12 100644 --- a/src/enc/asym.rs +++ b/src/enc/asym.rs @@ -20,18 +20,52 @@ impl KeyID { } } +/// Capabilities of each key +#[derive(Debug, Clone, Copy)] +pub enum KeyCapabilities { + /// signing *only* + Sign, + /// encrypt *only* + Encrypt, + /// key exchange *only* + Exchange, + /// both sign and encrypt + SignEncrypt, + /// both signing and key exchange + SignExchange, + /// both encrypt and key exchange + EncryptExchange, + /// All: sign, encrypt, Key Exchange + SignEncryptExchage, +} + /// Kind of key used in the handshake #[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)] +#[non_exhaustive] #[repr(u8)] -pub enum Key { - /// X25519 Public key - X25519 = 0, +pub enum KeyKind { + /// Ed25519 Public key (sign only) + Ed25519 = 0, + /// X25519 Public key (key exchange) + X25519, } -impl Key { - fn pub_len(&self) -> usize { +// FIXME: actually check this +const MIN_KEY_SIZE: usize = 32; +impl KeyKind { + /// return the expected length of the public key + pub fn pub_len(&self) -> usize { match self { // FIXME: 99% wrong size - Key::X25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN, + KeyKind::Ed25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN, + // FIXME: 99% wrong size + KeyKind::X25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN, + } + } + /// Get the capabilities of this key type + pub fn capabilities(&self) -> KeyCapabilities { + match self { + KeyKind::Ed25519 => KeyCapabilities::Sign, + KeyKind::X25519 => KeyCapabilities::Exchange, } } } @@ -50,9 +84,80 @@ impl KeyExchange { } } -/// Kind of key in the handshake +/// Kind of public key in the handshake +#[derive(Debug, Copy, Clone)] +#[allow(missing_debug_implementations)] +#[non_exhaustive] +pub enum PubKey { + /// Keys to be used only in key exchanges, not for signing + Exchange(ExchangePubKey), + /// Keys to be used only for signing + Signing, +} + +impl PubKey { + /// return the kind of public key + pub fn kind(&self) -> KeyKind { + match self { + // FIXME: lie, we don't fully support this + PubKey::Signing => KeyKind::Ed25519, + PubKey::Exchange(ex) => ex.kind(), + } + } + /// serialize the key into the buffer + /// NOTE: Assumes there is enough space + pub fn serialize_into(&self, out: &mut [u8]) { + assert!( + out.len() >= 1 + self.kind().pub_len(), + "Not enough out buffer", + ); + out[0] = self.kind() as u8; + match self { + PubKey::Signing => { + ::tracing::error!("serializing ed25519 not supported"); + return; + } + PubKey::Exchange(ex) => ex.serialize_into(&mut out[1..]), + } + } + /// Try to deserialize the pubkey from raw bytes + /// on success returns the public key and the number of parsed bytes + pub fn deserialize(raw: &[u8]) -> Result<(Self, usize), Error> { + if raw.len() < 1 + MIN_KEY_SIZE { + return Err(Error::NotEnoughData(0)); + } + let kind: KeyKind = match KeyKind::from_u8(raw[0]) { + Some(kind) => kind, + None => return Err(Error::UnsupportedKey(1)), + }; + if raw.len() < 1 + kind.pub_len() { + return Err(Error::NotEnoughData(1)); + } + match kind { + KeyKind::Ed25519 => { + ::tracing::error!("ed25519 keys are not yet supported"); + return Err(Error::Parsing); + } + KeyKind::X25519 => { + let pub_key: ::x25519_dalek::PublicKey = + match ::bincode::deserialize(&raw[1..(1 + kind.pub_len())]) + { + Ok(pub_key) => pub_key, + Err(_) => return Err(Error::Parsing), + }; + Ok(( + PubKey::Exchange(ExchangePubKey::X25519(pub_key)), + kind.pub_len(), + )) + } + } + } +} + +/// Kind of private key in the handshake #[derive(Clone)] #[allow(missing_debug_implementations)] +#[non_exhaustive] pub enum PrivKey { /// Keys to be used only in key exchanges, not for signing Exchange(ExchangePrivKey), @@ -63,6 +168,7 @@ pub enum PrivKey { /// Ephemeral private keys #[derive(Clone)] #[allow(missing_debug_implementations)] +#[non_exhaustive] pub enum ExchangePrivKey { /// X25519(Curve25519) used for key exchange X25519(::x25519_dalek::StaticSecret), @@ -70,9 +176,9 @@ pub enum ExchangePrivKey { impl ExchangePrivKey { /// Get the kind of key - pub fn kind(&self) -> Key { + pub fn kind(&self) -> KeyKind { match self { - ExchangePrivKey::X25519(_) => Key::X25519, + ExchangePrivKey::X25519(_) => KeyKind::X25519, } } /// Run the key exchange between two keys of the same kind @@ -99,30 +205,44 @@ impl ExchangePrivKey { /// all Ephemeral Public keys #[derive(Debug, Copy, Clone)] +#[non_exhaustive] pub enum ExchangePubKey { /// X25519(Curve25519) used for key exchange X25519(::x25519_dalek::PublicKey), } impl ExchangePubKey { - /// length of the public key used for key exchange - pub fn len(&self) -> usize { + /// Get the kind of key + pub fn kind(&self) -> KeyKind { match self { - ExchangePubKey::X25519(_) => 32, + ExchangePubKey::X25519(_) => KeyKind::X25519, + } + } + /// serialize the key into the buffer + /// NOTE: Assumes there is enough space + fn serialize_into(&self, out: &mut [u8]) { + match self { + ExchangePubKey::X25519(pk) => { + let bytes = pk.as_bytes(); + assert!(bytes.len() == 32, "x25519 should have been 32 bytes"); + out[..32].copy_from_slice(bytes); + } } } /// 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 = 32; if raw.len() < 1 + MIN_KEY_SIZE { - return Err(Error::NotEnoughData); + return Err(Error::NotEnoughData(0)); } - match Key::from_u8(raw[0]) { + match KeyKind::from_u8(raw[0]) { Some(kind) => match kind { - Key::X25519 => { + KeyKind::Ed25519 => { + ::tracing::error!("ed25519 keys are not yet supported"); + return Err(Error::Parsing); + } + KeyKind::X25519 => { let pub_key: ::x25519_dalek::PublicKey = match ::bincode::deserialize( &raw[1..(1 + kind.pub_len())], diff --git a/src/enc/errors.rs b/src/enc/errors.rs index ded1fc0..c0591b0 100644 --- a/src/enc/errors.rs +++ b/src/enc/errors.rs @@ -8,14 +8,13 @@ pub enum Error { Parsing, /// Not enough data #[error("not enough data")] - NotEnoughData, + NotEnoughData(usize), /// buffer too small #[error("buffer too small")] InsufficientBuffer, - /// Wrong Key type found. - /// You might have passed rsa keys where x25519 was expected - #[error("wrong key type")] - WrongKey, + /// Unsupported Key type found. + #[error("unsupported key type")] + UnsupportedKey(usize), /// Unsupported key exchange for this key #[error("unsupported key exchange")] UnsupportedKeyExchange, diff --git a/src/inner/mod.rs b/src/inner/mod.rs index ec09d1f..9ee6942 100644 --- a/src/inner/mod.rs +++ b/src/inner/mod.rs @@ -70,7 +70,7 @@ pub(crate) struct ThreadTracker { /// (udp_src_sender_port % total_threads) - 1 pub(crate) struct HandshakeTracker { thread_id: ThreadTracker, - key_exchanges: Vec<(asym::Key, asym::KeyExchange)>, + key_exchanges: Vec<(asym::KeyKind, asym::KeyExchange)>, ciphers: Vec, /// ephemeral keys used server side in key exchange keys_srv: Vec,