Skip to main content

rustls/
quic.rs

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