From 5efb31817180d08c4ffdff616ab80e5172276c29 Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Fri, 26 Jul 2019 15:46:24 +0200 Subject: Move parser code to zerocopy --- Cargo.lock | 70 ++++++++++++++++++++++ Cargo.toml | 4 +- src/device.rs | 5 +- src/messages.rs | 180 +++++++++++++++----------------------------------------- src/noise.rs | 30 +++++----- 5 files changed, 138 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b4d902..1ff70c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,22 @@ name = "opaque-debug" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.3.23" @@ -285,6 +301,27 @@ name = "subtle" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "0.15.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.42" @@ -300,11 +337,17 @@ name = "typenum" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "wg-handshake" version = "0.1.0" dependencies = [ "blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -312,6 +355,7 @@ dependencies = [ "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zerocopy 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -343,6 +387,25 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "zerocopy" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zerocopy-derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zerocopy-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" @@ -362,6 +425,8 @@ dependencies = [ "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3262021842bf00fe07dbd6cf34ff25c99d7a7ebef8deea84db72be3ea3bb0aff" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" @@ -381,9 +446,14 @@ dependencies = [ "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" +"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4aca1ba6bec2719576bd20dfe5b24d9359552e616d10bff257e50cd85f745d17" +"checksum zerocopy 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "56ae60eda58b25c5c4f5398e2144f72dc1881e50142e232b64e1ba8664d1ce38" +"checksum zerocopy-derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "746f425452bf1e4b74c78d594d5c6f51f8c978e57ba5c236a04ba1aecfc384a7" diff --git a/Cargo.toml b/Cargo.toml index 2ccb719..af24051 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "wg-handshake" version = "0.1.0" authors = ["Mathias Hall-Andersen "] edition = "2018" -license = "GPL-3.0" +license = "MIT" [dependencies] hex = "0.3" @@ -13,6 +13,8 @@ blake2 = "0.8.0" hmac = "0.7.1" rust-crypto = "^0.2" generic-array = "0.12.3" +zerocopy = "0.2.7" +byteorder = "1.3.1" [dependencies.x25519-dalek] version = "^0.5" diff --git a/src/device.rs b/src/device.rs index 838ae63..93ea2aa 100644 --- a/src/device.rs +++ b/src/device.rs @@ -202,7 +202,6 @@ mod tests { use super::*; use hex; use messages::*; - use std::convert::TryFrom; #[test] fn handshake() { @@ -234,7 +233,7 @@ mod tests { let msg1 = dev1.begin(&pk2).unwrap(); println!("msg1 = {}", hex::encode(&msg1[..])); - println!("msg1 = {:?}", Initiation::try_from(&msg1[..]).unwrap()); + println!("msg1 = {:?}", Initiation::parse(&msg1[..]).unwrap()); // process initiation and create response @@ -244,7 +243,7 @@ mod tests { let msg2 = msg2.unwrap(); println!("msg2 = {}", hex::encode(&msg2[..])); - println!("msg2 = {:?}", Response::try_from(&msg2[..]).unwrap()); + println!("msg2 = {:?}", Response::parse(&msg2[..]).unwrap()); assert!(!ks_r.confirmed, "Responders key-pair is confirmed"); diff --git a/src/messages.rs b/src/messages.rs index 136c899..04f1532 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,8 +1,11 @@ -use crate::types::*; use hex; -use std::convert::TryFrom; use std::fmt; -use std::mem; + +use byteorder::LittleEndian; +use zerocopy::byteorder::U32; +use zerocopy::{AsBytes, ByteSlice, FromBytes, LayoutVerified}; + +use crate::types::*; const SIZE_TAG: usize = 16; const SIZE_X25519_POINT: usize = 32; @@ -11,17 +14,11 @@ const SIZE_TIMESTAMP: usize = 12; pub const TYPE_INITIATION: u8 = 1; pub const TYPE_RESPONSE: u8 = 2; -/* 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)] +#[derive(Copy, Clone, FromBytes, AsBytes)] pub struct Initiation { - f_type: u32, - pub f_sender: u32, + f_type: U32, + pub f_sender: U32, pub f_ephemeral: [u8; SIZE_X25519_POINT], pub f_static: [u8; SIZE_X25519_POINT], pub f_static_tag: [u8; SIZE_TAG], @@ -29,63 +26,11 @@ pub struct Initiation { pub f_timestamp_tag: [u8; SIZE_TAG], } -impl TryFrom<&[u8]> for Initiation { - type Error = HandshakeError; - - fn try_from(value: &[u8]) -> Result { - // check length of slice matches message - - if value.len() != mem::size_of::() { - return Err(HandshakeError::InvalidMessageFormat); - } - - // create owned copy - - let mut owned = [0u8; mem::size_of::()]; - let mut msg: Self; - owned.copy_from_slice(value); - - // cast to Initiation - - unsafe { - msg = mem::transmute::<[u8; mem::size_of::()], Self>(owned); - }; - - // correct endianness - - msg.f_type = msg.f_type.to_le(); - msg.f_sender = msg.f_sender.to_le(); - - // check type and reserved fields - - if msg.f_type != (TYPE_INITIATION as u32) { - return Err(HandshakeError::InvalidMessageFormat); - } - - Ok(msg) - } -} - -impl Into> for Initiation { - fn into(self) -> Vec { - // correct endianness - let mut msg = self; - msg.f_type = msg.f_type.to_le(); - msg.f_sender = msg.f_sender.to_le(); - - // cast to array - let array: [u8; mem::size_of::()]; - unsafe { array = mem::transmute::()]>(msg) }; - - array.to_vec() - } -} - impl Default for Initiation { fn default() -> Self { Self { - f_type: TYPE_INITIATION as u32, - f_sender: 0, + f_type: >::new(TYPE_INITIATION as u32), + f_sender: >::new(0), f_ephemeral: [0u8; SIZE_X25519_POINT], f_static: [0u8; SIZE_X25519_POINT], f_static_tag: [0u8; SIZE_TAG], @@ -95,12 +40,25 @@ impl Default for Initiation { } } +impl Initiation { + pub fn parse(bytes: B) -> Result, HandshakeError> { + let msg: LayoutVerified = + LayoutVerified::new(bytes).ok_or(HandshakeError::InvalidMessageFormat)?; + + if msg.f_type.get() != (TYPE_INITIATION as u32) { + return Err(HandshakeError::InvalidMessageFormat); + } + + Ok(msg) + } +} + impl fmt::Debug for Initiation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "MessageInitiation {{ type = {}, sender = {}, ephemeral = {}, static = {}|{}, timestamp = {}|{} }}", - self.f_type, - self.f_sender, + self.f_type.get(), + self.f_sender.get(), hex::encode(self.f_ephemeral), hex::encode(self.f_static), hex::encode(self.f_static_tag), @@ -113,8 +71,8 @@ impl fmt::Debug for Initiation { #[cfg(test)] impl PartialEq for Initiation { fn eq(&self, other: &Self) -> bool { - self.f_type == other.f_type - && self.f_sender == other.f_sender + self.f_type.get() == other.f_type.get() + && self.f_sender.get() == other.f_sender.get() && self.f_ephemeral[..] == other.f_ephemeral[..] && self.f_static[..] == other.f_static[..] && self.f_static_tag[..] == other.f_static_tag[..] @@ -127,46 +85,21 @@ impl PartialEq for Initiation { impl Eq for Initiation {} #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, FromBytes, AsBytes)] pub struct Response { - f_type: u32, - pub f_sender: u32, - pub f_receiver: u32, + f_type: U32, + pub f_sender: U32, + pub f_receiver: U32, pub f_ephemeral: [u8; SIZE_X25519_POINT], pub f_empty_tag: [u8; SIZE_TAG], } -impl TryFrom<&[u8]> for Response { - type Error = HandshakeError; - - fn try_from(value: &[u8]) -> Result { - // check length of slice matches message - - if value.len() != mem::size_of::() { - return Err(HandshakeError::InvalidMessageFormat); - } - - // create owned copy - - let mut owned = [0u8; mem::size_of::()]; - let mut msg: Self; - owned.copy_from_slice(value); - - // cast to MessageResponse - - unsafe { - msg = mem::transmute::<[u8; mem::size_of::()], Self>(owned); - }; - - // correct endianness +impl Response { + pub fn parse(bytes: B) -> Result, HandshakeError> { + let msg: LayoutVerified = + LayoutVerified::new(bytes).ok_or(HandshakeError::InvalidMessageFormat)?; - msg.f_type = msg.f_type.to_le(); - msg.f_sender = msg.f_sender.to_le(); - msg.f_receiver = msg.f_receiver.to_le(); - - // check type and reserved fields - - if msg.f_type != (TYPE_RESPONSE as u32) { + if msg.f_type.get() != (TYPE_RESPONSE as u32) { return Err(HandshakeError::InvalidMessageFormat); } @@ -174,28 +107,12 @@ impl TryFrom<&[u8]> for Response { } } -impl Into> for Response { - fn into(self) -> Vec { - // correct endianness - let mut msg = self; - msg.f_type = msg.f_type.to_le(); - msg.f_sender = msg.f_sender.to_le(); - msg.f_receiver = msg.f_receiver.to_le(); - - // cast to array - let array: [u8; mem::size_of::()]; - unsafe { array = mem::transmute::()]>(msg) }; - - array.to_vec() - } -} - impl Default for Response { fn default() -> Self { Self { - f_type: TYPE_RESPONSE as u32, - f_sender: 0, - f_receiver: 0, + f_type: >::new(TYPE_RESPONSE as u32), + f_sender: >::ZERO, + f_receiver: >::ZERO, f_ephemeral: [0u8; SIZE_X25519_POINT], f_empty_tag: [0u8; SIZE_TAG], } @@ -234,8 +151,8 @@ mod tests { fn message_response_identity() { let mut msg: Response = Default::default(); - msg.f_sender = 146252; - msg.f_receiver = 554442; + msg.f_sender.set(146252); + msg.f_receiver.set(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, @@ -246,16 +163,16 @@ mod tests { 0x2f, 0xde, ]; - let buf: Vec = msg.into(); - let msg_p: Response = Response::try_from(&buf[..]).unwrap(); - assert_eq!(msg, msg_p); + let buf: Vec = msg.as_bytes().to_vec(); + let msg_p = Response::parse(&buf[..]).unwrap(); + assert_eq!(msg, *msg_p.into_ref()); } #[test] fn message_initiate_identity() { let mut msg: Initiation = Default::default(); - msg.f_sender = 575757; + msg.f_sender.set(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, @@ -278,7 +195,8 @@ mod tests { 0x2f, 0xde, ]; - let buf: Vec = msg.into(); - assert_eq!(msg, Initiation::try_from(&buf[..]).unwrap()); + let buf: Vec = msg.as_bytes().to_vec(); + let msg_p = Initiation::parse(&buf[..]).unwrap(); + assert_eq!(msg, *msg_p.into_ref()); } } diff --git a/src/noise.rs b/src/noise.rs index b45b690..1695627 100644 --- a/src/noise.rs +++ b/src/noise.rs @@ -1,5 +1,3 @@ -use std::convert::TryFrom; - // DH use x25519_dalek::PublicKey; use x25519_dalek::StaticSecret; @@ -17,6 +15,8 @@ use rand::rngs::OsRng; use generic_array::typenum::*; use generic_array::GenericArray; +use zerocopy::AsBytes; + use crate::device::Device; use crate::messages::{Initiation, Response}; use crate::peer::{Peer, State}; @@ -148,7 +148,7 @@ pub fn create_initiation( let hs = INITIAL_HS; let hs = HASH!(&hs, peer.pk.as_bytes()); - msg.f_sender = sender; + msg.f_sender.set(sender); // (E_priv, E_pub) := DH-Generate() @@ -214,7 +214,7 @@ pub fn create_initiation( // return message as vector - Ok(Initiation::into(msg)) + Ok(msg.as_bytes().to_vec()) } pub fn consume_initiation<'a, T: Copy>( @@ -223,7 +223,7 @@ pub fn consume_initiation<'a, T: Copy>( ) -> Result<(&'a Peer, TemporaryState), HandshakeError> { // parse message - let msg = Initiation::try_from(msg)?; + let msg = Initiation::parse(msg)?; // initialize state @@ -288,7 +288,7 @@ pub fn consume_initiation<'a, T: Copy>( // return state (to create response) - Ok((peer, (msg.f_sender, eph_r_pk, hs, ck))) + Ok((peer, (msg.f_sender.get(), eph_r_pk, hs, ck))) } pub fn create_response( @@ -301,8 +301,8 @@ pub fn create_response( let (receiver, eph_r_pk, hs, ck) = state; - msg.f_sender = sender; - msg.f_receiver = receiver; + msg.f_sender.set(sender); + msg.f_receiver.set(receiver); // (E_priv, E_pub) := DH-Generate() @@ -361,7 +361,7 @@ pub fn create_response( Ok(( peer.identifier, - Some(Response::into(msg)), + Some(msg.as_bytes().to_vec()), Some(KeyPair { confirmed: false, send: Key { @@ -376,17 +376,15 @@ pub fn create_response( )) } -pub fn consume_response( - device: &Device, - msg: &[u8], -) -> Result, HandshakeError> { +pub fn consume_response(device: &Device, msg: &[u8]) -> Result, HandshakeError> { + // parse message - let msg = Response::try_from(msg)?; + let msg = Response::parse(msg)?; // retrieve peer and associated state - let peer = device.lookup_id(msg.f_receiver)?; + let peer = device.lookup_id(msg.f_receiver.get())?; let (hs, ck, sender, eph_sk) = match peer.get_state() { State::Reset => Err(HandshakeError::InvalidState), State::InitiationSent { @@ -448,7 +446,7 @@ pub fn consume_response( key: key_send.into(), }, recv: Key { - id: msg.f_sender, + id: msg.f_sender.get(), key: key_recv.into(), }, }), -- cgit v1.2.3-59-g8ed1b