test(proto): verify HMAC field placement in protocol packets
This commit is contained in:
1 parent
5831f4a3b5
commit
ab855338af
4 files changed
+203
No files matched your search
@@ -29,6 +29,7 @@ pub fn encode_close_request(request: &CloseRequest, hmac_key: Option<&[u8]>) ->
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::{hmac, FLAG_HMAC};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn close_request_sizes() {
|
fn close_request_sizes() {
|
||||||
@@ -43,4 +44,22 @@ mod tests {
|
|||||||
28
|
28
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hmac_close_request_places_token_after_hmac() {
|
||||||
|
let packet = encode_close_request(
|
||||||
|
&CloseRequest {
|
||||||
|
token: 0x7896_b6ab_8771_5213,
|
||||||
|
},
|
||||||
|
Some(b"testkey"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(packet[3], FLAG_CLOSE | FLAG_HMAC);
|
||||||
|
assert_eq!(
|
||||||
|
&packet[4 + HMAC_SIZE..],
|
||||||
|
&0x7896_b6ab_8771_5213u64.to_le_bytes()
|
||||||
|
);
|
||||||
|
hmac::verify_hmac(b"testkey", &packet, hmac::hmac_offset()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -179,6 +179,32 @@ mod tests {
|
|||||||
assert!(packet[12..].iter().all(|byte| *byte == 0));
|
assert!(packet[12..].iter().all(|byte| *byte == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hmac_echo_request_places_token_and_sequence_after_hmac() {
|
||||||
|
let packet = encode_echo_request(
|
||||||
|
&EchoRequest {
|
||||||
|
token: 0x7896_b6ab_8771_5213,
|
||||||
|
sequence: 9,
|
||||||
|
params: default_params(),
|
||||||
|
payload: Vec::new(),
|
||||||
|
},
|
||||||
|
Some(b"testkey"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(packet.len(), 76);
|
||||||
|
assert_eq!(&packet[..4], &[0x14, 0xa7, 0x5b, FLAG_HMAC]);
|
||||||
|
assert_eq!(
|
||||||
|
&packet[4 + HMAC_SIZE..4 + HMAC_SIZE + TOKEN_SIZE],
|
||||||
|
&0x7896_b6ab_8771_5213u64.to_le_bytes()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
&packet[4 + HMAC_SIZE + TOKEN_SIZE..4 + HMAC_SIZE + TOKEN_SIZE + SEQ_SIZE],
|
||||||
|
&9_u32.to_le_bytes()
|
||||||
|
);
|
||||||
|
hmac::verify_hmac(b"testkey", &packet, hmac::hmac_offset()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn echo_reply_decodes_default_fields() {
|
fn echo_reply_decodes_default_fields() {
|
||||||
let packet = [
|
let packet = [
|
||||||
@@ -196,4 +222,25 @@ mod tests {
|
|||||||
assert!(reply.timestamps.recv_wall.is_some());
|
assert!(reply.timestamps.recv_wall.is_some());
|
||||||
assert!(reply.timestamps.midpoint_wall.is_none());
|
assert!(reply.timestamps.midpoint_wall.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hmac_echo_reply_decodes_default_fields_after_hmac() {
|
||||||
|
let params = default_params();
|
||||||
|
let layout = PacketLayout::echo(true, ¶ms);
|
||||||
|
let mut packet = Vec::with_capacity(layout.header_len());
|
||||||
|
write_header(&mut packet, FLAG_REPLY | FLAG_HMAC);
|
||||||
|
packet.extend_from_slice(&[0; HMAC_SIZE]);
|
||||||
|
packet.extend_from_slice(&0x7896_b6ab_8771_5213u64.to_le_bytes());
|
||||||
|
packet.extend_from_slice(&2_u32.to_le_bytes());
|
||||||
|
push_zeroed_layout_tail(layout, &mut packet);
|
||||||
|
hmac::compute_hmac_in_place(b"testkey", &mut packet, hmac::hmac_offset()).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(packet.len(), 76);
|
||||||
|
let reply = decode_echo_reply(&packet, ¶ms, Some(b"testkey")).unwrap();
|
||||||
|
assert_eq!(reply.token, 0x7896_b6ab_8771_5213);
|
||||||
|
assert_eq!(reply.sequence, 2);
|
||||||
|
assert_eq!(reply.recv_count, Some(0));
|
||||||
|
assert_eq!(reply.recv_window, Some(0));
|
||||||
|
assert_eq!(reply.payload.len(), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -131,6 +131,25 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expected_optional_len(stats: ReceivedStats, stamp_at: StampAt, clock: Clock) -> usize {
|
||||||
|
let stats_len = match stats {
|
||||||
|
ReceivedStats::None => 0,
|
||||||
|
ReceivedStats::Count => RECV_COUNT_SIZE,
|
||||||
|
ReceivedStats::Window => RECV_WINDOW_SIZE,
|
||||||
|
ReceivedStats::Both => RECV_COUNT_SIZE + RECV_WINDOW_SIZE,
|
||||||
|
};
|
||||||
|
let clock_count = match clock {
|
||||||
|
Clock::Wall | Clock::Monotonic => 1,
|
||||||
|
Clock::Both => 2,
|
||||||
|
};
|
||||||
|
let timestamp_groups = match stamp_at {
|
||||||
|
StampAt::None => 0,
|
||||||
|
StampAt::Send | StampAt::Receive | StampAt::Midpoint => 1,
|
||||||
|
StampAt::Both => 2,
|
||||||
|
};
|
||||||
|
stats_len + timestamp_groups * clock_count * TIMESTAMP_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verified_layout_lengths() {
|
fn verified_layout_lengths() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -177,6 +196,87 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn open_and_close_layout_lengths_account_for_hmac() {
|
||||||
|
assert_eq!(PacketLayout::open_request(false).header_len(), 4);
|
||||||
|
assert_eq!(PacketLayout::open_request(true).header_len(), 20);
|
||||||
|
assert_eq!(PacketLayout::open_reply(false).header_len(), 12);
|
||||||
|
assert_eq!(PacketLayout::open_reply(true).header_len(), 28);
|
||||||
|
assert_eq!(PacketLayout::close_request(false).header_len(), 12);
|
||||||
|
assert_eq!(PacketLayout::close_request(true).header_len(), 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn layout_matrix_matches_stats_timestamps_clock_and_hmac_rules() {
|
||||||
|
for stats in [
|
||||||
|
ReceivedStats::None,
|
||||||
|
ReceivedStats::Count,
|
||||||
|
ReceivedStats::Window,
|
||||||
|
ReceivedStats::Both,
|
||||||
|
] {
|
||||||
|
for stamp_at in [
|
||||||
|
StampAt::None,
|
||||||
|
StampAt::Send,
|
||||||
|
StampAt::Receive,
|
||||||
|
StampAt::Both,
|
||||||
|
StampAt::Midpoint,
|
||||||
|
] {
|
||||||
|
for clock in [Clock::Wall, Clock::Monotonic, Clock::Both] {
|
||||||
|
for hmac in [false, true] {
|
||||||
|
let params = params(stats, stamp_at, clock);
|
||||||
|
let layout = PacketLayout::echo(hmac, ¶ms);
|
||||||
|
let expected_len = HEADER_SIZE
|
||||||
|
+ TOKEN_SIZE
|
||||||
|
+ SEQ_SIZE
|
||||||
|
+ if hmac { HMAC_SIZE } else { 0 }
|
||||||
|
+ expected_optional_len(stats, stamp_at, clock);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
layout.header_len(),
|
||||||
|
expected_len,
|
||||||
|
"unexpected length for stats={stats:?} stamp_at={stamp_at:?} clock={clock:?} hmac={hmac}"
|
||||||
|
);
|
||||||
|
assert_eq!(layout.recv_count, stats.has_count());
|
||||||
|
assert_eq!(layout.recv_window, stats.has_window());
|
||||||
|
assert_eq!(
|
||||||
|
layout.recv_wall,
|
||||||
|
matches!(stamp_at, StampAt::Receive | StampAt::Both)
|
||||||
|
&& clock.has_wall()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
layout.recv_mono,
|
||||||
|
matches!(stamp_at, StampAt::Receive | StampAt::Both)
|
||||||
|
&& clock.has_mono()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
layout.midpoint_wall,
|
||||||
|
matches!(stamp_at, StampAt::Midpoint) && clock.has_wall()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
layout.midpoint_mono,
|
||||||
|
matches!(stamp_at, StampAt::Midpoint) && clock.has_mono()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
layout.send_wall,
|
||||||
|
matches!(stamp_at, StampAt::Send | StampAt::Both) && clock.has_wall()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
layout.send_mono,
|
||||||
|
matches!(stamp_at, StampAt::Send | StampAt::Both) && clock.has_mono()
|
||||||
|
);
|
||||||
|
|
||||||
|
if hmac {
|
||||||
|
assert_eq!(
|
||||||
|
echo_header_len(true, ¶ms) - echo_header_len(false, ¶ms),
|
||||||
|
HMAC_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_timestamp_layout_ignores_clock() {
|
fn no_timestamp_layout_ignores_clock() {
|
||||||
for clock in [Clock::Wall, Clock::Monotonic, Clock::Both] {
|
for clock in [Clock::Wall, Clock::Monotonic, Clock::Both] {
|
||||||
|
|||||||
@@ -130,6 +130,26 @@ mod tests {
|
|||||||
assert_eq!(&packet[4..], &default_params().encode());
|
assert_eq!(&packet[4..], &default_params().encode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hmac_open_request_inserts_hmac_before_params() {
|
||||||
|
let packet = encode_open_request(
|
||||||
|
&OpenRequest {
|
||||||
|
params: default_params(),
|
||||||
|
close: false,
|
||||||
|
},
|
||||||
|
Some(b"testkey"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
packet.len(),
|
||||||
|
4 + HMAC_SIZE + default_params().encode().len()
|
||||||
|
);
|
||||||
|
assert_eq!(&packet[..4], &[0x14, 0xa7, 0x5b, FLAG_OPEN | FLAG_HMAC]);
|
||||||
|
assert_eq!(&packet[4 + HMAC_SIZE..], &default_params().encode());
|
||||||
|
hmac::verify_hmac(b"testkey", &packet, hmac::hmac_offset()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn open_reply_decodes_token() {
|
fn open_reply_decodes_token() {
|
||||||
let mut packet = vec![0x14, 0xa7, 0x5b, 0x03];
|
let mut packet = vec![0x14, 0xa7, 0x5b, 0x03];
|
||||||
@@ -140,4 +160,21 @@ mod tests {
|
|||||||
assert_eq!(reply.token, 0x7896_b6ab_8771_5213);
|
assert_eq!(reply.token, 0x7896_b6ab_8771_5213);
|
||||||
assert_eq!(reply.params, default_params());
|
assert_eq!(reply.params, default_params());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hmac_open_reply_decodes_token_after_hmac_field() {
|
||||||
|
let mut packet = vec![0x14, 0xa7, 0x5b, FLAG_OPEN | FLAG_REPLY | FLAG_HMAC];
|
||||||
|
packet.extend_from_slice(&[0; HMAC_SIZE]);
|
||||||
|
packet.extend_from_slice(&0x7896_b6ab_8771_5213u64.to_le_bytes());
|
||||||
|
packet.extend_from_slice(&default_params().encode());
|
||||||
|
hmac::compute_hmac_in_place(b"testkey", &mut packet, hmac::hmac_offset()).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
packet.len(),
|
||||||
|
4 + HMAC_SIZE + TOKEN_SIZE + default_params().encode().len()
|
||||||
|
);
|
||||||
|
let reply = decode_open_reply(&packet, Some(b"testkey")).unwrap();
|
||||||
|
assert_eq!(reply.token, 0x7896_b6ab_8771_5213);
|
||||||
|
assert_eq!(reply.params, default_params());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user