rustls/
quic.rs

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