use std::fmt::Display;
use std::net::IpAddr;
use std::net::SocketAddr;
use std::time;
use bytes::Bytes;
use bytes::BytesMut;
use rand::RngCore;
use ring::aead;
use self::PacketType::*;
use crate::codec::Decoder;
use crate::codec::Encoder;
use crate::connection::space::SpaceId;
#[cfg(feature = "qlog")]
use crate::qlog;
use crate::ranges;
use crate::tls;
use crate::tls::Level;
use crate::tls::Open;
use crate::tls::Seal;
use crate::ConnectionId;
use crate::Error;
use crate::Result;
use crate::MAX_CID_LEN;
const HEADER_LONG_FORM_BIT: u8 = 0x80;
const HEADER_FIXED_BIT: u8 = 0x40;
const HEADER_KEY_PHASE_BIT: u8 = 0x04;
const PKT_TYPE_MASK: u8 = 0x30;
const PKT_NUM_LEN_MASK: u8 = 0x03;
const MAX_PKT_NUM_LEN: usize = 4;
const SAMPLE_LEN: usize = 16;
const RETRY_INTEGRITY_KEY_V1: [u8; 16] = [
0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e,
];
const RETRY_INTEGRITY_NONCE_V1: [u8; aead::NONCE_LEN] = [
0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb,
];
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PacketType {
VersionNegotiation,
Initial,
ZeroRTT,
Handshake,
Retry,
OneRTT,
}
impl PacketType {
pub fn to_level(self) -> Result<Level> {
match self {
Initial => Ok(Level::Initial),
ZeroRTT => Ok(Level::ZeroRTT),
Handshake => Ok(Level::Handshake),
OneRTT => Ok(Level::OneRTT),
_ => Err(Error::InternalError),
}
}
pub fn to_space(self) -> Result<SpaceId> {
match self {
Initial => Ok(SpaceId::Initial),
Handshake => Ok(SpaceId::Handshake),
ZeroRTT | OneRTT => Ok(SpaceId::Data),
_ => Err(Error::InternalError),
}
}
#[cfg(feature = "qlog")]
pub fn to_qlog(self) -> qlog::events::PacketType {
match self {
VersionNegotiation => qlog::events::PacketType::VersionNegotiation,
Initial => qlog::events::PacketType::Initial,
ZeroRTT => qlog::events::PacketType::ZeroRtt,
Handshake => qlog::events::PacketType::Handshake,
Retry => qlog::events::PacketType::Retry,
OneRTT => qlog::events::PacketType::OneRtt,
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct PacketHeader {
pub pkt_type: PacketType,
pub version: u32,
pub dcid: ConnectionId,
pub scid: ConnectionId,
pub pkt_num_len: usize,
pub pkt_num: u64,
pub token: Option<Vec<u8>>,
pub key_phase: bool,
}
impl PacketHeader {
pub fn to_bytes(&self, mut buf: &mut [u8]) -> Result<usize> {
let len = buf.len();
if self.pkt_type == OneRTT {
let mut first = HEADER_FIXED_BIT;
if self.key_phase {
first |= HEADER_KEY_PHASE_BIT;
}
first |= self.pkt_num_len.saturating_sub(1) as u8;
buf.write_u8(first)?;
buf.write(&self.dcid)?;
return Ok(len - buf.len());
}
let mut first = HEADER_LONG_FORM_BIT | HEADER_FIXED_BIT;
let pkt_type: u8 = match self.pkt_type {
Initial => 0x00,
ZeroRTT => 0x01,
Handshake => 0x02,
Retry => 0x03,
_ => return Err(Error::InternalError),
};
first |= pkt_type << 4;
first |= self.pkt_num_len.saturating_sub(1) as u8;
buf.write_u8(first)?;
buf.write_u32(self.version)?;
buf.write_u8(self.dcid.len() as u8)?;
buf.write(&self.dcid)?;
buf.write_u8(self.scid.len() as u8)?;
buf.write(&self.scid)?;
match self.pkt_type {
Initial => match self.token {
Some(ref v) => {
buf.write_varint(v.len() as u64)?;
buf.write(v)?;
}
None => {
buf.write_varint(0)?;
}
},
Retry => {
buf.write(self.token.as_ref().unwrap())?;
}
_ => (),
}
Ok(len - buf.len())
}
pub fn from_bytes(mut buf: &[u8], dcid_len: usize) -> Result<(PacketHeader, usize)> {
let len = buf.len();
let first = buf.read_u8()?;
if !PacketHeader::long_header(first) {
let dcid = buf.read(dcid_len)?;
return Ok((
PacketHeader {
pkt_type: OneRTT,
version: 0,
dcid: ConnectionId::new(&dcid),
scid: ConnectionId::default(),
pkt_num: 0,
pkt_num_len: 0,
token: None,
key_phase: false,
},
len - buf.len(),
));
}
let version = buf.read_u32()?;
let pkt_type = if version == 0 {
VersionNegotiation
} else {
match (first & PKT_TYPE_MASK) >> 4 {
0x00 => Initial,
0x01 => ZeroRTT,
0x02 => Handshake,
0x03 => Retry,
_ => return Err(Error::InvalidPacket),
}
};
let dcid_len = buf.read_u8()?;
if crate::version_is_supported(version) && dcid_len > MAX_CID_LEN as u8 {
return Err(Error::InvalidPacket);
}
let dcid = buf.read(dcid_len as usize)?;
let scid_len = buf.read_u8()?;
if crate::version_is_supported(version) && scid_len > MAX_CID_LEN as u8 {
return Err(Error::InvalidPacket);
}
let scid = buf.read(scid_len as usize)?;
let mut token: Option<Vec<u8>> = None;
match pkt_type {
Initial => {
let token_len = buf.read_varint()?;
if token_len > 0 {
token = Some(buf.read(token_len as usize)?);
}
}
Retry => {
if buf.len() < aead::AES_128_GCM.tag_len() {
return Err(Error::InvalidPacket);
}
let token_len = buf.len() - aead::AES_128_GCM.tag_len();
token = Some(buf.read(token_len)?);
}
_ => (),
};
Ok((
PacketHeader {
pkt_type,
version,
dcid: ConnectionId::new(&dcid),
scid: ConnectionId::new(&scid),
pkt_num: 0,
pkt_num_len: 0,
token,
key_phase: false,
},
len - buf.len(),
))
}
pub fn header_info(mut buf: &[u8], dcid_len: usize) -> Result<(bool, u32, ConnectionId)> {
let first = buf.read_u8()?;
if !PacketHeader::long_header(first) {
let dcid = buf.read(dcid_len)?;
let dcid = ConnectionId::new(&dcid);
return Ok((false, 0, dcid));
}
let version = buf.read_u32()?;
let dcid_len = buf.read_u8()?;
let dcid = buf.read(dcid_len as usize)?;
let dcid = ConnectionId::new(&dcid);
Ok((true, version, dcid))
}
fn long_header(header_first_byte: u8) -> bool {
header_first_byte & HEADER_LONG_FORM_BIT != 0
}
}
impl std::fmt::Debug for PacketHeader {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self.pkt_type)?;
if self.pkt_type != OneRTT {
write!(f, " ver={:x}", self.version)?;
}
write!(f, " dcid={:?}", self.dcid)?;
if self.pkt_type != OneRTT {
write!(f, " scid={:?}", self.scid)?;
}
if let Some(ref token) = self.token {
write!(f, " token=")?;
for b in token {
write!(f, "{b:02x}")?;
}
}
if self.pkt_type == OneRTT {
write!(f, " key_phase={}", self.key_phase)?;
}
Ok(())
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn encrypt_packet(
pkt_buf: &mut [u8],
cid_seq: Option<u32>,
pkt_num: u64,
pkt_num_len: usize,
payload_len: usize,
payload_offset: usize,
extra_in: Option<&[u8]>,
aead: &Seal,
) -> Result<usize> {
if pkt_buf.len() < payload_offset + payload_len {
return Err(Error::BufferTooShort);
}
let (pkt_hdr, payload) = pkt_buf.split_at_mut(payload_offset);
let ciphertext_len = aead.seal(
cid_seq,
pkt_num, pkt_hdr, payload, payload_len, extra_in,
)?;
encrypt_header(pkt_hdr, pkt_num_len, payload, aead)?;
Ok(payload_offset + ciphertext_len)
}
fn encrypt_header(
hdr_buf: &mut [u8],
pkt_num_len: usize,
payload: &[u8],
aead: &Seal,
) -> Result<()> {
let sample_start = MAX_PKT_NUM_LEN - pkt_num_len;
let sample = &payload[sample_start..sample_start + SAMPLE_LEN];
let mask = aead.new_mask(sample)?;
let (first, rest) = hdr_buf.split_at_mut(1);
if PacketHeader::long_header(first[0]) {
first[0] ^= mask[0] & 0x0f;
} else {
first[0] ^= mask[0] & 0x1f;
}
let (_, pkt_num_buf) = rest.split_at_mut(rest.len() - pkt_num_len);
for i in 0..pkt_num_len {
pkt_num_buf[i] ^= mask[i + 1];
}
Ok(())
}
#[allow(unexpected_cfgs)]
pub(crate) fn decrypt_payload(
pkt_buf: &mut [u8],
payload_offset: usize,
payload_len: usize,
cid_seq: Option<u32>,
pkt_num: u64,
aead: &Open,
) -> Result<bytes::Bytes> {
if pkt_buf.len() < payload_offset + payload_len {
return Err(Error::BufferTooShort);
}
let (header_buf, payload_buf) = pkt_buf.split_at_mut(payload_offset);
let payload_buf = &mut payload_buf[..payload_len];
let mut plaintext = BytesMut::zeroed(payload_len);
if cfg!(feature = "fuzzing") {
return Ok(Bytes::copy_from_slice(payload_buf));
}
let payload_len = aead.open(
cid_seq,
pkt_num,
header_buf,
payload_buf,
&mut plaintext[..],
)?;
plaintext.truncate(payload_len);
Ok(plaintext.freeze())
}
pub(crate) fn decrypt_header(
pkt_buf: &mut [u8],
pkt_num_offset: usize,
hdr: &mut PacketHeader,
aead: &Open,
plaintext_mode: bool,
) -> Result<()> {
let pkt_buf_min = if !plaintext_mode {
pkt_num_offset + MAX_PKT_NUM_LEN + SAMPLE_LEN
} else {
pkt_num_offset + MAX_PKT_NUM_LEN
};
if pkt_buf.len() < pkt_buf_min {
return Err(Error::BufferTooShort);
}
let mut first = pkt_buf[0];
let (pkt_num_len, pkt_num_buf) = if !plaintext_mode {
let sample_start = pkt_num_offset + MAX_PKT_NUM_LEN;
let sample = &pkt_buf[sample_start..sample_start + SAMPLE_LEN];
let mask = aead.new_mask(sample)?;
if PacketHeader::long_header(first) {
first ^= mask[0] & 0x0f;
} else {
first ^= mask[0] & 0x1f;
}
let pkt_num_len = usize::from((first & PKT_NUM_LEN_MASK) + 1);
let pkt_num_buf = &mut pkt_buf[pkt_num_offset..pkt_num_offset + pkt_num_len];
for i in 0..pkt_num_len {
pkt_num_buf[i] ^= mask[i + 1];
}
(pkt_num_len, pkt_num_buf)
} else {
let pkt_num_len = usize::from((first & PKT_NUM_LEN_MASK) + 1);
let pkt_num_buf = &mut pkt_buf[pkt_num_offset..pkt_num_offset + pkt_num_len];
(pkt_num_len, pkt_num_buf)
};
let pkt_num = {
let mut b: &[u8] = pkt_num_buf;
match pkt_num_len {
1 => u64::from(b.read_u8()?),
2 => u64::from(b.read_u16()?),
3 => u64::from(b.read_u24()?),
4 => u64::from(b.read_u32()?),
_ => return Err(Error::InvalidPacket),
}
};
pkt_buf[0] = first;
hdr.pkt_num_len = pkt_num_len;
hdr.pkt_num = pkt_num;
if hdr.pkt_type == OneRTT {
hdr.key_phase = (first & HEADER_KEY_PHASE_BIT) != 0;
}
Ok(())
}
pub(crate) fn decode_packet_num(largest_pn: u64, truncated_pn: u64, pkt_num_len: usize) -> u64 {
let pn_nbits = pkt_num_len * 8;
let expected_pn = largest_pn + 1;
let pn_win = 1 << pn_nbits;
let pn_hwin = pn_win / 2;
let pn_mask = pn_win - 1;
let candidate_pn = (expected_pn & !pn_mask) | truncated_pn;
if candidate_pn + pn_hwin <= expected_pn && candidate_pn < (1 << 62) - pn_win {
return candidate_pn + pn_win;
}
if candidate_pn > expected_pn + pn_hwin && candidate_pn >= pn_win {
return candidate_pn - pn_win;
}
candidate_pn
}
pub(crate) fn encode_packet_num(pkt_num: u64, len: usize, mut buf: &mut [u8]) -> Result<usize> {
match len {
1 => buf.write_u8(pkt_num as u8)?,
2 => buf.write_u16(pkt_num as u16)?,
3 => buf.write_u24(pkt_num as u32)?,
4 => buf.write_u32(pkt_num as u32)?,
_ => return Err(Error::InvalidPacket),
};
Ok(len)
}
pub(crate) fn packet_num_len(pkt_num: u64, largest_acked: Option<u64>) -> usize {
let num_unacked = if let Some(largest_acked) = largest_acked {
pkt_num.saturating_sub(largest_acked)
} else {
pkt_num.saturating_add(1)
};
let min_bits = u64::BITS - num_unacked.leading_zeros() + 1; ((min_bits + 7) / 8) as usize }
pub fn version_negotiation(scid: &[u8], dcid: &[u8], mut buf: &mut [u8]) -> Result<usize> {
let len = buf.len();
let first = rand::random::<u8>() | HEADER_LONG_FORM_BIT;
buf.write_u8(first)?;
buf.write_u32(0)?;
buf.write_u8(dcid.len() as u8)?;
buf.write(dcid)?;
buf.write_u8(scid.len() as u8)?;
buf.write(scid)?;
buf.write_u32(crate::QUIC_VERSION_V1)?;
Ok(len - buf.len())
}
pub fn retry(
scid: &[u8],
dcid: &[u8],
odcid: &[u8],
token: &[u8],
version: u32,
out: &mut [u8],
) -> Result<usize> {
if !crate::version_is_supported(version) {
return Err(Error::UnknownVersion);
}
let hdr = PacketHeader {
pkt_type: Retry,
version,
dcid: ConnectionId::new(dcid),
scid: ConnectionId::new(scid),
pkt_num: 0,
pkt_num_len: 0,
token: Some(token.to_vec()),
key_phase: false,
};
let hdr_len = hdr.to_bytes(out)?;
let tag = compute_retry_integrity_tag(&out[..hdr_len], odcid, version)?;
let mut out = &mut out[hdr_len..];
out.write(tag.as_ref())?;
Ok(hdr_len + tag.as_ref().len())
}
fn compute_retry_integrity_tag(retry_hdr: &[u8], odcid: &[u8], _version: u32) -> Result<aead::Tag> {
let mut pseudo_pkt = vec![0_u8; 1 + odcid.len() + retry_hdr.len()];
let mut pb = pseudo_pkt.as_mut_slice();
pb.write_u8(odcid.len() as u8)?;
pb.write(odcid)?;
pb.write(retry_hdr)?;
let (key, nonce) = (&RETRY_INTEGRITY_KEY_V1, RETRY_INTEGRITY_NONCE_V1);
let key = aead::LessSafeKey::new(
aead::UnboundKey::new(&aead::AES_128_GCM, key).map_err(|_| Error::CryptoFail)?,
);
let nonce = aead::Nonce::assume_unique_for_key(nonce);
let aad = aead::Aad::from(&pseudo_pkt);
key.seal_in_place_separate_tag(nonce, aad, &mut [])
.map_err(|_| Error::CryptoFail)
}
pub fn verify_retry_integrity_tag(buf: &mut [u8], odcid: &[u8], version: u32) -> Result<()> {
let len = aead::AES_128_GCM.tag_len();
if buf.len() < len {
return Err(Error::BufferTooShort);
}
let hdr_buf = &buf[..buf.len() - len];
let tag = compute_retry_integrity_tag(hdr_buf, odcid, version)?;
ring::constant_time::verify_slices_are_equal(&buf[buf.len() - len..], tag.as_ref())
.map_err(|_| Error::CryptoFail)?;
Ok(())
}
pub fn stateless_reset(pkt_len: usize, token: &[u8], mut out: &mut [u8]) -> Result<usize> {
if pkt_len > out.len() {
return Err(Error::BufferTooShort);
}
if pkt_len < crate::MIN_RESET_PACKET_LEN {
return Err(Error::InternalError);
}
if token.len() != crate::RESET_TOKEN_LEN {
return Err(Error::InternalError);
}
let unpredict_len = pkt_len - crate::RESET_TOKEN_LEN;
rand::thread_rng().fill_bytes(&mut out[..unpredict_len]);
out[0] = (out[0] & 0b0011_1111) | HEADER_FIXED_BIT;
out = &mut out[unpredict_len..];
out.write(token)?;
Ok(pkt_len)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::token::ResetToken;
use std::net::Ipv4Addr;
use std::net::SocketAddrV4;
#[test]
fn initial_pkt() -> Result<()> {
let mut initial_hdr = PacketHeader {
pkt_type: PacketType::Initial,
version: 1,
dcid: ConnectionId {
len: 20,
data: [1; 20],
},
scid: ConnectionId {
len: 20,
data: [3; 20],
},
pkt_num: 0,
pkt_num_len: 0,
token: None,
key_phase: false,
};
assert_eq!(
format!("{:?}", initial_hdr),
"Initial ver=1 \
dcid=0101010101010101010101010101010101010101 \
scid=0303030303030303030303030303030303030303"
);
let mut buf = [0; 128];
let len = initial_hdr.to_bytes(&mut buf)?;
assert_eq!(
(initial_hdr.clone(), len),
PacketHeader::from_bytes(&mut buf, 20)?
);
initial_hdr.token = Some(vec![4; 24]);
assert_eq!(
format!("{:?}", initial_hdr),
"Initial ver=1 \
dcid=0101010101010101010101010101010101010101 \
scid=0303030303030303030303030303030303030303 \
token=040404040404040404040404040404040404040404040404"
);
let len = initial_hdr.to_bytes(&mut buf)?;
assert_eq!(
(initial_hdr.clone(), len),
PacketHeader::from_bytes(&mut buf, 20)?
);
let info = PacketHeader::header_info(&mut buf, 20)?;
assert_eq!(info, (true, initial_hdr.version, initial_hdr.dcid));
Ok(())
}
#[test]
fn handshake_pkt() -> Result<()> {
let hsk_hdr = PacketHeader {
pkt_type: PacketType::Handshake,
version: 1,
dcid: ConnectionId {
len: 20,
data: [0xa; 20],
},
scid: ConnectionId {
len: 20,
data: [0xb; 20],
},
pkt_num: 0,
pkt_num_len: 0,
token: None,
key_phase: false,
};
assert_eq!(
format!("{:?}", hsk_hdr),
"Handshake ver=1 \
dcid=0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a \
scid=0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
);
let mut buf = [0; 128];
let len = hsk_hdr.to_bytes(&mut buf)?;
assert_eq!(
(hsk_hdr.clone(), len),
PacketHeader::from_bytes(&mut buf, 20)?
);
let info = PacketHeader::header_info(&mut buf, 20)?;
assert_eq!(info, (true, hsk_hdr.version, hsk_hdr.dcid));
Ok(())
}
#[test]
fn zero_rtt_pkt() -> Result<()> {
let zero_rtt_hdr = PacketHeader {
pkt_type: PacketType::ZeroRTT,
version: 1,
dcid: ConnectionId {
len: 20,
data: [0xc; 20],
},
scid: ConnectionId {
len: 20,
data: [0xd; 20],
},
pkt_num: 0,
pkt_num_len: 0,
token: None,
key_phase: false,
};
assert_eq!(
format!("{:?}", zero_rtt_hdr),
"ZeroRTT ver=1 \
dcid=0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c \
scid=0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d"
);
let mut buf = [0; 128];
let len = zero_rtt_hdr.to_bytes(&mut buf)?;
assert_eq!(
(zero_rtt_hdr.clone(), len),
PacketHeader::from_bytes(&mut buf, 20)?
);
let info = PacketHeader::header_info(&mut buf, 20)?;
assert_eq!(info, (true, zero_rtt_hdr.version, zero_rtt_hdr.dcid));
Ok(())
}
#[test]
fn one_rtt_pkt() -> Result<()> {
let mut one_rtt_hdr = PacketHeader {
pkt_type: PacketType::OneRTT,
version: 0,
dcid: ConnectionId {
len: 20,
data: [0xc; 20],
},
scid: ConnectionId::default(),
pkt_num: 0,
pkt_num_len: 0,
token: None,
key_phase: false,
};
assert_eq!(
format!("{:?}", one_rtt_hdr),
"OneRTT \
dcid=0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c key_phase=false"
);
let mut buf = [0; 128];
let len = one_rtt_hdr.to_bytes(&mut buf)?;
assert_eq!(
(one_rtt_hdr.clone(), len),
PacketHeader::from_bytes(&mut buf, 20)?
);
one_rtt_hdr.key_phase = true;
assert_eq!(
format!("{:?}", one_rtt_hdr),
"OneRTT \
dcid=0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c key_phase=true"
);
one_rtt_hdr.to_bytes(&mut buf)?;
assert_eq!(PacketHeader::from_bytes(&mut buf, 20)?.0.key_phase, false);
let info = PacketHeader::header_info(&mut buf, 20)?;
assert_eq!(info, (false, one_rtt_hdr.version, one_rtt_hdr.dcid));
Ok(())
}
#[test]
fn version_negotiation_pkt() -> Result<()> {
let scid = ConnectionId {
len: 20,
data: [0xc; 20],
};
let dcid = ConnectionId {
len: 20,
data: [0xd; 20],
};
let mut buf = [0; 128];
let len = version_negotiation(&scid, &dcid, &mut buf)?;
let br = &buf[..len];
let (hdr, hdr_len) = PacketHeader::from_bytes(br, 20)?;
assert_eq!(hdr.pkt_type, PacketType::VersionNegotiation);
assert_eq!(hdr.scid, scid);
assert_eq!(hdr.dcid, dcid);
assert_eq!(len, hdr_len + 4);
assert_eq!(
format!("{:?}", hdr),
"VersionNegotiation ver=0 \
dcid=0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d \
scid=0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"
);
let info = PacketHeader::header_info(&mut buf, 20)?;
assert_eq!(info, (true, hdr.version, hdr.dcid));
let mut br = &buf[hdr_len..];
let ver = br.read_u32()?;
assert_eq!(ver, crate::QUIC_VERSION_V1);
assert_eq!(hdr.to_bytes(&mut buf), Err(Error::InternalError));
Ok(())
}
#[test]
fn retry_pkt() -> Result<()> {
let scid = ConnectionId {
len: 20,
data: [0xc; 20],
};
let dcid = ConnectionId {
len: 20,
data: [0xd; 20],
};
let odcid = ConnectionId {
len: 20,
data: [0xe; 20],
};
let token = [
0x71, 0x75, 0x69, 0x63, 0xc0, 0xa8, 0x01, 0x0a, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
];
let mut buf = [0; 128];
let len = retry(
&scid,
&dcid,
&odcid,
&token,
crate::QUIC_VERSION_V1,
&mut buf,
)?;
let br = &buf[..len];
let (hdr, hdr_len) = PacketHeader::from_bytes(br, 20)?;
assert_eq!(hdr.pkt_type, PacketType::Retry);
assert_eq!(hdr.scid, scid);
assert_eq!(hdr.dcid, dcid);
assert_eq!(hdr.version, crate::QUIC_VERSION_V1);
assert_eq!(hdr.token, Some(token.to_vec()));
assert_eq!(hdr_len, len - aead::AES_128_GCM.tag_len());
assert_eq!(
format!("{:?}", hdr),
"Retry ver=1 \
dcid=0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d \
scid=0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c \
token=71756963c0a8010a0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e"
);
let info = PacketHeader::header_info(&mut buf, 20)?;
assert_eq!(info, (true, hdr.version, hdr.dcid));
verify_retry_integrity_tag(&mut buf[..len], &odcid, crate::QUIC_VERSION_V1)?;
Ok(())
}
#[test]
fn stateless_reset_pkt() -> Result<()> {
let token = [0xc; crate::RESET_TOKEN_LEN];
let mut buf = [0; 128];
assert_eq!(
stateless_reset(64, &token, &mut buf[..10]),
Err(Error::BufferTooShort)
);
assert_eq!(
stateless_reset(16, &token, &mut buf),
Err(Error::InternalError)
);
assert_eq!(
stateless_reset(64, &token[..10], &mut buf),
Err(Error::InternalError)
);
let len = stateless_reset(64, &token, &mut buf)?;
let buf = &buf[..len];
assert_eq!(buf[0] & 0b1100_0000, 0b0100_0000); assert_eq!(ResetToken::from_bytes(buf)?.0, token);
Ok(())
}
#[test]
fn packet_type() -> Result<()> {
let test_cases = [
(
PacketType::Initial,
Ok(Level::Initial),
Ok(SpaceId::Initial),
),
(
PacketType::Handshake,
Ok(Level::Handshake),
Ok(SpaceId::Handshake),
),
(
PacketType::ZeroRTT,
Ok(Level::ZeroRTT),
Ok(SpaceId::Data), ),
(
PacketType::OneRTT,
Ok(Level::OneRTT),
Ok(SpaceId::Data), ),
(
PacketType::VersionNegotiation,
Err(Error::InternalError),
Err(Error::InternalError),
),
(
PacketType::Retry,
Err(Error::InternalError),
Err(Error::InternalError),
),
];
for case in test_cases {
let pkt_type = case.0;
assert_eq!(pkt_type.to_level(), case.1);
assert_eq!(pkt_type.to_space(), case.2);
}
Ok(())
}
#[test]
fn packet_num() -> Result<()> {
let test_cases = [
(0, None, 1),
(127, Some(0), 1),
(128, Some(0), 2),
(129, Some(0), 2),
(1174, Some(996), 2),
(32767, Some(0), 2),
(32768, Some(0), 3),
(8388607, Some(0), 3),
(8388608, Some(0), 4),
(2147483647, Some(0), 4),
(2147483648, Some(1), 4),
(4294967296, Some(4294967295), 1),
(4611686018427387903, Some(4611686018427387902), 1),
];
const U8_MAX: u64 = (1 << 8) - 1;
const U16_MAX: u64 = (1 << 16) - 1;
const U24_MAX: u64 = (1 << 24) - 1;
const U32_MAX: u64 = (1 << 32) - 1;
let mut buf = [0; 4];
for case in test_cases {
let pkt_num = case.0;
let largest_acked = case.1;
let pkt_num_len = packet_num_len(pkt_num, largest_acked);
assert_eq!(pkt_num_len, case.2);
let range = (pkt_num - largest_acked.unwrap_or(0)) * 2 as u64;
if range <= U8_MAX {
assert!(pkt_num_len == 1);
} else if range <= U16_MAX {
assert!(pkt_num_len == 2);
} else if range <= U24_MAX {
assert!(pkt_num_len == 3);
} else if range <= U32_MAX {
assert!(pkt_num_len == 4);
} else {
unreachable!();
}
let len = encode_packet_num(pkt_num, pkt_num_len, &mut buf[..])?;
assert_eq!(len, pkt_num_len);
let mut b = &buf[..];
let pkt_num_truncated = match len {
1 => u64::from(b.read_u8()?),
2 => u64::from(b.read_u16()?),
3 => u64::from(b.read_u24()?),
4 => u64::from(b.read_u32()?),
_ => unreachable!(),
};
let pkt_num_decoded =
decode_packet_num(largest_acked.unwrap_or(0), pkt_num_truncated, len);
assert_eq!(pkt_num, pkt_num_decoded);
}
let pkt_num_len = packet_num_len(0xac5c02, Some(0xabe8b3));
assert_eq!(pkt_num_len, 2);
let pkt_num = decode_packet_num(0xa82f30ea, 0x9b32, 2);
assert_eq!(pkt_num, 0xa82f9b32);
Ok(())
}
#[test]
fn packet_cid_len() -> Result<()> {
let pkts = [
[
0xc0, 0x00, 0x00, 0x00, 0x01, 0x15, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x14, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x00,
],
[
0xc0, 0x00, 0x00, 0x00, 0x01, 0x14, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x15, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x00,
],
];
for pkt in pkts {
assert_eq!(
PacketHeader::from_bytes(&pkt[..], 20),
Err(Error::InvalidPacket)
);
}
Ok(())
}
#[test]
fn client_initial_protection() -> Result<()> {
let mut pkt = [
0xc0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08,
0x00, 0x00, 0x44, 0x9e, 0x7b, 0x9a, 0xec, 0x34, 0xd1, 0xb1, 0xc9, 0x8d, 0xd7, 0x68,
0x9f, 0xb8, 0xec, 0x11, 0xd2, 0x42, 0xb1, 0x23, 0xdc, 0x9b, 0xd8, 0xba, 0xb9, 0x36,
0xb4, 0x7d, 0x92, 0xec, 0x35, 0x6c, 0x0b, 0xab, 0x7d, 0xf5, 0x97, 0x6d, 0x27, 0xcd,
0x44, 0x9f, 0x63, 0x30, 0x00, 0x99, 0xf3, 0x99, 0x1c, 0x26, 0x0e, 0xc4, 0xc6, 0x0d,
0x17, 0xb3, 0x1f, 0x84, 0x29, 0x15, 0x7b, 0xb3, 0x5a, 0x12, 0x82, 0xa6, 0x43, 0xa8,
0xd2, 0x26, 0x2c, 0xad, 0x67, 0x50, 0x0c, 0xad, 0xb8, 0xe7, 0x37, 0x8c, 0x8e, 0xb7,
0x53, 0x9e, 0xc4, 0xd4, 0x90, 0x5f, 0xed, 0x1b, 0xee, 0x1f, 0xc8, 0xaa, 0xfb, 0xa1,
0x7c, 0x75, 0x0e, 0x2c, 0x7a, 0xce, 0x01, 0xe6, 0x00, 0x5f, 0x80, 0xfc, 0xb7, 0xdf,
0x62, 0x12, 0x30, 0xc8, 0x37, 0x11, 0xb3, 0x93, 0x43, 0xfa, 0x02, 0x8c, 0xea, 0x7f,
0x7f, 0xb5, 0xff, 0x89, 0xea, 0xc2, 0x30, 0x82, 0x49, 0xa0, 0x22, 0x52, 0x15, 0x5e,
0x23, 0x47, 0xb6, 0x3d, 0x58, 0xc5, 0x45, 0x7a, 0xfd, 0x84, 0xd0, 0x5d, 0xff, 0xfd,
0xb2, 0x03, 0x92, 0x84, 0x4a, 0xe8, 0x12, 0x15, 0x46, 0x82, 0xe9, 0xcf, 0x01, 0x2f,
0x90, 0x21, 0xa6, 0xf0, 0xbe, 0x17, 0xdd, 0xd0, 0xc2, 0x08, 0x4d, 0xce, 0x25, 0xff,
0x9b, 0x06, 0xcd, 0xe5, 0x35, 0xd0, 0xf9, 0x20, 0xa2, 0xdb, 0x1b, 0xf3, 0x62, 0xc2,
0x3e, 0x59, 0x6d, 0x11, 0xa4, 0xf5, 0xa6, 0xcf, 0x39, 0x48, 0x83, 0x8a, 0x3a, 0xec,
0x4e, 0x15, 0xda, 0xf8, 0x50, 0x0a, 0x6e, 0xf6, 0x9e, 0xc4, 0xe3, 0xfe, 0xb6, 0xb1,
0xd9, 0x8e, 0x61, 0x0a, 0xc8, 0xb7, 0xec, 0x3f, 0xaf, 0x6a, 0xd7, 0x60, 0xb7, 0xba,
0xd1, 0xdb, 0x4b, 0xa3, 0x48, 0x5e, 0x8a, 0x94, 0xdc, 0x25, 0x0a, 0xe3, 0xfd, 0xb4,
0x1e, 0xd1, 0x5f, 0xb6, 0xa8, 0xe5, 0xeb, 0xa0, 0xfc, 0x3d, 0xd6, 0x0b, 0xc8, 0xe3,
0x0c, 0x5c, 0x42, 0x87, 0xe5, 0x38, 0x05, 0xdb, 0x05, 0x9a, 0xe0, 0x64, 0x8d, 0xb2,
0xf6, 0x42, 0x64, 0xed, 0x5e, 0x39, 0xbe, 0x2e, 0x20, 0xd8, 0x2d, 0xf5, 0x66, 0xda,
0x8d, 0xd5, 0x99, 0x8c, 0xca, 0xbd, 0xae, 0x05, 0x30, 0x60, 0xae, 0x6c, 0x7b, 0x43,
0x78, 0xe8, 0x46, 0xd2, 0x9f, 0x37, 0xed, 0x7b, 0x4e, 0xa9, 0xec, 0x5d, 0x82, 0xe7,
0x96, 0x1b, 0x7f, 0x25, 0xa9, 0x32, 0x38, 0x51, 0xf6, 0x81, 0xd5, 0x82, 0x36, 0x3a,
0xa5, 0xf8, 0x99, 0x37, 0xf5, 0xa6, 0x72, 0x58, 0xbf, 0x63, 0xad, 0x6f, 0x1a, 0x0b,
0x1d, 0x96, 0xdb, 0xd4, 0xfa, 0xdd, 0xfc, 0xef, 0xc5, 0x26, 0x6b, 0xa6, 0x61, 0x17,
0x22, 0x39, 0x5c, 0x90, 0x65, 0x56, 0xbe, 0x52, 0xaf, 0xe3, 0xf5, 0x65, 0x63, 0x6a,
0xd1, 0xb1, 0x7d, 0x50, 0x8b, 0x73, 0xd8, 0x74, 0x3e, 0xeb, 0x52, 0x4b, 0xe2, 0x2b,
0x3d, 0xcb, 0xc2, 0xc7, 0x46, 0x8d, 0x54, 0x11, 0x9c, 0x74, 0x68, 0x44, 0x9a, 0x13,
0xd8, 0xe3, 0xb9, 0x58, 0x11, 0xa1, 0x98, 0xf3, 0x49, 0x1d, 0xe3, 0xe7, 0xfe, 0x94,
0x2b, 0x33, 0x04, 0x07, 0xab, 0xf8, 0x2a, 0x4e, 0xd7, 0xc1, 0xb3, 0x11, 0x66, 0x3a,
0xc6, 0x98, 0x90, 0xf4, 0x15, 0x70, 0x15, 0x85, 0x3d, 0x91, 0xe9, 0x23, 0x03, 0x7c,
0x22, 0x7a, 0x33, 0xcd, 0xd5, 0xec, 0x28, 0x1c, 0xa3, 0xf7, 0x9c, 0x44, 0x54, 0x6b,
0x9d, 0x90, 0xca, 0x00, 0xf0, 0x64, 0xc9, 0x9e, 0x3d, 0xd9, 0x79, 0x11, 0xd3, 0x9f,
0xe9, 0xc5, 0xd0, 0xb2, 0x3a, 0x22, 0x9a, 0x23, 0x4c, 0xb3, 0x61, 0x86, 0xc4, 0x81,
0x9e, 0x8b, 0x9c, 0x59, 0x27, 0x72, 0x66, 0x32, 0x29, 0x1d, 0x6a, 0x41, 0x82, 0x11,
0xcc, 0x29, 0x62, 0xe2, 0x0f, 0xe4, 0x7f, 0xeb, 0x3e, 0xdf, 0x33, 0x0f, 0x2c, 0x60,
0x3a, 0x9d, 0x48, 0xc0, 0xfc, 0xb5, 0x69, 0x9d, 0xbf, 0xe5, 0x89, 0x64, 0x25, 0xc5,
0xba, 0xc4, 0xae, 0xe8, 0x2e, 0x57, 0xa8, 0x5a, 0xaf, 0x4e, 0x25, 0x13, 0xe4, 0xf0,
0x57, 0x96, 0xb0, 0x7b, 0xa2, 0xee, 0x47, 0xd8, 0x05, 0x06, 0xf8, 0xd2, 0xc2, 0x5e,
0x50, 0xfd, 0x14, 0xde, 0x71, 0xe6, 0xc4, 0x18, 0x55, 0x93, 0x02, 0xf9, 0x39, 0xb0,
0xe1, 0xab, 0xd5, 0x76, 0xf2, 0x79, 0xc4, 0xb2, 0xe0, 0xfe, 0xb8, 0x5c, 0x1f, 0x28,
0xff, 0x18, 0xf5, 0x88, 0x91, 0xff, 0xef, 0x13, 0x2e, 0xef, 0x2f, 0xa0, 0x93, 0x46,
0xae, 0xe3, 0x3c, 0x28, 0xeb, 0x13, 0x0f, 0xf2, 0x8f, 0x5b, 0x76, 0x69, 0x53, 0x33,
0x41, 0x13, 0x21, 0x19, 0x96, 0xd2, 0x00, 0x11, 0xa1, 0x98, 0xe3, 0xfc, 0x43, 0x3f,
0x9f, 0x25, 0x41, 0x01, 0x0a, 0xe1, 0x7c, 0x1b, 0xf2, 0x02, 0x58, 0x0f, 0x60, 0x47,
0x47, 0x2f, 0xb3, 0x68, 0x57, 0xfe, 0x84, 0x3b, 0x19, 0xf5, 0x98, 0x40, 0x09, 0xdd,
0xc3, 0x24, 0x04, 0x4e, 0x84, 0x7a, 0x4f, 0x4a, 0x0a, 0xb3, 0x4f, 0x71, 0x95, 0x95,
0xde, 0x37, 0x25, 0x2d, 0x62, 0x35, 0x36, 0x5e, 0x9b, 0x84, 0x39, 0x2b, 0x06, 0x10,
0x85, 0x34, 0x9d, 0x73, 0x20, 0x3a, 0x4a, 0x13, 0xe9, 0x6f, 0x54, 0x32, 0xec, 0x0f,
0xd4, 0xa1, 0xee, 0x65, 0xac, 0xcd, 0xd5, 0xe3, 0x90, 0x4d, 0xf5, 0x4c, 0x1d, 0xa5,
0x10, 0xb0, 0xff, 0x20, 0xdc, 0xc0, 0xc7, 0x7f, 0xcb, 0x2c, 0x0e, 0x0e, 0xb6, 0x05,
0xcb, 0x05, 0x04, 0xdb, 0x87, 0x63, 0x2c, 0xf3, 0xd8, 0xb4, 0xda, 0xe6, 0xe7, 0x05,
0x76, 0x9d, 0x1d, 0xe3, 0x54, 0x27, 0x01, 0x23, 0xcb, 0x11, 0x45, 0x0e, 0xfc, 0x60,
0xac, 0x47, 0x68, 0x3d, 0x7b, 0x8d, 0x0f, 0x81, 0x13, 0x65, 0x56, 0x5f, 0xd9, 0x8c,
0x4c, 0x8e, 0xb9, 0x36, 0xbc, 0xab, 0x8d, 0x06, 0x9f, 0xc3, 0x3b, 0xd8, 0x01, 0xb0,
0x3a, 0xde, 0xa2, 0xe1, 0xfb, 0xc5, 0xaa, 0x46, 0x3d, 0x08, 0xca, 0x19, 0x89, 0x6d,
0x2b, 0xf5, 0x9a, 0x07, 0x1b, 0x85, 0x1e, 0x6c, 0x23, 0x90, 0x52, 0x17, 0x2f, 0x29,
0x6b, 0xfb, 0x5e, 0x72, 0x40, 0x47, 0x90, 0xa2, 0x18, 0x10, 0x14, 0xf3, 0xb9, 0x4a,
0x4e, 0x97, 0xd1, 0x17, 0xb4, 0x38, 0x13, 0x03, 0x68, 0xcc, 0x39, 0xdb, 0xb2, 0xd1,
0x98, 0x06, 0x5a, 0xe3, 0x98, 0x65, 0x47, 0x92, 0x6c, 0xd2, 0x16, 0x2f, 0x40, 0xa2,
0x9f, 0x0c, 0x3c, 0x87, 0x45, 0xc0, 0xf5, 0x0f, 0xba, 0x38, 0x52, 0xe5, 0x66, 0xd4,
0x45, 0x75, 0xc2, 0x9d, 0x39, 0xa0, 0x3f, 0x0c, 0xda, 0x72, 0x19, 0x84, 0xb6, 0xf4,
0x40, 0x59, 0x1f, 0x35, 0x5e, 0x12, 0xd4, 0x39, 0xff, 0x15, 0x0a, 0xab, 0x76, 0x13,
0x49, 0x9d, 0xbd, 0x49, 0xad, 0xab, 0xc8, 0x67, 0x6e, 0xef, 0x02, 0x3b, 0x15, 0xb6,
0x5b, 0xfc, 0x5c, 0xa0, 0x69, 0x48, 0x10, 0x9f, 0x23, 0xf3, 0x50, 0xdb, 0x82, 0x12,
0x35, 0x35, 0xeb, 0x8a, 0x74, 0x33, 0xbd, 0xab, 0xcb, 0x90, 0x92, 0x71, 0xa6, 0xec,
0xbc, 0xb5, 0x8b, 0x93, 0x6a, 0x88, 0xcd, 0x4e, 0x8f, 0x2e, 0x6f, 0xf5, 0x80, 0x01,
0x75, 0xf1, 0x13, 0x25, 0x3d, 0x8f, 0xa9, 0xca, 0x88, 0x85, 0xc2, 0xf5, 0x52, 0xe6,
0x57, 0xdc, 0x60, 0x3f, 0x25, 0x2e, 0x1a, 0x8e, 0x30, 0x8f, 0x76, 0xf0, 0xbe, 0x79,
0xe2, 0xfb, 0x8f, 0x5d, 0x5f, 0xbb, 0xe2, 0xe3, 0x0e, 0xca, 0xdd, 0x22, 0x07, 0x23,
0xc8, 0xc0, 0xae, 0xa8, 0x07, 0x8c, 0xdf, 0xcb, 0x38, 0x68, 0x26, 0x3f, 0xf8, 0xf0,
0x94, 0x00, 0x54, 0xda, 0x48, 0x78, 0x18, 0x93, 0xa7, 0xe4, 0x9a, 0xd5, 0xaf, 0xf4,
0xaf, 0x30, 0x0c, 0xd8, 0x04, 0xa6, 0xb6, 0x27, 0x9a, 0xb3, 0xff, 0x3a, 0xfb, 0x64,
0x49, 0x1c, 0x85, 0x19, 0x4a, 0xab, 0x76, 0x0d, 0x58, 0xa6, 0x06, 0x65, 0x4f, 0x9f,
0x44, 0x00, 0xe8, 0xb3, 0x85, 0x91, 0x35, 0x6f, 0xbf, 0x64, 0x25, 0xac, 0xa2, 0x6d,
0xc8, 0x52, 0x44, 0x25, 0x9f, 0xf2, 0xb1, 0x9c, 0x41, 0xb9, 0xf9, 0x6f, 0x3c, 0xa9,
0xec, 0x1d, 0xde, 0x43, 0x4d, 0xa7, 0xd2, 0xd3, 0x92, 0xb9, 0x05, 0xdd, 0xf3, 0xd1,
0xf9, 0xaf, 0x93, 0xd1, 0xaf, 0x59, 0x50, 0xbd, 0x49, 0x3f, 0x5a, 0xa7, 0x31, 0xb4,
0x05, 0x6d, 0xf3, 0x1b, 0xd2, 0x67, 0xb6, 0xb9, 0x0a, 0x07, 0x98, 0x31, 0xaa, 0xf5,
0x79, 0xbe, 0x0a, 0x39, 0x01, 0x31, 0x37, 0xaa, 0xc6, 0xd4, 0x04, 0xf5, 0x18, 0xcf,
0xd4, 0x68, 0x40, 0x64, 0x7e, 0x78, 0xbf, 0xe7, 0x06, 0xca, 0x4c, 0xf5, 0xe9, 0xc5,
0x45, 0x3e, 0x9f, 0x7c, 0xfd, 0x2b, 0x8b, 0x4c, 0x8d, 0x16, 0x9a, 0x44, 0xe5, 0x5c,
0x88, 0xd4, 0xa9, 0xa7, 0xf9, 0x47, 0x42, 0x41, 0xe2, 0x21, 0xaf, 0x44, 0x86, 0x00,
0x18, 0xab, 0x08, 0x56, 0x97, 0x2e, 0x19, 0x4c, 0xd9, 0x34,
];
let dcid: [u8; 8] = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
let crypto_frame = [
0x06, 0x00, 0x40, 0xf1, 0x01, 0x00, 0x00, 0xed, 0x03, 0x03, 0xeb, 0xf8, 0xfa, 0x56,
0xf1, 0x29, 0x39, 0xb9, 0x58, 0x4a, 0x38, 0x96, 0x47, 0x2e, 0xc4, 0x0b, 0xb8, 0x63,
0xcf, 0xd3, 0xe8, 0x68, 0x04, 0xfe, 0x3a, 0x47, 0xf0, 0x6a, 0x2b, 0x69, 0x48, 0x4c,
0x00, 0x00, 0x04, 0x13, 0x01, 0x13, 0x02, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
0x10, 0x00, 0x0e, 0x00, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06,
0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x10, 0x00, 0x07, 0x00, 0x05, 0x04, 0x61,
0x6c, 0x70, 0x6e, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x93, 0x70, 0xb2, 0xc9, 0xca, 0xa4,
0x7f, 0xba, 0xba, 0xf4, 0x55, 0x9f, 0xed, 0xba, 0x75, 0x3d, 0xe1, 0x71, 0xfa, 0x71,
0xf5, 0x0f, 0x1c, 0xe1, 0x5d, 0x43, 0xe9, 0x94, 0xec, 0x74, 0xd7, 0x48, 0x00, 0x2b,
0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0e, 0x04, 0x03, 0x05,
0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x00, 0x2d, 0x00,
0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01, 0x00, 0x39, 0x00, 0x32, 0x04,
0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x04, 0x80, 0x00, 0xff,
0xff, 0x07, 0x04, 0x80, 0x00, 0xff, 0xff, 0x08, 0x01, 0x10, 0x01, 0x04, 0x80, 0x00,
0x75, 0x30, 0x09, 0x01, 0x10, 0x0f, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57,
0x08, 0x06, 0x04, 0x80, 0x00, 0xff, 0xff,
];
let (mut hdr, read) = PacketHeader::from_bytes(&pkt[..], 0)?;
let (length, pkt_num_off) = {
let mut b = &pkt[read..];
(b.read_varint()? as usize, pkt.len() - b.len())
};
assert_eq!(hdr.pkt_type, PacketType::Initial);
assert_eq!(hdr.version, crate::QUIC_VERSION_V1);
assert_eq!(&hdr.dcid[..], &dcid[..]);
assert_eq!(hdr.scid.len(), 0);
assert_eq!(hdr.token, None);
let (open, _) = tls::derive_initial_secrets(&hdr.dcid, hdr.version, true)?;
decrypt_header(&mut pkt[..], pkt_num_off, &mut hdr, &open, false)?;
assert_eq!(hdr.pkt_num_len, 4);
hdr.pkt_num = decode_packet_num(0, hdr.pkt_num, hdr.pkt_num_len);
assert_eq!(hdr.pkt_num, 2);
let payload_off = pkt_num_off + hdr.pkt_num_len;
let payload_len = length - hdr.pkt_num_len;
let plaintext = decrypt_payload(
&mut pkt[..],
payload_off,
payload_len,
None,
hdr.pkt_num,
&open,
)?;
assert_eq!(plaintext[..crypto_frame.len()], crypto_frame);
Ok(())
}
#[test]
fn server_initial_protection() -> Result<()> {
let mut pkt = [
0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62,
0xb5, 0x00, 0x40, 0x75, 0xc0, 0xd9, 0x5a, 0x48, 0x2c, 0xd0, 0x99, 0x1c, 0xd2, 0x5b,
0x0a, 0xac, 0x40, 0x6a, 0x58, 0x16, 0xb6, 0x39, 0x41, 0x00, 0xf3, 0x7a, 0x1c, 0x69,
0x79, 0x75, 0x54, 0x78, 0x0b, 0xb3, 0x8c, 0xc5, 0xa9, 0x9f, 0x5e, 0xde, 0x4c, 0xf7,
0x3c, 0x3e, 0xc2, 0x49, 0x3a, 0x18, 0x39, 0xb3, 0xdb, 0xcb, 0xa3, 0xf6, 0xea, 0x46,
0xc5, 0xb7, 0x68, 0x4d, 0xf3, 0x54, 0x8e, 0x7d, 0xde, 0xb9, 0xc3, 0xbf, 0x9c, 0x73,
0xcc, 0x3f, 0x3b, 0xde, 0xd7, 0x4b, 0x56, 0x2b, 0xfb, 0x19, 0xfb, 0x84, 0x02, 0x2f,
0x8e, 0xf4, 0xcd, 0xd9, 0x37, 0x95, 0xd7, 0x7d, 0x06, 0xed, 0xbb, 0x7a, 0xaf, 0x2f,
0x58, 0x89, 0x18, 0x50, 0xab, 0xbd, 0xca, 0x3d, 0x20, 0x39, 0x8c, 0x27, 0x64, 0x56,
0xcb, 0xc4, 0x21, 0x58, 0x40, 0x7d, 0xd0, 0x74, 0xee,
];
let odcid: [u8; 8] = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
let scid: [u8; 8] = [0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5];
let crypto_frame = [
0x02, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x5a, 0x02, 0x00, 0x00, 0x56, 0x03,
0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1, 0x63, 0x2e, 0x96, 0x67, 0x78,
0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf, 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43,
0x0b, 0x9a, 0x04, 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00,
0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69, 0x0b, 0x84, 0xd0,
0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68, 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83,
0x4d, 0x53, 0x11, 0xbc, 0xf3, 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03,
0x04,
];
let (mut hdr, read) = PacketHeader::from_bytes(&pkt[..], 0)?;
let (length, pkt_num_off) = {
let mut b = &pkt[read..];
(b.read_varint()? as usize, pkt.len() - b.len())
};
assert_eq!(hdr.pkt_type, PacketType::Initial);
assert_eq!(hdr.version, crate::QUIC_VERSION_V1);
assert_eq!(hdr.dcid.len(), 0);
assert_eq!(&hdr.scid[..], &scid[..]);
assert_eq!(hdr.token, None);
let (open, _) = tls::derive_initial_secrets(&odcid, hdr.version, false)?;
decrypt_header(&mut pkt[..], pkt_num_off, &mut hdr, &open, false)?;
assert_eq!(hdr.pkt_num_len, 2);
hdr.pkt_num = decode_packet_num(0, hdr.pkt_num, hdr.pkt_num_len);
assert_eq!(hdr.pkt_num, 1);
let payload_off = pkt_num_off + hdr.pkt_num_len;
let payload_len = length - hdr.pkt_num_len;
let plaintext = decrypt_payload(
&mut pkt[..],
payload_off,
payload_len,
None,
hdr.pkt_num,
&open,
)?;
assert_eq!(plaintext[..crypto_frame.len()], crypto_frame);
Ok(())
}
#[test]
fn onertt_chacha20_protection() -> Result<()> {
let pkt_hdr_data = [0x42, 0x00, 0xbf, 0xf4];
let pkt_num = 654_360_564;
let pkt_num_len = 3;
let pkt_payload = [01];
let secret = [
0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42, 0x27, 0x48, 0xad,
0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0, 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3,
0x0f, 0x21, 0x63, 0x2b,
];
let pkt_expected = [
0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6, 0x90, 0x80, 0x57,
0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb,
];
let (hdr, _) = PacketHeader::from_bytes(&pkt_hdr_data[..], 0)?;
assert_eq!(hdr.pkt_type, PacketType::OneRTT);
let mut out = vec![0_u8; pkt_expected.len()];
let mut b = out.as_mut_slice();
b.write(&pkt_hdr_data)?;
b.write(&pkt_payload)?;
let aead = Seal::new_with_secret(tls::Algorithm::ChaCha20Poly1305, secret.to_vec())?;
let written = encrypt_packet(
out.as_mut_slice(),
None,
pkt_num,
pkt_num_len,
pkt_payload.len(),
pkt_hdr_data.len(),
None,
&aead,
)?;
assert_eq!(written, pkt_expected.len());
assert_eq!(&out[..written], &pkt_expected[..]);
Ok(())
}
#[test]
fn multipath_protection() -> Result<()> {
let mut out = vec![0_u8; 128];
let pkt_hdr = PacketHeader {
pkt_type: PacketType::OneRTT,
version: 0,
dcid: ConnectionId::random(),
scid: ConnectionId::default(),
pkt_num: 10,
pkt_num_len: packet_num_len(10, Some(1)),
token: None,
key_phase: false,
};
let pkt_payload = [01, 02, 03, 04];
let cid_seq = Some(2);
let mut secret = [0u8; 32];
rand::thread_rng().fill_bytes(&mut secret);
let mut written = pkt_hdr.to_bytes(&mut out)?;
written += encode_packet_num(pkt_hdr.pkt_num, 1, &mut out[written..])?;
let (payload_off, payload_end) = (written, written + pkt_payload.len());
out[payload_off..payload_end].copy_from_slice(&pkt_payload);
let seal = Seal::new_with_secret(tls::Algorithm::ChaCha20Poly1305, secret.to_vec())?;
let written = encrypt_packet(
out.as_mut_slice(),
cid_seq,
pkt_hdr.pkt_num,
pkt_hdr.pkt_num_len,
pkt_payload.len(),
payload_off,
None,
&seal,
)?;
out.truncate(written);
let (mut hdr, read) = PacketHeader::from_bytes(&out, crate::MAX_CID_LEN)?;
assert_eq!(hdr.pkt_type, pkt_hdr.pkt_type);
assert_eq!(hdr.dcid, pkt_hdr.dcid);
assert_eq!(hdr.key_phase, pkt_hdr.key_phase);
let open = Open::new_with_secret(tls::Algorithm::ChaCha20Poly1305, secret.to_vec())?;
decrypt_header(&mut out, read, &mut hdr, &open, false)?;
assert_eq!(hdr.pkt_num_len, pkt_hdr.pkt_num_len);
assert_eq!(hdr.pkt_num, pkt_hdr.pkt_num);
let payload_off = read + hdr.pkt_num_len;
let payload_len = out.len() - read - hdr.pkt_num_len;
let plaintext = decrypt_payload(
&mut out,
payload_off,
payload_len,
cid_seq,
hdr.pkt_num,
&open,
)?;
assert_eq!(&pkt_payload[..], &plaintext);
Ok(())
}
#[test]
fn buffer_too_short() -> Result<()> {
let mut buf = [0; 1];
let br = &buf[..];
assert_eq!(PacketHeader::from_bytes(br, 20), Err(Error::BufferTooShort));
let bw = &mut buf[..];
let (open, _) =
tls::derive_initial_secrets(&ConnectionId::random(), crate::QUIC_VERSION_V1, false)?;
let mut hdr = PacketHeader {
pkt_type: PacketType::OneRTT,
version: 0,
dcid: ConnectionId::random(),
scid: ConnectionId::default(),
pkt_num: 0,
pkt_num_len: 0,
token: None,
key_phase: false,
};
assert_eq!(
decrypt_header(bw, 10, &mut hdr, &open, false),
Err(Error::BufferTooShort)
);
assert_eq!(
decrypt_payload(bw, 10, 10, None, 0, &open),
Err(Error::BufferTooShort)
);
assert_eq!(
verify_retry_integrity_tag(bw, &ConnectionId::random(), crate::QUIC_VERSION_V1),
Err(Error::BufferTooShort)
);
Ok(())
}
}