Skip to main content

net_wire/quic/frame/
crypto.rs

1//! RFC 9000 CRYPTO frame parsing.
2
3use super::super::varint::QuicVarInt;
4use super::parse::{QuicFrameField, QuicFrameParseError};
5
6const MAX_CRYPTO_RANGE_END: u64 = (1 << 62) - 1;
7
8/// A checked borrowed RFC 9000 CRYPTO frame view.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct QuicCryptoFrame<'a> {
11    bytes: &'a [u8],
12    frame_type: QuicVarInt<'a>,
13    offset: QuicVarInt<'a>,
14    length: QuicVarInt<'a>,
15    crypto_data: &'a [u8],
16}
17
18impl<'a> QuicCryptoFrame<'a> {
19    /// Returns the exact encoded frame bytes.
20    pub const fn as_bytes(self) -> &'a [u8] {
21        self.bytes
22    }
23
24    /// Returns the exact encoded frame-type variable integer.
25    pub const fn frame_type(self) -> QuicVarInt<'a> {
26        self.frame_type
27    }
28
29    /// Returns the exact encoded CRYPTO offset variable integer.
30    pub const fn offset(self) -> QuicVarInt<'a> {
31        self.offset
32    }
33
34    /// Returns the exact encoded CRYPTO data-length variable integer.
35    pub const fn length(self) -> QuicVarInt<'a> {
36        self.length
37    }
38
39    /// Returns the exact borrowed CRYPTO data bytes, which may be empty.
40    pub const fn crypto_data(self) -> &'a [u8] {
41        self.crypto_data
42    }
43}
44
45pub(super) fn parse_crypto<'a>(
46    bytes: &'a [u8],
47    frame_type: QuicVarInt<'a>,
48    offset: usize,
49) -> Result<(QuicCryptoFrame<'a>, &'a [u8]), QuicFrameParseError> {
50    let offset_start = frame_type.byte_len();
51    let offset_offset = offset + offset_start;
52    let crypto_offset =
53        QuicVarInt::parse(&bytes[offset_start..]).map_err(|error| QuicFrameParseError::Field {
54            field: QuicFrameField::CryptoOffset,
55            offset: offset_offset,
56            error,
57        })?;
58
59    let length_start = offset_start + crypto_offset.byte_len();
60    let length_offset = offset + length_start;
61    let length =
62        QuicVarInt::parse(&bytes[length_start..]).map_err(|error| QuicFrameParseError::Field {
63            field: QuicFrameField::CryptoLength,
64            offset: length_offset,
65            error,
66        })?;
67
68    let range_end = crypto_offset.value().checked_add(length.value());
69    if range_end.is_none_or(|end| end > MAX_CRYPTO_RANGE_END) {
70        return Err(QuicFrameParseError::FieldRangeOutOfRange {
71            field: QuicFrameField::CryptoOffset,
72            offset: offset_offset,
73            start: crypto_offset.value(),
74            length: length.value(),
75            maximum: MAX_CRYPTO_RANGE_END,
76        });
77    }
78
79    let length_value = length.value();
80    let length_usize =
81        usize::try_from(length_value).map_err(|_| QuicFrameParseError::LengthNotRepresentable {
82            field: QuicFrameField::CryptoLength,
83            offset: length_offset,
84            value: length_value,
85        })?;
86    // Each parsed variable integer is at most eight bytes wide.
87    let data_start = length_start + length.byte_len();
88    let data_offset = offset + data_start;
89    let data_end =
90        data_start
91            .checked_add(length_usize)
92            .ok_or(QuicFrameParseError::LengthOverflow {
93                field: QuicFrameField::CryptoData,
94                offset: data_offset,
95                length: length_usize,
96            })?;
97    let available = bytes.len() - data_start;
98    if available < length_usize {
99        return Err(QuicFrameParseError::IncompleteBytes {
100            field: QuicFrameField::CryptoData,
101            offset: data_offset,
102            required: length_usize,
103            available,
104        });
105    }
106
107    Ok((
108        QuicCryptoFrame {
109            bytes: &bytes[..data_end],
110            frame_type,
111            offset: crypto_offset,
112            length,
113            crypto_data: &bytes[data_start..data_end],
114        },
115        &bytes[data_end..],
116    ))
117}