Skip to main content

rustls/
quic.rs

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