Skip to main content

rustls/
quic.rs

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