1use std::mem;
2use std::ops::{Index, IndexMut};
3
4use tracing::{debug, trace};
5
6use super::SpaceKind;
7use crate::connection::assembler::Assembler;
8use crate::crypto::{self, HeaderKey, KeyPair, Keys, PacketKey};
9use crate::packet::{Packet, PartialDecode};
10use crate::token::ResetToken;
11use rand::{CryptoRng, RngExt};
12
13use crate::{ConnectionId, Instant, Side};
14use crate::{RESET_TOKEN_SIZE, TransportError};
15
16use super::PathId;
17use super::spaces::PacketSpace;
18
19const KEY_UPDATE_MARGIN: u64 = 10_000;
23
24pub(super) struct UnprotectHeaderResult {
25 pub(super) packet: Option<Packet>,
28 pub(super) stateless_reset: bool,
30}
31
32pub(super) struct DecryptPacketResult {
33 pub(super) packet_number: u64,
35 pub(super) outgoing_key_update_acked: bool,
37 pub(super) incoming_key_update: bool,
39}
40
41pub(super) struct PrevCrypto {
42 pub(super) crypto: KeyPair<Box<dyn PacketKey>>,
45 pub(super) end_packet: Option<(u64, Instant)>,
52 pub(super) update_unacked: bool,
54}
55
56pub(super) struct ZeroRttCrypto {
57 pub(super) header: Box<dyn HeaderKey>,
58 pub(super) packet: Box<dyn PacketKey>,
59}
60
61impl ZeroRttCrypto {
62 fn keys(&self) -> (&dyn HeaderKey, &dyn PacketKey) {
63 (self.header.as_ref(), self.packet.as_ref())
64 }
65}
66
67pub(super) struct CryptoState {
75 pub(super) spaces: [CryptoSpace; 3],
77 pub(super) session: Box<dyn crypto::Session>,
79
80 pub(super) accepted_0rtt: bool,
85 pub(super) zero_rtt_enabled: bool,
87 pub(super) zero_rtt_crypto: Option<ZeroRttCrypto>,
89 sent_with_zero_rtt: u64,
91
92 pub(super) next_crypto: Option<KeyPair<Box<dyn PacketKey>>>,
100 pub(super) prev_crypto: Option<PrevCrypto>,
102 pub(super) key_phase: bool,
104 pub(super) key_phase_size: u64,
106}
107
108impl CryptoState {
109 pub(super) fn new(
110 session: Box<dyn crypto::Session>,
111 init_cid: ConnectionId,
112 side: Side,
113 rng: &mut impl CryptoRng,
114 ) -> Self {
115 let initial_keys = session.initial_keys(init_cid, side);
116 let initial_space = CryptoSpace {
117 keys: Some(initial_keys),
118 ..Default::default()
119 };
120 Self {
121 spaces: [initial_space, Default::default(), Default::default()],
122 session,
123 next_crypto: None,
124 prev_crypto: None,
125 accepted_0rtt: false,
126 zero_rtt_enabled: false,
127 zero_rtt_crypto: None,
128 sent_with_zero_rtt: 0,
129 key_phase: false,
130 key_phase_size: rng.random_range(10..1000),
137 }
138 }
139
140 pub(super) fn unprotect_header(
142 &self,
143 partial_decode: PartialDecode,
144 stateless_reset_token: Option<ResetToken>,
145 ) -> Option<UnprotectHeaderResult> {
146 let encryption_level = partial_decode.encryption_level();
147 let header_crypto = match encryption_level {
148 Some(level) => match self.remote_crypto(level) {
149 Some(crypto) => Some(crypto.0),
150 None => {
151 let bytes = partial_decode.len();
152 debug!(?encryption_level, bytes, "dropping unexpected packet");
153 return None;
154 }
155 },
156 None => None,
158 };
159
160 let packet = partial_decode.data();
161 let stateless_reset = packet.len() >= RESET_TOKEN_SIZE + 5
162 && stateless_reset_token.as_deref() == Some(&packet[packet.len() - RESET_TOKEN_SIZE..]);
163
164 match partial_decode.finish(header_crypto) {
165 Ok(packet) => Some(UnprotectHeaderResult {
166 packet: Some(packet),
167 stateless_reset,
168 }),
169 Err(_) if stateless_reset => Some(UnprotectHeaderResult {
170 packet: None,
171 stateless_reset: true,
172 }),
173 Err(e) => {
174 trace!("unable to complete packet decoding: {}", e);
175 None
176 }
177 }
178 }
179
180 pub(super) fn decrypt_packet_body(
182 &self,
183 packet: &mut Packet,
184 path_id: PathId,
185 spaces: &[PacketSpace; 3],
186 ) -> Result<Option<DecryptPacketResult>, Option<TransportError>> {
187 let conn_key_phase = self.key_phase;
188 if !packet.header.is_protected() {
189 return Ok(None);
191 }
192 let space = packet.header.space();
193
194 if path_id != PathId::ZERO && space != SpaceKind::Data {
195 return Err(Some(TransportError::PROTOCOL_VIOLATION(
197 "multipath packet on non Data packet number space",
198 )));
199 }
200 let rx_packet_number = spaces[space]
204 .path_space(path_id)
205 .and_then(|s| s.largest_received_packet_number);
206 let packet_number = packet
207 .header
208 .number()
209 .ok_or(None)?
210 .expand(rx_packet_number.map(|n| n + 1).unwrap_or_default());
211 let packet_key_phase = packet.header.key_phase();
212
213 let mut crypto_update = false;
214 let crypto = if packet.header.is_0rtt() {
215 let (_, packet) = self.remote_crypto(EncryptionLevel::ZeroRtt).unwrap();
216 packet
217 } else if packet_key_phase == conn_key_phase || space != SpaceKind::Data {
218 let (_, packet) = self.remote_crypto(space.encryption_level()).unwrap();
219 packet
220 } else if let Some(prev) = self.prev_crypto.as_ref().filter(|crypto| {
221 crypto.end_packet.is_none_or(|(pn, _)| packet_number < pn)
225 }) {
226 &*prev.crypto.remote
227 } else {
228 crypto_update = true;
233 &*self.next_crypto.as_ref().unwrap().remote
234 };
235
236 crypto
237 .decrypt(
238 path_id,
239 packet_number,
240 &packet.header_data,
241 &mut packet.payload,
242 )
243 .map_err(|_| {
244 trace!("decryption failed with packet number {}", packet_number);
245 None
246 })?;
247
248 if !packet.reserved_bits_valid() {
249 return Err(Some(TransportError::PROTOCOL_VIOLATION(
250 "reserved bits set",
251 )));
252 }
253
254 let mut outgoing_key_update_acked = false;
255 if let Some(ref prev) = self.prev_crypto
256 && prev.end_packet.is_none()
257 && packet_key_phase == conn_key_phase
258 {
259 outgoing_key_update_acked = true;
260 }
261
262 if crypto_update {
263 let invalid_packet_number =
268 rx_packet_number.is_some_and(|rx_packet| packet_number <= rx_packet);
269 if invalid_packet_number || self.prev_crypto.as_ref().is_some_and(|x| x.update_unacked)
270 {
271 trace!(?packet_number, ?rx_packet_number, %path_id, "crypto update failed");
272 return Err(Some(TransportError::KEY_UPDATE_ERROR("")));
273 }
274 }
275
276 Ok(Some(DecryptPacketResult {
277 packet_number,
278 outgoing_key_update_acked,
279 incoming_key_update: crypto_update,
280 }))
281 }
282
283 pub(super) fn has_keys(&self, level: EncryptionLevel) -> bool {
285 match level {
286 EncryptionLevel::Initial => self.spaces[0].keys.is_some(),
287 EncryptionLevel::ZeroRtt => self.zero_rtt_crypto.is_some(),
288 EncryptionLevel::Handshake => self.spaces[1].keys.is_some(),
289 EncryptionLevel::OneRtt => self.spaces[2].keys.is_some(),
290 }
291 }
292
293 pub(super) fn discard_temporary_keys(&mut self) {
295 self.zero_rtt_crypto = None;
296 self.prev_crypto = None;
297 }
298
299 pub(super) fn enable_zero_rtt(
301 &mut self,
302 header: Box<dyn HeaderKey>,
303 packet: Box<dyn PacketKey>,
304 ) {
305 self.zero_rtt_enabled = true;
306 self.zero_rtt_crypto = Some(ZeroRttCrypto { header, packet });
307 }
308
309 pub(super) fn discard_zero_rtt(&mut self) {
311 self.zero_rtt_crypto = None;
312 }
313
314 pub(super) fn integrity_limit(&self, space: SpaceKind) -> Option<u64> {
316 let keys = self.spaces[space].keys.as_ref()?;
317 Some(keys.packet.local.integrity_limit())
318 }
319
320 pub(super) fn local_crypto(
325 &self,
326 level: EncryptionLevel,
327 ) -> Option<(&dyn HeaderKey, &dyn PacketKey)> {
328 match level {
329 EncryptionLevel::Initial => self.spaces[0].keys.as_ref().map(Keys::local),
330 EncryptionLevel::Handshake => self.spaces[1].keys.as_ref().map(Keys::local),
331 EncryptionLevel::OneRtt => self.spaces[2].keys.as_ref().map(Keys::local),
332 EncryptionLevel::ZeroRtt => self.zero_rtt_crypto.as_ref().map(ZeroRttCrypto::keys),
334 }
335 }
336
337 fn remote_crypto(&self, level: EncryptionLevel) -> Option<(&dyn HeaderKey, &dyn PacketKey)> {
341 match level {
342 EncryptionLevel::Initial => self.spaces[0].keys.as_ref().map(Keys::remote),
343 EncryptionLevel::Handshake => self.spaces[1].keys.as_ref().map(Keys::remote),
344 EncryptionLevel::OneRtt => self.spaces[2].keys.as_ref().map(Keys::remote),
345 EncryptionLevel::ZeroRtt => self.zero_rtt_crypto.as_ref().map(ZeroRttCrypto::keys),
347 }
348 }
349
350 pub(super) fn encryption_keys(
359 &self,
360 kind: SpaceKind,
361 side: Side,
362 ) -> Option<(&dyn HeaderKey, &dyn PacketKey, EncryptionLevel)> {
363 let mut keys = self.spaces[kind].keys.as_ref().map(Keys::local);
364 let mut level = match kind {
365 SpaceKind::Initial => EncryptionLevel::Initial,
366 SpaceKind::Handshake => EncryptionLevel::Handshake,
367 SpaceKind::Data => EncryptionLevel::OneRtt,
368 };
369
370 if keys.is_none() && kind == SpaceKind::Data && side.is_client() {
372 keys = self.zero_rtt_crypto.as_ref().map(ZeroRttCrypto::keys);
373 level = EncryptionLevel::ZeroRtt;
374 }
375
376 keys.map(|(header_keys, packet_keys)| (header_keys, packet_keys, level))
377 }
378
379 pub(super) fn update_keys(&mut self, end_packet: Option<(u64, Instant)>, remote: bool) {
386 trace!("executing key update");
387
388 let new = self
389 .session
390 .next_1rtt_keys()
391 .expect("only called for `Data` packets");
392 let confidentiality_limit = new.local.confidentiality_limit();
393 let old = mem::replace(
394 &mut self.spaces[SpaceKind::Data]
395 .keys
396 .as_mut()
397 .unwrap() .packet,
399 mem::replace(self.next_crypto.as_mut().unwrap(), new),
400 );
401 self.prev_crypto = Some(PrevCrypto {
402 crypto: old,
403 end_packet,
404 update_unacked: remote,
405 });
406
407 self.key_phase_size = confidentiality_limit.saturating_sub(KEY_UPDATE_MARGIN);
408 self.key_phase = !self.key_phase;
409 self.spaces[2].sent_with_keys = 0;
410 }
411
412 pub(crate) fn sent_with_keys(&self, level: EncryptionLevel) -> u64 {
417 match level {
418 EncryptionLevel::Initial => self.spaces[0].sent_with_keys,
419 EncryptionLevel::ZeroRtt => self.sent_with_zero_rtt,
420 EncryptionLevel::Handshake => self.spaces[1].sent_with_keys,
421 EncryptionLevel::OneRtt => self.spaces[2].sent_with_keys,
422 }
423 }
424
425 pub(crate) fn remaining_packet_budget(&self, level: EncryptionLevel) -> Option<u64> {
434 let sent_with_keys = self.sent_with_keys(level);
435 let (_header_keys, packet_keys) = self.local_crypto(level)?;
436 let limit = match level {
437 EncryptionLevel::OneRtt => self.key_phase_size.min(packet_keys.confidentiality_limit()),
438 _ => packet_keys.confidentiality_limit(),
439 };
440
441 Some(limit.saturating_sub(sent_with_keys))
442 }
443
444 pub(crate) fn inc_sent_with_keys(&mut self, level: EncryptionLevel) {
446 let count = match level {
447 EncryptionLevel::Initial => &mut self.spaces[0].sent_with_keys,
448 EncryptionLevel::ZeroRtt => &mut self.sent_with_zero_rtt,
449 EncryptionLevel::Handshake => &mut self.spaces[1].sent_with_keys,
450 EncryptionLevel::OneRtt => &mut self.spaces[2].sent_with_keys,
451 };
452 *count = count.saturating_add(1u64);
453 }
454}
455
456#[derive(Default)]
458pub(super) struct CryptoSpace {
459 pub(super) keys: Option<Keys>,
461 pub(super) crypto_stream: Assembler,
463 pub(super) crypto_offset: u64,
465 pub(super) sent_with_keys: u64,
467}
468
469#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
471pub(crate) enum EncryptionLevel {
472 Initial,
474 ZeroRtt,
476 Handshake,
478 OneRtt,
480}
481
482impl From<SpaceKind> for crate::packet::SpaceId {
483 fn from(kind: SpaceKind) -> Self {
484 match kind {
485 SpaceKind::Initial => Self::Initial,
486 SpaceKind::Handshake => Self::Handshake,
487 SpaceKind::Data => Self::Data,
488 }
489 }
490}
491
492impl IndexMut<SpaceKind> for [CryptoSpace; 3] {
493 fn index_mut(&mut self, index: SpaceKind) -> &mut Self::Output {
494 &mut self[index as usize]
495 }
496}
497
498impl Index<SpaceKind> for [CryptoSpace; 3] {
499 type Output = CryptoSpace;
500
501 fn index(&self, index: SpaceKind) -> &Self::Output {
502 &self[index as usize]
503 }
504}