From e0e95d9679e4cb0eb905d9f0910a49fe86586982 Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Thu, 18 Jul 2019 19:52:23 +0200 Subject: Begin creation of response --- Cargo.toml | 1 + src/device.rs | 36 +++++++++------ src/lib.rs | 4 ++ src/messages.rs | 134 ++++++++++++++++++++++++++++---------------------------- src/noise.rs | 36 +++++++++++---- src/peer.rs | 31 +++++++++++++ src/types.rs | 16 ++++--- 7 files changed, 164 insertions(+), 94 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 354f8aa..2d27e3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "wg-handshake" version = "0.1.0" authors = ["Mathias Hall-Andersen "] edition = "2018" +license = "GPL-3.0" [dependencies] rand = "0.6.5" diff --git a/src/device.rs b/src/device.rs index 85adc69..0635a5e 100644 --- a/src/device.rs +++ b/src/device.rs @@ -60,13 +60,13 @@ impl Device { // map : pk -> new index - self.pkmap.insert(*pk.as_bytes(), self.peers.len()); + let idx = self.peers.len(); + self.pkmap.insert(*pk.as_bytes(), idx); // map : new index -> peer self.peers.push(Peer::new( - pk, - self.sk.diffie_hellman(&pk) + idx, pk, self.sk.diffie_hellman(&pk) )); Ok(()) @@ -115,19 +115,12 @@ impl Device { None => Err(HandshakeError::UnknownPublicKey), Some(&idx) => { let peer = &self.peers[idx]; - let id = self.allocate(idx); - noise::create_initiation(self, peer, id) + let sender = self.allocate(idx); + noise::create_initiation(self, peer, sender) } } } - pub fn lookup(&self, pk : &PublicKey) -> Result<&Peer, HandshakeError> { - match self.pkmap.get(pk.as_bytes()) { - Some(&idx) => Ok(&self.peers[idx]), - _ => Err(HandshakeError::UnknownPublicKey) - } - } - /// Process a handshake message. /// /// # Arguments @@ -136,7 +129,17 @@ impl Device { pub fn process(&self, msg : &[u8]) -> Result { match msg.get(0) { Some(&messages::TYPE_INITIATION) => { - noise::process_initiation(self, msg) + // consume the initiation + let (peer, receiver, hs, ck) = noise::consume_initiation(self, msg)?; + + // allocate index for response + let sender = self.allocate(peer.idx); + + // create response + noise::create_response(self, peer, sender, receiver, hs, ck).map_err(|e| { + self.release(sender); + e + }) }, Some(&messages::TYPE_RESPONSE) => { Err(HandshakeError::InvalidMessageFormat) @@ -144,6 +147,13 @@ impl Device { _ => Err(HandshakeError::InvalidMessageFormat) } } + + pub fn lookup(&self, pk : &PublicKey) -> Result<&Peer, HandshakeError> { + match self.pkmap.get(pk.as_bytes()) { + Some(&idx) => Ok(&self.peers[idx]), + _ => Err(HandshakeError::UnknownPublicKey) + } + } } impl Device { diff --git a/src/lib.rs b/src/lib.rs index ee22a9b..e2d9b8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,3 +4,7 @@ mod messages; mod peer; mod device; mod timestamp; + +// publicly exposed interface + +pub use device::Device; diff --git a/src/messages.rs b/src/messages.rs index da26e48..52a3393 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -11,10 +11,12 @@ const SIZE_TIMESTAMP : usize = 12; pub const TYPE_INITIATION : u8 = 1; pub const TYPE_RESPONSE : u8 = 2; - -/* Wireguard handshake (noise) initiation message - * initator -> responder +/* Functions related to the packing / unpacking of + * the fixed-sized noise handshake messages. + * + * The unpacked types are unexposed implementation details. */ + #[repr(C)] #[derive(Copy, Clone)] pub struct Initiation { @@ -83,15 +85,6 @@ impl Into> for Initiation { } } -impl fmt::Debug for Initiation { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, - "MessageInitiation {{ type = {} }}", - self.f_type - ) - } -} - impl Default for Initiation { fn default() -> Self { Self { @@ -106,6 +99,15 @@ impl Default for Initiation { } } +impl fmt::Debug for Initiation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, + "MessageInitiation {{ type = {} }}", + self.f_type + ) + } +} + #[cfg(test)] impl PartialEq for Initiation { fn eq(&self, other: &Self) -> bool { @@ -122,10 +124,6 @@ impl PartialEq for Initiation { #[cfg(test)] impl Eq for Initiation {} - -/* Wireguard handshake (noise) responder message - * responder -> initator - */ #[repr(C)] #[derive(Copy, Clone)] pub struct Response { @@ -194,6 +192,19 @@ impl Into> for Response { } } +impl Default for Response { + fn default() -> Self { + Self { + f_type : TYPE_RESPONSE as u32, + f_sender : 0, + f_receiver : 0, + f_ephemeral : [0u8; SIZE_X25519_POINT], + f_empty_tag : [0u8; SIZE_TAG] + } + } +} + + impl fmt::Debug for Response { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, @@ -220,23 +231,20 @@ mod tests { #[test] fn message_response_identity() { - let msg = Response { - f_type : TYPE_RESPONSE as u32, - f_sender : 146252, - f_receiver : 554442, - f_ephemeral : [ - // ephemeral public key - 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, - 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, - 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, - 0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f - ], - f_empty_tag : [ - // tag - 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, - 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde - ] - }; + let mut msg : Response = Default::default(); + + msg.f_sender = 146252; + msg.f_receiver = 554442; + msg.f_ephemeral = [ + 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, + 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, + 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, + 0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f + ]; + msg.f_empty_tag = [ + 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, + 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde + ]; let buf : Vec = msg.into(); let msg_p : Response = Response::try_from(&buf[..]).unwrap(); @@ -245,39 +253,33 @@ mod tests { #[test] fn message_initiate_identity() { - let msg = Initiation { - f_type : TYPE_INITIATION as u32, - f_sender : 575757, - f_ephemeral : [ - // ephemeral public key - 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, - 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, - 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, - 0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f - ], - f_static : [ - // encrypted static public key - 0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06, - 0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c, 0x5d, 0xa4, - 0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9, - 0xeb, 0x6a, 0xec, 0xc3, 0x3c, 0xda, 0x47, 0xe1 - ], - f_static_tag : [ - // poly1305 tag - 0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, - 0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42 - ], - f_timestamp : [ - // timestamp - 0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, - 0x78, 0x28, 0x57, 0x42 - ], - f_timestamp_tag : [ - // poly1305 tag - 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, - 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde - ] - }; + let mut msg : Initiation = Default::default(); + + msg.f_sender = 575757; + msg.f_ephemeral = [ + 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, + 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, + 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, + 0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f + ]; + msg.f_static = [ + 0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06, + 0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c, 0x5d, 0xa4, + 0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9, + 0xeb, 0x6a, 0xec, 0xc3, 0x3c, 0xda, 0x47, 0xe1 + ]; + msg.f_static_tag = [ + 0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, + 0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42 + ]; + msg.f_timestamp = [ + 0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, + 0x78, 0x28, 0x57, 0x42 + ]; + msg.f_timestamp_tag = [ + 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, + 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde + ]; let buf : Vec = msg.into(); assert_eq!(msg, Initiation::try_from(&buf[..]).unwrap()); diff --git a/src/noise.rs b/src/noise.rs index 9de03cd..9f127e8 100644 --- a/src/noise.rs +++ b/src/noise.rs @@ -14,6 +14,9 @@ use crypto::aead::{AeadEncryptor,AeadDecryptor}; use rand::rngs::OsRng; +use generic_array::typenum::U32; +use generic_array::GenericArray; + use crate::types::*; use crate::peer::{State, Peer}; use crate::device::Device; @@ -248,7 +251,10 @@ pub fn create_initiation( Ok(Initiation::into(msg)) } -pub fn process_initiation(device : &Device, msg : &[u8]) -> Result { +pub fn consume_initiation<'a>( + device : &'a Device, + msg : &[u8] +) -> Result<(&'a Peer, u32, GenericArray, GenericArray), HandshakeError> { // parse message @@ -310,15 +316,27 @@ pub fn process_initiation(device : &Device, msg : &[u8]) -> Result, + ck : GenericArray +) -> Result { + + let mut msg : Response = Default::default(); + + // parse message Ok(Output(None, None)) } diff --git a/src/peer.rs b/src/peer.rs index 6c4bb3c..e656d56 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -9,7 +9,14 @@ use x25519_dalek::SharedSecret; use crate::types::*; use crate::timestamp; +/* Represents the recomputation and state of a peer. + * + * This type is only for internal use and not exposed. + */ + pub struct Peer { + pub idx : usize, + // mutable state state : Mutex, timestamp : Mutex>, @@ -31,10 +38,12 @@ pub enum State { impl Peer { pub fn new( + idx : usize, pk : PublicKey, // public key of peer ss : SharedSecret // precomputed DH(static, static) ) -> Self { Self { + idx : idx, state : Mutex::new(State::Reset), timestamp : Mutex::new(None), pk : pk, @@ -62,6 +71,28 @@ impl Peer { *state = state_new; } + /// # Arguments + /// + /// * ts_new - The timestamp + /// + /// # Returns + /// + /// A Boolean indicating if the state was updated + pub fn check_timestamp(&self, + timestamp_new : ×tamp::TAI64N) -> Result<(), HandshakeError> { + + let mut timestamp = self.timestamp.lock().unwrap(); + match *timestamp { + None => Ok(()), + Some(timestamp_old) => if timestamp::compare(×tamp_old, ×tamp_new) { + *timestamp = Some(*timestamp_new); + Ok(()) + } else { + Err(HandshakeError::OldTimestamp) + } + } + } + /// Set the mutable state of the peer conditioned on the timestamp being newer /// /// # Arguments diff --git a/src/types.rs b/src/types.rs index 464ad81..a2a7cdd 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,11 +1,6 @@ use std::fmt; use std::error::Error; -use x25519_dalek::PublicKey; -use x25519_dalek::SharedSecret; - -use crate::timestamp; - // config error #[derive(Debug)] @@ -45,7 +40,16 @@ pub enum HandshakeError { impl fmt::Display for HandshakeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "HandshakeError") + match self { + HandshakeError::DecryptionFailure => + write!(f, "Failed to AEAD:OPEN"), + HandshakeError::UnknownPublicKey => + write!(f, "Unknown public key"), + HandshakeError::InvalidMessageFormat => + write!(f, "Invalid handshake message format"), + HandshakeError::OldTimestamp => + write!(f, "Timestamp is less/equal to the newest") + } } } -- cgit v1.2.3-59-g8ed1b