aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJake McGinty <me@jake.su>2018-02-12 23:56:38 +0000
committerJake McGinty <me@jake.su>2018-02-13 01:26:39 +0000
commit43c80f2489d429d168ec3e9c3664908971ffeac3 (patch)
treebc12f596c8a6633d9f597ecd62c090a4605e4d81 /src
parentconsolidate more handshake crypto (diff)
downloadwireguard-rs-43c80f2489d429d168ec3e9c3664908971ffeac3.tar.xz
wireguard-rs-43c80f2489d429d168ec3e9c3664908971ffeac3.zip
verify mac1 for handshake messages
Diffstat (limited to 'src')
-rw-r--r--src/consts.rs1
-rw-r--r--src/interface/mod.rs8
-rw-r--r--src/interface/peer_server.rs36
-rw-r--r--src/main.rs1
-rw-r--r--src/noise.rs16
-rw-r--r--src/protocol/peer.rs9
6 files changed, 53 insertions, 18 deletions
diff --git a/src/consts.rs b/src/consts.rs
index f5059d0..f810ad4 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -22,3 +22,4 @@ pub const AEAD_TAG_SIZE: usize = 16;
pub const TRANSPORT_OVERHEAD: usize = TRANSPORT_HEADER_SIZE + AEAD_TAG_SIZE;
pub const MAX_SEGMENT_SIZE: usize = (1 << 16) - 1;
pub const MAX_CONTENT_SIZE: usize = MAX_SEGMENT_SIZE - TRANSPORT_OVERHEAD;
+pub const PADDING_MULTIPLE: usize = 16;
diff --git a/src/interface/mod.rs b/src/interface/mod.rs
index 41b4a66..38c306c 100644
--- a/src/interface/mod.rs
+++ b/src/interface/mod.rs
@@ -18,6 +18,7 @@ use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr};
use std::time::Duration;
use types::{InterfaceInfo};
+use x25519_dalek as x25519;
use pnet::packet::ipv4::Ipv4Packet;
@@ -190,7 +191,10 @@ impl Interface {
let mut state = state.borrow_mut();
match event {
UpdateEvent::PrivateKey(private_key) => {
+ let pub_key = x25519::generate_public(&private_key);
+ info!("our pubkey: {}", base64::encode(pub_key.as_bytes()));
state.interface_info.private_key = Some(private_key);
+ state.interface_info.pub_key = Some(*pub_key.as_bytes());
debug!("set new private key");
},
UpdateEvent::ListenPort(port) => {
@@ -202,7 +206,7 @@ impl Interface {
let mut peer = Peer::new(info.clone());
let private_key = &state.interface_info.private_key.expect("no private key!");
- let (init_packet, our_index) = peer.initiate_new_session(private_key).unwrap();
+ let (init_packet, our_index) = peer.initiate_new_session(private_key).expect("initiate_new_session");
let peer = Rc::new(RefCell::new(peer));
@@ -219,7 +223,7 @@ impl Interface {
future::ok(())
}
- }).map_err(|_| ());
+ }).map_err(|e| { warn!("error {:?}", e); () });
core.run(peer_server.join(utun_fut.join(config_fut.join(config_server)))).unwrap();
}
diff --git a/src/interface/peer_server.rs b/src/interface/peer_server.rs
index 2470335..1fe6724 100644
--- a/src/interface/peer_server.rs
+++ b/src/interface/peer_server.rs
@@ -122,6 +122,14 @@ impl PeerServer {
let mut state = self.shared_state.borrow_mut();
match packet[0] {
1 => {
+ ensure!(packet.len() == 148, "handshake init packet length is incorrect");
+ {
+ let pubkey = state.interface_info.pub_key.as_ref()
+ .ok_or_else(|| format_err!("must have local interface key"))?;
+ let (mac_in, mac_out) = packet.split_at(116);
+ Noise::verify_mac1(pubkey, mac_in, &mac_out[..16])?;
+ }
+
let their_index = LittleEndian::read_u32(&packet[4..]);
let mut noise = Noise::build_responder(
@@ -145,12 +153,19 @@ impl PeerServer {
let _ = state.index_map.insert(next_index, peer_ref.clone());
self.send_to_peer((addr, response));
- info!("sent handshake response, ratcheted session.");
+ info!("sent handshake response, ratcheted session (index {}).", next_index);
},
2 => {
- let our_index = LittleEndian::read_u32(&packet[8..]);
- let peer_ref = state.index_map.get(&our_index)
- .ok_or_else(|| format_err!("unknown our_index"))?
+ ensure!(packet.len() == 92, "handshake resp packet length is incorrect");
+ {
+ let pubkey = state.interface_info.pub_key.as_ref()
+ .ok_or_else(|| format_err!("must have local interface key"))?;
+ let (mac_in, mac_out) = packet.split_at(60);
+ Noise::verify_mac1(pubkey, mac_in, &mac_out[..16])?;
+ }
+ let our_index = LittleEndian::read_u32(&packet[8..]);
+ let peer_ref = state.index_map.get(&our_index)
+ .ok_or_else(|| format_err!("unknown our_index ({})", our_index))?
.clone();
let mut peer = peer_ref.borrow_mut();
let dead_index = peer.process_incoming_handshake_response(&packet)?;
@@ -288,7 +303,9 @@ impl Future for PeerServer {
// Handle pending state-changing timers
loop {
match self.timer_rx.poll() {
- Ok(Async::Ready(Some(message))) => self.handle_timer(message).unwrap(),
+ Ok(Async::Ready(Some(message))) => {
+ let _ = self.handle_timer(message).map_err(|e| warn!("TIMER ERR: {:?}", e));
+ },
Ok(Async::NotReady) => break,
Ok(Async::Ready(None)) | Err(_) => return Err(()),
}
@@ -297,7 +314,9 @@ impl Future for PeerServer {
// Handle UDP packets from the outside world
loop {
match self.udp_stream.poll() {
- Ok(Async::Ready(Some((addr, packet)))) => self.handle_incoming_packet(addr, packet).unwrap(),
+ Ok(Async::Ready(Some((addr, packet)))) => {
+ let _ = self.handle_incoming_packet(addr, packet).map_err(|e| warn!("UDP ERR: {:?}", e));
+ },
Ok(Async::NotReady) => break,
Ok(Async::Ready(None)) | Err(_) => return Err(()),
}
@@ -305,9 +324,8 @@ impl Future for PeerServer {
// Handle packets coming from the local tunnel
loop {
- match self.peek_from_tun_and_handle() {
- Ok(false) => break,
- Err(_) => return Err(()),
+ match self.peek_from_tun_and_handle().map_err(|e| { warn!("TUN ERR: {:?}", e); e }) {
+ Ok(false) | Err(_) => break,
_ => {}
}
}
diff --git a/src/main.rs b/src/main.rs
index ddade34..4efebf6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -31,6 +31,7 @@ extern crate tokio_uds;
extern crate tokio_utun;
extern crate tokio_timer;
extern crate treebitmap;
+extern crate x25519_dalek;
mod consts;
mod error;
diff --git a/src/noise.rs b/src/noise.rs
index beddbfa..3e08099 100644
--- a/src/noise.rs
+++ b/src/noise.rs
@@ -2,6 +2,7 @@ use blake2_rfc::blake2s::{Blake2s, blake2s};
use failure::{Error, SyncFailure};
use snow::{NoiseBuilder, Session};
use snow::params::NoiseParams;
+use snow::wrappers::crypto_wrapper::Dh25519;
use types::{InterfaceInfo, PeerInfo};
@@ -30,10 +31,9 @@ impl Noise {
Ok(Noise::new_foundation(local_privkey)
.build_responder()
.map_err(SyncFailure::new)?)
-
}
- pub fn build_mac1(pub_key: &[u8], mac_input: &mut [u8], mac_output: &mut [u8]) {
+ pub fn build_mac1(pub_key: &[u8], mac_input: &[u8], mac_output: &mut [u8]) {
debug_assert!(mac_output.len() == 16);
let mut mac_key_input = [0; 40];
mac_key_input[..8].copy_from_slice(b"mac1----");
@@ -42,4 +42,16 @@ impl Noise {
let mac = blake2s(16, mac_key.as_bytes(), mac_input);
mac_output.copy_from_slice(mac.as_bytes());
}
+
+ pub fn verify_mac1(pub_key: &[u8], mac_input: &[u8], mac: &[u8]) -> Result<(), Error> {
+ debug_assert!(mac.len() == 16);
+ let mut mac_key_input = [0; 40];
+ mac_key_input[..8].copy_from_slice(b"mac1----");
+ mac_key_input[8..40].copy_from_slice(pub_key);
+ let mac_key = blake2s(32, &[], &mac_key_input);
+ let our_mac = blake2s(16, mac_key.as_bytes(), mac_input);
+
+ ensure!(mac == our_mac.as_bytes(), "mac mismatch");
+ Ok(())
+ }
}
diff --git a/src/protocol/peer.rs b/src/protocol/peer.rs
index 2afb4c4..1852569 100644
--- a/src/protocol/peer.rs
+++ b/src/protocol/peer.rs
@@ -196,7 +196,7 @@ impl Peer {
let mut next_session = Session::with_their_index(noise, their_index);
let next_index = next_session.our_index;
let response_packet = self.get_response_packet(&mut next_session)?;
- self.set_next_session(next_session);
+ self.set_next_session(next_session.into_transport_mode());
self.info.endpoint = Some(addr); // update peer endpoint after successful authentication
self.last_handshake_tai64n = Some(timestamp);
@@ -205,14 +205,14 @@ impl Peer {
}
fn get_response_packet(&mut self, next_session: &mut Session) -> Result<Vec<u8>, Error> {
- let mut packet = vec![0; 76];
+ let mut packet = vec![0; 92];
packet[0] = 2; /* Type: Response */
LittleEndian::write_u32(&mut packet[4..], next_session.our_index);
LittleEndian::write_u32(&mut packet[8..], next_session.their_index);
next_session.noise.write_message(&[], &mut packet[12..]).map_err(SyncFailure::new)?;
{
- let (mac_in, mac_out) = packet.split_at_mut(44);
+ let (mac_in, mac_out) = packet.split_at_mut(60);
Noise::build_mac1(&self.info.pub_key, mac_in, &mut mac_out[..16]);
}
@@ -222,9 +222,8 @@ impl Peer {
pub fn process_incoming_handshake_response(&mut self, packet: &[u8]) -> Result<Option<u32>, Error> {
let their_index = LittleEndian::read_u32(&packet[4..]);
let mut session = mem::replace(&mut self.sessions.next, None).ok_or_else(|| format_err!("no next session"))?;
- let len = session.noise.read_message(&packet[12..60], &mut []).map_err(SyncFailure::new)?;
+ let _ = session.noise.read_message(&packet[12..60], &mut []).map_err(SyncFailure::new)?;
- ensure!(len == 0, "non-zero payload length in handshake response");
session.their_index = their_index;
let session = session.into_transport_mode();