More on negotiation and dnssec record verification
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
08d2755656
commit
5b338c8758
|
@ -11,6 +11,7 @@ use ::std::rc::Rc;
|
||||||
|
|
||||||
/// Handshake errors
|
/// Handshake errors
|
||||||
#[derive(::thiserror::Error, Debug, Copy, Clone)]
|
#[derive(::thiserror::Error, Debug, Copy, Clone)]
|
||||||
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Error while parsing the handshake packet
|
/// Error while parsing the handshake packet
|
||||||
/// TODO: more detailed parsing errors
|
/// TODO: more detailed parsing errors
|
||||||
|
@ -25,6 +26,12 @@ pub enum Error {
|
||||||
/// Not enough data
|
/// Not enough data
|
||||||
#[error("not enough data")]
|
#[error("not enough data")]
|
||||||
NotEnoughData,
|
NotEnoughData,
|
||||||
|
/// Could not find common cryptography
|
||||||
|
#[error("Negotiation of keys/hkdfs/ciphers failed")]
|
||||||
|
Negotiation,
|
||||||
|
/// Could not generate Keys
|
||||||
|
#[error("Key generation failed")]
|
||||||
|
KeyGeneration,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List of possible handshakes
|
/// List of possible handshakes
|
||||||
|
|
|
@ -46,7 +46,7 @@ use crate::{
|
||||||
connection::handshake::HandshakeID,
|
connection::handshake::HandshakeID,
|
||||||
enc::{
|
enc::{
|
||||||
self,
|
self,
|
||||||
asym::{KeyExchangeKind, KeyID, PubKey},
|
asym::{ExchangePubKey, KeyExchangeKind, KeyID, PubKey},
|
||||||
hkdf::HkdfKind,
|
hkdf::HkdfKind,
|
||||||
sym::CipherKind,
|
sym::CipherKind,
|
||||||
},
|
},
|
||||||
|
@ -498,7 +498,7 @@ impl Record {
|
||||||
let (public_key, bytes) = match PubKey::deserialize(
|
let (public_key, bytes) = match PubKey::deserialize(
|
||||||
&raw[bytes_parsed..(bytes_parsed + pubkey_length)],
|
&raw[bytes_parsed..(bytes_parsed + pubkey_length)],
|
||||||
) {
|
) {
|
||||||
Ok(public_key_and_bytes) => public_key_and_bytes,
|
Ok((public_key, bytes)) => (public_key, bytes),
|
||||||
Err(enc::Error::UnsupportedKey(_)) => {
|
Err(enc::Error::UnsupportedKey(_)) => {
|
||||||
// continue parsing. This could be a new pubkey type
|
// continue parsing. This could be a new pubkey type
|
||||||
// that is not supported by an older client
|
// that is not supported by an older client
|
||||||
|
@ -582,6 +582,14 @@ impl Record {
|
||||||
if idx.0 as usize >= result.public_keys.len() {
|
if idx.0 as usize >= result.public_keys.len() {
|
||||||
return Err(Error::Max16PublicKeys);
|
return Err(Error::Max16PublicKeys);
|
||||||
}
|
}
|
||||||
|
if !result.public_keys[idx.0 as usize]
|
||||||
|
.1
|
||||||
|
.kind()
|
||||||
|
.capabilities()
|
||||||
|
.has_exchange()
|
||||||
|
{
|
||||||
|
return Err(Error::UnsupportedData(bytes_parsed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if bytes_parsed != raw.len() {
|
if bytes_parsed != raw.len() {
|
||||||
|
|
|
@ -41,6 +41,17 @@ pub enum KeyCapabilities {
|
||||||
/// All: sign, encrypt, Key Exchange
|
/// All: sign, encrypt, Key Exchange
|
||||||
SignEncryptExchage,
|
SignEncryptExchage,
|
||||||
}
|
}
|
||||||
|
impl KeyCapabilities {
|
||||||
|
/// Check if this key supports eky exchage
|
||||||
|
pub fn has_exchange(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
KeyCapabilities::Exchange
|
||||||
|
| KeyCapabilities::SignExchange
|
||||||
|
| KeyCapabilities::SignEncryptExchage => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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)]
|
||||||
|
@ -253,7 +264,7 @@ impl ExchangePubKey {
|
||||||
}
|
}
|
||||||
/// serialize the key into the buffer
|
/// serialize the key into the buffer
|
||||||
/// NOTE: Assumes there is enough space
|
/// NOTE: Assumes there is enough space
|
||||||
fn serialize_into(&self, out: &mut [u8]) {
|
pub fn serialize_into(&self, out: &mut [u8]) {
|
||||||
match self {
|
match self {
|
||||||
ExchangePubKey::X25519(pk) => {
|
ExchangePubKey::X25519(pk) => {
|
||||||
let bytes = pk.as_bytes();
|
let bytes = pk.as_bytes();
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
connection::{
|
connection::{
|
||||||
self,
|
self,
|
||||||
handshake::{
|
handshake::{
|
||||||
|
self,
|
||||||
dirsync::{self, DirSync},
|
dirsync::{self, DirSync},
|
||||||
Handshake, HandshakeData,
|
Handshake, HandshakeData,
|
||||||
},
|
},
|
||||||
|
@ -13,7 +14,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
dnssec,
|
dnssec,
|
||||||
enc::{
|
enc::{
|
||||||
asym::{self, PubKey},
|
asym::{self, PrivKey, PubKey},
|
||||||
hkdf::{self, Hkdf, HkdfKind},
|
hkdf::{self, Hkdf, HkdfKind},
|
||||||
sym::{self, Secret},
|
sym::{self, Secret},
|
||||||
Random,
|
Random,
|
||||||
|
@ -181,6 +182,9 @@ impl Worker {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure this server has a public key
|
||||||
|
// that supports one of the key exchanges that
|
||||||
|
// *we* support
|
||||||
for idx in addr.public_key_idx.iter() {
|
for idx in addr.public_key_idx.iter() {
|
||||||
let key_supported_k_x =
|
let key_supported_k_x =
|
||||||
dnssec_record.public_keys[idx.0 as usize]
|
dnssec_record.public_keys[idx.0 as usize]
|
||||||
|
@ -198,7 +202,7 @@ impl Worker {
|
||||||
addr,
|
addr,
|
||||||
dnssec_record.public_keys
|
dnssec_record.public_keys
|
||||||
[idx.0 as usize],
|
[idx.0 as usize],
|
||||||
exchange,
|
exchange.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
None => return None,
|
None => return None,
|
||||||
|
@ -217,25 +221,27 @@ impl Worker {
|
||||||
continue 'mainloop;
|
continue 'mainloop;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let hkdf = match hkdf::client_select_hkdf(
|
let hkdf_selected = match hkdf::client_select_hkdf(
|
||||||
&self.cfg,
|
&self.cfg,
|
||||||
&dnssec_record.hkdfs,
|
&dnssec_record.hkdfs,
|
||||||
) {
|
) {
|
||||||
Some(hkdf) => hkdf,
|
Some(hkdf_selected) => hkdf_selected,
|
||||||
None => {
|
None => {
|
||||||
let _ = send_res
|
let _ = send_res.send(Err(
|
||||||
.send(Err(crate::Error::HandshakeNegotiation));
|
handshake::Error::Negotiation.into(),
|
||||||
|
));
|
||||||
continue 'mainloop;
|
continue 'mainloop;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let cipher = match sym::client_select_cipher(
|
let cipher_selected = match sym::client_select_cipher(
|
||||||
&self.cfg,
|
&self.cfg,
|
||||||
&dnssec_record.ciphers,
|
&dnssec_record.ciphers,
|
||||||
) {
|
) {
|
||||||
Some(cipher) => cipher,
|
Some(cipher_selected) => cipher_selected,
|
||||||
None => {
|
None => {
|
||||||
let _ = send_res
|
let _ = send_res.send(Err(
|
||||||
.send(Err(crate::Error::HandshakeNegotiation));
|
handshake::Error::Negotiation.into(),
|
||||||
|
));
|
||||||
continue 'mainloop;
|
continue 'mainloop;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -243,8 +249,36 @@ impl Worker {
|
||||||
let (priv_key, pub_key) =
|
let (priv_key, pub_key) =
|
||||||
match exchange.new_keypair(&self.rand) {
|
match exchange.new_keypair(&self.rand) {
|
||||||
Ok(pair) => pair,
|
Ok(pair) => pair,
|
||||||
Err(_) => todo!(),
|
Err(_) => {
|
||||||
|
::tracing::error!("Failed to generate keys");
|
||||||
|
let _ = send_res.send(Err(
|
||||||
|
handshake::Error::KeyGeneration.into(),
|
||||||
|
));
|
||||||
|
continue 'mainloop;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
let hkdf;
|
||||||
|
if let PubKey::Exchange(srv_pub) = key.1 {
|
||||||
|
let secret =
|
||||||
|
match priv_key.key_exchange(exchange, srv_pub) {
|
||||||
|
Ok(secret) => secret,
|
||||||
|
Err(_) => {
|
||||||
|
::tracing::warn!(
|
||||||
|
"Could not run the key exchange"
|
||||||
|
);
|
||||||
|
let _ = send_res.send(Err(
|
||||||
|
handshake::Error::Negotiation.into(),
|
||||||
|
));
|
||||||
|
continue 'mainloop;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
hkdf = Hkdf::new(hkdf_selected, b"fenrir", secret);
|
||||||
|
} else {
|
||||||
|
// crate::dnssec already verifies that the keys
|
||||||
|
// listed in dnssec::Record.addresses.public_key_idx
|
||||||
|
// are PubKey::Exchange
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
// build request
|
// build request
|
||||||
/*
|
/*
|
||||||
let req_data = dirsync::ReqData {
|
let req_data = dirsync::ReqData {
|
||||||
|
|
|
@ -62,9 +62,6 @@ pub enum Error {
|
||||||
/// Resolution problems. wrong or incomplete DNSSEC data
|
/// Resolution problems. wrong or incomplete DNSSEC data
|
||||||
#[error("DNSSEC resolution: {0}")]
|
#[error("DNSSEC resolution: {0}")]
|
||||||
Resolution(String),
|
Resolution(String),
|
||||||
/// No common cryptographic primitives
|
|
||||||
#[error("No common cryptographic primitives")]
|
|
||||||
HandshakeNegotiation,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instance of a fenrir endpoint
|
/// Instance of a fenrir endpoint
|
||||||
|
|
Loading…
Reference in New Issue