Begin creation of response

This commit is contained in:
Mathias Hall-Andersen
2019-07-18 19:52:23 +02:00
parent 14e9647afd
commit e0e95d9679
7 changed files with 164 additions and 94 deletions

View File

@@ -3,6 +3,7 @@ name = "wg-handshake"
version = "0.1.0" version = "0.1.0"
authors = ["Mathias Hall-Andersen <mathias@hall-andersen.dk>"] authors = ["Mathias Hall-Andersen <mathias@hall-andersen.dk>"]
edition = "2018" edition = "2018"
license = "GPL-3.0"
[dependencies] [dependencies]
rand = "0.6.5" rand = "0.6.5"

View File

@@ -60,13 +60,13 @@ impl Device {
// map : pk -> new index // 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 // map : new index -> peer
self.peers.push(Peer::new( self.peers.push(Peer::new(
pk, idx, pk, self.sk.diffie_hellman(&pk)
self.sk.diffie_hellman(&pk)
)); ));
Ok(()) Ok(())
@@ -115,19 +115,12 @@ impl Device {
None => Err(HandshakeError::UnknownPublicKey), None => Err(HandshakeError::UnknownPublicKey),
Some(&idx) => { Some(&idx) => {
let peer = &self.peers[idx]; let peer = &self.peers[idx];
let id = self.allocate(idx); let sender = self.allocate(idx);
noise::create_initiation(self, peer, id) 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. /// Process a handshake message.
/// ///
/// # Arguments /// # Arguments
@@ -136,7 +129,17 @@ impl Device {
pub fn process(&self, msg : &[u8]) -> Result<Output, HandshakeError> { pub fn process(&self, msg : &[u8]) -> Result<Output, HandshakeError> {
match msg.get(0) { match msg.get(0) {
Some(&messages::TYPE_INITIATION) => { 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) => { Some(&messages::TYPE_RESPONSE) => {
Err(HandshakeError::InvalidMessageFormat) Err(HandshakeError::InvalidMessageFormat)
@@ -144,6 +147,13 @@ impl Device {
_ => Err(HandshakeError::InvalidMessageFormat) _ => 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 { impl Device {

View File

@@ -4,3 +4,7 @@ mod messages;
mod peer; mod peer;
mod device; mod device;
mod timestamp; mod timestamp;
// publicly exposed interface
pub use device::Device;

View File

@@ -11,10 +11,12 @@ const SIZE_TIMESTAMP : usize = 12;
pub const TYPE_INITIATION : u8 = 1; pub const TYPE_INITIATION : u8 = 1;
pub const TYPE_RESPONSE : u8 = 2; pub const TYPE_RESPONSE : u8 = 2;
/* Functions related to the packing / unpacking of
/* Wireguard handshake (noise) initiation message * the fixed-sized noise handshake messages.
* initator -> responder *
* The unpacked types are unexposed implementation details.
*/ */
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Initiation { pub struct Initiation {
@@ -83,15 +85,6 @@ impl Into<Vec<u8>> 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 { impl Default for Initiation {
fn default() -> Self { fn default() -> Self {
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)] #[cfg(test)]
impl PartialEq for Initiation { impl PartialEq for Initiation {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
@@ -122,10 +124,6 @@ impl PartialEq for Initiation {
#[cfg(test)] #[cfg(test)]
impl Eq for Initiation {} impl Eq for Initiation {}
/* Wireguard handshake (noise) responder message
* responder -> initator
*/
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Response { pub struct Response {
@@ -194,6 +192,19 @@ impl Into<Vec<u8>> 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 { impl fmt::Debug for Response {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, write!(f,
@@ -220,23 +231,20 @@ mod tests {
#[test] #[test]
fn message_response_identity() { fn message_response_identity() {
let msg = Response { let mut msg : Response = Default::default();
f_type : TYPE_RESPONSE as u32,
f_sender : 146252, msg.f_sender = 146252;
f_receiver : 554442, msg.f_receiver = 554442;
f_ephemeral : [ msg.f_ephemeral = [
// ephemeral public key
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51,
0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e,
0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67,
0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f 0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f
], ];
f_empty_tag : [ msg.f_empty_tag = [
// tag
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05,
0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde
] ];
};
let buf : Vec<u8> = msg.into(); let buf : Vec<u8> = msg.into();
let msg_p : Response = Response::try_from(&buf[..]).unwrap(); let msg_p : Response = Response::try_from(&buf[..]).unwrap();
@@ -245,39 +253,33 @@ mod tests {
#[test] #[test]
fn message_initiate_identity() { fn message_initiate_identity() {
let msg = Initiation { let mut msg : Initiation = Default::default();
f_type : TYPE_INITIATION as u32,
f_sender : 575757, msg.f_sender = 575757;
f_ephemeral : [ msg.f_ephemeral = [
// ephemeral public key
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51,
0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e,
0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67,
0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f 0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f
], ];
f_static : [ msg.f_static = [
// encrypted static public key
0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06, 0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06,
0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c, 0x5d, 0xa4, 0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c, 0x5d, 0xa4,
0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9, 0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9,
0xeb, 0x6a, 0xec, 0xc3, 0x3c, 0xda, 0x47, 0xe1 0xeb, 0x6a, 0xec, 0xc3, 0x3c, 0xda, 0x47, 0xe1
], ];
f_static_tag : [ msg.f_static_tag = [
// poly1305 tag
0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, 0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02,
0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42 0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42
], ];
f_timestamp : [ msg.f_timestamp = [
// timestamp
0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, 0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0,
0x78, 0x28, 0x57, 0x42 0x78, 0x28, 0x57, 0x42
], ];
f_timestamp_tag : [ msg.f_timestamp_tag = [
// poly1305 tag
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05,
0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde
] ];
};
let buf : Vec<u8> = msg.into(); let buf : Vec<u8> = msg.into();
assert_eq!(msg, Initiation::try_from(&buf[..]).unwrap()); assert_eq!(msg, Initiation::try_from(&buf[..]).unwrap());

View File

@@ -14,6 +14,9 @@ use crypto::aead::{AeadEncryptor,AeadDecryptor};
use rand::rngs::OsRng; use rand::rngs::OsRng;
use generic_array::typenum::U32;
use generic_array::GenericArray;
use crate::types::*; use crate::types::*;
use crate::peer::{State, Peer}; use crate::peer::{State, Peer};
use crate::device::Device; use crate::device::Device;
@@ -248,7 +251,10 @@ pub fn create_initiation(
Ok(Initiation::into(msg)) Ok(Initiation::into(msg))
} }
pub fn process_initiation(device : &Device, msg : &[u8]) -> Result<Output, HandshakeError> { pub fn consume_initiation<'a>(
device : &'a Device,
msg : &[u8]
) -> Result<(&'a Peer, u32, GenericArray<u8, U32>, GenericArray<u8, U32>), HandshakeError> {
// parse message // parse message
@@ -310,15 +316,27 @@ pub fn process_initiation(device : &Device, msg : &[u8]) -> Result<Output, Hands
&msg.f_timestamp_tag // tag &msg.f_timestamp_tag // tag
)?; )?;
// update state of peer // check and update timestamp
peer.set_state_timestamp( peer.check_timestamp(&ts)?;
State::InitiationSent{
hs : hs, // return state (to create response)
ck : ck
}, Ok((peer, msg.f_sender, hs, ck))
&ts }
)?;
pub fn create_response(
device : &Device,
peer : &Peer,
sender : u32,
receiver : u32,
hs : GenericArray<u8, U32>,
ck : GenericArray<u8, U32>
) -> Result<Output, HandshakeError> {
let mut msg : Response = Default::default();
// parse message
Ok(Output(None, None)) Ok(Output(None, None))
} }

View File

@@ -9,7 +9,14 @@ use x25519_dalek::SharedSecret;
use crate::types::*; use crate::types::*;
use crate::timestamp; 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 struct Peer {
pub idx : usize,
// mutable state // mutable state
state : Mutex<State>, state : Mutex<State>,
timestamp : Mutex<Option<timestamp::TAI64N>>, timestamp : Mutex<Option<timestamp::TAI64N>>,
@@ -31,10 +38,12 @@ pub enum State {
impl Peer { impl Peer {
pub fn new( pub fn new(
idx : usize,
pk : PublicKey, // public key of peer pk : PublicKey, // public key of peer
ss : SharedSecret // precomputed DH(static, static) ss : SharedSecret // precomputed DH(static, static)
) -> Self { ) -> Self {
Self { Self {
idx : idx,
state : Mutex::new(State::Reset), state : Mutex::new(State::Reset),
timestamp : Mutex::new(None), timestamp : Mutex::new(None),
pk : pk, pk : pk,
@@ -62,6 +71,28 @@ impl Peer {
*state = state_new; *state = state_new;
} }
/// # Arguments
///
/// * ts_new - The timestamp
///
/// # Returns
///
/// A Boolean indicating if the state was updated
pub fn check_timestamp(&self,
timestamp_new : &timestamp::TAI64N) -> Result<(), HandshakeError> {
let mut timestamp = self.timestamp.lock().unwrap();
match *timestamp {
None => Ok(()),
Some(timestamp_old) => if timestamp::compare(&timestamp_old, &timestamp_new) {
*timestamp = Some(*timestamp_new);
Ok(())
} else {
Err(HandshakeError::OldTimestamp)
}
}
}
/// Set the mutable state of the peer conditioned on the timestamp being newer /// Set the mutable state of the peer conditioned on the timestamp being newer
/// ///
/// # Arguments /// # Arguments

View File

@@ -1,11 +1,6 @@
use std::fmt; use std::fmt;
use std::error::Error; use std::error::Error;
use x25519_dalek::PublicKey;
use x25519_dalek::SharedSecret;
use crate::timestamp;
// config error // config error
#[derive(Debug)] #[derive(Debug)]
@@ -45,7 +40,16 @@ pub enum HandshakeError {
impl fmt::Display for HandshakeError { impl fmt::Display for HandshakeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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")
}
} }
} }