1use core::fmt;
4
5use super::{
6 QuicTransportParameter, QuicTransportParameterId, QuicTransportParameterIter,
7 QuicTransportParameterParseError, QuicTransportParameterValueError,
8};
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub enum QuicTransportParameterSender {
13 Client,
15 Server,
17}
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
25pub enum QuicTransportParameterHandshakeContext<'a> {
26 Client {
28 initial_source_connection_id: &'a [u8],
30 },
31 Server {
33 initial_source_connection_id: &'a [u8],
35 original_destination_connection_id: &'a [u8],
37 retry_source_connection_id: Option<&'a [u8]>,
39 },
40}
41
42#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46pub enum QuicTransportParameterHandshakeError {
47 SenderContextMismatch {
49 sender: QuicTransportParameterSender,
51 context_sender: QuicTransportParameterSender,
53 },
54 Structural {
56 error: QuicTransportParameterParseError,
58 },
59 Missing {
61 id: QuicTransportParameterId,
63 },
64 Unexpected {
66 id: QuicTransportParameterId,
68 offset: usize,
70 },
71 ConnectionIdMismatch {
73 id: QuicTransportParameterId,
75 offset: usize,
77 },
78}
79
80impl fmt::Display for QuicTransportParameterHandshakeError {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 match self {
83 Self::SenderContextMismatch {
84 sender,
85 context_sender,
86 } => write!(
87 f,
88 "QUIC transport-parameter sender {sender:?} does not match handshake context for {context_sender:?}"
89 ),
90 Self::Structural { error } => {
91 write!(
92 f,
93 "QUIC handshake transport parameters are not structural: {error}"
94 )
95 }
96 Self::Missing { id } => write!(
97 f,
98 "QUIC handshake transport parameter ID {} is required but missing",
99 id.raw()
100 ),
101 Self::Unexpected { id, offset } => write!(
102 f,
103 "QUIC handshake transport parameter ID {} at tuple offset {offset} is unexpected",
104 id.raw()
105 ),
106 Self::ConnectionIdMismatch { id, offset } => write!(
107 f,
108 "QUIC handshake transport parameter ID {} at tuple offset {offset} does not match its packet connection ID",
109 id.raw()
110 ),
111 }
112 }
113}
114
115#[derive(Clone, Copy, Debug, Eq, PartialEq)]
120pub enum QuicTransportParameterSemanticError {
121 Structural {
123 error: QuicTransportParameterParseError,
125 },
126 Value {
128 id: QuicTransportParameterId,
130 offset: usize,
132 error: QuicTransportParameterValueError,
134 },
135 ForbiddenSender {
137 id: QuicTransportParameterId,
139 offset: usize,
141 },
142 BelowMinimum {
144 id: QuicTransportParameterId,
146 offset: usize,
148 value: u64,
150 minimum: u64,
152 },
153 AboveMaximum {
155 id: QuicTransportParameterId,
157 offset: usize,
159 value: u64,
161 maximum: u64,
163 },
164}
165
166impl fmt::Display for QuicTransportParameterSemanticError {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 match self {
169 Self::Structural { error } => {
170 write!(f, "QUIC transport parameters are not structural: {error}")
171 }
172 Self::Value { id, offset, error } => write!(
173 f,
174 "QUIC transport parameter ID {} at tuple offset {offset} has an invalid value: {error}",
175 id.raw()
176 ),
177 Self::ForbiddenSender { id, offset } => write!(
178 f,
179 "QUIC client transport parameter ID {} at tuple offset {offset} is server-only",
180 id.raw()
181 ),
182 Self::BelowMinimum {
183 id,
184 offset,
185 value,
186 minimum,
187 } => write!(
188 f,
189 "QUIC transport parameter ID {} at tuple offset {offset} has value {value}, below minimum {minimum}",
190 id.raw()
191 ),
192 Self::AboveMaximum {
193 id,
194 offset,
195 value,
196 maximum,
197 } => write!(
198 f,
199 "QUIC transport parameter ID {} at tuple offset {offset} has value {value}, above maximum {maximum}",
200 id.raw()
201 ),
202 }
203 }
204}
205
206#[derive(Clone, Copy, Debug, Eq, PartialEq)]
208pub struct QuicTransportParametersV1<'a> {
209 bytes: &'a [u8],
210 sender: QuicTransportParameterSender,
211}
212
213impl<'a> QuicTransportParametersV1<'a> {
214 pub const fn as_bytes(self) -> &'a [u8] {
216 self.bytes
217 }
218
219 pub const fn sender(self) -> QuicTransportParameterSender {
221 self.sender
222 }
223
224 pub const fn iter(self) -> QuicTransportParameterIter<'a> {
226 QuicTransportParameterIter::new(self.bytes)
227 }
228
229 pub fn validate_handshake(
234 self,
235 context: QuicTransportParameterHandshakeContext<'_>,
236 ) -> Result<(), QuicTransportParameterHandshakeError> {
237 let context_sender = match context {
238 QuicTransportParameterHandshakeContext::Client { .. } => {
239 QuicTransportParameterSender::Client
240 }
241 QuicTransportParameterHandshakeContext::Server { .. } => {
242 QuicTransportParameterSender::Server
243 }
244 };
245 if self.sender != context_sender {
246 return Err(
247 QuicTransportParameterHandshakeError::SenderContextMismatch {
248 sender: self.sender,
249 context_sender,
250 },
251 );
252 }
253
254 match context {
255 QuicTransportParameterHandshakeContext::Client {
256 initial_source_connection_id,
257 } => validate_client_handshake(self, initial_source_connection_id),
258 QuicTransportParameterHandshakeContext::Server {
259 initial_source_connection_id,
260 original_destination_connection_id,
261 retry_source_connection_id,
262 } => validate_server_handshake(
263 self,
264 initial_source_connection_id,
265 original_destination_connection_id,
266 retry_source_connection_id,
267 ),
268 }
269 }
270}
271
272fn validate_client_handshake(
273 parameters: QuicTransportParametersV1<'_>,
274 initial_source_connection_id: &[u8],
275) -> Result<(), QuicTransportParameterHandshakeError> {
276 let mut initial_present = false;
277 let mut offset = 0;
278 for parameter in parameters.iter() {
279 let parameter = parameter
280 .map_err(|error| QuicTransportParameterHandshakeError::Structural { error })?;
281 let id = parameter.parameter_id();
282 if id == QuicTransportParameterId::INITIAL_SOURCE_CONNECTION_ID {
283 initial_present = true;
284 if parameter.value() != initial_source_connection_id {
285 return Err(QuicTransportParameterHandshakeError::ConnectionIdMismatch {
286 id,
287 offset,
288 });
289 }
290 }
291 offset += parameter.as_bytes().len();
292 }
293 if !initial_present {
294 return Err(QuicTransportParameterHandshakeError::Missing {
295 id: QuicTransportParameterId::INITIAL_SOURCE_CONNECTION_ID,
296 });
297 }
298 Ok(())
299}
300
301fn validate_server_handshake(
302 parameters: QuicTransportParametersV1<'_>,
303 initial_source_connection_id: &[u8],
304 original_destination_connection_id: &[u8],
305 retry_source_connection_id: Option<&[u8]>,
306) -> Result<(), QuicTransportParameterHandshakeError> {
307 let mut initial_present = false;
308 let mut original_present = false;
309 let mut retry_present = false;
310 let mut offset = 0;
311 for parameter in parameters.iter() {
312 let parameter = parameter
313 .map_err(|error| QuicTransportParameterHandshakeError::Structural { error })?;
314 let id = parameter.parameter_id();
315 match id {
316 QuicTransportParameterId::INITIAL_SOURCE_CONNECTION_ID => {
317 initial_present = true;
318 if parameter.value() != initial_source_connection_id {
319 return Err(QuicTransportParameterHandshakeError::ConnectionIdMismatch {
320 id,
321 offset,
322 });
323 }
324 }
325 QuicTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID => {
326 original_present = true;
327 if parameter.value() != original_destination_connection_id {
328 return Err(QuicTransportParameterHandshakeError::ConnectionIdMismatch {
329 id,
330 offset,
331 });
332 }
333 }
334 QuicTransportParameterId::RETRY_SOURCE_CONNECTION_ID => {
335 let Some(expected) = retry_source_connection_id else {
336 return Err(QuicTransportParameterHandshakeError::Unexpected { id, offset });
337 };
338 retry_present = true;
339 if parameter.value() != expected {
340 return Err(QuicTransportParameterHandshakeError::ConnectionIdMismatch {
341 id,
342 offset,
343 });
344 }
345 }
346 _ => {}
347 }
348 offset += parameter.as_bytes().len();
349 }
350 if !initial_present {
351 return Err(QuicTransportParameterHandshakeError::Missing {
352 id: QuicTransportParameterId::INITIAL_SOURCE_CONNECTION_ID,
353 });
354 }
355 if !original_present {
356 return Err(QuicTransportParameterHandshakeError::Missing {
357 id: QuicTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID,
358 });
359 }
360 if retry_source_connection_id.is_some() && !retry_present {
361 return Err(QuicTransportParameterHandshakeError::Missing {
362 id: QuicTransportParameterId::RETRY_SOURCE_CONNECTION_ID,
363 });
364 }
365 Ok(())
366}
367
368pub(super) fn validate<'a>(
369 bytes: &'a [u8],
370 sender: QuicTransportParameterSender,
371) -> Result<QuicTransportParametersV1<'a>, QuicTransportParameterSemanticError> {
372 let mut offset = 0;
373 let parameters = QuicTransportParameterIter::new(bytes);
374 for parameter in parameters {
375 let parameter =
376 parameter.map_err(|error| QuicTransportParameterSemanticError::Structural { error })?;
377 validate_parameter(parameter, sender, offset)?;
378 offset += parameter.as_bytes().len();
379 }
380 Ok(QuicTransportParametersV1 { bytes, sender })
381}
382
383fn validate_parameter(
384 parameter: QuicTransportParameter<'_>,
385 sender: QuicTransportParameterSender,
386 offset: usize,
387) -> Result<(), QuicTransportParameterSemanticError> {
388 let id = parameter.parameter_id();
389 if sender == QuicTransportParameterSender::Client && is_server_only(id) {
390 return Err(QuicTransportParameterSemanticError::ForbiddenSender { id, offset });
391 }
392
393 match id.raw() {
394 0x00 | 0x0f | 0x10 => parameter
395 .connection_id()
396 .map(|_| ())
397 .map_err(|error| value_error(id, offset, error)),
398 0x01 | 0x04 | 0x05 | 0x06 | 0x07 => parameter
399 .integer()
400 .map(|_| ())
401 .map_err(|error| value_error(id, offset, error)),
402 0x02 => parameter
403 .stateless_reset_token()
404 .map(|_| ())
405 .map_err(|error| value_error(id, offset, error)),
406 0x03 => validate_minimum(parameter, offset, 1200),
407 0x08 | 0x09 => validate_maximum(parameter, offset, 1u64 << 60),
408 0x0a => validate_maximum(parameter, offset, 20),
409 0x0b => validate_maximum(parameter, offset, (1u64 << 14) - 1),
410 0x0c => parameter
411 .disable_active_migration()
412 .map_err(|error| value_error(id, offset, error)),
413 0x0d => parameter
414 .preferred_address()
415 .map(|_| ())
416 .map_err(|error| value_error(id, offset, error)),
417 0x0e => validate_minimum(parameter, offset, 2),
418 _ => Ok(()),
419 }
420}
421
422fn validate_minimum(
423 parameter: QuicTransportParameter<'_>,
424 offset: usize,
425 minimum: u64,
426) -> Result<(), QuicTransportParameterSemanticError> {
427 let id = parameter.parameter_id();
428 let value = parameter
429 .integer()
430 .map_err(|error| value_error(id, offset, error))?
431 .value();
432 if value < minimum {
433 return Err(QuicTransportParameterSemanticError::BelowMinimum {
434 id,
435 offset,
436 value,
437 minimum,
438 });
439 }
440 Ok(())
441}
442
443fn validate_maximum(
444 parameter: QuicTransportParameter<'_>,
445 offset: usize,
446 maximum: u64,
447) -> Result<(), QuicTransportParameterSemanticError> {
448 let id = parameter.parameter_id();
449 let value = parameter
450 .integer()
451 .map_err(|error| value_error(id, offset, error))?
452 .value();
453 if value > maximum {
454 return Err(QuicTransportParameterSemanticError::AboveMaximum {
455 id,
456 offset,
457 value,
458 maximum,
459 });
460 }
461 Ok(())
462}
463
464fn value_error(
465 id: QuicTransportParameterId,
466 offset: usize,
467 error: QuicTransportParameterValueError,
468) -> QuicTransportParameterSemanticError {
469 QuicTransportParameterSemanticError::Value { id, offset, error }
470}
471
472const fn is_server_only(id: QuicTransportParameterId) -> bool {
473 matches!(id.raw(), 0x00 | 0x02 | 0x0d | 0x10)
474}