Begin creation of response
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -4,3 +4,7 @@ mod messages;
|
||||
mod peer;
|
||||
mod device;
|
||||
mod timestamp;
|
||||
|
||||
// publicly exposed interface
|
||||
|
||||
pub use device::Device;
|
||||
|
||||
134
src/messages.rs
134
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<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());
|
||||
|
||||
36
src/noise.rs
36
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<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))
|
||||
}
|
||||
|
||||
31
src/peer.rs
31
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<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 : ×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
|
||||
|
||||
16
src/types.rs
16
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user