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]
205 .path_space(path_id)
206 .and_then(|s| s.largest_received_packet_number);
207 let packet_number = packet
208 .header
209 .number()
210 .ok_or(None)?
211 .expand(rx_packet_number.map(|n| n + 1).unwrap_or_default());
212 let packet_key_phase = packet.header.key_phase();
213
214 let mut crypto_update = false;
215 let crypto = if packet.header.is_0rtt() {
216 let (_, packet) = self.remote_crypto(EncryptionLevel::ZeroRtt).unwrap();
217 packet
218 } else if packet_key_phase == conn_key_phase || space != SpaceKind::Data {
219 let (_, packet) = self.remote_crypto(space.encryption_level()).unwrap();
220 packet
221 } else if let Some(prev) = self.prev_crypto.as_ref().filter(|crypto| {
222 crypto.end_packet.is_none_or(|(pn, _)| packet_number < pn)
226 }) {
227 &*prev.crypto.remote
228 } else {
229 crypto_update = true;
234 &*self.next_crypto.as_ref().unwrap().remote
235 };
236
237 crypto
238 .decrypt(
239 path_id,
240 packet_number,
241 &packet.header_data,
242 &mut packet.payload,
243 )
244 .map_err(|_| {
245 trace!("decryption failed with packet number {}", packet_number);
246 None
247 })?;
248
249 if !packet.reserved_bits_valid() {
250 return Err(Some(TransportError::PROTOCOL_VIOLATION(
251 "reserved bits set",
252 )));
253 }
254
255 let mut outgoing_key_update_acked = false;
256 if let Some(ref prev) = self.prev_crypto
257 && prev.end_packet.is_none()
258 && packet_key_phase == conn_key_phase
259 {
260 outgoing_key_update_acked = true;
261 }
262
263 if crypto_update {
264 let invalid_packet_number =
269 rx_packet_number.is_some_and(|rx_packet| packet_number <= rx_packet);
270 if invalid_packet_number || self.prev_crypto.as_ref().is_some_and(|x| x.update_unacked)
271 {
272 trace!(?packet_number, ?rx_packet_number, %path_id, "crypto update failed");
273 return Err(Some(TransportError::KEY_UPDATE_ERROR("")));
274 }
275 }
276
277 Ok(Some(DecryptPacketResult {
278 packet_number,
279 outgoing_key_update_acked,
280 incoming_key_update: crypto_update,
281 }))
282 }
283
284 pub(super) fn has_keys(&self, level: EncryptionLevel) -> bool {
286 match level {
287 EncryptionLevel::Initial => self.spaces[0].keys.is_some(),
288 EncryptionLevel::ZeroRtt => self.zero_rtt_crypto.is_some(),
289 EncryptionLevel::Handshake => self.spaces[1].keys.is_some(),
290 EncryptionLevel::OneRtt => self.spaces[2].keys.is_some(),
291 }
292 }
293
294 pub(super) fn discard_temporary_keys(&mut self) {
296 self.zero_rtt_crypto = None;
297 self.prev_crypto = None;
298 }
299
300 pub(super) fn enable_zero_rtt(
302 &mut self,
303 header: Box<dyn HeaderKey>,
304 packet: Box<dyn PacketKey>,
305 ) {
306 self.zero_rtt_enabled = true;
307 self.zero_rtt_crypto = Some(ZeroRttCrypto { header, packet });
308 }
309
310 pub(super) fn discard_zero_rtt(&mut self) {
312 self.zero_rtt_crypto = None;
313 }
314
315 pub(super) fn integrity_limit(&self, space: SpaceKind) -> Option<u64> {
317 let keys = self.spaces[space].keys.as_ref()?;
318 Some(keys.packet.local.integrity_limit())
319 }
320
321 pub(super) fn local_crypto(
326 &self,
327 level: EncryptionLevel,
328 ) -> Option<(&dyn HeaderKey, &dyn PacketKey)> {
329 match level {
330 EncryptionLevel::Initial => self.spaces[0].keys.as_ref().map(Keys::local),
331 EncryptionLevel::Handshake => self.spaces[1].keys.as_ref().map(Keys::local),
332 EncryptionLevel::OneRtt => self.spaces[2].keys.as_ref().map(Keys::local),
333 EncryptionLevel::ZeroRtt => self.zero_rtt_crypto.as_ref().map(ZeroRttCrypto::keys),
335 }
336 }
337
338 fn remote_crypto(&self, level: EncryptionLevel) -> Option<(&dyn HeaderKey, &dyn PacketKey)> {
342 match level {
343 EncryptionLevel::Initial => self.spaces[0].keys.as_ref().map(Keys::remote),
344 EncryptionLevel::Handshake => self.spaces[1].keys.as_ref().map(Keys::remote),
345 EncryptionLevel::OneRtt => self.spaces[2].keys.as_ref().map(Keys::remote),
346 EncryptionLevel::ZeroRtt => self.zero_rtt_crypto.as_ref().map(ZeroRttCrypto::keys),
348 }
349 }
350
351 pub(super) fn encryption_keys(
360 &self,
361 kind: SpaceKind,
362 side: Side,
363 ) -> Option<(&dyn HeaderKey, &dyn PacketKey, EncryptionLevel)> {
364 let mut keys = self.spaces[kind].keys.as_ref().map(Keys::local);
365 let mut level = match kind {
366 SpaceKind::Initial => EncryptionLevel::Initial,
367 SpaceKind::Handshake => EncryptionLevel::Handshake,
368 SpaceKind::Data => EncryptionLevel::OneRtt,
369 };
370
371 if keys.is_none() && kind == SpaceKind::Data && side.is_client() {
373 keys = self.zero_rtt_crypto.as_ref().map(ZeroRttCrypto::keys);
374 level = EncryptionLevel::ZeroRtt;
375 }
376
377 keys.map(|(header_keys, packet_keys)| (header_keys, packet_keys, level))
378 }
379
380 pub(super) fn update_keys(&mut self, end_packet: Option<(u64, Instant)>, remote: bool) {
387 trace!("executing key update");
388
389 let new = self
390 .session
391 .next_1rtt_keys()
392 .expect("only called for `Data` packets");
393 let confidentiality_limit = new.local.confidentiality_limit();
394 let old = mem::replace(
395 &mut self.spaces[SpaceKind::Data]
396 .keys
397 .as_mut()
398 .unwrap() .packet,
400 mem::replace(self.next_crypto.as_mut().unwrap(), new),
401 );
402 self.prev_crypto = Some(PrevCrypto {
403 crypto: old,
404 end_packet,
405 update_unacked: remote,
406 });
407
408 self.key_phase_size = confidentiality_limit.saturating_sub(KEY_UPDATE_MARGIN);
409 self.key_phase = !self.key_phase;
410 self.spaces[2].sent_with_keys = 0;
411 }
412
413 pub(crate) fn sent_with_keys(&self, level: EncryptionLevel) -> u64 {
418 match level {
419 EncryptionLevel::Initial => self.spaces[0].sent_with_keys,
420 EncryptionLevel::ZeroRtt => self.sent_with_zero_rtt,
421 EncryptionLevel::Handshake => self.spaces[1].sent_with_keys,
422 EncryptionLevel::OneRtt => self.spaces[2].sent_with_keys,
423 }
424 }
425
426 pub(crate) fn remaining_packet_budget(&self, level: EncryptionLevel) -> Option<u64> {
435 let sent_with_keys = self.sent_with_keys(level);
436 let (_header_keys, packet_keys) = self.local_crypto(level)?;
437 let limit = match level {
438 EncryptionLevel::OneRtt => self.key_phase_size.min(packet_keys.confidentiality_limit()),
439 _ => packet_keys.confidentiality_limit(),
440 };
441
442 Some(limit.saturating_sub(sent_with_keys))
443 }
444
445 pub(crate) fn inc_sent_with_keys(&mut self, level: EncryptionLevel) {
447 let count = match level {
448 EncryptionLevel::Initial => &mut self.spaces[0].sent_with_keys,
449 EncryptionLevel::ZeroRtt => &mut self.sent_with_zero_rtt,
450 EncryptionLevel::Handshake => &mut self.spaces[1].sent_with_keys,
451 EncryptionLevel::OneRtt => &mut self.spaces[2].sent_with_keys,
452 };
453 *count = count.saturating_add(1u64);
454 }
455}
456
457#[derive(Default)]
459pub(super) struct CryptoSpace {
460 pub(super) keys: Option<Keys>,
462 pub(super) crypto_stream: Assembler,
464 pub(super) crypto_offset: u64,
466 pub(super) sent_with_keys: u64,
468}
469
470#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
472pub(crate) enum EncryptionLevel {
473 Initial,
475 ZeroRtt,
477 Handshake,
479 OneRtt,
481}
482
483impl From<SpaceKind> for crate::packet::SpaceId {
484 fn from(kind: SpaceKind) -> Self {
485 match kind {
486 SpaceKind::Initial => Self::Initial,
487 SpaceKind::Handshake => Self::Handshake,
488 SpaceKind::Data => Self::Data,
489 }
490 }
491}
492
493impl IndexMut<SpaceKind> for [CryptoSpace; 3] {
494 fn index_mut(&mut self, index: SpaceKind) -> &mut Self::Output {
495 &mut self[index as usize]
496 }
497}
498
499impl Index<SpaceKind> for [CryptoSpace; 3] {
500 type Output = CryptoSpace;
501
502 fn index(&self, index: SpaceKind) -> &Self::Output {
503 &self[index as usize]
504 }
505}