quik_core/
packet.rs

1use std::io;
2
3use quik_util::*;
4
5use crate::common::{ConnectionId, PacketNumber, VarInt};
6use crate::crypto::Crypto;
7// Packets handled by the middle layer
8
9pub enum Packet<'a> {
10    VersionNegotiation(VersionNegotiation),
11    Initial(Initial<'a>),
12    ZeroRTT(ZeroRTT),
13    Handshake(Handshake),
14    Retry(Retry<'a>),
15    OneRtt(OneRtt),
16}
17
18pub struct VersionNegotiation {
19    pub src_cid: ConnectionId,
20    pub dst_cid: ConnectionId,
21    // TODO ew this isn't zero copy
22    pub supported_versions: Vec<u32>,
23}
24
25pub struct Initial<'a> {
26    pub src_cid: ConnectionId,
27    pub dst_cid: ConnectionId,
28    pub version: u32,
29
30    pub token: &'a [u8],
31    // variable length
32    pub packet_number: u32,
33}
34
35pub struct ZeroRTT {
36    pub src_cid: ConnectionId,
37    pub dst_cid: ConnectionId,
38    pub version: u32,
39
40    // variable length
41    pub packet_number: u32,
42}
43
44pub struct Handshake {
45    pub src_cid: ConnectionId,
46    pub dst_cid: ConnectionId,
47    pub version: u32,
48
49    // variable length
50    pub packet_number: u32,
51}
52
53pub struct Retry<'a> {
54    pub src_cid: ConnectionId,
55    pub dst_cid: ConnectionId,
56    pub version: u32,
57
58    pub retry_token: &'a [u8],
59    pub retry_integrity_tag: u128,
60}
61
62// This one actually uses the short header
63pub struct OneRtt {
64    pub dst_cid: ConnectionId,
65    pub spin: u8,
66    pub key_phase: u8,
67
68    // variable length
69    pub packet_number: u32,
70}
71
72pub enum RemainingBuf {
73    Decrypted(Vec<u8>),
74    // Raw(&'a [u8]),
75    None,
76}
77
78impl<'a> Packet<'a> {
79    pub async fn parse(
80        crypto: &impl Crypto,
81        mut data: &'a [u8],
82    ) -> Result<(Packet<'a>, RemainingBuf)> {
83        let first_byte = data.read_u8()?;
84        // Header Form (1) bit
85        if first_byte >> 7 != 0 {
86            // Long Header
87            // https://datatracker.ietf.org/doc/html/rfc9000#long-header
88
89            // Fixed Bit (1) = 1 - ignored
90            // Long Packet Type (2) - not used in VersionNegotiation
91            let packet_type = (first_byte >> 4) & 0b11;
92            // Reserved (2) - ignored
93            // Packet Number Length (2) - not used in Retry & VersionNegotiation
94            let packet_number_length_encoded = first_byte & 0b11;
95            let packet_number_length = 1 + packet_number_length_encoded as usize;
96
97            let version = data.read_u32::<NetworkEndian>()?;
98            let dst_cid = ConnectionId::parse(&mut data)?;
99            let src_cid = ConnectionId::parse(&mut data)?;
100
101            if version == 0 {
102                // VersionNegotiation packet
103                // https://datatracker.ietf.org/doc/html/rfc9000#name-version-negotiation-packet
104
105                let (versions_bytes, _remainder) = data.as_chunks::<4>();
106                let versions = versions_bytes
107                    .iter()
108                    .map(|b| (&b[..]).read_u32::<NetworkEndian>())
109                    .collect::<io::Result<Vec<u32>>>()?;
110                // TODO check remainder?
111
112                let packet = Packet::VersionNegotiation(VersionNegotiation {
113                    src_cid,
114                    dst_cid: dst_cid.clone(),
115                    supported_versions: versions,
116                });
117                return Ok((packet, RemainingBuf::None));
118            }
119            match packet_type {
120                0b00 => {
121                    // Initial packet
122                    // https://datatracker.ietf.org/doc/html/rfc9000#name-initial-packet
123
124                    let token_length = VarInt::parse(&mut data)?;
125                    let token = data.slice(token_length.into())?;
126                    let length = VarInt::parse(&mut data)?; // TODO use this
127                    let packet_number = PacketNumber::parse(&mut data, packet_number_length)?;
128
129                    let packet = Packet::Initial(Initial {
130                        src_cid,
131                        dst_cid: dst_cid.clone(),
132                        version,
133                        token,
134                        packet_number,
135                    });
136                    let payload = crypto
137                        .decrypt_initial_data(dst_cid, version, false, &mut data)
138                        .await?;
139                    Ok((packet, RemainingBuf::Decrypted(payload)))
140                }
141                0b01 => {
142                    // 0-RTT packet
143                    // https://datatracker.ietf.org/doc/html/rfc9000#name-0-rtt
144
145                    let length = VarInt::parse(&mut data)?; // TODO use this
146                    let packet_number = PacketNumber::parse(&mut data, packet_number_length)?;
147                    let payload = data.to_vec(); // TODO: decrypt
148
149                    let packet = Packet::ZeroRTT(ZeroRTT {
150                        src_cid,
151                        dst_cid: dst_cid.clone(),
152                        version,
153                        packet_number,
154                    });
155                    Ok((packet, RemainingBuf::Decrypted(payload)))
156                }
157                0b10 => {
158                    // Handshake packet
159                    // https://datatracker.ietf.org/doc/html/rfc9000#packet-handshake
160
161                    let length = VarInt::parse(&mut data)?; // TODO use this
162                    let packet_number = PacketNumber::parse(&mut data, packet_number_length)?;
163                    let payload = data.to_vec(); // TODO: decrypt
164
165                    let packet = Packet::Handshake(Handshake {
166                        src_cid,
167                        dst_cid: dst_cid.clone(),
168                        version,
169                        packet_number,
170                    });
171                    Ok((packet, RemainingBuf::Decrypted(payload)))
172                }
173                0b11 => {
174                    // Retry packet
175                    // https://datatracker.ietf.org/doc/html/rfc9000#name-retry-packet
176
177                    // TODO is this encoding even correct? wtf is a retry token?
178                    let (retry_token, retry_integrity_tag) = data
179                        .split_last_chunk::<16>() // 128bits/8 = 16 bytes
180                        .ok_or_else(|| "Packet too short for Retry Token")?;
181                    let retry_integrity_tag =
182                        (&retry_integrity_tag[..]).read_u128::<NetworkEndian>()?;
183
184                    let packet = Packet::Retry(Retry {
185                        src_cid,
186                        dst_cid: dst_cid.clone(),
187                        version,
188                        retry_token,
189                        retry_integrity_tag,
190                    });
191                    Ok((packet, RemainingBuf::None))
192                }
193                _ => unreachable!(),
194            }
195        } else {
196            // Short Header
197            // https://datatracker.ietf.org/doc/html/rfc9000#name-short-header-packets
198
199            // Fixed Bit (1) = 1 - ignored
200            // Spin Bit (1)
201            let spin = (first_byte >> 5) & 1;
202            // Reserved (2) - ignored
203            // Key Phase (1)
204            let key_phase = (first_byte >> 2) & 1;
205            // Packet Number Length (2)
206            let packet_number_length_encoded = first_byte & 0b11;
207            let packet_number_length = 1 + packet_number_length_encoded as usize;
208            let dst_cid = ConnectionId::parse(&mut data)?;
209
210            // Currently 1-RTT packets are the only Short Header packets
211            // https://datatracker.ietf.org/doc/html/rfc9000#name-1-rtt-packet
212            let packet_number = PacketNumber::parse(&mut data, packet_number_length)?;
213            let payload = data.to_vec(); // TODO: decrypt
214
215            let packet = Packet::OneRtt(OneRtt {
216                dst_cid: dst_cid.clone(),
217                packet_number,
218                spin,
219                key_phase,
220            });
221            Ok((packet, RemainingBuf::Decrypted(payload)))
222        }
223    }
224}