Begin creation of response
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
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_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());
|
||||||
|
|||||||
36
src/noise.rs
36
src/noise.rs
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/peer.rs
31
src/peer.rs
@@ -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 : ×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
|
/// Set the mutable state of the peer conditioned on the timestamp being newer
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
|||||||
16
src/types.rs
16
src/types.rs
@@ -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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user