use std::borrow::Cow;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite};
use crate::nts::AlgorithmDescription;
use crate::nts::DEFAULT_NUMBER_OF_COOKIES;
use crate::packet::Cipher;
use super::record::NtsRecord;
use super::{AeadAlgorithm, ErrorCode, NextProtocol, NtsError, WarningCode};
const MAX_MESSAGE_SIZE: u64 = 4096;
pub enum Request<'a> {
KeyExchange {
algorithms: Cow<'a, [AeadAlgorithm]>,
#[cfg_attr(feature = "__internal-fuzz", allow(private_interfaces))]
protocols: Cow<'a, [NextProtocol]>,
denied_servers: Cow<'a, [Cow<'a, str>]>,
},
FixedKey {
authentication: Cow<'a, str>,
c2s_key: Box<dyn Cipher>,
s2c_key: Box<dyn Cipher>,
algorithm: AeadAlgorithm,
#[cfg_attr(feature = "__internal-fuzz", allow(private_interfaces))]
protocol: NextProtocol,
keep_alive: bool,
},
Support {
authentication: Cow<'a, str>,
wants_protocols: bool,
wants_algorithms: bool,
keep_alive: bool,
},
}
impl Request<'_> {
#[expect(clippy::too_many_lines)]
pub async fn parse(reader: impl AsyncRead + Unpin) -> Result<Self, NtsError> {
let mut reader = reader.take(MAX_MESSAGE_SIZE);
let mut protocols = None;
let mut algorithms = None;
let mut authentication = None;
let mut denied_servers = vec![];
let mut wants_protocols = false;
let mut wants_algorithms = false;
let mut keep_alive = false;
let mut key_bytes = None;
loop {
let record = NtsRecord::parse(&mut reader).await?;
match record {
NtsRecord::EndOfMessage => break,
NtsRecord::NextProtocol { protocol_ids } => {
if protocols.is_some() {
return Err(NtsError::Invalid);
}
protocols = Some(protocol_ids);
}
NtsRecord::AeadAlgorithm { algorithm_ids } => {
if algorithms.is_some() {
return Err(NtsError::Invalid);
}
algorithms = Some(algorithm_ids);
}
NtsRecord::FixedKeyRequest { c2s, s2c } => {
if key_bytes.is_some() {
return Err(NtsError::Invalid);
}
key_bytes = Some((c2s, s2c));
}
NtsRecord::SupportedAlgorithmList { .. } => {
if wants_algorithms {
return Err(NtsError::Invalid);
}
wants_algorithms = true;
}
NtsRecord::SupportedNextProtocolList { .. } => {
if wants_protocols {
return Err(NtsError::Invalid);
}
wants_protocols = true;
}
NtsRecord::NtpServerDeny { denied } => {
denied_servers.push(denied);
}
NtsRecord::Authentication { key } => {
if authentication.is_some() {
return Err(NtsError::Invalid);
}
authentication = Some(key);
}
NtsRecord::KeepAlive => keep_alive = true,
NtsRecord::Unknown { critical: true, .. } => {
return Err(NtsError::UnrecognizedCriticalRecord);
}
NtsRecord::Unknown { .. } | NtsRecord::Server { .. } | NtsRecord::Port { .. } => {}
NtsRecord::Error { .. }
| NtsRecord::Warning { .. }
| NtsRecord::NewCookie { .. } => return Err(NtsError::Invalid),
}
}
if wants_algorithms || wants_protocols {
return if let Some(authentication) = authentication
&& key_bytes.is_none()
&& protocols.is_none()
&& algorithms.is_none()
{
Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
})
} else {
Err(NtsError::Invalid)
};
} else if let Some(key_bytes) = key_bytes {
return if let (Some(authentication), Some(protocols), Some(algorithms)) =
(authentication, protocols, algorithms)
{
use crate::packet::{AesSivCmac256, AesSivCmac512};
if protocols.len() != 1 || algorithms.len() != 1 {
return Err(NtsError::Invalid);
}
let (c2s_key, s2c_key): (Box<dyn Cipher>, Box<dyn Cipher>) = match algorithms[0] {
AeadAlgorithm::AeadAesSivCmac256 => match (
AesSivCmac256::from_key_bytes(&key_bytes.0),
AesSivCmac256::from_key_bytes(&key_bytes.1),
) {
(Ok(c2s), Ok(s2c)) => (Box::new(c2s), Box::new(s2c)),
_ => return Err(NtsError::IncorrectSizedKey),
},
AeadAlgorithm::AeadAesSivCmac512 => match (
AesSivCmac512::from_key_bytes(&key_bytes.0),
AesSivCmac512::from_key_bytes(&key_bytes.1),
) {
(Ok(c2s), Ok(s2c)) => (Box::new(c2s), Box::new(s2c)),
_ => return Err(NtsError::IncorrectSizedKey),
},
AeadAlgorithm::Unknown(v) => return Err(NtsError::AeadNotSupported(v)),
};
Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm: algorithms[0],
protocol: protocols[0],
keep_alive,
})
} else {
Err(NtsError::Invalid)
};
}
if let (Some(protocols), Some(algorithms)) = (protocols, algorithms) {
Ok(Request::KeyExchange {
algorithms,
protocols,
denied_servers: denied_servers.into(),
})
} else {
Err(NtsError::Invalid)
}
}
pub async fn serialize(
self,
mut writer: impl AsyncWrite + Unpin,
) -> Result<(), std::io::Error> {
match self {
Request::KeyExchange {
algorithms,
protocols,
denied_servers,
} => {
NtsRecord::NextProtocol {
protocol_ids: protocols,
}
.serialize(&mut writer)
.await?;
NtsRecord::AeadAlgorithm {
algorithm_ids: algorithms,
}
.serialize(&mut writer)
.await?;
for denied in denied_servers.iter() {
use std::ops::Deref;
NtsRecord::NtpServerDeny {
denied: denied.deref().into(),
}
.serialize(&mut writer)
.await?;
}
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
}
Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
} => {
NtsRecord::Authentication {
key: authentication,
}
.serialize(&mut writer)
.await?;
NtsRecord::FixedKeyRequest {
c2s: c2s_key.key_bytes().into(),
s2c: s2c_key.key_bytes().into(),
}
.serialize(&mut writer)
.await?;
NtsRecord::NextProtocol {
protocol_ids: [protocol].as_slice().into(),
}
.serialize(&mut writer)
.await?;
NtsRecord::AeadAlgorithm {
algorithm_ids: [algorithm].as_slice().into(),
}
.serialize(&mut writer)
.await?;
if keep_alive {
NtsRecord::KeepAlive.serialize(&mut writer).await?;
}
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
}
Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
} => {
NtsRecord::Authentication {
key: authentication,
}
.serialize(&mut writer)
.await?;
if wants_protocols {
NtsRecord::SupportedNextProtocolList {
supported_protocols: [].as_slice().into(),
}
.serialize(&mut writer)
.await?;
}
if wants_algorithms {
NtsRecord::SupportedAlgorithmList {
supported_algorithms: [].as_slice().into(),
}
.serialize(&mut writer)
.await?;
}
if keep_alive {
NtsRecord::KeepAlive.serialize(&mut writer).await?;
}
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
}
}
Ok(())
}
}
pub struct KeyExchangeResponse<'a> {
#[cfg_attr(feature = "__internal-fuzz", allow(private_interfaces))]
pub protocol: NextProtocol,
pub algorithm: AeadAlgorithm,
pub cookies: Cow<'a, [Cow<'a, [u8]>]>,
pub server: Option<Cow<'a, str>>,
pub port: Option<u16>,
pub keep_alive: bool,
}
impl KeyExchangeResponse<'_> {
pub async fn parse(reader: impl AsyncRead + Unpin) -> Result<Self, NtsError> {
let mut reader = reader.take(MAX_MESSAGE_SIZE);
let mut protocol = None;
let mut algorithm = None;
let mut cookies = vec![];
let mut server = None;
let mut port = None;
let mut keep_alive = false;
loop {
let record = NtsRecord::parse(&mut reader).await?;
match record {
NtsRecord::EndOfMessage => break,
NtsRecord::NextProtocol { protocol_ids } => {
if protocol.is_some() {
return Err(NtsError::Invalid);
}
match protocol_ids.split_first() {
None => return Err(NtsError::NoOverlappingProtocol),
Some((&id, [])) => protocol = Some(id),
_ => return Err(NtsError::Invalid),
}
}
NtsRecord::AeadAlgorithm { algorithm_ids } => {
if algorithm.is_some() {
return Err(NtsError::Invalid);
}
match algorithm_ids.split_first() {
None => return Err(NtsError::NoOverlappingAlgorithm),
Some((&id, [])) => algorithm = Some(id),
_ => return Err(NtsError::Invalid),
}
}
NtsRecord::NewCookie { cookie_data } => {
if cookies.len() < DEFAULT_NUMBER_OF_COOKIES {
cookies.push(cookie_data);
}
}
NtsRecord::Server { name } => {
if server.is_some() {
return Err(NtsError::Invalid);
}
server = Some(name);
}
NtsRecord::Port {
port: received_port,
} => {
if port.is_some() {
return Err(NtsError::Invalid);
}
port = Some(received_port);
}
NtsRecord::KeepAlive => keep_alive = true,
NtsRecord::Error { errorcode } => return Err(NtsError::Error(errorcode)),
NtsRecord::Warning { warningcode } => match warningcode {
WarningCode::Unknown(code) => return Err(NtsError::UnknownWarning(code)),
},
NtsRecord::Unknown { critical: true, .. } => {
return Err(NtsError::UnrecognizedCriticalRecord);
}
NtsRecord::Unknown { .. } | NtsRecord::Authentication { .. } => {}
NtsRecord::NtpServerDeny { .. }
| NtsRecord::FixedKeyRequest { .. }
| NtsRecord::SupportedAlgorithmList { .. }
| NtsRecord::SupportedNextProtocolList { .. } => return Err(NtsError::Invalid),
}
}
if let (Some(protocol), Some(algorithm)) = (protocol, algorithm) {
Ok(KeyExchangeResponse {
protocol,
algorithm,
cookies: cookies.into(),
server,
port,
keep_alive,
})
} else {
Err(NtsError::Invalid)
}
}
pub async fn serialize(
self,
mut writer: impl AsyncWrite + Unpin,
) -> Result<(), std::io::Error> {
NtsRecord::NextProtocol {
protocol_ids: [self.protocol].as_slice().into(),
}
.serialize(&mut writer)
.await?;
NtsRecord::AeadAlgorithm {
algorithm_ids: [self.algorithm].as_slice().into(),
}
.serialize(&mut writer)
.await?;
for cookie_data in self.cookies.iter() {
NtsRecord::NewCookie {
cookie_data: Cow::Borrowed(cookie_data),
}
.serialize(&mut writer)
.await?;
}
if let Some(name) = self.server {
NtsRecord::Server { name }.serialize(&mut writer).await?;
}
if let Some(port) = self.port {
NtsRecord::Port { port }.serialize(&mut writer).await?;
}
if self.keep_alive {
NtsRecord::KeepAlive.serialize(&mut writer).await?;
}
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
Ok(())
}
}
pub enum NoOverlapResponse {
NoOverlappingAlgorithm { protocol: NextProtocol },
NoOverlappingProtocol,
}
impl NoOverlapResponse {
pub async fn serialize(
self,
mut writer: impl AsyncWrite + Unpin,
) -> Result<(), std::io::Error> {
match self {
NoOverlapResponse::NoOverlappingAlgorithm { protocol } => {
NtsRecord::NextProtocol {
protocol_ids: [protocol].as_slice().into(),
}
.serialize(&mut writer)
.await?;
NtsRecord::AeadAlgorithm {
algorithm_ids: [].as_slice().into(),
}
.serialize(&mut writer)
.await?;
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
}
NoOverlapResponse::NoOverlappingProtocol => {
NtsRecord::NextProtocol {
protocol_ids: [].as_slice().into(),
}
.serialize(&mut writer)
.await?;
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
}
}
Ok(())
}
}
pub struct ErrorResponse {
pub errorcode: ErrorCode,
}
impl ErrorResponse {
pub async fn serialize(
self,
mut writer: impl AsyncWrite + Unpin,
) -> Result<(), std::io::Error> {
NtsRecord::Error {
errorcode: self.errorcode,
}
.serialize(&mut writer)
.await?;
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
Ok(())
}
}
pub struct SupportsResponse<'a> {
pub algorithms: Option<Cow<'a, [AlgorithmDescription]>>,
pub protocols: Option<Cow<'a, [NextProtocol]>>,
pub keep_alive: bool,
}
impl SupportsResponse<'_> {
pub async fn serialize(
self,
mut writer: impl AsyncWrite + Unpin,
) -> Result<(), std::io::Error> {
if let Some(supported_algorithms) = self.algorithms {
NtsRecord::SupportedAlgorithmList {
supported_algorithms,
}
.serialize(&mut writer)
.await?;
}
if let Some(supported_protocols) = self.protocols {
NtsRecord::SupportedNextProtocolList {
supported_protocols,
}
.serialize(&mut writer)
.await?;
}
if self.keep_alive {
NtsRecord::KeepAlive.serialize(&mut writer).await?;
}
NtsRecord::EndOfMessage.serialize(&mut writer).await?;
Ok(())
}
}
#[cfg(test)]
#[expect(
clippy::too_many_lines,
reason = "Long tests are not really a big problem"
)]
mod tests {
use std::{
future::Future,
io::Error,
pin::pin,
task::{Context, Poll, Waker},
};
use super::*;
fn swrap<'a, F, T, U>(f: F, t: T, buf: &'a mut Vec<u8>) -> Result<(), Error>
where
F: FnOnce(T, &'a mut Vec<u8>) -> U,
U: Future<Output = Result<(), Error>>,
{
let Poll::Ready(result) = pin!(f(t, buf)).poll(&mut Context::from_waker(Waker::noop()))
else {
panic!("Future stalled unexpectedly.");
};
result
}
fn pwrap<'a, F, T, U>(f: F, buf: &'a [u8]) -> Result<T, NtsError>
where
F: FnOnce(&'a [u8]) -> U,
U: Future<Output = Result<T, NtsError>>,
{
let Poll::Ready(result) = pin!(f(buf)).poll(&mut Context::from_waker(Waker::noop())) else {
panic!("Future stalled unexpectedly");
};
result
}
#[test]
fn test_error_response() {
let mut buf = vec![];
assert!(matches!(
swrap(
ErrorResponse::serialize,
ErrorResponse {
errorcode: ErrorCode::InternalServerError
},
&mut buf
),
Ok(())
));
assert_eq!(buf, [0x80, 2, 0, 2, 0, 2, 0x80, 0, 0, 0]);
}
#[test]
fn test_request_basic() {
let Ok(request) = pwrap(
Request::parse,
&[0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 0, 0, 0],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
..
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac256].as_slice());
assert_eq!(protocols, [NextProtocol::NTPv4].as_slice());
}
_ => panic!("Unexpected misparse of message"),
}
let Ok(request) = pwrap(
Request::parse,
&[
0x80, 1, 0, 4, 0x80, 1, 0, 0, 0x80, 4, 0, 2, 0, 17, 0x80, 0, 0, 0,
],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
..
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac512].as_slice());
assert_eq!(
protocols,
[NextProtocol::DraftNTPv5, NextProtocol::NTPv4].as_slice()
);
}
_ => panic!("Unexpected misparse of message"),
}
}
#[test]
fn test_request_basic_reject_incomplete() {
assert!(pwrap(Request::parse, &[0x80, 1, 0, 2, 0, 0, 0x80, 0, 0, 0]).is_err());
assert!(pwrap(Request::parse, &[0x80, 4, 0, 2, 0, 15, 0x80, 0, 0, 0]).is_err());
assert!(pwrap(Request::parse, &[0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0]).is_err());
}
#[test]
fn test_request_basic_reject_multiple() {
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 4, 0, 2, 0, 17, 0x80, 1, 0, 2, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 1, 0, 2, 0x80, 1, 0x80, 0, 0,
0
]
)
.is_err()
);
}
#[test]
fn test_request_basic_reject_problematic() {
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0xC0, 1, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0xC0, 4, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 2, 0, 2, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 3, 0, 2, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0, 5, 0, 4, 1, 2, 3, 4, 0x80, 0, 0,
0
]
)
.is_err()
);
}
#[test]
fn test_request_basic_reject_unknown_critical() {
assert!(
pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 50, 0, 2, 0, 1, 0x80, 0, 0, 0
]
)
.is_err()
);
}
#[test]
fn test_request_basic_ignore() {
let Ok(request) = pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0, 50, 0, 2, 1, 2, 0x80, 0, 0, 0,
],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
..
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac256].as_slice());
assert_eq!(protocols, [NextProtocol::NTPv4].as_slice());
}
_ => panic!("Unexpected misparse of message"),
}
let Ok(request) = pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 6, 0, 2, b'h', b'i', 0x80, 0, 0, 0,
],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
..
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac256].as_slice());
assert_eq!(protocols, [NextProtocol::NTPv4].as_slice());
}
_ => panic!("Unexpected misparse of message"),
}
let Ok(request) = pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 7, 0, 2, 0, 124, 0x80, 0, 0, 0,
],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
..
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac256].as_slice());
assert_eq!(protocols, [NextProtocol::NTPv4].as_slice());
}
_ => panic!("Unexpected misparse of message"),
}
let Ok(request) = pwrap(
Request::parse,
&[
0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x40, 3, 0, 2, b'h', b'i', 0x80, 0, 0, 0,
],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
..
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac256].as_slice());
assert_eq!(protocols, [NextProtocol::NTPv4].as_slice());
}
_ => panic!("Unexpected misparse of message"),
}
let Ok(request) = pwrap(
Request::parse,
&[
0x40, 5, 0, 2, b'h', b'i', 0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x80, 0, 0, 0,
],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
..
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac256].as_slice());
assert_eq!(protocols, [NextProtocol::NTPv4].as_slice());
}
_ => panic!("Unexpected misparse of message"),
}
}
#[test]
fn test_request_basic_denied_servers() {
let Ok(request) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0x80, 4, 0, 2, 0, 15, 0x80, 1, 0, 2, 0, 0, 0x40, 3, 0, 2,
b'h', b'i', 0x80, 0, 0, 0,
],
) else {
panic!("Expected parse");
};
match request {
Request::KeyExchange {
algorithms,
protocols,
denied_servers,
} => {
assert_eq!(algorithms, [AeadAlgorithm::AeadAesSivCmac256].as_slice());
assert_eq!(protocols, [NextProtocol::NTPv4].as_slice());
assert_eq!(denied_servers, ["hi"].as_slice());
}
_ => panic!("Unexpected misparse of message"),
}
}
#[test]
fn test_request_basic_serialize() {
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::KeyExchange {
algorithms: [
AeadAlgorithm::AeadAesSivCmac512,
AeadAlgorithm::AeadAesSivCmac256
]
.as_slice()
.into(),
protocols: [NextProtocol::NTPv4].as_slice().into(),
denied_servers: vec![].into(),
},
&mut buf
),
Ok(())
));
assert_eq!(
buf,
[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 4, 0, 17, 0, 15, 0x80, 0, 0, 0
]
);
}
#[test]
fn test_request_basic_serialize_denied_servers() {
let mut buf = vec![];
assert!(
swrap(
Request::serialize,
Request::KeyExchange {
algorithms: [AeadAlgorithm::AeadAesSivCmac256].as_slice().into(),
protocols: [NextProtocol::NTPv4].as_slice().into(),
denied_servers: ["hi".into()].as_slice().into(),
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x40, 3, 0, 2, b'h', b'i', 0x80, 0, 0, 0
]
);
}
#[test]
fn test_request_fixedkey() {
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 0,
0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31
]
);
assert_eq!(
s2c_key.key_bytes(),
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(!keep_alive);
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0x80, 1, 0, 2, 0,
0, 0x80, 4, 0, 2, 0, 17, 0x80, 0, 0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(
s2c_key.key_bytes(),
[
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac512);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(!keep_alive);
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0xC0, 2, 0, 64, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80,
0, 0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31
]
);
assert_eq!(
s2c_key.key_bytes(),
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(!keep_alive);
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0xC0, 2, 0, 64, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x40,
0, 0, 0, 0x80, 0, 0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31
]
);
assert_eq!(
s2c_key.key_bytes(),
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(keep_alive);
}
#[test]
fn test_request_fixedkey_reject_unauthenticated() {
assert!(
pwrap(
Request::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 0, 0,
0,
],
)
.is_err()
);
}
#[test]
fn test_request_fixedkey_reject_incomplete() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 4, 0, 2, 0, 15, 0x80, 0, 0,
0,
],
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 0, 0, 0,
],
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2,
0, 15,
],
)
.is_err()
);
}
#[test]
fn test_request_fixedkey_reject_multiple() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0,
2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 0, 0, 0,
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 4, 0, 0, 0x80, 1, 0x80,
4, 0, 2, 0, 15, 0x80, 0, 0, 0,
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 4,
0, 15, 0, 15, 0x80, 0, 0, 0,
]
)
.is_err()
);
}
#[test]
fn test_request_fixedkey_reject_wrong_size_keys() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 4, 1, 2, 3, 4, 0x80, 1, 0, 2, 0, 0, 0x80, 4,
0, 2, 0, 15, 0x80, 0, 0, 0
]
)
.is_err()
);
}
#[test]
fn test_request_fixedkey_reject_unknown_algorithm() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2,
0, 2, 0x80, 0, 0, 0,
]
)
.is_err()
);
}
#[test]
fn test_request_fixedkey_reject_problematic() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2,
0, 15, 0xC0, 1, 0, 0, 0x80, 0, 0, 0,
],
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2,
0, 15, 0xC0, 4, 0, 0, 0x80, 0, 0, 0,
],
)
.is_err()
);
}
#[test]
fn test_request_fixedkey_reject_unknown_critical() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2,
0, 15, 0x80, 50, 0, 2, 1, 2, 0x80, 0, 0, 0,
],
)
.is_err()
);
}
#[test]
fn test_request_fixedkey_ignore() {
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 6,
0, 2, b'h', b'i', 0x80, 0, 0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31
]
);
assert_eq!(
s2c_key.key_bytes(),
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(!keep_alive);
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 7,
0, 2, 0, 124, 0x80, 0, 0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31
]
);
assert_eq!(
s2c_key.key_bytes(),
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(!keep_alive);
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x40, 3,
0, 2, b'h', b'i', 0x80, 0, 0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31
]
);
assert_eq!(
s2c_key.key_bytes(),
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(!keep_alive);
let Ok(Request::FixedKey {
authentication,
c2s_key,
s2c_key,
algorithm,
protocol,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0, 50,
0, 2, 1, 2, 0x80, 0, 0, 0,
],
)
else {
panic!("Expected parse as fixedkey");
};
assert_eq!(authentication, "a");
assert_eq!(
c2s_key.key_bytes(),
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31
]
);
assert_eq!(
s2c_key.key_bytes(),
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
);
assert_eq!(algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(protocol, NextProtocol::NTPv4);
assert!(!keep_alive);
}
#[test]
fn test_request_fixedkey_serialize() {
use crate::packet::AesSivCmac256;
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::FixedKey {
authentication: "a".into(),
c2s_key: Box::new(AesSivCmac256::new(
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
]
.into()
)),
s2c_key: Box::new(AesSivCmac256::new(
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
.into()
)),
algorithm: AeadAlgorithm::AeadAesSivCmac256,
protocol: NextProtocol::NTPv4,
keep_alive: false,
},
&mut buf
),
Ok(())
));
assert_eq!(
buf,
[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 0,
0, 0
]
);
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::FixedKey {
authentication: "a".into(),
c2s_key: Box::new(AesSivCmac256::new(
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
]
.into()
)),
s2c_key: Box::new(AesSivCmac256::new(
[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
]
.into()
)),
algorithm: AeadAlgorithm::AeadAesSivCmac256,
protocol: NextProtocol::NTPv4,
keep_alive: true,
},
&mut buf
),
Ok(())
));
assert_eq!(
buf,
[
0x40, 5, 0, 1, b'a', 0xC0, 2, 0, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x40, 0,
0, 0, 0x80, 0, 0, 0
]
);
}
#[test]
fn test_request_support() {
let Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
}) = pwrap(
Request::parse,
&[0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0x80, 0, 0, 0],
)
else {
panic!("Parse problem");
};
assert_eq!(authentication, "a");
assert!(wants_algorithms);
assert!(!wants_protocols);
assert!(!keep_alive);
let Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
}) = pwrap(
Request::parse,
&[0x40, 5, 0, 1, b'a', 0xC0, 4, 0, 0, 0x80, 0, 0, 0],
)
else {
panic!("Parse problem");
};
assert_eq!(authentication, "a");
assert!(!wants_algorithms);
assert!(wants_protocols);
assert!(!keep_alive);
let Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 0, 0, 0,
],
)
else {
panic!("Parse problem");
};
assert_eq!(authentication, "a");
assert!(wants_algorithms);
assert!(wants_protocols);
assert!(!keep_alive);
let Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x40, 0, 0, 0, 0x80, 0, 0, 0,
],
)
else {
panic!("Parse problem");
};
assert_eq!(authentication, "a");
assert!(wants_algorithms);
assert!(wants_protocols);
assert!(keep_alive);
}
#[test]
fn test_request_support_reject_unauthenticated() {
assert!(pwrap(Request::parse, &[0xC0, 1, 0, 0, 0x80, 0, 0, 0],).is_err());
assert!(pwrap(Request::parse, &[0xC0, 4, 0, 0, 0x80, 0, 0, 0],).is_err());
assert!(
pwrap(
Request::parse,
&[0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 0, 0, 0,],
)
.is_err()
);
}
#[test]
fn test_request_support_reject_multiple() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 1, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 4, 0, 0, 0xC0, 4, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
}
#[test]
fn test_request_support_reject_problematic() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0xC0, 2, 0, 2, 1, 2, 0x80,
0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 2, 0, 2, 0, 0, 0x80,
0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 3, 0, 2, 0, 0, 0x80,
0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 1, 0, 2, 0, 0, 0x80,
0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80,
0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 5, 0, 2, 1, 2, 0x80,
0, 0, 0
]
)
.is_err()
);
}
#[test]
fn test_request_support_reject_unknown_critical() {
assert!(
pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 50, 0, 0, 0x80, 0, 0,
0
]
)
.is_err()
);
}
#[test]
fn test_request_support_ignore() {
let Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 6, 0, 2, b'h', b'i', 0x80,
0, 0, 0,
],
)
else {
panic!("Parse problem");
};
assert_eq!(authentication, "a");
assert!(wants_algorithms);
assert!(wants_protocols);
assert!(!keep_alive);
let Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x80, 7, 0, 2, 0, 124, 0x80, 0,
0, 0,
],
)
else {
panic!("Parse problem");
};
assert_eq!(authentication, "a");
assert!(wants_algorithms);
assert!(wants_protocols);
assert!(!keep_alive);
let Ok(Request::Support {
authentication,
wants_protocols,
wants_algorithms,
keep_alive,
}) = pwrap(
Request::parse,
&[
0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0xC0, 4, 0, 0, 0x40, 3, 0, 2, b'h', b'i', 0x80,
0, 0, 0,
],
)
else {
panic!("Parse problem");
};
assert_eq!(authentication, "a");
assert!(wants_algorithms);
assert!(wants_protocols);
assert!(!keep_alive);
}
#[test]
fn test_request_support_serialize() {
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::Support {
authentication: "a".into(),
wants_algorithms: false,
wants_protocols: false,
keep_alive: false,
},
&mut buf
),
Ok(())
));
assert_eq!(buf, [0x40, 5, 0, 1, b'a', 0x80, 0, 0, 0]);
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::Support {
authentication: "a".into(),
wants_algorithms: true,
wants_protocols: false,
keep_alive: false,
},
&mut buf
),
Ok(())
));
assert_eq!(buf, [0x40, 5, 0, 1, b'a', 0xC0, 1, 0, 0, 0x80, 0, 0, 0]);
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::Support {
authentication: "a".into(),
wants_algorithms: false,
wants_protocols: true,
keep_alive: false,
},
&mut buf
),
Ok(())
));
assert_eq!(buf, [0x40, 5, 0, 1, b'a', 0xC0, 4, 0, 0, 0x80, 0, 0, 0]);
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::Support {
authentication: "a".into(),
wants_algorithms: true,
wants_protocols: true,
keep_alive: false,
},
&mut buf
),
Ok(())
));
assert_eq!(
buf,
[
0x40, 5, 0, 1, b'a', 0xC0, 4, 0, 0, 0xC0, 1, 0, 0, 0x80, 0, 0, 0
]
);
let mut buf = vec![];
assert!(matches!(
swrap(
Request::serialize,
Request::Support {
authentication: "a".into(),
wants_algorithms: true,
wants_protocols: true,
keep_alive: true,
},
&mut buf
),
Ok(())
));
assert_eq!(
buf,
[
0x40, 5, 0, 1, b'a', 0xC0, 4, 0, 0, 0xC0, 1, 0, 0, 0x40, 0, 0, 0, 0x80, 0, 0, 0
]
);
}
#[test]
fn test_key_exchange_response_parse_basic() {
let Ok(response) = pwrap(
KeyExchangeResponse::parse,
&[0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 17, 0x80, 0, 0, 0],
) else {
panic!("Expected succesful parse");
};
assert_eq!(response.protocol, NextProtocol::NTPv4);
assert_eq!(response.algorithm, AeadAlgorithm::AeadAesSivCmac512);
assert_eq!(response.cookies, [].as_slice() as &[Cow<'static, [u8]>]);
assert_eq!(response.port, None);
assert_eq!(response.server, None);
assert!(!response.keep_alive);
let Ok(response) = pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 17, 0x80, 5, 0, 2, 1, 2, 0x80, 5, 0, 2, 3,
4, 0x80, 0, 0, 0,
],
) else {
panic!("Expected succesful parse");
};
assert_eq!(response.protocol, NextProtocol::NTPv4);
assert_eq!(response.algorithm, AeadAlgorithm::AeadAesSivCmac512);
assert_eq!(
response.cookies,
[[1u8, 2].as_slice().into(), [3u8, 4].as_slice().into()].as_slice()
as &[Cow<'static, [u8]>]
);
assert_eq!(response.port, None);
assert_eq!(response.server, None);
assert!(!response.keep_alive);
let Ok(response) = pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 6, 0, 2, b'h', b'i', 0x80, 0, 0, 0,
],
) else {
panic!("Expected succesful parse");
};
assert_eq!(response.protocol, NextProtocol::NTPv4);
assert_eq!(response.algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(response.cookies, [].as_slice() as &[Cow<'static, [u8]>]);
assert_eq!(response.port, None);
assert_eq!(response.server, Some("hi".into()));
assert!(!response.keep_alive);
let Ok(response) = pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 7, 0, 2, 0, 5, 0x80, 0, 0, 0,
],
) else {
panic!("Expected succesful parse");
};
assert_eq!(response.protocol, NextProtocol::NTPv4);
assert_eq!(response.algorithm, AeadAlgorithm::AeadAesSivCmac256);
assert_eq!(response.cookies, [].as_slice() as &[Cow<'static, [u8]>]);
assert_eq!(response.port, Some(5));
assert_eq!(response.server, None);
assert!(!response.keep_alive);
let Ok(response) = pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 17, 0x80, 5, 0, 2, 1, 2, 0x80, 5, 0, 2, 3,
4, 0x80, 6, 0, 2, b'h', b'i', 0x80, 7, 0, 2, 0, 5, 0x80, 0, 0, 0,
],
) else {
panic!("Expected succesful parse");
};
assert_eq!(response.protocol, NextProtocol::NTPv4);
assert_eq!(response.algorithm, AeadAlgorithm::AeadAesSivCmac512);
assert_eq!(
response.cookies,
[[1u8, 2].as_slice().into(), [3u8, 4].as_slice().into()].as_slice()
as &[Cow<'static, [u8]>]
);
assert_eq!(response.port, Some(5));
assert_eq!(response.server, Some("hi".into()));
assert!(!response.keep_alive);
let Ok(response) = pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 17, 0x80, 5, 0, 2, 1, 2, 0x80, 5, 0, 2, 3,
4, 0x80, 6, 0, 2, b'h', b'i', 0x80, 7, 0, 2, 0, 5, 0x40, 0, 0, 0, 0x80, 0, 0, 0,
],
) else {
panic!("Expected succesful parse");
};
assert_eq!(response.protocol, NextProtocol::NTPv4);
assert_eq!(response.algorithm, AeadAlgorithm::AeadAesSivCmac512);
assert_eq!(
response.cookies,
[[1u8, 2].as_slice().into(), [3u8, 4].as_slice().into()].as_slice()
as &[Cow<'static, [u8]>]
);
assert_eq!(response.port, Some(5));
assert_eq!(response.server, Some("hi".into()));
assert!(response.keep_alive);
}
#[test]
fn test_key_exchange_response_reject_incomplete() {
assert!(
pwrap(
KeyExchangeResponse::parse,
&[0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4]
)
.is_err()
);
assert!(
pwrap(
KeyExchangeResponse::parse,
&[0x80, 1, 0, 2, 0, 0, 0x80, 0, 0, 0]
)
.is_err()
);
assert!(
pwrap(
KeyExchangeResponse::parse,
&[0x80, 4, 0, 2, 0, 4, 0x80, 0, 0, 0]
)
.is_err()
);
}
#[test]
fn test_key_exchange_response_reject_multiple() {
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 4, 0, 0, 0x80, 1, 0x80, 4, 0, 2, 0, 15, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 4, 0, 15, 0, 17, 0x80, 0, 0, 0
]
)
.is_err()
);
}
#[test]
fn test_key_exchange_response_reject_repeated() {
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 15, 0x80, 4, 0, 2, 0, 17, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 1, 0, 2, 0x80, 1, 0x80, 4, 0, 2, 0, 15, 0x80, 0, 0,
0
]
)
.is_err()
);
}
#[test]
fn test_key_exchange_response_reject_problematic() {
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0xC0, 4, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0xC0, 1, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0xC0, 2, 0, 2, 1, 2, 0x80, 0, 0, 0
]
)
.is_err()
);
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0xC0, 3, 0, 2, b'h', b'i', 0x80, 0,
0, 0
]
)
.is_err()
);
}
#[test]
fn test_key_exchange_response_reject_unknown_critical() {
assert!(
pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0x80, 50, 0, 0, 0x80, 0, 0, 0
]
)
.is_err()
);
}
#[test]
fn test_key_exchange_response_ignore() {
let Ok(response) = pwrap(
KeyExchangeResponse::parse,
&[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0, 50, 0, 0, 0x80, 0, 0, 0,
],
) else {
panic!("Expected succesful parse");
};
assert_eq!(response.protocol, NextProtocol::NTPv4);
assert_eq!(response.algorithm, AeadAlgorithm::Unknown(4));
assert_eq!(response.cookies, [].as_slice() as &[Cow<'static, [u8]>]);
assert_eq!(response.port, None);
assert_eq!(response.server, None);
assert!(!response.keep_alive);
}
#[test]
fn test_key_exchange_response_parse_error_warning() {
assert!(matches!(
pwrap(
KeyExchangeResponse::parse,
&[0x80, 2, 0, 2, 0, 0, 0x80, 0, 0, 0]
),
Err(NtsError::Error(ErrorCode::UnrecognizedCriticalRecord))
));
assert!(matches!(
pwrap(
KeyExchangeResponse::parse,
&[0x80, 3, 0, 2, 0, 1, 0x80, 0, 0, 0]
),
Err(NtsError::UnknownWarning(1))
));
}
#[test]
fn test_key_exchange_response_no_overlap() {
assert!(matches!(
pwrap(KeyExchangeResponse::parse, &[0x80, 1, 0, 0, 0x80, 0, 0, 0]),
Err(NtsError::NoOverlappingProtocol)
));
assert!(matches!(
pwrap(
KeyExchangeResponse::parse,
&[0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 0, 0x80, 0, 0, 0]
),
Err(NtsError::NoOverlappingAlgorithm)
));
}
#[test]
fn test_key_exchange_response_serialize() {
let mut buf = vec![];
assert!(
swrap(
KeyExchangeResponse::serialize,
KeyExchangeResponse {
protocol: NextProtocol::NTPv4,
algorithm: AeadAlgorithm::Unknown(4),
cookies: [].as_slice().into(),
server: None,
port: None,
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0x80, 0, 0, 0]
);
let mut buf = vec![];
assert!(
swrap(
KeyExchangeResponse::serialize,
KeyExchangeResponse {
protocol: NextProtocol::NTPv4,
algorithm: AeadAlgorithm::Unknown(4),
cookies: [[1, 2, 3].as_slice().into(), [4, 5].as_slice().into()]
.as_slice()
.into(),
server: None,
port: None,
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0, 5, 0, 3, 1, 2, 3, 0, 5, 0, 2, 4, 5,
0x80, 0, 0, 0
]
);
let mut buf = vec![];
assert!(
swrap(
KeyExchangeResponse::serialize,
KeyExchangeResponse {
protocol: NextProtocol::NTPv4,
algorithm: AeadAlgorithm::Unknown(4),
cookies: [].as_slice().into(),
server: Some("hi".into()),
port: None,
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0x80, 6, 0, 2, b'h', b'i', 0x80, 0, 0, 0
]
);
let mut buf = vec![];
assert!(
swrap(
KeyExchangeResponse::serialize,
KeyExchangeResponse {
protocol: NextProtocol::NTPv4,
algorithm: AeadAlgorithm::Unknown(4),
cookies: [].as_slice().into(),
server: None,
port: Some(15),
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0x80, 7, 0, 2, 0, 15, 0x80, 0, 0, 0
]
);
let mut buf = vec![];
assert!(
swrap(
KeyExchangeResponse::serialize,
KeyExchangeResponse {
protocol: NextProtocol::NTPv4,
algorithm: AeadAlgorithm::Unknown(4),
cookies: [[1, 2, 3].as_slice().into(), [4, 5].as_slice().into()]
.as_slice()
.into(),
server: Some("hi".into()),
port: Some(15),
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0, 5, 0, 3, 1, 2, 3, 0, 5, 0, 2, 4, 5,
0x80, 6, 0, 2, b'h', b'i', 0x80, 7, 0, 2, 0, 15, 0x80, 0, 0, 0
]
);
let mut buf = vec![];
assert!(
swrap(
KeyExchangeResponse::serialize,
KeyExchangeResponse {
protocol: NextProtocol::NTPv4,
algorithm: AeadAlgorithm::Unknown(4),
cookies: [[1, 2, 3].as_slice().into(), [4, 5].as_slice().into()]
.as_slice()
.into(),
server: Some("hi".into()),
port: Some(15),
keep_alive: true,
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[
0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 2, 0, 4, 0, 5, 0, 3, 1, 2, 3, 0, 5, 0, 2, 4, 5,
0x80, 6, 0, 2, b'h', b'i', 0x80, 7, 0, 2, 0, 15, 0x40, 0, 0, 0, 0x80, 0, 0, 0
]
);
}
#[test]
fn test_support_response() {
let mut buf = vec![];
assert!(
swrap(
SupportsResponse::serialize,
SupportsResponse {
algorithms: Some(
[AeadAlgorithm::AeadAesSivCmac256.description().unwrap()]
.as_slice()
.into()
),
protocols: None,
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(buf, [0xC0, 1, 0, 4, 0, 15, 0, 32, 0x80, 0, 0, 0]);
let mut buf = vec![];
assert!(
swrap(
SupportsResponse::serialize,
SupportsResponse {
algorithms: Some(
[AeadAlgorithm::AeadAesSivCmac256.description().unwrap()]
.as_slice()
.into()
),
protocols: Some([NextProtocol::NTPv4].as_slice().into()),
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(
buf,
[
0xC0, 1, 0, 4, 0, 15, 0, 32, 0xC0, 4, 0, 2, 0, 0, 0x80, 0, 0, 0
]
);
let mut buf = vec![];
assert!(
swrap(
SupportsResponse::serialize,
SupportsResponse {
algorithms: None,
protocols: Some([NextProtocol::NTPv4].as_slice().into()),
keep_alive: false,
},
&mut buf
)
.is_ok()
);
assert_eq!(buf, [0xC0, 4, 0, 2, 0, 0, 0x80, 0, 0, 0]);
let mut buf = vec![];
assert!(
swrap(
SupportsResponse::serialize,
SupportsResponse {
algorithms: None,
protocols: Some([NextProtocol::NTPv4].as_slice().into()),
keep_alive: true,
},
&mut buf
)
.is_ok()
);
assert_eq!(buf, [0xC0, 4, 0, 2, 0, 0, 0x40, 0, 0, 0, 0x80, 0, 0, 0]);
}
#[test]
fn test_no_overlap_response() {
let mut buf = vec![];
assert!(
swrap(
NoOverlapResponse::serialize,
NoOverlapResponse::NoOverlappingAlgorithm {
protocol: NextProtocol::NTPv4
},
&mut buf
)
.is_ok()
);
assert_eq!(buf, [0x80, 1, 0, 2, 0, 0, 0x80, 4, 0, 0, 0x80, 0, 0, 0]);
let mut buf = vec![];
assert!(
swrap(
NoOverlapResponse::serialize,
NoOverlapResponse::NoOverlappingProtocol,
&mut buf
)
.is_ok()
);
assert_eq!(buf, [0x80, 1, 0, 0, 0x80, 0, 0, 0]);
}
}