Skip to main content

rustls/
quic.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::ops::Deref;
4use core::{fmt, mem};
5
6use pki_types::FipsStatus;
7
8pub use crate::common_state::Side;
9use crate::common_state::{ConnectionOutputs, Protocol};
10use crate::conn::{
11    Accepted, ClientNext, Connection, MessageIter, MessageIterMode, ServerNext, SideData,
12    Transport, VerifyPeerIdentity, sealed,
13};
14use crate::crypto::cipher::{AeadKey, Iv, Payload};
15use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock};
16use crate::error::{ApiMisuse, Error};
17use crate::msgs::{Message, MessagePayload, ServerExtensionsInput, TransportParameters};
18use crate::server::{ServerConfig, ServerSide};
19use crate::suites::SupportedCipherSuite;
20use crate::sync::Arc;
21use crate::tls13::Tls13CipherSuite;
22use crate::tls13::key_schedule::{
23    hkdf_expand_label, hkdf_expand_label_aead_key, hkdf_expand_label_block,
24};
25use crate::{ClientSide, TlsInputBuffer};
26impl Connection<ServerSide, Quic> {
27    /// Make a new QUIC server [`Connection`]
28    ///
29    /// This differs from `Connection::new()` in that it takes an extra `params` argument,
30    /// which contains the TLS-encoded transport parameters to send.
31    pub fn new_quic(
32        config: Arc<ServerConfig>,
33        version: Version,
34        params: Vec<u8>,
35    ) -> Result<Self, Error> {
36        check_server_config(&config)?;
37        let exts = ServerExtensionsInput {
38            transport_parameters: Some(match version {
39                Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
40            }),
41        };
42
43        Self::for_server(
44            config,
45            exts,
46            Quic {
47                version,
48                ..Quic::default()
49            },
50        )
51    }
52}
53
54/// An in-progress QUIC client handshake.
55///
56/// Make one of these using [`ClientConnectionBuilder::start_quic_handshake()`].
57///
58/// [`ClientConnectionBuilder::start_quic_handshake()`]: crate::client::ClientConnectionBuilder::start_quic_handshake
59#[non_exhaustive]
60#[derive(Debug)]
61pub enum ClientHandshake {
62    /// More data needs to be received to make progress.
63    NeedsInput(NeedsInput<ClientSide>),
64
65    /// The server's presented identity must be verified.
66    ///
67    /// See [`VerifyPeerIdentity<ClientSide, Quic>`] for how to proceed.
68    VerifyServerIdentity(VerifyPeerIdentity<ClientSide, Quic>),
69
70    /// The handshake is complete.
71    Complete(Connection<ClientSide, Quic>),
72}
73
74impl FromConn<ClientSide> for ClientHandshake {
75    fn from_conn(
76        mut conn: Connection<ClientSide, Quic>,
77        output: &mut Vec<QuicEvent>,
78    ) -> Result<Self, Error> {
79        output.extend(conn.transport.events());
80
81        Ok(match ClientNext::try_from(conn)? {
82            ClientNext::NeedsInput(conn) => Self::NeedsInput(NeedsInput(conn)),
83
84            ClientNext::VerifyServerIdentity(verify) => Self::VerifyServerIdentity(verify),
85
86            ClientNext::Complete(conn) => Self::Complete(conn),
87        })
88    }
89}
90
91/// An in-progress QUIC server handshake.
92#[non_exhaustive]
93#[derive(Debug)]
94pub enum ServerHandshake {
95    /// More data needs to be received to make progress.
96    NeedsInput(NeedsInput<ServerSide>),
97
98    /// A complete `ClientHello` has been received.
99    ///
100    /// The handshake can be progressed by choosing a [`ServerConfig`] based on
101    /// [`Accepted::client_hello()`] and providing it to [`Accepted::choose_config()`].
102    Accepted(Accepted<Quic>),
103
104    /// The client's presented identity must be verified.
105    ///
106    /// See [`VerifyPeerIdentity<ServerSide, Quic>`] for how to proceed.
107    VerifyClientIdentity(VerifyPeerIdentity<ServerSide, Quic>),
108
109    /// The handshake is complete.
110    Complete(Connection<ServerSide, Quic>),
111}
112
113impl ServerHandshake {
114    /// Creates a new QUIC [`ServerHandshake`] via the payload of the [`ServerHandshake::NeedsInput`] variant.
115    ///
116    /// It is a fundamental fact of server TLS connections that the server reads first; this is reflected
117    /// in the returned type.
118    ///
119    /// You may wrap this in the [`ServerHandshake::NeedsInput`] variant to generalise the type to a
120    /// [`ServerHandshake`].
121    ///
122    /// The returned object should be fed data from a single potential client.
123    pub fn start(version: Version) -> NeedsInput<ServerSide> {
124        NeedsInput(Connection::for_acceptor(Quic {
125            version,
126            ..Quic::default()
127        }))
128    }
129}
130
131impl FromConn<ServerSide> for ServerHandshake {
132    fn from_conn(
133        mut conn: Connection<ServerSide, Quic>,
134        output: &mut Vec<QuicEvent>,
135    ) -> Result<Self, Error> {
136        output.extend(conn.transport.events());
137
138        Ok(match ServerNext::try_from(conn)? {
139            ServerNext::NeedsInput(conn) => Self::NeedsInput(NeedsInput(conn)),
140
141            ServerNext::ChooseConfig(accepted) => Self::Accepted(accepted),
142
143            ServerNext::VerifyClientIdentity(verify) => Self::VerifyClientIdentity(verify),
144
145            ServerNext::Complete(conn) => Self::Complete(conn),
146        })
147    }
148}
149
150impl Accepted<Quic> {
151    /// Choose a [`ServerConfig`] to progress the handshake.
152    ///
153    /// Resolves an [`Accepted`], providing the [`ServerConfig`] that should be used for
154    /// the session, and the TLS-encoded QUIC transport parameters to send.
155    ///
156    /// Returns an error if configuration-dependent validation of the received
157    /// `ClientHello` message fails.
158    ///
159    /// Events are appended to `output`.
160    pub fn choose_config(
161        self,
162        config: Arc<ServerConfig>,
163        params: Vec<u8>,
164        output: &mut Vec<QuicEvent>,
165    ) -> Result<ServerHandshake, Error> {
166        check_server_config(&config)?;
167
168        let exts = ServerExtensionsInput {
169            transport_parameters: Some(match self.conn.transport.version {
170                Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
171            }),
172        };
173
174        let mut tls = Vec::new();
175        let conn = self.partial_choose_config(config, exts, &mut tls)?;
176
177        // In QUIC mode, handshake output is emitted via `QuicEvent`s, not `tls`.
178        debug_assert!(tls.is_empty());
179        ServerHandshake::from_conn(conn, output)
180    }
181}
182
183pub(crate) trait FromConn<Side: SideData> {
184    fn from_conn(
185        conn: Connection<Side, Quic>,
186        output: &mut Vec<QuicEvent>,
187    ) -> Result<Side::QuicHandshake, Error>;
188}
189
190/// More data needs to be processed to make progress.
191///
192/// Provide the data to [`Self::process()`].
193///
194/// This type dereferences to [`ConnectionOutputs`]. Individual outputs are `None`
195/// until they are learned during the handshake.
196pub struct NeedsInput<Side: SideData>(pub(crate) Connection<Side, Quic>);
197
198impl<Side: SideData> NeedsInput<Side> {
199    /// Return the TLS-encoded transport parameters received from the peer.
200    ///
201    /// While the transport parameters are available before the handshake completes,
202    /// they cannot be fully trusted until then. Reliance on them should be minimized.
203    /// Any tampering with the parameters will cause the handshake to fail.
204    pub fn quic_transport_parameters(&self) -> Option<&[u8]> {
205        self.0.transport.transport_parameters()
206    }
207
208    /// Compute the keys for encrypting/decrypting 0-RTT packets, if available.
209    pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
210        self.0.transport.zero_rtt_keys(&self.0)
211    }
212
213    /// Progress the handshake by receiving further unencrypted TLS handshake data.
214    ///
215    /// The input should be ordered QUIC CRYPTO stream data for one encryption level.
216    ///
217    /// Handshake data obtained from separate encryption levels should be supplied in separate calls.
218    ///
219    /// How much of the `input` buffer is consumed is recorded by a call to
220    /// [`TlsInputBuffer::discard()`].  Unconsumed data should be presented again on the next call.
221    ///
222    /// An error from this function is fatal to the connection, as it consumes the [`NeedsInput`]
223    /// object.
224    ///
225    /// On success, this returns a [`ClientHandshake`] or [`ServerHandshake`] (depending on
226    /// `Side`) specifying what to do to progress the connection.  If this contains another
227    /// [`NeedsInput`] object then obtaining more input is certainly necessary.
228    ///
229    /// `output` has any resulting handshake messages or key changes appended to it.
230    pub fn process(
231        mut self,
232        input: &mut dyn TlsInputBuffer,
233        output: &mut Vec<QuicEvent>,
234    ) -> Result<Side::QuicHandshake, Error> {
235        self.0
236            .common
237            .recv
238            .deframer
239            .input_quic(input.slice_mut())?;
240
241        self.0.process(input, &mut Vec::new())?;
242        Side::QuicHandshake::from_conn(self.0, output)
243    }
244
245    /// Returns data learned during the connection, specific to this side.
246    pub fn side(&self) -> &Side {
247        &self.0.side
248    }
249}
250
251impl<Side: SideData> Deref for NeedsInput<Side> {
252    type Target = ConnectionOutputs;
253
254    fn deref(&self) -> &Self::Target {
255        self.0.deref()
256    }
257}
258
259impl<Side: SideData> fmt::Debug for NeedsInput<Side> {
260    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261        f.debug_struct("quic::NeedsInput")
262            .finish_non_exhaustive()
263    }
264}
265
266fn check_server_config(config: &ServerConfig) -> Result<(), Error> {
267    let suites = &config.provider.tls13_cipher_suites;
268    if suites.is_empty() {
269        return Err(ApiMisuse::QuicRequiresTls13Support.into());
270    }
271
272    if !suites
273        .iter()
274        .any(|scs| scs.quic.is_some())
275    {
276        return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
277    }
278
279    if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
280        return Err(ApiMisuse::QuicRestrictsMaxEarlyDataSize.into());
281    }
282
283    Ok(())
284}
285
286/// QUIC events that should be handled by the caller.
287#[expect(clippy::large_enum_variant)]
288#[derive(Debug)]
289#[non_exhaustive]
290pub enum QuicEvent {
291    /// These bytes should be handled as an unencrypted TLS handshake message.
292    Message(Vec<u8>),
293
294    /// The key material should be changed.
295    KeyChange(KeyChange),
296}
297
298impl<Side: SideData> Connection<Side, Quic> {
299    /// Consume unencrypted TLS handshake data.
300    ///
301    /// Handshake data obtained from separate encryption levels should be supplied in separate calls.
302    ///
303    /// How much of the `input` buffer is consumed is recorded by a call to
304    /// [`TlsInputBuffer::discard()`].  Unconsumed data should be presented again on the next call.
305    pub fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
306        self.common
307            .recv
308            .deframer
309            .input_quic(input.slice_mut())?;
310
311        let mut tls = Vec::new();
312        let mut iter = MessageIter::new(input, &mut tls, self, MessageIterMode::All);
313
314        let result = match iter.next(false) {
315            Some(Ok(_)) | None => Ok(()),
316            Some(Err(e)) => Err(e),
317        };
318
319        input.discard(self.common.recv.deframer.take_discard());
320        result
321    }
322
323    /// Obtain pending events that the caller should process.
324    ///
325    /// All pending events are returned as an iterator.
326    pub fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
327        self.transport.events()
328    }
329
330    /// Compute the keys for encrypting/decrypting 0-RTT packets, if available
331    pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
332        self.transport.zero_rtt_keys(self)
333    }
334
335    /// Return the TLS-encoded transport parameters for the session's peer.
336    ///
337    /// While the transport parameters are technically available prior to the
338    /// completion of the handshake, they cannot be fully trusted until the
339    /// handshake completes, and reliance on them should be minimized.
340    /// However, any tampering with the parameters will cause the handshake
341    /// to fail.
342    pub fn quic_transport_parameters(&self) -> Option<&[u8]> {
343        self.transport.transport_parameters()
344    }
345}
346
347/// The QUIC transport: TLS handshake messages and key changes delivered as [`QuicEvent`]s.
348#[derive(Default)]
349pub struct Quic {
350    pub(crate) version: Version,
351    /// QUIC transport parameters received from the peer during the handshake
352    pub(crate) params: Option<Vec<u8>>,
353    pub(crate) events: Vec<QuicEvent>,
354    pub(crate) early_secret: Option<OkmBlock>,
355}
356
357impl Quic {
358    pub(crate) fn send_msg(&mut self, m: Message<'_>, _must_encrypt: bool) {
359        if let MessagePayload::Alert(_) = m.payload {
360            // alerts are sent out-of-band in QUIC mode
361            return;
362        }
363
364        debug_assert!(
365            matches!(
366                m.payload,
367                MessagePayload::Handshake { .. } | MessagePayload::HandshakeFlight(_)
368            ),
369            "QUIC uses TLS for the cryptographic handshake only"
370        );
371        let mut bytes = Vec::new();
372        m.payload.encode(&mut bytes);
373        self.events
374            .push(QuicEvent::Message(bytes));
375    }
376
377    pub(crate) fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
378        mem::take(&mut self.events).into_iter()
379    }
380
381    fn zero_rtt_keys(&self, outputs: &ConnectionOutputs) -> Option<DirectionalKeys> {
382        let suite = outputs
383            .negotiated_cipher_suite()
384            .and_then(|suite| match suite {
385                SupportedCipherSuite::Tls13(suite) => Some(suite),
386                _ => None,
387            })?;
388
389        let suite = Suite {
390            inner: suite,
391            quic: suite.quic?,
392        };
393
394        Some(DirectionalKeys::new(
395            suite,
396            self.early_secret.as_ref()?,
397            self.version,
398        ))
399    }
400
401    fn transport_parameters(&self) -> Option<&[u8]> {
402        self.params.as_ref().map(|v| v.as_ref())
403    }
404}
405
406impl Transport for Quic {}
407
408impl sealed::Transport for Quic {
409    fn protocol(&self) -> Protocol {
410        Protocol::Quic(self.version)
411    }
412
413    fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
414        Some(self)
415    }
416}
417
418impl QuicOutput for Quic {
419    fn transport_parameters(&mut self, params: Vec<u8>) {
420        self.params = Some(params);
421    }
422
423    fn early_secret(&mut self, secret: Option<OkmBlock>) {
424        self.early_secret = secret;
425    }
426
427    fn handshake_secrets(&mut self, secrets: SecretUpdate) {
428        self.events
429            .push(QuicEvent::KeyChange(KeyChange::Handshake {
430                keys: Keys::new(&Secrets::new(secrets, self.version)),
431            }));
432    }
433
434    fn traffic_secrets(&mut self, secrets: SecretUpdate) {
435        let mut secrets = Secrets::new(secrets, self.version);
436        let keys = Keys::new(&secrets);
437        secrets.update();
438        self.events
439            .push(QuicEvent::KeyChange(KeyChange::OneRtt {
440                keys,
441                next: secrets,
442            }));
443    }
444
445    fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) {
446        self.send_msg(m, must_encrypt);
447    }
448}
449
450pub(crate) trait QuicOutput {
451    fn transport_parameters(&mut self, params: Vec<u8>);
452
453    fn early_secret(&mut self, secret: Option<OkmBlock>);
454
455    fn handshake_secrets(&mut self, secrets: SecretUpdate);
456
457    fn traffic_secrets(&mut self, secrets: SecretUpdate);
458
459    fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
460}
461
462/// Secrets used to encrypt/decrypt traffic
463#[derive(Clone)]
464pub struct Secrets {
465    /// Secret used to encrypt packets transmitted by the client
466    pub(crate) client: OkmBlock,
467    /// Secret used to encrypt packets transmitted by the server
468    pub(crate) server: OkmBlock,
469    /// Cipher suite used with these secrets
470    suite: Suite,
471    side: Side,
472    version: Version,
473}
474
475impl Secrets {
476    pub(crate) fn new(update: SecretUpdate, version: Version) -> Self {
477        Self {
478            client: update.client,
479            server: update.server,
480            suite: update.suite,
481            side: update.side,
482            version,
483        }
484    }
485
486    /// Derive the next set of packet keys
487    pub fn next_packet_keys(&mut self) -> PacketKeySet {
488        let keys = PacketKeySet::new(self);
489        self.update();
490        keys
491    }
492
493    pub(crate) fn update(&mut self) {
494        self.client = hkdf_expand_label_block(
495            self.suite
496                .inner
497                .hkdf_provider
498                .expander_for_okm(&self.client)
499                .as_ref(),
500            self.version.key_update_label(),
501            &[],
502        );
503        self.server = hkdf_expand_label_block(
504            self.suite
505                .inner
506                .hkdf_provider
507                .expander_for_okm(&self.server)
508                .as_ref(),
509            self.version.key_update_label(),
510            &[],
511        );
512    }
513
514    fn local_remote(&self) -> (&OkmBlock, &OkmBlock) {
515        match self.side {
516            Side::Client => (&self.client, &self.server),
517            Side::Server => (&self.server, &self.client),
518        }
519    }
520}
521
522pub(crate) struct SecretUpdate {
523    pub(crate) client: OkmBlock,
524    pub(crate) server: OkmBlock,
525    pub(crate) suite: Suite,
526    pub(crate) side: Side,
527}
528
529/// Keys used to communicate in a single direction
530#[expect(clippy::exhaustive_structs)]
531pub struct DirectionalKeys {
532    /// Encrypts or decrypts a packet's headers
533    pub header: Box<dyn HeaderProtectionKey>,
534    /// Encrypts or decrypts the payload of a packet
535    pub packet: Box<dyn PacketKey>,
536}
537
538impl DirectionalKeys {
539    pub(crate) fn new(suite: Suite, secret: &OkmBlock, version: Version) -> Self {
540        let builder = KeyBuilder::new(secret, version, suite.quic, suite.inner.hkdf_provider);
541        Self {
542            header: builder.header_protection_key(),
543            packet: builder.packet_key(),
544        }
545    }
546}
547
548/// All AEADs we support have 16-byte tags.
549const TAG_LEN: usize = 16;
550
551/// Authentication tag from an AEAD seal operation.
552pub struct Tag([u8; TAG_LEN]);
553
554impl From<&[u8]> for Tag {
555    fn from(value: &[u8]) -> Self {
556        let mut array = [0u8; TAG_LEN];
557        array.copy_from_slice(value);
558        Self(array)
559    }
560}
561
562impl AsRef<[u8]> for Tag {
563    fn as_ref(&self) -> &[u8] {
564        &self.0
565    }
566}
567
568/// How a [`Tls13CipherSuite`] generates [`PacketKey`]s and [`HeaderProtectionKey`]s.
569pub trait Algorithm: Send + Sync {
570    /// Produce a [`PacketKey`] for this suite.
571    ///
572    /// `key` and `iv` is the key material to use.
573    fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>;
574
575    /// Produce a [`HeaderProtectionKey`] for this suite.
576    ///
577    /// `key` is the key material, which is [`Self::aead_key_len()`] bytes in length.
578    fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>;
579
580    /// The length in bytes of keys for this Algorithm.
581    ///
582    /// This controls the size of [`AeadKey`]s presented to [`Self::packet_key()`] and
583    /// [`Self::header_protection_key()`].
584    fn aead_key_len(&self) -> usize;
585
586    /// The FIPS validation status of this algorithm.
587    fn fips(&self) -> FipsStatus {
588        FipsStatus::Unvalidated
589    }
590}
591
592/// A QUIC header protection key
593pub trait HeaderProtectionKey: Send + Sync {
594    /// Adds QUIC Header Protection.
595    ///
596    /// `sample` must contain the sample of encrypted payload; see
597    /// [Header Protection Sample].
598    ///
599    /// `first` must reference the first byte of the header, referred to as
600    /// `packet[0]` in [Header Protection Application].
601    ///
602    /// `packet_number` must reference the Packet Number field; this is
603    /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application].
604    ///
605    /// Returns an error without modifying anything if `sample` is not
606    /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]),
607    /// or `packet_number` is longer than allowed (see [Packet Number Encoding and Decoding]).
608    ///
609    /// Otherwise, `first` and `packet_number` will have the header protection added.
610    ///
611    /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1
612    /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2
613    /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1
614    fn encrypt_in_place(
615        &self,
616        sample: &[u8],
617        first: &mut u8,
618        packet_number: &mut [u8],
619    ) -> Result<(), Error>;
620
621    /// Removes QUIC Header Protection.
622    ///
623    /// `sample` must contain the sample of encrypted payload; see
624    /// [Header Protection Sample].
625    ///
626    /// `first` must reference the first byte of the header, referred to as
627    /// `packet[0]` in [Header Protection Application].
628    ///
629    /// `packet_number` must reference the Packet Number field; this is
630    /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application].
631    ///
632    /// Returns an error without modifying anything if `sample` is not
633    /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]),
634    /// or `packet_number` is longer than allowed (see
635    /// [Packet Number Encoding and Decoding]).
636    ///
637    /// Otherwise, `first` and `packet_number` will have the header protection removed.
638    ///
639    /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1
640    /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2
641    /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1
642    fn decrypt_in_place(
643        &self,
644        sample: &[u8],
645        first: &mut u8,
646        packet_number: &mut [u8],
647    ) -> Result<(), Error>;
648
649    /// Expected sample length for the key's algorithm
650    fn sample_len(&self) -> usize;
651}
652
653/// Keys to encrypt or decrypt the payload of a packet
654pub trait PacketKey: Send + Sync {
655    /// Encrypt a QUIC packet
656    ///
657    /// Takes a `packet_number` and optional `path_id`, used to derive the nonce; the packet
658    /// `header`, which is used as the additional authenticated data; and the `payload`. The
659    /// authentication tag is returned if encryption succeeds.
660    ///
661    /// Fails if and only if the payload is longer than allowed by the cipher suite's AEAD algorithm.
662    ///
663    /// When provided, the `path_id` is used for multipath encryption as described in
664    /// <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-15.html#section-2.4>.
665    fn encrypt_in_place(
666        &self,
667        packet_number: u64,
668        header: &[u8],
669        payload: &mut [u8],
670        path_id: Option<u32>,
671    ) -> Result<Tag, Error>;
672
673    /// Decrypt a QUIC packet
674    ///
675    /// Takes a `packet_number` and optional `path_id`, used to derive the nonce; the packet
676    /// `header`, which is used as the additional authenticated data, and the `payload`, which
677    /// includes the authentication tag.
678    ///
679    /// On success, returns the slice of `payload` containing the decrypted data.
680    ///
681    /// When provided, the `path_id` is used for multipath encryption as described in
682    /// <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-15.html#section-2.4>.
683    fn decrypt_in_place<'a>(
684        &self,
685        packet_number: u64,
686        header: &[u8],
687        payload: &'a mut [u8],
688        path_id: Option<u32>,
689    ) -> Result<&'a [u8], Error>;
690
691    /// Tag length for the underlying AEAD algorithm
692    fn tag_len(&self) -> usize;
693
694    /// Number of QUIC packets that can be safely encrypted with a single key of this type.
695    ///
696    /// Once a `PacketKey` produced for this suite has encrypted more than
697    /// `confidentiality_limit` packets, an attacker gains an advantage in distinguishing it
698    /// from an ideal pseudorandom permutation (PRP).
699    ///
700    /// This is to be set on the assumption that packets are maximally sized --
701    /// 2 ** 16. For non-QUIC TCP connections see [`CipherSuiteCommon::confidentiality_limit`][csc-limit].
702    ///
703    /// [csc-limit]: crate::crypto::CipherSuiteCommon::confidentiality_limit
704    fn confidentiality_limit(&self) -> u64;
705
706    /// Number of QUIC packets that can be safely decrypted with a single key of this type
707    ///
708    /// Once a `PacketKey` produced for this suite has failed to decrypt `integrity_limit`
709    /// packets, an attacker gains an advantage in forging packets.
710    ///
711    /// This is not relevant for TLS over TCP (which is also implemented in this crate)
712    /// because a single failed decryption is fatal to the connection.
713    /// However, this quantity is used by QUIC.
714    fn integrity_limit(&self) -> u64;
715}
716
717/// Packet protection keys for bidirectional 1-RTT communication
718#[expect(clippy::exhaustive_structs)]
719pub struct PacketKeySet {
720    /// Encrypts outgoing packets
721    pub local: Box<dyn PacketKey>,
722    /// Decrypts incoming packets
723    pub remote: Box<dyn PacketKey>,
724}
725
726impl PacketKeySet {
727    fn new(secrets: &Secrets) -> Self {
728        let (local, remote) = secrets.local_remote();
729        let (version, alg, hkdf) = (
730            secrets.version,
731            secrets.suite.quic,
732            secrets.suite.inner.hkdf_provider,
733        );
734
735        Self {
736            local: KeyBuilder::new(local, version, alg, hkdf).packet_key(),
737            remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(),
738        }
739    }
740}
741
742/// Helper for building QUIC packet and header protection keys
743pub struct KeyBuilder<'a> {
744    expander: Box<dyn HkdfExpander>,
745    version: Version,
746    alg: &'a dyn Algorithm,
747}
748
749impl<'a> KeyBuilder<'a> {
750    /// Create a new KeyBuilder
751    pub fn new(
752        secret: &OkmBlock,
753        version: Version,
754        alg: &'a dyn Algorithm,
755        hkdf: &'a dyn Hkdf,
756    ) -> Self {
757        Self {
758            expander: hkdf.expander_for_okm(secret),
759            version,
760            alg,
761        }
762    }
763
764    /// Derive packet keys
765    pub fn packet_key(&self) -> Box<dyn PacketKey> {
766        let aead_key_len = self.alg.aead_key_len();
767        let packet_key = hkdf_expand_label_aead_key(
768            self.expander.as_ref(),
769            aead_key_len,
770            self.version.packet_key_label(),
771            &[],
772        );
773
774        let packet_iv =
775            hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]);
776        self.alg
777            .packet_key(packet_key, packet_iv)
778    }
779
780    /// Derive header protection keys
781    pub fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> {
782        let header_key = hkdf_expand_label_aead_key(
783            self.expander.as_ref(),
784            self.alg.aead_key_len(),
785            self.version.header_key_label(),
786            &[],
787        );
788        self.alg
789            .header_protection_key(header_key)
790    }
791}
792
793/// Produces QUIC initial keys from a TLS 1.3 ciphersuite and a QUIC key generation algorithm.
794#[non_exhaustive]
795#[derive(Clone, Copy)]
796pub struct Suite {
797    /// The TLS 1.3 ciphersuite used to derive keys.
798    pub inner: &'static Tls13CipherSuite,
799    /// The QUIC key generation algorithm used to derive keys.
800    pub quic: &'static dyn Algorithm,
801}
802
803impl Suite {
804    /// Produce a set of initial keys given the connection ID, side and version
805    pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys {
806        Keys::initial(version, *self, client_dst_connection_id, side)
807    }
808}
809
810impl TryFrom<&'static Tls13CipherSuite> for Suite {
811    type Error = ApiMisuse;
812
813    fn try_from(suite: &'static Tls13CipherSuite) -> Result<Self, Self::Error> {
814        Ok(Self {
815            inner: suite,
816            quic: suite
817                .quic
818                .ok_or(ApiMisuse::NoQuicCompatibleCipherSuites)?,
819        })
820    }
821}
822
823impl fmt::Debug for Suite {
824    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
825        f.debug_struct("Suite")
826            .field("inner", &self.inner)
827            .finish_non_exhaustive()
828    }
829}
830
831/// Complete set of keys used to communicate with the peer
832#[expect(clippy::exhaustive_structs)]
833pub struct Keys {
834    /// Encrypts outgoing packets
835    pub local: DirectionalKeys,
836    /// Decrypts incoming packets
837    pub remote: DirectionalKeys,
838}
839
840impl Keys {
841    /// Construct keys for use with initial packets
842    pub fn initial(
843        version: Version,
844        suite: Suite,
845        client_dst_connection_id: &[u8],
846        side: Side,
847    ) -> Self {
848        const CLIENT_LABEL: &[u8] = b"client in";
849        const SERVER_LABEL: &[u8] = b"server in";
850        let salt = version.initial_salt();
851        let hs_secret = suite
852            .inner
853            .hkdf_provider
854            .extract_from_secret(Some(salt), client_dst_connection_id);
855
856        let secrets = Secrets {
857            client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]),
858            server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]),
859            suite,
860            side,
861            version,
862        };
863
864        Self::new(&secrets)
865    }
866
867    fn new(secrets: &Secrets) -> Self {
868        let (local, remote) = secrets.local_remote();
869        Self {
870            local: DirectionalKeys::new(secrets.suite, local, secrets.version),
871            remote: DirectionalKeys::new(secrets.suite, remote, secrets.version),
872        }
873    }
874}
875
876/// Key material for use in QUIC packet spaces
877///
878/// QUIC uses 4 different sets of keys (and progressive key updates for long-running connections):
879///
880/// * Initial: these can be created from [`Keys::initial()`]
881/// * 0-RTT keys: can be retrieved from [`Connection::zero_rtt_keys()`]
882/// * Handshake: these are returned from [`Connection::events()`] after `ClientHello` and
883///   `ServerHello` messages have been exchanged
884/// * 1-RTT keys: these are returned from [`Connection::events()`] after the handshake is done
885///
886/// Once the 1-RTT keys have been exchanged, either side may initiate a key update. Progressive
887/// update keys can be obtained from the [`Secrets`] returned in [`KeyChange::OneRtt`]. Note that
888/// only packet keys are updated by key updates; header protection keys remain the same.
889#[expect(clippy::exhaustive_enums)]
890pub enum KeyChange {
891    /// Keys for the handshake space
892    Handshake {
893        /// Header and packet keys for the handshake space
894        keys: Keys,
895    },
896    /// Keys for 1-RTT data
897    OneRtt {
898        /// Header and packet keys for 1-RTT data
899        keys: Keys,
900        /// Secrets to derive updated keys from
901        next: Secrets,
902    },
903}
904
905impl fmt::Debug for KeyChange {
906    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907        match self {
908            Self::Handshake { .. } => f
909                .debug_struct("Handshake")
910                .finish_non_exhaustive(),
911            Self::OneRtt { .. } => f
912                .debug_struct("OneRtt")
913                .finish_non_exhaustive(),
914        }
915    }
916}
917
918/// QUIC protocol version
919///
920/// Governs version-specific behavior in the TLS layer
921#[non_exhaustive]
922#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
923pub enum Version {
924    /// First stable RFC
925    #[default]
926    V1,
927    /// Anti-ossification variant of V1
928    V2,
929}
930
931impl Version {
932    fn initial_salt(self) -> &'static [u8; 20] {
933        match self {
934            Self::V1 => &[
935                // https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets
936                0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
937                0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
938            ],
939            Self::V2 => &[
940                // https://tools.ietf.org/html/rfc9369.html#name-initial-salt
941                0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26,
942                0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
943            ],
944        }
945    }
946
947    /// Key derivation label for packet keys.
948    pub(crate) fn packet_key_label(&self) -> &'static [u8] {
949        match self {
950            Self::V1 => b"quic key",
951            Self::V2 => b"quicv2 key",
952        }
953    }
954
955    /// Key derivation label for packet "IV"s.
956    pub(crate) fn packet_iv_label(&self) -> &'static [u8] {
957        match self {
958            Self::V1 => b"quic iv",
959            Self::V2 => b"quicv2 iv",
960        }
961    }
962
963    /// Key derivation for header keys.
964    pub(crate) fn header_key_label(&self) -> &'static [u8] {
965        match self {
966            Self::V1 => b"quic hp",
967            Self::V2 => b"quicv2 hp",
968        }
969    }
970
971    fn key_update_label(&self) -> &'static [u8] {
972        match self {
973            Self::V1 => b"quic ku",
974            Self::V2 => b"quicv2 ku",
975        }
976    }
977}
978
979#[cfg(all(test, any(target_arch = "aarch64", target_arch = "x86_64")))]
980mod tests {
981    use super::*;
982    use crate::crypto::TLS13_TEST_SUITE;
983    use crate::crypto::tls13::OkmBlock;
984    use crate::quic::{HeaderProtectionKey, Side, Version};
985
986    #[test]
987    fn key_update_test_vector() {
988        fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool {
989            x.as_ref() == y.as_ref()
990        }
991
992        let mut secrets = Secrets {
993            // Constant dummy values for reproducibility
994            client: OkmBlock::new(
995                &[
996                    0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
997                    0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
998                    0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
999                ][..],
1000            ),
1001            server: OkmBlock::new(
1002                &[
1003                    0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
1004                    0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
1005                    0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
1006                ][..],
1007            ),
1008            suite: Suite {
1009                inner: TLS13_TEST_SUITE,
1010                quic: &FakeAlgorithm,
1011            },
1012            side: Side::Client,
1013            version: Version::V1,
1014        };
1015        secrets.update();
1016
1017        assert!(equal_okm(
1018            &secrets.client,
1019            &OkmBlock::new(
1020                &[
1021                    0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
1022                    0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
1023                    0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
1024                ][..]
1025            )
1026        ));
1027        assert!(equal_okm(
1028            &secrets.server,
1029            &OkmBlock::new(
1030                &[
1031                    0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
1032                    0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
1033                    0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
1034                ][..]
1035            )
1036        ));
1037    }
1038
1039    struct FakeAlgorithm;
1040
1041    impl Algorithm for FakeAlgorithm {
1042        fn packet_key(&self, _key: AeadKey, _iv: Iv) -> Box<dyn PacketKey> {
1043            unimplemented!()
1044        }
1045
1046        fn header_protection_key(&self, _key: AeadKey) -> Box<dyn HeaderProtectionKey> {
1047            unimplemented!()
1048        }
1049
1050        fn aead_key_len(&self) -> usize {
1051            16
1052        }
1053    }
1054
1055    #[test]
1056    fn auto_traits() {
1057        fn assert_auto<T: Send + Sync>() {}
1058        assert_auto::<Box<dyn PacketKey>>();
1059        assert_auto::<Box<dyn HeaderProtectionKey>>();
1060    }
1061}