aboutsummaryrefslogtreecommitdiffstats
path: root/src/handshake/macs.rs
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2019-08-05 21:37:31 +0200
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2019-08-05 21:37:31 +0200
commitabc8cacf44247597aa76213770ff49e0505a19b7 (patch)
treec0509b8a6babe099f3bd8fdc579746c7a58f999f /src/handshake/macs.rs
parentValidate mac2 field (diff)
downloadwireguard-rs-abc8cacf44247597aa76213770ff49e0505a19b7.tar.xz
wireguard-rs-abc8cacf44247597aa76213770ff49e0505a19b7.zip
Checking of mac2 fields on initiation & response
In addition, moved the rng out. This will allow allocating one instance per worker, rather than every call.
Diffstat (limited to 'src/handshake/macs.rs')
-rw-r--r--src/handshake/macs.rs88
1 files changed, 45 insertions, 43 deletions
diff --git a/src/handshake/macs.rs b/src/handshake/macs.rs
index d95489f..65fd7fa 100644
--- a/src/handshake/macs.rs
+++ b/src/handshake/macs.rs
@@ -1,15 +1,14 @@
-use std::time::{Duration, Instant};
-
-use rand::CryptoRng;
-use rand::RngCore;
-
+use rand::{CryptoRng, RngCore};
use spin::Mutex;
+use std::time::{Duration, Instant};
use blake2::Blake2s;
+use sodiumoxide::crypto::aead::xchacha20poly1305_ietf;
use subtle::ConstantTimeEq;
use x25519_dalek::PublicKey;
-use sodiumoxide::crypto::aead::xchacha20poly1305_ietf;
+use std::net::SocketAddr;
+use zerocopy::AsBytes;
use super::messages::{CookieReply, MacsFooter};
use super::types::HandshakeError;
@@ -100,6 +99,23 @@ pub struct Generator {
cookie: Option<Cookie>,
}
+fn addr_to_mac_bytes(addr: &SocketAddr) -> Vec<u8> {
+ match addr {
+ SocketAddr::V4(addr) => {
+ let mut res = Vec::with_capacity(4 + 2);
+ res.extend(&addr.ip().octets());
+ res.extend(&addr.port().to_le_bytes());
+ res
+ }
+ SocketAddr::V6(addr) => {
+ let mut res = Vec::with_capacity(16 + 2);
+ res.extend(&addr.ip().octets());
+ res.extend(&addr.port().to_le_bytes());
+ res
+ }
+ }
+}
+
impl Generator {
/// Initalize a new mac field generator
///
@@ -193,12 +209,12 @@ impl Validator {
}
}
- fn get_tau(&self, src: &[u8]) -> Result<[u8; SIZE_COOKIE], HandshakeError> {
+ fn get_tau(&self, src: &[u8]) -> Option<[u8; SIZE_COOKIE]> {
let secret = self.secret.lock();
if secret.birth.elapsed() < Duration::from_secs(SECS_COOKIE_UPDATE) {
- Ok(MAC!(&secret.value, src))
+ Some(MAC!(&secret.value, src))
} else {
- Err(HandshakeError::InvalidMac2)
+ None
}
}
@@ -219,25 +235,26 @@ impl Validator {
MAC!(&secret.value, src)
}
- fn create_cookie_reply<T>(
+ pub fn create_cookie_reply<T>(
&self,
rng: &mut T,
receiver: u32, // receiver id of incoming message
- src: &[u8], // source address of incoming message
+ src: &SocketAddr, // source address of incoming message
macs: &MacsFooter, // footer of incoming message
msg: &mut CookieReply, // resulting cookie reply
) where
T: RngCore + CryptoRng,
{
+ let src = addr_to_mac_bytes(src);
msg.f_receiver.set(receiver);
rng.fill_bytes(&mut msg.f_nonce);
XSEAL!(
- &self.cookie_key, // key
- &msg.f_nonce, // nonce
- &macs.f_mac1, // ad
- &self.get_set_tau(rng, src), // pt
- &mut msg.f_cookie, // ct
- &mut msg.f_cookie_tag // tag
+ &self.cookie_key, // key
+ &msg.f_nonce, // nonce
+ &macs.f_mac1, // ad
+ &self.get_set_tau(rng, &src), // pt
+ &mut msg.f_cookie, // ct
+ &mut msg.f_cookie_tag // tagf
);
}
@@ -256,25 +273,11 @@ impl Validator {
}
}
- /// Check the mac2 field against the inner message
- ///
- /// # Arguments
- ///
- /// - inner: The inner message covered by the mac1 field
- /// - src: Source address
- /// - macs: The mac footer
- pub fn check_mac2(
- &self,
- inner: &[u8],
- src: &[u8],
- macs: &MacsFooter,
- ) -> Result<(), HandshakeError> {
- let tau = self.get_tau(src)?;
- let valid_mac2: bool = MAC!(&tau, inner, macs.f_mac1).ct_eq(&macs.f_mac2).into();
- if !valid_mac2 {
- Err(HandshakeError::InvalidMac2)
- } else {
- Ok(())
+ pub fn check_mac2(&self, inner: &[u8], src: &SocketAddr, macs: &MacsFooter) -> bool {
+ let src = addr_to_mac_bytes(src);
+ match self.get_tau(&src) {
+ Some(tau) => MAC!(&tau, inner, macs.f_mac1).ct_eq(&macs.f_mac2).into(),
+ None => false,
}
}
}
@@ -295,10 +298,11 @@ mod tests {
proptest! {
#[test]
- fn test_cookie_reply(inner1 : Vec<u8>, inner2 : Vec<u8>, src: Vec<u8>, receiver : u32) {
+ fn test_cookie_reply(inner1 : Vec<u8>, inner2 : Vec<u8>, receiver : u32) {
let mut msg = CookieReply::default();
- let mut rng = OsRng::new().unwrap();
+ let mut rng = OsRng::new().expect("failed to create rng");
let mut macs = MacsFooter::default();
+ let src = "127.0.0.1:8080".parse().unwrap();
let (validator, mut generator) = new_validator_generator();
// generate mac1 for first message
@@ -308,10 +312,8 @@ mod tests {
// check validity of mac1
validator.check_mac1(&inner1[..], &macs).expect("mac1 of inner1 did not validate");
-
- // generate cookie reply in response
- validator.create_cookie_reply(&mut rng, receiver, &src[..], &macs, &mut msg);
- assert_eq!(msg.f_receiver.get(), receiver);
+ assert_eq!(validator.check_mac2(&inner1[..], &src, &macs), false, "mac2 of inner2 did not validate");
+ validator.create_cookie_reply(&mut rng, receiver, &src, &macs, &mut msg);
// consume cookie reply
generator.process(&msg).expect("failed to process CookieReply");
@@ -323,7 +325,7 @@ mod tests {
// check validity of mac1 and mac2
validator.check_mac1(&inner2[..], &macs).expect("mac1 of inner2 did not validate");
- validator.check_mac2(&inner2[..], &src[..], &macs).expect("mac2 of inner2 did not validate");
+ assert!(validator.check_mac2(&inner2[..], &src, &macs), "mac2 of inner2 did not validate");
}
}
}