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