DNSSEC: add ciphers/key exchanges/hkdfs
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
c6a3bf0820
commit
1bae4c9953
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
dnssec,
|
dnssec,
|
||||||
enc::{
|
enc::{
|
||||||
asym::PubKey,
|
asym::PubKey,
|
||||||
hkdf::HkdfSha3,
|
hkdf::Hkdf,
|
||||||
sym::{CipherKind, CipherRecv, CipherSend},
|
sym::{CipherKind, CipherRecv, CipherSend},
|
||||||
Random,
|
Random,
|
||||||
},
|
},
|
||||||
|
@ -55,7 +55,7 @@ pub struct Connection {
|
||||||
/// Sending Connection ID
|
/// Sending Connection ID
|
||||||
pub id_send: IDSend,
|
pub id_send: IDSend,
|
||||||
/// The main hkdf used for all secrets in this connection
|
/// The main hkdf used for all secrets in this connection
|
||||||
pub hkdf: HkdfSha3,
|
pub hkdf: Hkdf,
|
||||||
/// Cipher for decrypting data
|
/// Cipher for decrypting data
|
||||||
pub cipher_recv: CipherRecv,
|
pub cipher_recv: CipherRecv,
|
||||||
/// Cipher for encrypting data
|
/// Cipher for encrypting data
|
||||||
|
@ -76,7 +76,7 @@ pub enum Role {
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
hkdf: HkdfSha3,
|
hkdf: Hkdf,
|
||||||
cipher: CipherKind,
|
cipher: CipherKind,
|
||||||
role: Role,
|
role: Role,
|
||||||
rand: &Random,
|
rand: &Random,
|
||||||
|
|
|
@ -3,27 +3,51 @@
|
||||||
//!
|
//!
|
||||||
//! Encoding and decoding in base85, RFC1924
|
//! Encoding and decoding in base85, RFC1924
|
||||||
//!
|
//!
|
||||||
//!
|
|
||||||
//! Basic encoding idea:
|
//! Basic encoding idea:
|
||||||
//! * 1 byte: half-bytes
|
//! * 1 byte: divided in two:
|
||||||
//! * half: num of addresses
|
//! * half: num of addresses
|
||||||
//! * half: num of pubkeys
|
//! * half: num of pubkeys
|
||||||
|
//! * 1 byte: divided in half:
|
||||||
|
//! * half: number of key exchanges
|
||||||
|
//! * half: number of Hkdfs
|
||||||
|
//! * 1 byte: divided in half:
|
||||||
|
//! * half: number of ciphers
|
||||||
|
//! * half: nothing
|
||||||
//! [ # list of addresses
|
//! [ # list of addresses
|
||||||
//! * 1 byte: bitfield
|
//! * 1 byte: bitfield
|
||||||
//! * 0..1 ipv4/ipv6
|
//! * 0..1 ipv4/ipv6
|
||||||
//! * 2..4 priority (for failover)
|
//! * 2..4 priority (for failover)
|
||||||
//! * 5..7 weight between priority
|
//! * 5..7 weight between priority
|
||||||
//! * 1 byte: public key id
|
//! * 1 byte: divided in half:
|
||||||
|
//! * half: num of public key ids
|
||||||
|
//! * half: num of handhskae ids
|
||||||
//! * 2 bytes: UDP port
|
//! * 2 bytes: UDP port
|
||||||
|
//! * [ 1 byte per public key id ]
|
||||||
|
//! * [ 1 byte per handshake id ]
|
||||||
//! * X bytes: IP
|
//! * X bytes: IP
|
||||||
//! ]
|
//! ]
|
||||||
//! [ # list of pubkeys
|
//! [ # list of pubkeys
|
||||||
//! * 1 byte: pubkey id
|
//! * 1 byte: pubkey id
|
||||||
|
//! * 1 byte: pubkey length
|
||||||
//! * 1 byte: pubkey type
|
//! * 1 byte: pubkey type
|
||||||
//! * Y bytes: pubkey
|
//! * Y bytes: pubkey
|
||||||
//! ]
|
//! ]
|
||||||
|
//! [ # list of supported key exchanges
|
||||||
|
//! * 1 byte for each cipher
|
||||||
|
//! ]
|
||||||
|
//! [ # list of supported HDKFs
|
||||||
|
//! * 1 byte for each hkdf
|
||||||
|
//! ]
|
||||||
|
//! [ # list of supported ciphers
|
||||||
|
//! * 1 byte for each cipher
|
||||||
|
//! ]
|
||||||
|
|
||||||
use crate::enc::{self, asym::PubKey};
|
use crate::enc::{
|
||||||
|
self,
|
||||||
|
asym::{KeyExchange, PubKey},
|
||||||
|
hkdf::HkdfKind,
|
||||||
|
sym::CipherKind,
|
||||||
|
};
|
||||||
use ::core::num::NonZeroU16;
|
use ::core::num::NonZeroU16;
|
||||||
use ::num_traits::FromPrimitive;
|
use ::num_traits::FromPrimitive;
|
||||||
use ::std::{net::IpAddr, vec::Vec};
|
use ::std::{net::IpAddr, vec::Vec};
|
||||||
|
@ -220,6 +244,10 @@ impl Address {
|
||||||
bitfield |= self.weight as u8;
|
bitfield |= self.weight as u8;
|
||||||
|
|
||||||
raw.push(bitfield);
|
raw.push(bitfield);
|
||||||
|
let len_combined: u8 = self.public_key_ids.len() as u8;
|
||||||
|
let len_combined = len_combined << 4;
|
||||||
|
let len_combined = len_combined | self.handshake_ids.len() as u8;
|
||||||
|
raw.push(len_combined);
|
||||||
|
|
||||||
raw.extend_from_slice(
|
raw.extend_from_slice(
|
||||||
&(match self.port {
|
&(match self.port {
|
||||||
|
@ -228,10 +256,12 @@ impl Address {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
raw.push(self.public_key_ids.len() as u8);
|
|
||||||
for id in self.public_key_ids.iter() {
|
for id in self.public_key_ids.iter() {
|
||||||
raw.push(id.0);
|
raw.push(id.0);
|
||||||
}
|
}
|
||||||
|
for id in self.handshake_ids.iter() {
|
||||||
|
raw.push(*id as u8);
|
||||||
|
}
|
||||||
|
|
||||||
match self.ip {
|
match self.ip {
|
||||||
IpAddr::V4(ip) => {
|
IpAddr::V4(ip) => {
|
||||||
|
@ -250,19 +280,11 @@ impl Address {
|
||||||
}
|
}
|
||||||
let ip_type = raw[0] >> 6;
|
let ip_type = raw[0] >> 6;
|
||||||
let is_ipv6: bool;
|
let is_ipv6: bool;
|
||||||
let total_length: usize;
|
|
||||||
match ip_type {
|
match ip_type {
|
||||||
0 => {
|
0 => {
|
||||||
is_ipv6 = false;
|
is_ipv6 = false;
|
||||||
total_length = 8;
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
total_length = 20;
|
|
||||||
if raw.len() < total_length {
|
|
||||||
return Err(Error::NotEnoughData(1));
|
|
||||||
}
|
|
||||||
is_ipv6 = true
|
|
||||||
}
|
}
|
||||||
|
1 => is_ipv6 = true,
|
||||||
_ => return Err(Error::UnsupportedData(0)),
|
_ => return Err(Error::UnsupportedData(0)),
|
||||||
}
|
}
|
||||||
let raw_priority = (raw[0] << 2) >> 5;
|
let raw_priority = (raw[0] << 2) >> 5;
|
||||||
|
@ -270,28 +292,33 @@ 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();
|
||||||
|
|
||||||
|
// UDP port
|
||||||
let raw_port = u16::from_le_bytes([raw[1], raw[2]]);
|
let raw_port = u16::from_le_bytes([raw[1], raw[2]]);
|
||||||
|
let port = if raw_port == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(NonZeroU16::new(raw_port).unwrap())
|
||||||
|
};
|
||||||
|
|
||||||
// Add publickey ids
|
// Add publickey ids
|
||||||
let num_pubkey_ids = raw[3] as usize;
|
let num_pubkey_ids = (raw[3] >> 4) as usize;
|
||||||
if raw.len() < 3 + num_pubkey_ids {
|
let num_handshake_ids = (raw[3] & 0x0F) as usize;
|
||||||
|
if raw.len() <= 3 + num_pubkey_ids + num_handshake_ids {
|
||||||
return Err(Error::NotEnoughData(3));
|
return Err(Error::NotEnoughData(3));
|
||||||
}
|
}
|
||||||
|
let mut bytes_parsed = 4;
|
||||||
let mut public_key_ids = Vec::with_capacity(num_pubkey_ids);
|
let mut public_key_ids = Vec::with_capacity(num_pubkey_ids);
|
||||||
|
for raw_pubkey_id in
|
||||||
for raw_pubkey_id in raw[4..num_pubkey_ids].iter() {
|
raw[bytes_parsed..(bytes_parsed + num_pubkey_ids)].iter()
|
||||||
|
{
|
||||||
public_key_ids.push(PublicKeyID(*raw_pubkey_id));
|
public_key_ids.push(PublicKeyID(*raw_pubkey_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add handshake ids
|
// add handshake ids
|
||||||
let next_ptr = 3 + num_pubkey_ids;
|
bytes_parsed = bytes_parsed + 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);
|
let mut handshake_ids = Vec::with_capacity(num_handshake_ids);
|
||||||
for raw_handshake_id in
|
for raw_handshake_id in
|
||||||
raw[next_ptr..(next_ptr + num_pubkey_ids)].iter()
|
raw[bytes_parsed..(bytes_parsed + num_handshake_ids)].iter()
|
||||||
{
|
{
|
||||||
match HandshakeID::from_u8(*raw_handshake_id) {
|
match HandshakeID::from_u8(*raw_handshake_id) {
|
||||||
Some(h_id) => handshake_ids.push(h_id),
|
Some(h_id) => handshake_ids.push(h_id),
|
||||||
|
@ -304,26 +331,24 @@ impl Address {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let next_ptr = next_ptr + num_pubkey_ids;
|
bytes_parsed = bytes_parsed + num_handshake_ids;
|
||||||
|
|
||||||
let port = if raw_port == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(NonZeroU16::new(raw_port).unwrap())
|
|
||||||
};
|
|
||||||
let ip = if is_ipv6 {
|
let ip = if is_ipv6 {
|
||||||
let ip_end = next_ptr + 16;
|
let ip_end = bytes_parsed + 16;
|
||||||
if raw.len() < ip_end {
|
if raw.len() < ip_end {
|
||||||
return Err(Error::NotEnoughData(next_ptr));
|
return Err(Error::NotEnoughData(bytes_parsed));
|
||||||
}
|
}
|
||||||
let raw_ip: [u8; 16] = raw[next_ptr..ip_end].try_into().unwrap();
|
let raw_ip: [u8; 16] =
|
||||||
|
raw[bytes_parsed..ip_end].try_into().unwrap();
|
||||||
|
bytes_parsed = bytes_parsed + 16;
|
||||||
IpAddr::from(raw_ip)
|
IpAddr::from(raw_ip)
|
||||||
} else {
|
} else {
|
||||||
let ip_end = next_ptr + 4;
|
let ip_end = bytes_parsed + 4;
|
||||||
if raw.len() < ip_end {
|
if raw.len() < ip_end {
|
||||||
return Err(Error::NotEnoughData(next_ptr));
|
return Err(Error::NotEnoughData(bytes_parsed));
|
||||||
}
|
}
|
||||||
let raw_ip: [u8; 4] = raw[next_ptr..ip_end].try_into().unwrap();
|
let raw_ip: [u8; 4] = raw[bytes_parsed..ip_end].try_into().unwrap();
|
||||||
|
bytes_parsed = bytes_parsed + 4;
|
||||||
IpAddr::from(raw_ip)
|
IpAddr::from(raw_ip)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -336,7 +361,7 @@ impl Address {
|
||||||
public_key_ids,
|
public_key_ids,
|
||||||
handshake_ids,
|
handshake_ids,
|
||||||
},
|
},
|
||||||
total_length,
|
bytes_parsed,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,6 +378,12 @@ pub struct Record {
|
||||||
/// List of all authentication servers' addresses.
|
/// List of all authentication servers' addresses.
|
||||||
/// Multiple ones can point to the same authentication server
|
/// Multiple ones can point to the same authentication server
|
||||||
pub addresses: Vec<Address>,
|
pub addresses: Vec<Address>,
|
||||||
|
/// List of supported key exchanges
|
||||||
|
pub key_exchanges: Vec<KeyExchange>,
|
||||||
|
/// List of supported key exchanges
|
||||||
|
pub hkdfs: Vec<HkdfKind>,
|
||||||
|
/// List of supported ciphers
|
||||||
|
pub ciphers: Vec<CipherKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Record {
|
impl Record {
|
||||||
|
@ -371,15 +402,27 @@ impl Record {
|
||||||
if self.addresses.len() > 16 {
|
if self.addresses.len() > 16 {
|
||||||
return Err(Error::Max16Addresses);
|
return Err(Error::Max16Addresses);
|
||||||
}
|
}
|
||||||
|
if self.key_exchanges.len() > 16 {
|
||||||
|
return Err(Error::Max16KeyExchanges);
|
||||||
|
}
|
||||||
|
if self.hkdfs.len() > 16 {
|
||||||
|
return Err(Error::Max16Hkdfs);
|
||||||
|
}
|
||||||
|
if self.ciphers.len() > 16 {
|
||||||
|
return Err(Error::Max16Ciphers);
|
||||||
|
}
|
||||||
// everything else is all good
|
// everything else is all good
|
||||||
|
|
||||||
let total_size: usize = 1
|
let total_size: usize = 3
|
||||||
+ self.addresses.iter().map(|a| a.raw_len()).sum::<usize>()
|
+ self.addresses.iter().map(|a| a.raw_len()).sum::<usize>()
|
||||||
+ self
|
+ self
|
||||||
.public_keys
|
.public_keys
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, key)| 1 + key.kind().pub_len())
|
.map(|(_, key)| 3 + key.kind().pub_len())
|
||||||
.sum::<usize>();
|
.sum::<usize>()
|
||||||
|
+ self.key_exchanges.len()
|
||||||
|
+ self.hkdfs.len()
|
||||||
|
+ self.ciphers.len();
|
||||||
|
|
||||||
let mut raw = Vec::with_capacity(total_size);
|
let mut raw = Vec::with_capacity(total_size);
|
||||||
|
|
||||||
|
@ -387,33 +430,56 @@ impl Record {
|
||||||
let len_combined: u8 = self.addresses.len() as u8;
|
let len_combined: u8 = self.addresses.len() as u8;
|
||||||
let len_combined = len_combined << 4;
|
let len_combined = len_combined << 4;
|
||||||
let len_combined = len_combined | self.public_keys.len() as u8;
|
let len_combined = len_combined | self.public_keys.len() as u8;
|
||||||
|
|
||||||
raw.push(len_combined);
|
raw.push(len_combined);
|
||||||
|
// number of key exchanges and hkdfs
|
||||||
|
let len_combined: u8 = self.key_exchanges.len() as u8;
|
||||||
|
let len_combined = len_combined << 4;
|
||||||
|
let len_combined = len_combined | self.hkdfs.len() as u8;
|
||||||
|
raw.push(len_combined);
|
||||||
|
let num_of_ciphers: u8 = (self.ciphers.len() as u8) << 4;
|
||||||
|
raw.push(num_of_ciphers);
|
||||||
|
|
||||||
for address in self.addresses.iter() {
|
for address in self.addresses.iter() {
|
||||||
address.encode_into(&mut raw);
|
address.encode_into(&mut raw);
|
||||||
}
|
}
|
||||||
for (public_key_id, public_key) in self.public_keys.iter() {
|
for (public_key_id, public_key) in self.public_keys.iter() {
|
||||||
raw.push(public_key_id.0);
|
raw.push(public_key_id.0);
|
||||||
|
raw.push(public_key.kind().pub_len() as u8);
|
||||||
|
raw.push(public_key.kind() as u8);
|
||||||
public_key.serialize_into(&mut raw);
|
public_key.serialize_into(&mut raw);
|
||||||
}
|
}
|
||||||
|
for k_x in self.key_exchanges.iter() {
|
||||||
|
raw.push(*k_x as u8);
|
||||||
|
}
|
||||||
|
for h in self.hkdfs.iter() {
|
||||||
|
raw.push(*h as u8);
|
||||||
|
}
|
||||||
|
for c in self.ciphers.iter() {
|
||||||
|
raw.push(*c as u8);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(::base85::encode(&raw))
|
Ok(::base85::encode(&raw))
|
||||||
}
|
}
|
||||||
/// Decode from base85 to the actual object
|
/// Decode from base85 to the actual object
|
||||||
pub fn decode(raw: &[u8]) -> Result<Self, Error> {
|
pub fn decode(raw: &[u8]) -> Result<Self, Error> {
|
||||||
// bare minimum for 1 address and key
|
// bare minimum for 1 address, 1 key, 1 key exchange and 1 cipher
|
||||||
const MIN_RAW_LENGTH: usize = 1 + 8 + 8;
|
const MIN_RAW_LENGTH: usize = 1 + 1 + 1 + 8 + 9 + 1 + 1;
|
||||||
if raw.len() <= MIN_RAW_LENGTH {
|
if raw.len() <= MIN_RAW_LENGTH {
|
||||||
return Err(Error::NotEnoughData(0));
|
return Err(Error::NotEnoughData(0));
|
||||||
}
|
}
|
||||||
let mut num_addresses = (raw[0] >> 4) as usize;
|
let mut num_addresses = (raw[0] >> 4) as usize;
|
||||||
let mut num_public_keys = (raw[0] & 0x0F) as usize;
|
let mut num_public_keys = (raw[0] & 0x0F) as usize;
|
||||||
let mut bytes_parsed = 1;
|
let mut num_key_exchanges = (raw[1] >> 4) as usize;
|
||||||
|
let mut num_hkdfs = (raw[1] & 0x0F) as usize;
|
||||||
|
let mut num_ciphers = (raw[2] >> 4) as usize;
|
||||||
|
let mut bytes_parsed = 3;
|
||||||
|
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
addresses: Vec::with_capacity(num_addresses),
|
addresses: Vec::with_capacity(num_addresses),
|
||||||
public_keys: Vec::with_capacity(num_public_keys),
|
public_keys: Vec::with_capacity(num_public_keys),
|
||||||
|
key_exchanges: Vec::with_capacity(num_key_exchanges),
|
||||||
|
hkdfs: Vec::with_capacity(num_hkdfs),
|
||||||
|
ciphers: Vec::with_capacity(num_ciphers),
|
||||||
};
|
};
|
||||||
|
|
||||||
while num_addresses > 0 {
|
while num_addresses > 0 {
|
||||||
|
@ -433,23 +499,97 @@ impl Record {
|
||||||
num_addresses = num_addresses - 1;
|
num_addresses = num_addresses - 1;
|
||||||
}
|
}
|
||||||
while num_public_keys > 0 {
|
while num_public_keys > 0 {
|
||||||
|
if bytes_parsed + 2 >= raw.len() {
|
||||||
|
return Err(Error::NotEnoughData(bytes_parsed));
|
||||||
|
}
|
||||||
let id = PublicKeyID(raw[bytes_parsed]);
|
let id = PublicKeyID(raw[bytes_parsed]);
|
||||||
bytes_parsed = bytes_parsed + 1;
|
bytes_parsed = bytes_parsed + 1;
|
||||||
let (public_key, bytes) =
|
let pubkey_length = raw[bytes_parsed] as usize;
|
||||||
match PubKey::deserialize(&raw[bytes_parsed..]) {
|
bytes_parsed = bytes_parsed + 1;
|
||||||
Ok(public_key) => public_key,
|
if pubkey_length + bytes_parsed >= raw.len() {
|
||||||
Err(enc::Error::UnsupportedKey(b)) => {
|
return Err(Error::NotEnoughData(bytes_parsed));
|
||||||
return Err(Error::UnsupportedData(bytes_parsed + b))
|
}
|
||||||
}
|
let (public_key, bytes) = match PubKey::deserialize(
|
||||||
Err(enc::Error::NotEnoughData(b)) => {
|
&raw[bytes_parsed..(bytes_parsed + pubkey_length)],
|
||||||
return Err(Error::NotEnoughData(bytes_parsed + b))
|
) {
|
||||||
}
|
Ok(public_key_and_bytes) => public_key_and_bytes,
|
||||||
_ => return Err(Error::UnknownData(bytes_parsed)),
|
Err(enc::Error::UnsupportedKey(_)) => {
|
||||||
};
|
// continue parsing. This could be a new pubkey type
|
||||||
|
// that is not supported by an older client
|
||||||
|
::tracing::warn!("Unsupported public key type");
|
||||||
|
bytes_parsed = bytes_parsed + pubkey_length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
return Err(Error::UnsupportedData(bytes_parsed));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if bytes != 1 + pubkey_length {
|
||||||
|
return Err(Error::UnsupportedData(bytes_parsed));
|
||||||
|
}
|
||||||
bytes_parsed = bytes_parsed + bytes;
|
bytes_parsed = bytes_parsed + bytes;
|
||||||
result.public_keys.push((id, public_key));
|
result.public_keys.push((id, public_key));
|
||||||
num_public_keys = num_public_keys - 1;
|
num_public_keys = num_public_keys - 1;
|
||||||
}
|
}
|
||||||
|
if bytes_parsed + num_key_exchanges + num_hkdfs + num_ciphers
|
||||||
|
!= raw.len()
|
||||||
|
{
|
||||||
|
return Err(Error::NotEnoughData(bytes_parsed));
|
||||||
|
}
|
||||||
|
while num_key_exchanges > 0 {
|
||||||
|
let key_exchange = match KeyExchange::from_u8(raw[bytes_parsed]) {
|
||||||
|
Some(key_exchange) => key_exchange,
|
||||||
|
None => {
|
||||||
|
// continue parsing. This could be a new key exchange type
|
||||||
|
// that is not supported by an older client
|
||||||
|
::tracing::warn!(
|
||||||
|
"Unknown Key exchange {}. Ignoring",
|
||||||
|
raw[bytes_parsed]
|
||||||
|
);
|
||||||
|
bytes_parsed = bytes_parsed + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bytes_parsed = bytes_parsed + 1;
|
||||||
|
result.key_exchanges.push(key_exchange);
|
||||||
|
num_key_exchanges = num_key_exchanges - 1;
|
||||||
|
}
|
||||||
|
while num_hkdfs > 0 {
|
||||||
|
let hkdf = match HkdfKind::from_u8(raw[bytes_parsed]) {
|
||||||
|
Some(hkdf) => hkdf,
|
||||||
|
None => {
|
||||||
|
// continue parsing. This could be a new hkdf type
|
||||||
|
// that is not supported by an older client
|
||||||
|
::tracing::warn!(
|
||||||
|
"Unknown hkdf {}. Ignoring",
|
||||||
|
raw[bytes_parsed]
|
||||||
|
);
|
||||||
|
bytes_parsed = bytes_parsed + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bytes_parsed = bytes_parsed + 1;
|
||||||
|
result.hkdfs.push(hkdf);
|
||||||
|
num_hkdfs = num_hkdfs - 1;
|
||||||
|
}
|
||||||
|
while num_ciphers > 0 {
|
||||||
|
let cipher = match CipherKind::from_u8(raw[bytes_parsed]) {
|
||||||
|
Some(cipher) => cipher,
|
||||||
|
None => {
|
||||||
|
// continue parsing. This could be a new cipher type
|
||||||
|
// that is not supported by an older client
|
||||||
|
::tracing::warn!(
|
||||||
|
"Unknown Cipher {}. Ignoring",
|
||||||
|
raw[bytes_parsed]
|
||||||
|
);
|
||||||
|
bytes_parsed = bytes_parsed + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bytes_parsed = bytes_parsed + 1;
|
||||||
|
result.ciphers.push(cipher);
|
||||||
|
num_ciphers = num_ciphers - 1;
|
||||||
|
}
|
||||||
if bytes_parsed != raw.len() {
|
if bytes_parsed != raw.len() {
|
||||||
Err(Error::UnknownData(bytes_parsed))
|
Err(Error::UnknownData(bytes_parsed))
|
||||||
} else {
|
} else {
|
||||||
|
@ -470,6 +610,15 @@ pub enum Error {
|
||||||
/// Too many addresses (max 16)
|
/// Too many addresses (max 16)
|
||||||
#[error("can't encode more than 16 addresses")]
|
#[error("can't encode more than 16 addresses")]
|
||||||
Max16Addresses,
|
Max16Addresses,
|
||||||
|
/// Too many key exchanges (max 16)
|
||||||
|
#[error("can't encode more than 16 key exchanges")]
|
||||||
|
Max16KeyExchanges,
|
||||||
|
/// Too many Hkdfs (max 16)
|
||||||
|
#[error("can't encode more than 16 Hkdfs")]
|
||||||
|
Max16Hkdfs,
|
||||||
|
/// Too many ciphers (max 16)
|
||||||
|
#[error("can't encode more than 16 Ciphers")]
|
||||||
|
Max16Ciphers,
|
||||||
/// We need at least one public key
|
/// We need at least one public key
|
||||||
#[error("no public keys found")]
|
#[error("no public keys found")]
|
||||||
NoPublicKeyFound,
|
NoPublicKeyFound,
|
||||||
|
|
|
@ -1,12 +1,52 @@
|
||||||
//! Hash-based Key Derivation Function
|
//! Hash-based Key Derivation Function
|
||||||
//! We just repackage other crates
|
//! We just repackage other crates
|
||||||
|
|
||||||
use ::hkdf::Hkdf;
|
|
||||||
use ::sha3::Sha3_256;
|
use ::sha3::Sha3_256;
|
||||||
use ::zeroize::Zeroize;
|
use ::zeroize::Zeroize;
|
||||||
|
|
||||||
use crate::enc::sym::Secret;
|
use crate::enc::sym::Secret;
|
||||||
|
|
||||||
|
/// Kind of HKDF
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum HkdfKind {
|
||||||
|
/// Sha3
|
||||||
|
Sha3 = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic wrapper on Hkdfs
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Hkdf {
|
||||||
|
/// Sha3 based
|
||||||
|
Sha3(HkdfSha3),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake debug implementation to avoid leaking secrets
|
||||||
|
impl ::core::fmt::Debug for Hkdf {
|
||||||
|
fn fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> Result<(), ::std::fmt::Error> {
|
||||||
|
::core::fmt::Debug::fmt("[hidden hkdf]", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hkdf {
|
||||||
|
/// New Hkdf
|
||||||
|
pub fn new(kind: HkdfKind, salt: &[u8], key: Secret) -> Self {
|
||||||
|
match kind {
|
||||||
|
HkdfKind::Sha3 => Self::Sha3(HkdfSha3::new(salt, key)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Get a secret generated from the key and a given context
|
||||||
|
pub fn get_secret(&self, context: &[u8]) -> Secret {
|
||||||
|
match self {
|
||||||
|
Hkdf::Sha3(sha3) => sha3.get_secret(context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hack & tricks:
|
// Hack & tricks:
|
||||||
// HKDF are pretty important, but this lib don't zero out the data.
|
// HKDF are pretty important, but this lib don't zero out the data.
|
||||||
// we can't use #[derive(Zeroing)] either.
|
// we can't use #[derive(Zeroing)] either.
|
||||||
|
@ -14,10 +54,10 @@ use crate::enc::sym::Secret;
|
||||||
|
|
||||||
#[derive(Zeroize)]
|
#[derive(Zeroize)]
|
||||||
#[zeroize(drop)]
|
#[zeroize(drop)]
|
||||||
struct Zeroable([u8; ::core::mem::size_of::<Hkdf<Sha3_256>>()]);
|
struct Zeroable([u8; ::core::mem::size_of::<::hkdf::Hkdf<Sha3_256>>()]);
|
||||||
|
|
||||||
union HkdfInner {
|
union HkdfInner {
|
||||||
hkdf: ::core::mem::ManuallyDrop<Hkdf<Sha3_256>>,
|
hkdf: ::core::mem::ManuallyDrop<::hkdf::Hkdf<Sha3_256>>,
|
||||||
zeroable: ::core::mem::ManuallyDrop<Zeroable>,
|
zeroable: ::core::mem::ManuallyDrop<Zeroable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +90,7 @@ pub struct HkdfSha3 {
|
||||||
impl HkdfSha3 {
|
impl HkdfSha3 {
|
||||||
/// Instantiate a new HKDF with Sha3-256
|
/// Instantiate a new HKDF with Sha3-256
|
||||||
pub fn new(salt: &[u8], key: Secret) -> Self {
|
pub fn new(salt: &[u8], key: Secret) -> Self {
|
||||||
let hkdf = Hkdf::<Sha3_256>::new(Some(salt), key.as_ref());
|
let hkdf = ::hkdf::Hkdf::<Sha3_256>::new(Some(salt), key.as_ref());
|
||||||
Self {
|
Self {
|
||||||
inner: HkdfInner {
|
inner: HkdfInner {
|
||||||
hkdf: ::core::mem::ManuallyDrop::new(hkdf),
|
hkdf: ::core::mem::ManuallyDrop::new(hkdf),
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
enc::{
|
enc::{
|
||||||
self, asym,
|
self, asym,
|
||||||
hkdf::HkdfSha3,
|
hkdf::{Hkdf, HkdfKind},
|
||||||
sym::{CipherKind, CipherRecv},
|
sym::{CipherKind, CipherRecv},
|
||||||
},
|
},
|
||||||
Error,
|
Error,
|
||||||
|
@ -26,7 +26,7 @@ pub(crate) struct AuthNeededInfo {
|
||||||
/// Parsed handshake packet
|
/// Parsed handshake packet
|
||||||
pub handshake: Handshake,
|
pub handshake: Handshake,
|
||||||
/// hkdf generated from the handshake
|
/// hkdf generated from the handshake
|
||||||
pub hkdf: HkdfSha3,
|
pub hkdf: Hkdf,
|
||||||
/// cipher to be used in both directions
|
/// cipher to be used in both directions
|
||||||
pub cipher: CipherKind,
|
pub cipher: CipherKind,
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ impl HandshakeTracker {
|
||||||
Ok(shared_key) => shared_key,
|
Ok(shared_key) => shared_key,
|
||||||
Err(e) => return Err(handshake::Error::Key(e).into()),
|
Err(e) => return Err(handshake::Error::Key(e).into()),
|
||||||
};
|
};
|
||||||
let hkdf = HkdfSha3::new(b"fenrir", shared_key);
|
let hkdf = Hkdf::new(HkdfKind::Sha3, b"fenrir", shared_key);
|
||||||
let secret_recv = hkdf.get_secret(b"to_server");
|
let secret_recv = hkdf.get_secret(b"to_server");
|
||||||
let cipher_recv = CipherRecv::new(req.cipher, secret_recv);
|
let cipher_recv = CipherRecv::new(req.cipher, secret_recv);
|
||||||
use crate::enc::sym::AAD;
|
use crate::enc::sym::AAD;
|
||||||
|
|
|
@ -11,7 +11,12 @@ use crate::{
|
||||||
ConnList, Connection, IDSend, Packet,
|
ConnList, Connection, IDSend, Packet,
|
||||||
},
|
},
|
||||||
dnssec,
|
dnssec,
|
||||||
enc::{asym::PubKey, hkdf::HkdfSha3, sym::Secret, Random},
|
enc::{
|
||||||
|
asym::PubKey,
|
||||||
|
hkdf::{Hkdf, HkdfKind},
|
||||||
|
sym::Secret,
|
||||||
|
Random,
|
||||||
|
},
|
||||||
inner::{HandshakeAction, HandshakeTracker, ThreadTracker},
|
inner::{HandshakeAction, HandshakeTracker, ThreadTracker},
|
||||||
};
|
};
|
||||||
use ::std::{rc::Rc, sync::Arc, vec::Vec};
|
use ::std::{rc::Rc, sync::Arc, vec::Vec};
|
||||||
|
@ -381,7 +386,8 @@ impl Worker {
|
||||||
// SECURITY:
|
// SECURITY:
|
||||||
//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 = HkdfSha3::new(
|
let hkdf = Hkdf::new(
|
||||||
|
HkdfKind::Sha3,
|
||||||
cci.service_id.as_bytes(),
|
cci.service_id.as_bytes(),
|
||||||
resp_data.service_key,
|
resp_data.service_key,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue