aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJake McGinty <me@jake.su>2018-02-12 16:52:32 +0000
committerJake McGinty <me@jake.su>2018-02-12 16:54:59 +0000
commitcffba769212e40892a54222d8bebedc550582af3 (patch)
tree7be4da438df63a9557318ba86dfccef1523a6a6c /src
parentlet Peer process its incoming handshake (diff)
downloadwireguard-rs-cffba769212e40892a54222d8bebedc550582af3.tar.xz
wireguard-rs-cffba769212e40892a54222d8bebedc550582af3.zip
validate incoming handshake timestamps
Diffstat (limited to 'src')
-rw-r--r--src/interface/peer_server.rs5
-rw-r--r--src/main.rs1
-rw-r--r--src/protocol/peer.rs16
-rw-r--r--src/tai64n.rs36
4 files changed, 50 insertions, 8 deletions
diff --git a/src/interface/peer_server.rs b/src/interface/peer_server.rs
index 5fe6bc3..2ad363a 100644
--- a/src/interface/peer_server.rs
+++ b/src/interface/peer_server.rs
@@ -129,8 +129,9 @@ impl PeerServer {
&state.interface_info.private_key.ok_or_else(|| format_err!("no private key!"))?)?;
let mut timestamp = [0u8; 12];
- let _ = noise.read_message(&packet[8..116], &mut timestamp)
+ let len = noise.read_message(&packet[8..116], &mut timestamp)
.map_err(SyncFailure::new)?;
+ ensure!(len == 12, "incorrect handshake payload length");
let mut peer_ref = {
let their_pubkey = noise.get_remote_static().expect("must have remote static key");
@@ -141,7 +142,7 @@ impl PeerServer {
};
let mut peer = peer_ref.borrow_mut();
- let (response, next_index, dead_index) = peer.process_incoming_handshake(addr, their_index, &timestamp, noise)?;
+ let (response, next_index, dead_index) = peer.process_incoming_handshake(addr, their_index, timestamp.into(), noise)?;
let _ = state.index_map.insert(next_index, peer_ref.clone());
if let Some(index) = dead_index {
let _ = state.index_map.remove(&index);
diff --git a/src/main.rs b/src/main.rs
index 36eb5d7..ddade34 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -40,6 +40,7 @@ mod protocol;
mod types;
mod anti_replay;
mod router;
+mod tai64n;
mod ip_packet;
use std::path::PathBuf;
diff --git a/src/protocol/peer.rs b/src/protocol/peer.rs
index 6c2fe9f..d8e0433 100644
--- a/src/protocol/peer.rs
+++ b/src/protocol/peer.rs
@@ -15,6 +15,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use std::thread::JoinHandle;
use base64;
use hex;
+use tai64n::TAI64N;
use time;
use rand::{self, Rng};
use snow;
@@ -31,6 +32,7 @@ pub struct Peer {
pub tx_bytes: u64,
pub rx_bytes: u64,
pub last_handshake: Option<SystemTime>,
+ pub last_handshake_tai64n: Option<TAI64N>,
}
impl PartialEq for Peer {
@@ -205,16 +207,13 @@ impl Peer {
}
pub fn get_handshake_packet(&mut self) -> Result<Vec<u8>, Error> {
- let now = time::get_time();
- let mut tai64n = [0; 12];
- BigEndian::write_i64(&mut tai64n[0..], 4611686018427387914 + now.sec);
- BigEndian::write_i32(&mut tai64n[8..], now.nsec);
+ let tai64n = TAI64N::now();
let mut initiation_packet = vec![0; 148];
initiation_packet[0] = 1; /* Type: Initiation */
let next = self.sessions.next.as_mut().ok_or_else(|| format_err!("missing next session"))?;
LittleEndian::write_u32(&mut initiation_packet[4..], next.our_index);
- next.noise.write_message(&tai64n, &mut initiation_packet[8..]).map_err(SyncFailure::new)?;
+ next.noise.write_message(&*tai64n, &mut initiation_packet[8..]).map_err(SyncFailure::new)?;
let mut mac_key_input = [0; 40];
memcpy(&mut mac_key_input, b"mac1----");
@@ -230,9 +229,13 @@ impl Peer {
/// and generates a response.
///
/// Returns: the response packet (type 0x02), and an optional dead session index that was removed.
- pub fn process_incoming_handshake(&mut self, addr: SocketAddr, their_index: u32, timestamp: &[u8], mut noise: snow::Session)
+ pub fn process_incoming_handshake(&mut self, addr: SocketAddr, their_index: u32, timestamp: TAI64N, mut noise: snow::Session)
-> Result<(Vec<u8>, u32, Option<u32>), Error> {
+ if let Some(ref last_tai64n) = self.last_handshake_tai64n {
+ ensure!(&timestamp > last_tai64n, "handshake timestamp earlier than last handshake's timestamp");
+ }
+
// TODO: verify timestamp
// TODO: hacked up API until it's officially supported in snow.
match noise {
@@ -250,6 +253,7 @@ impl Peer {
let dead_index = self.ratchet_session()?.map(|session| session.our_index);
self.info.endpoint = Some(addr); // update peer endpoint after successful authentication
+ self.last_handshake_tai64n = Some(timestamp);
Ok((response_packet, next_index, dead_index))
}
diff --git a/src/tai64n.rs b/src/tai64n.rs
new file mode 100644
index 0000000..818d57d
--- /dev/null
+++ b/src/tai64n.rs
@@ -0,0 +1,36 @@
+use byteorder::{ByteOrder, BigEndian};
+use std::time::{SystemTime, UNIX_EPOCH};
+use std::ops::Deref;
+use time;
+
+const TAI64N_BASE: i64 = 4611686018427387914;
+
+#[derive(PartialEq, PartialOrd)]
+pub struct TAI64N {
+ tai64n: [u8; 12]
+}
+
+impl TAI64N {
+ pub fn now() -> TAI64N {
+ let mut tai64n = [0u8; 12];
+ let now = time::get_time();
+ BigEndian::write_i64(&mut tai64n[0..], TAI64N_BASE + now.sec);
+ BigEndian::write_i32(&mut tai64n[8..], now.nsec);
+
+ TAI64N { tai64n }
+ }
+}
+
+impl Deref for TAI64N {
+ type Target = [u8; 12];
+
+ fn deref(&self) -> &[u8; 12] {
+ &self.tai64n
+ }
+}
+
+impl From<[u8; 12]> for TAI64N {
+ fn from(tai64n: [u8; 12]) -> Self {
+ TAI64N { tai64n }
+ }
+}