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
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
],
f_empty_tag : [
// tag
];
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
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
],
f_static : [
// encrypted static public key
];
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
],
f_static_tag : [
// poly1305 tag
];
msg.f_static_tag = [
0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02,
0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42
],
f_timestamp : [
// timestamp
];
msg.f_timestamp = [
0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0,
0x78, 0x28, 0x57, 0x42
],
f_timestamp_tag : [
// poly1305 tag
];
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")
}
}
}