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"
authors = ["Mathias Hall-Andersen <mathias@hall-andersen.dk>"]
edition = "2018"
license = "GPL-3.0"
[dependencies]
rand = "0.6.5"

View File

@@ -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<Output, HandshakeError> {
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 {

View File

@@ -4,3 +4,7 @@ mod messages;
mod peer;
mod device;
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_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<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 {
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<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 {
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<u8> = 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<u8> = msg.into();
assert_eq!(msg, Initiation::try_from(&buf[..]).unwrap());

View File

@@ -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<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
@@ -310,15 +316,27 @@ pub fn process_initiation(device : &Device, msg : &[u8]) -> Result<Output, Hands
&msg.f_timestamp_tag // tag
)?;
// update state of peer
// check and update timestamp
peer.set_state_timestamp(
State::InitiationSent{
hs : hs,
ck : ck
},
&ts
)?;
peer.check_timestamp(&ts)?;
// return state (to create response)
Ok((peer, msg.f_sender, hs, ck))
}
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))
}

View File

@@ -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<State>,
timestamp : Mutex<Option<timestamp::TAI64N>>,
@@ -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 : &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
///
/// # Arguments

View File

@@ -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")
}
}
}