summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/handshake/device.rs25
-rw-r--r--src/handshake/macs.rs93
-rw-r--r--src/handshake/peer.rs4
-rw-r--r--src/handshake/types.rs2
4 files changed, 97 insertions, 27 deletions
diff --git a/src/handshake/device.rs b/src/handshake/device.rs
index f3458ae..2a676a8 100644
--- a/src/handshake/device.rs
+++ b/src/handshake/device.rs
@@ -8,6 +8,7 @@ use rand::rngs::OsRng;
use x25519_dalek::PublicKey;
use x25519_dalek::StaticSecret;
+use super::macs;
use super::messages::{CookieReply, Initiation, Response};
use super::messages::{TYPE_COOKIEREPLY, TYPE_INITIATION, TYPE_RESPONSE};
use super::noise;
@@ -17,6 +18,7 @@ use super::types::*;
pub struct Device<T> {
pub sk: StaticSecret, // static secret key
pub pk: PublicKey, // static public key
+ macs: macs::Validator, // validator for the mac fields
pk_map: HashMap<[u8; 32], Peer<T>>, // public key -> peer state
id_map: RwLock<HashMap<u32, [u8; 32]>>, // receiver ids -> public key
}
@@ -34,9 +36,11 @@ where
///
/// * `sk` - x25519 scalar representing the local private key
pub fn new(sk: StaticSecret) -> Device<T> {
+ let pk = PublicKey::from(&sk);
Device {
- pk: PublicKey::from(&sk),
- sk: sk,
+ pk,
+ sk,
+ macs: macs::Validator::new(pk),
pk_map: HashMap::new(),
id_map: RwLock::new(HashMap::new()),
}
@@ -167,7 +171,9 @@ where
// add macs to initation
- peer.macs.generate(msg.noise.as_bytes(), &mut msg.macs);
+ peer.macs
+ .lock()
+ .generate(msg.noise.as_bytes(), &mut msg.macs);
Ok(msg.as_bytes().to_owned())
}
@@ -184,8 +190,10 @@ where
Some(&TYPE_INITIATION) => {
let msg = Initiation::parse(msg)?;
- // check mac footer and ratelimiter for initiation
+ // check mac1 field
+ self.macs.check_mac1(msg.noise.as_bytes(), &msg.macs)?;
+ // check ratelimiter
// consume the initiation
let (peer, st) = noise::consume_initiation(self, &msg.noise)?;
@@ -203,9 +211,11 @@ where
})?;
// add macs to response
+ peer.macs
+ .lock()
+ .generate(resp.noise.as_bytes(), &mut resp.macs);
- resp.macs.f_mac1 = [8u8; 16];
-
+ // return unconfirmed keypair and the response as vector
Ok((
peer.identifier,
Some(resp.as_bytes().to_owned()),
@@ -215,7 +225,8 @@ where
Some(&TYPE_RESPONSE) => {
let msg = Response::parse(msg)?;
- // check mac footer and ratelimiter
+ // check mac1 field
+ self.macs.check_mac1(msg.noise.as_bytes(), &msg.macs)?;
noise::consume_response(self, &msg.noise)
}
diff --git a/src/handshake/macs.rs b/src/handshake/macs.rs
index 9092daa..f558362 100644
--- a/src/handshake/macs.rs
+++ b/src/handshake/macs.rs
@@ -1,10 +1,11 @@
-use std::time::Instant;
+use std::time::{Duration, Instant};
use blake2::Blake2s;
use subtle::ConstantTimeEq;
use x25519_dalek::PublicKey;
use super::messages::{CookieReply, MacsFooter};
+use super::types::HandshakeError;
const LABEL_MAC1: &[u8] = b"mac1----";
const LABEL_COOKIE: &[u8] = b"cookie--";
@@ -12,6 +13,8 @@ const LABEL_COOKIE: &[u8] = b"cookie--";
const SIZE_COOKIE: usize = 16;
const SIZE_MAC: usize = 16; // blake2s-mac128
+const SECS_COOKIE_UPDATE: u64 = 120;
+
macro_rules! HASH {
( $($input:expr),* ) => {{
use blake2::Digest;
@@ -38,39 +41,93 @@ macro_rules! MAC {
}};
}
+struct Cookie {
+ value: [u8; 16],
+ birth: Instant,
+}
+
pub struct Generator {
mac1_key: [u8; 32],
- cookie_value: [u8; 16],
- cookie_birth: Option<Instant>, // when was the cookie set?
+ last_mac1: Option<[u8; 16]>,
+ cookie: Option<Cookie>,
}
impl Generator {
+ /// Initalize a new mac field generator
+ ///
+ /// # Arguments
+ ///
+ /// - pk: The public key of the peer to which the generator is associated
+ ///
+ /// # Returns
+ ///
+ /// A freshly initated generator
pub fn new(pk: PublicKey) -> Generator {
Generator {
mac1_key: HASH!(LABEL_MAC1, pk.as_bytes()).into(),
- cookie_value: [0u8; SIZE_COOKIE],
- cookie_birth: None,
+ last_mac1: None,
+ cookie: None,
}
}
- fn mac1(&self, msg: &[u8]) -> [u8; SIZE_MAC] {
- MAC!(&self.mac1_key, msg)
+ /// Process a CookieReply message
+ ///
+ /// # Arguments
+ ///
+ /// - reply: CookieReply to process
+ ///
+ /// # Returns
+ ///
+ /// Can fail if the cookie reply fails to validate
+ /// (either indicating that it is outdated or malformed)
+ pub fn process(&mut self, reply: &CookieReply) -> Option<HandshakeError> {
+ self.cookie = Some(Cookie {
+ birth: Instant::now(),
+ value: reply.f_cookie,
+ });
+ None
}
- fn mac2(&self, msg: &[u8]) -> [u8; SIZE_MAC] {
- MAC!(&self.cookie_value, msg)
+ /// Generate both mac fields for an inner message
+ ///
+ /// # Arguments
+ ///
+ /// - inner: A byteslice representing the inner message to be covered
+ /// - macs: The destination mac footer for the resulting macs
+ pub fn generate(&mut self, inner: &[u8], macs: &mut MacsFooter) {
+ macs.f_mac1 = MAC!(&self.mac1_key, inner);
+ macs.f_mac2 = match &self.cookie {
+ Some(cookie) => {
+ if cookie.birth.elapsed() > Duration::from_secs(SECS_COOKIE_UPDATE) {
+ self.cookie = None;
+ [0u8; SIZE_MAC]
+ } else {
+ MAC!(&cookie.value, inner, macs.f_mac1)
+ }
+ }
+ None => [0u8; SIZE_MAC],
+ };
+ self.last_mac1 = Some(macs.f_mac1);
}
+}
- pub fn set_cookie(&mut self, cookie: &[u8; SIZE_COOKIE]) {
- self.cookie_birth = Some(Instant::now());
- self.cookie_value = *cookie;
- }
+pub struct Validator {
+ mac1_key: [u8; 32],
+}
- pub fn generate(&self, inner: &[u8], macs : &mut MacsFooter) {
+impl Validator {
+ pub fn new(pk: PublicKey) -> Validator {
+ Validator {
+ mac1_key: HASH!(LABEL_MAC1, pk.as_bytes()).into(),
+ }
+ }
+ pub fn check_mac1(&self, inner: &[u8], macs: &MacsFooter) -> Result<(), HandshakeError> {
+ let valid_mac1: bool = MAC!(&self.mac1_key, inner).ct_eq(&macs.f_mac1).into();
+ if !valid_mac1 {
+ Err(HandshakeError::InvalidMac1)
+ } else {
+ Ok(())
+ }
}
}
-
-pub struct Validator {}
-
-impl Validator {}
diff --git a/src/handshake/peer.rs b/src/handshake/peer.rs
index 309a9cf..9645799 100644
--- a/src/handshake/peer.rs
+++ b/src/handshake/peer.rs
@@ -26,7 +26,7 @@ pub struct Peer<T> {
timestamp: Mutex<Option<timestamp::TAI64N>>,
// state related to DoS mitigation fields
- pub(crate) macs: macs::Generator,
+ pub(crate) macs: Mutex<macs::Generator>,
// constant state
pub(crate) pk: PublicKey, // public key of peer
@@ -73,7 +73,7 @@ where
ss: SharedSecret, // precomputed DH(static, static)
) -> Self {
Self {
- macs: macs::Generator::new(pk),
+ macs: Mutex::new(macs::Generator::new(pk)),
identifier: identifier,
state: Mutex::new(State::Reset),
timestamp: Mutex::new(None),
diff --git a/src/handshake/types.rs b/src/handshake/types.rs
index 0d9a5d3..6a35e1c 100644
--- a/src/handshake/types.rs
+++ b/src/handshake/types.rs
@@ -42,6 +42,7 @@ pub enum HandshakeError {
InvalidMessageFormat,
OldTimestamp,
InvalidState,
+ InvalidMac1,
}
impl fmt::Display for HandshakeError {
@@ -55,6 +56,7 @@ impl fmt::Display for HandshakeError {
HandshakeError::InvalidMessageFormat => write!(f, "Invalid handshake message format"),
HandshakeError::OldTimestamp => write!(f, "Timestamp is less/equal to the newest"),
HandshakeError::InvalidState => write!(f, "Message does not apply to handshake state"),
+ HandshakeError::InvalidMac1 => write!(f, "Message has invalid mac1 field"),
}
}
}