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