Skip to main content

rustls/
quic.rs

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