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