1use crate::coding::{put_varint, Reader};
5use crate::crypto::{CryptoProvider, HeaderKey};
6use std::ops::Range;
7
8pub const VERSION_1: u32 = 0x0000_0001;
9pub const VERSION_2: u32 = 0x6b33_43cf;
11pub const MAX_CID_LEN: usize = 20;
12pub const MIN_INITIAL_SIZE: usize = 1200;
14pub const MIN_RESET_SIZE: usize = 21;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum PacketType {
19 Initial,
20 ZeroRtt,
21 Handshake,
22 Retry,
23 OneRtt,
24 VersionNegotiation,
25}
26
27pub fn long_type_bits(version: u32, ty: PacketType) -> u8 {
29 let v1 = match ty {
30 PacketType::Initial => 0,
31 PacketType::ZeroRtt => 1,
32 PacketType::Handshake => 2,
33 _ => 3,
34 };
35 if version == VERSION_2 {
36 (v1 + 1) & 3
37 } else {
38 v1
39 }
40}
41
42fn long_type_from_bits(version: u32, bits: u8) -> PacketType {
43 let v1 = if version == VERSION_2 { (bits + 3) & 3 } else { bits };
44 match v1 {
45 0 => PacketType::Initial,
46 1 => PacketType::ZeroRtt,
47 2 => PacketType::Handshake,
48 _ => PacketType::Retry,
49 }
50}
51
52#[derive(Clone, Debug)]
54pub struct Header {
55 pub ty: PacketType,
56 pub version: u32,
57 pub dcid: Range<usize>,
58 pub scid: Range<usize>,
59 pub token: Range<usize>,
61 pub pn_offset: usize,
63 pub end: usize,
65}
66
67pub fn parse_header(buf: &[u8], start: usize, short_dcid_len: usize) -> Option<Header> {
70 let mut r = Reader::new(&buf[start..]);
71 let first = r.u8()?;
72 if first & 0x80 == 0 {
73 let dcid = start + 1..start + 1 + short_dcid_len;
75 if dcid.end > buf.len() {
76 return None;
77 }
78 return Some(Header {
79 ty: PacketType::OneRtt,
80 version: 0,
81 dcid: dcid.clone(),
82 scid: 0..0,
83 token: 0..0,
84 pn_offset: dcid.end,
85 end: buf.len(),
86 });
87 }
88 let version = r.u32()?;
89 let dlen = r.u8()? as usize;
90 let d0 = start + r.position();
91 r.bytes(dlen)?;
92 let slen = r.u8()? as usize;
93 let s0 = start + r.position();
94 r.bytes(slen)?;
95 let dcid = d0..d0 + dlen;
96 let scid = s0..s0 + slen;
97 if dlen > MAX_CID_LEN || slen > MAX_CID_LEN {
100 return None;
101 }
102 if version == 0 {
103 let t0 = start + r.position();
104 return Some(Header {
105 ty: PacketType::VersionNegotiation,
106 version,
107 dcid,
108 scid,
109 token: t0..buf.len(),
110 pn_offset: buf.len(),
111 end: buf.len(),
112 });
113 }
114 if !is_supported(version) {
115 return Some(Header {
117 ty: PacketType::Initial,
118 version,
119 dcid,
120 scid,
121 token: 0..0,
122 pn_offset: buf.len(),
123 end: buf.len(),
124 });
125 }
126 let ty = long_type_from_bits(version, (first >> 4) & 3);
127 let mut token = 0..0;
128 if ty == PacketType::Retry {
129 let t0 = start + r.position();
130 if buf.len() < t0 + 16 {
131 return None;
132 }
133 return Some(Header { ty, version, dcid, scid, token: t0..buf.len() - 16, pn_offset: buf.len(), end: buf.len() });
134 }
135 if ty == PacketType::Initial {
136 let t = r.vbytes()?;
137 let t0 = start + r.position() - t.len();
138 token = t0..t0 + t.len();
139 }
140 let len = r.varint()? as usize;
141 let pn_offset = start + r.position();
142 if len > buf.len() - pn_offset {
143 return None;
144 }
145 Some(Header { ty, version, dcid, scid, token, pn_offset, end: pn_offset + len })
146}
147
148pub fn is_supported(version: u32) -> bool {
149 version == VERSION_1 || version == VERSION_2
150}
151
152pub fn unprotect(buf: &mut [u8], start: usize, pn_offset: usize, end: usize, hp: &dyn HeaderKey) -> Option<(u64, usize)> {
154 let sample_at = pn_offset + 4;
155 if sample_at + 16 > end {
156 return None;
157 }
158 let mask = hp.mask(&buf[sample_at..sample_at + 16]);
159 let long = buf[start] & 0x80 != 0;
160 buf[start] ^= mask[0] & if long { 0x0f } else { 0x1f };
161 let pn_len = (buf[start] & 3) as usize + 1;
162 let mut pn = 0u64;
163 for i in 0..pn_len {
164 buf[pn_offset + i] ^= mask[1 + i];
165 pn = (pn << 8) | buf[pn_offset + i] as u64;
166 }
167 Some((pn, pn_len))
168}
169
170pub fn protect(buf: &mut [u8], start: usize, pn_offset: usize, pn_len: usize, hp: &dyn HeaderKey) {
172 let sample_at = pn_offset + 4;
173 let mask = hp.mask(&buf[sample_at..sample_at + 16]);
174 let long = buf[start] & 0x80 != 0;
175 buf[start] ^= mask[0] & if long { 0x0f } else { 0x1f };
176 for i in 0..pn_len {
177 buf[pn_offset + i] ^= mask[1 + i];
178 }
179}
180
181pub fn decode_pn(largest: Option<u64>, truncated: u64, pn_len: usize) -> u64 {
183 let expected = largest.map_or(0, |l| l + 1);
184 let win = 1u64 << (pn_len * 8);
185 let hwin = win / 2;
186 let mask = win - 1;
187 let candidate = (expected & !mask) | truncated;
188 if candidate + hwin <= expected && candidate < (1 << 62) - win {
189 candidate + win
190 } else if candidate > expected + hwin && candidate >= win {
191 candidate - win
192 } else {
193 candidate
194 }
195}
196
197pub fn pn_len(pn: u64, largest_acked: Option<u64>) -> usize {
199 let unacked = match largest_acked {
200 Some(l) => pn - l,
201 None => pn + 1,
202 };
203 let range = unacked.saturating_mul(2);
204 if range < 1 << 8 {
205 1
206 } else if range < 1 << 16 {
207 2
208 } else if range < 1 << 24 {
209 3
210 } else {
211 4
212 }
213}
214
215pub fn version_negotiation(out: &mut Vec<u8>, random: u8, dcid: &[u8], scid: &[u8], versions: &[u32]) {
217 out.push(0x80 | (random & 0x7f) | 0x40);
218 out.extend_from_slice(&0u32.to_be_bytes());
219 out.push(scid.len() as u8);
220 out.extend_from_slice(scid);
221 out.push(dcid.len() as u8);
222 out.extend_from_slice(dcid);
223 for v in versions {
224 out.extend_from_slice(&v.to_be_bytes());
225 }
226 out.extend_from_slice(&0x1a2a_3a4au32.to_be_bytes());
228}
229
230#[allow(clippy::too_many_arguments)]
232pub fn retry(
233 out: &mut Vec<u8>,
234 provider: &dyn CryptoProvider,
235 version: u32,
236 random: u8,
237 odcid: &[u8],
238 dcid: &[u8],
239 scid: &[u8],
240 token: &[u8],
241) {
242 let start = out.len();
243 out.push(0xc0 | (long_type_bits(version, PacketType::Retry) << 4) | (random & 0x0f));
244 out.extend_from_slice(&version.to_be_bytes());
245 out.push(dcid.len() as u8);
246 out.extend_from_slice(dcid);
247 out.push(scid.len() as u8);
248 out.extend_from_slice(scid);
249 out.extend_from_slice(token);
250 let tag = retry_tag(provider, version, odcid, &out[start..]);
251 out.extend_from_slice(&tag);
252}
253
254pub fn retry_tag(provider: &dyn CryptoProvider, version: u32, odcid: &[u8], packet: &[u8]) -> [u8; 16] {
256 let mut pseudo = Vec::with_capacity(1 + odcid.len() + packet.len());
257 pseudo.push(odcid.len() as u8);
258 pseudo.extend_from_slice(odcid);
259 pseudo.extend_from_slice(packet);
260 provider.retry_tag(version, &pseudo)
261}
262
263#[allow(clippy::too_many_arguments)]
266pub fn put_long_header(
267 out: &mut Vec<u8>,
268 version: u32,
269 ty: PacketType,
270 dcid: &[u8],
271 scid: &[u8],
272 token: Option<&[u8]>,
273 pn: u64,
274 pn_len: usize,
275) -> (usize, usize) {
276 out.push(0xc0 | (long_type_bits(version, ty) << 4) | (pn_len as u8 - 1));
277 out.extend_from_slice(&version.to_be_bytes());
278 out.push(dcid.len() as u8);
279 out.extend_from_slice(dcid);
280 out.push(scid.len() as u8);
281 out.extend_from_slice(scid);
282 if let Some(t) = token {
283 put_varint(out, t.len() as u64);
284 out.extend_from_slice(t);
285 }
286 let len_at = out.len();
287 out.extend_from_slice(&[0x40, 0]);
288 let pn_at = out.len();
289 out.extend_from_slice(&pn.to_be_bytes()[8 - pn_len..]);
290 (len_at, pn_at)
291}
292
293pub fn put_short_header(out: &mut Vec<u8>, spin: bool, key_phase: bool, dcid: &[u8], pn: u64, pn_len: usize) -> usize {
295 out.push(0x40 | (spin as u8) << 5 | (key_phase as u8) << 2 | (pn_len as u8 - 1));
296 out.extend_from_slice(dcid);
297 let pn_at = out.len();
298 out.extend_from_slice(&pn.to_be_bytes()[8 - pn_len..]);
299 pn_at
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305
306 #[test]
307 fn rfc9000_appendix_a_packet_numbers() {
308 assert_eq!(pn_len(0xac5c02, Some(0xabe8b3)), 2);
310 assert_eq!(pn_len(0xace8fe, Some(0xabe8b3)), 3);
311 assert_eq!(decode_pn(Some(0xa82f30ea), 0x9b32, 2), 0xa82f9b32);
313 assert_eq!(decode_pn(None, 0, 1), 0);
314 assert_eq!(decode_pn(Some(0xff), 0x00, 1), 0x100);
315 assert_eq!(decode_pn(Some(0x100), 0xff, 1), 0xff);
316 assert_eq!(pn_len(0, None), 1);
317 }
318
319 #[test]
320 fn header_roundtrip_and_types() {
321 for v in [VERSION_1, VERSION_2] {
322 let mut out = Vec::new();
323 let (len_at, pn_at) =
324 put_long_header(&mut out, v, PacketType::Handshake, &[1, 2, 3], &[4, 5], None, 7, 2);
325 out.extend_from_slice(&[0; 20]);
326 let n = out.len() - pn_at;
327 crate::coding::put_varint_fixed(&mut out[len_at..], n as u64, 2);
328 let h = parse_header(&out, 0, 0).unwrap();
329 assert_eq!(h.ty, PacketType::Handshake);
330 assert_eq!(&out[h.dcid.clone()], &[1, 2, 3]);
331 assert_eq!(&out[h.scid.clone()], &[4, 5]);
332 assert_eq!(h.pn_offset, pn_at);
333 assert_eq!(h.end, out.len());
334 }
335 assert_eq!(long_type_bits(VERSION_2, PacketType::Initial), 1);
336 assert_eq!(long_type_bits(VERSION_2, PacketType::Retry), 0);
337 let mut out = Vec::new();
339 put_long_header(&mut out, VERSION_1, PacketType::Initial, &[1; 8], &[], Some(b"t"), 0, 1);
340 assert!(parse_header(&out, 0, 0).is_some());
341 out[17] = 0x7f;
342 out[18] = 0xff;
343 assert!(parse_header(&out, 0, 0).is_none());
344 }
345}