Skip to main content

net_wire/quic/packet/
long.rs

1//! Version-aware bounded views of protected QUIC long packets.
2
3use super::super::varint::{QuicVarInt, QuicVarIntParseError};
4use super::header::{QuicConnectionIdField, QuicLongHeader, QuicLongPacketType, QuicVersion};
5use super::parse::QuicPacketParseError;
6
7/// A borrowed QUIC v1 or v2 protected Initial, 0-RTT, or Handshake packet.
8///
9/// This view bounds the packet using its unprotected length field but deliberately leaves packet
10/// number length, protected payload, and all cryptographic interpretation opaque.
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub struct QuicProtectedLongPacket<'a> {
13    bytes: &'a [u8],
14    header: QuicLongHeader<'a>,
15    packet_type: QuicLongPacketType,
16    token_length: Option<QuicVarInt<'a>>,
17    token: Option<&'a [u8]>,
18    length: QuicVarInt<'a>,
19    packet_number_offset: usize,
20    protected_remainder: &'a [u8],
21}
22
23impl<'a> QuicProtectedLongPacket<'a> {
24    /// Assembles a protected long-packet view from builder-validated wire components.
25    pub(crate) const fn from_validated(
26        bytes: &'a [u8],
27        header: QuicLongHeader<'a>,
28        packet_type: QuicLongPacketType,
29        token_fields: Option<(QuicVarInt<'a>, &'a [u8])>,
30        length: QuicVarInt<'a>,
31        packet_number_offset: usize,
32        protected_remainder: &'a [u8],
33    ) -> Self {
34        let (token_length, token) = match token_fields {
35            Some((token_length, token)) => (Some(token_length), Some(token)),
36            None => (None, None),
37        };
38        Self {
39            bytes,
40            header,
41            packet_type,
42            token_length,
43            token,
44            length,
45            packet_number_offset,
46            protected_remainder,
47        }
48    }
49
50    /// Parses one exact protected Initial, 0-RTT, or Handshake packet and returns its suffix.
51    pub fn parse(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), QuicPacketParseError> {
52        let header = QuicLongHeader::parse(bytes)?;
53        let version = header.version();
54        if version != QuicVersion::V1 && version != QuicVersion::V2 {
55            return Err(QuicPacketParseError::UnsupportedVersion { version });
56        }
57        if !header.has_fixed_bit() {
58            return Err(QuicPacketParseError::FixedBitNotSet {
59                first_byte: header.first_byte(),
60            });
61        }
62        validate_connection_id(
63            QuicConnectionIdField::Destination,
64            header.destination_connection_id().len(),
65        )?;
66        validate_connection_id(
67            QuicConnectionIdField::Source,
68            header.source_connection_id().len(),
69        )?;
70
71        let packet_type = match header.long_packet_type() {
72            Some(packet_type) => packet_type,
73            None => return Err(QuicPacketParseError::UnsupportedVersion { version }),
74        };
75        if packet_type == QuicLongPacketType::Retry {
76            return Err(QuicPacketParseError::NotLengthDelimited { packet_type });
77        }
78
79        let header_end = header.as_bytes().len();
80        let (token_length, token, length_offset) = if packet_type == QuicLongPacketType::Initial {
81            let token_length = parse_varint_at(bytes, header_end)?;
82            let token_start = checked_end(header_end, token_length.byte_len())?;
83            let token_end = checked_end(token_start, to_usize(token_length.value())?)?;
84            require(bytes, token_end)?;
85            (
86                Some(token_length),
87                Some(&bytes[token_start..token_end]),
88                token_end,
89            )
90        } else {
91            (None, None, header_end)
92        };
93
94        let length = parse_varint_at(bytes, length_offset)?;
95        if length.value() < 2 {
96            return Err(QuicPacketParseError::ProtectedRemainderTooShort {
97                minimum: 2,
98                actual: length.value(),
99            });
100        }
101        let packet_number_offset = checked_end(length_offset, length.byte_len())?;
102        let packet_end = checked_end(packet_number_offset, to_usize(length.value())?)?;
103        require(bytes, packet_end)?;
104
105        Ok((
106            Self {
107                bytes: &bytes[..packet_end],
108                header,
109                packet_type,
110                token_length,
111                token,
112                length,
113                packet_number_offset,
114                protected_remainder: &bytes[packet_number_offset..packet_end],
115            },
116            &bytes[packet_end..],
117        ))
118    }
119
120    /// Returns the accepted invariant long-header prefix.
121    pub const fn header(self) -> QuicLongHeader<'a> {
122        self.header
123    }
124
125    /// Returns the supported QUIC version.
126    pub const fn version(self) -> QuicVersion {
127        self.header.version()
128    }
129
130    /// Returns the semantic Initial, 0-RTT, or Handshake type.
131    pub const fn packet_type(self) -> QuicLongPacketType {
132        self.packet_type
133    }
134
135    /// Returns the exact Initial token-length representation, if this is an Initial packet.
136    pub const fn token_length(self) -> Option<QuicVarInt<'a>> {
137        self.token_length
138    }
139
140    /// Returns the exact Initial token, including an empty token, if this is an Initial packet.
141    pub const fn token(self) -> Option<&'a [u8]> {
142        self.token
143    }
144
145    /// Returns the exact protected packet-length representation.
146    pub const fn length(self) -> QuicVarInt<'a> {
147        self.length
148    }
149
150    /// Returns the absolute offset of the protected packet number from packet start.
151    pub const fn packet_number_offset(self) -> usize {
152        self.packet_number_offset
153    }
154
155    /// Returns the exact bounded packet-number-and-protected-payload region.
156    pub const fn protected_remainder(self) -> &'a [u8] {
157        self.protected_remainder
158    }
159
160    /// Returns the exact complete length-delimited packet bytes.
161    pub const fn as_bytes(self) -> &'a [u8] {
162        self.bytes
163    }
164}
165
166fn validate_connection_id(
167    field: QuicConnectionIdField,
168    length: usize,
169) -> Result<(), QuicPacketParseError> {
170    if length > 20 {
171        return Err(QuicPacketParseError::ConnectionIdTooLong { field, length });
172    }
173    Ok(())
174}
175
176fn parse_varint_at<'a>(
177    bytes: &'a [u8],
178    offset: usize,
179) -> Result<QuicVarInt<'a>, QuicPacketParseError> {
180    match QuicVarInt::parse(&bytes[offset..]) {
181        Ok(value) => Ok(value),
182        Err(QuicVarIntParseError::Incomplete {
183            required,
184            available: _,
185        }) => Err(QuicPacketParseError::Incomplete {
186            required: checked_end(offset, required)?,
187            available: bytes.len(),
188        }),
189    }
190}
191
192fn to_usize(value: u64) -> Result<usize, QuicPacketParseError> {
193    usize::try_from(value).map_err(|_| QuicPacketParseError::LengthNotRepresentable { value })
194}
195
196fn checked_end(offset: usize, length: usize) -> Result<usize, QuicPacketParseError> {
197    offset
198        .checked_add(length)
199        .ok_or(QuicPacketParseError::LengthOverflow { offset, length })
200}
201
202fn require(bytes: &[u8], required: usize) -> Result<(), QuicPacketParseError> {
203    if bytes.len() < required {
204        return Err(QuicPacketParseError::Incomplete {
205            required,
206            available: bytes.len(),
207        });
208    }
209    Ok(())
210}