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 ];
], msg.f_empty_tag = [
f_empty_tag : [ 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05,
// tag 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, ];
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 ];
], msg.f_static = [
f_static : [ 0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06,
// encrypted static public key 0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c, 0x5d, 0xa4,
0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06, 0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9,
0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c, 0x5d, 0xa4, 0xeb, 0x6a, 0xec, 0xc3, 0x3c, 0xda, 0x47, 0xe1
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,
f_static_tag : [ 0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42
// poly1305 tag ];
0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, msg.f_timestamp = [
0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42 0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0,
], 0x78, 0x28, 0x57, 0x42
f_timestamp : [ ];
// timestamp msg.f_timestamp_tag = [
0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05,
0x78, 0x28, 0x57, 0x42 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde
], ];
f_timestamp_tag : [
// poly1305 tag
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05,
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")
}
} }
} }