noq_proto/crypto/
rustls.rs

1use std::{any::Any, io, str, sync::Arc};
2
3use aes_gcm::{KeyInit, aead::AeadMutInPlace};
4use bytes::BytesMut;
5pub use rustls::Error;
6use rustls::{
7    self, CipherSuite,
8    pki_types::{CertificateDer, ServerName},
9    quic::{Connection, HeaderProtectionKey, KeyChange, PacketKey, Secrets, Suite, Version},
10};
11#[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
12use rustls::{client::danger::ServerCertVerifier, pki_types::PrivateKeyDer};
13
14use crate::{
15    ConnectError, ConnectionId, PathId, Side, TransportError, TransportErrorCode,
16    crypto::{
17        self, CryptoError, ExportKeyingMaterialError, HeaderKey, KeyPair, Keys, UnsupportedVersion,
18    },
19    transport_parameters::TransportParameters,
20};
21
22impl From<Side> for rustls::Side {
23    fn from(s: Side) -> Self {
24        match s {
25            Side::Client => Self::Client,
26            Side::Server => Self::Server,
27        }
28    }
29}
30
31/// A rustls TLS session
32pub struct TlsSession {
33    version: Version,
34    got_handshake_data: bool,
35    next_secrets: Option<Secrets>,
36    inner: Connection,
37    suite: Suite,
38}
39
40impl TlsSession {
41    fn side(&self) -> Side {
42        match self.inner {
43            Connection::Client(_) => Side::Client,
44            Connection::Server(_) => Side::Server,
45        }
46    }
47}
48
49impl crypto::Session for TlsSession {
50    fn initial_keys(&self, dst_cid: ConnectionId, side: Side) -> Keys {
51        initial_keys(self.version, dst_cid, side, &self.suite)
52    }
53
54    fn handshake_data(&self) -> Option<Box<dyn Any>> {
55        if !self.got_handshake_data {
56            return None;
57        }
58        Some(Box::new(HandshakeData {
59            protocol: self.inner.alpn_protocol().map(|x| x.into()),
60            server_name: match self.inner {
61                Connection::Client(_) => None,
62                Connection::Server(ref session) => session.server_name().map(|x| x.into()),
63            },
64            #[cfg(feature = "__rustls-post-quantum-test")]
65            negotiated_key_exchange_group: self
66                .inner
67                .negotiated_key_exchange_group()
68                .expect("key exchange group is negotiated")
69                .name(),
70        }))
71    }
72
73    /// For the rustls `TlsSession`, the `Any` type is `Vec<rustls::pki_types::CertificateDer>`
74    fn peer_identity(&self) -> Option<Box<dyn Any>> {
75        self.inner.peer_certificates().map(|v| -> Box<dyn Any> {
76            Box::new(
77                v.iter()
78                    .map(|v| v.clone().into_owned())
79                    .collect::<Vec<CertificateDer<'static>>>(),
80            )
81        })
82    }
83
84    fn early_crypto(&self) -> Option<(Box<dyn HeaderKey>, Box<dyn crypto::PacketKey>)> {
85        let keys = self.inner.zero_rtt_keys()?;
86        Some((Box::new(keys.header), Box::new(keys.packet)))
87    }
88
89    fn early_data_accepted(&self) -> Option<bool> {
90        match self.inner {
91            Connection::Client(ref session) => Some(session.is_early_data_accepted()),
92            _ => None,
93        }
94    }
95
96    fn is_handshaking(&self) -> bool {
97        self.inner.is_handshaking()
98    }
99
100    fn read_handshake(&mut self, buf: &[u8]) -> Result<bool, TransportError> {
101        self.inner.read_hs(buf).map_err(|e| {
102            if let Some(alert) = self.inner.alert() {
103                TransportError {
104                    code: TransportErrorCode::crypto(alert.into()),
105                    frame: crate::frame::MaybeFrame::None,
106                    reason: e.to_string(),
107                    crypto: Some(Arc::new(e)),
108                }
109            } else {
110                TransportError::PROTOCOL_VIOLATION(format!("TLS error: {e}"))
111            }
112        })?;
113        if !self.got_handshake_data {
114            // Hack around the lack of an explicit signal from rustls to reflect ClientHello being
115            // ready on incoming connections, or ALPN negotiation completing on outgoing
116            // connections.
117            let have_server_name = match self.inner {
118                Connection::Client(_) => false,
119                Connection::Server(ref session) => session.server_name().is_some(),
120            };
121            if self.inner.alpn_protocol().is_some() || have_server_name || !self.is_handshaking() {
122                self.got_handshake_data = true;
123                return Ok(true);
124            }
125        }
126        Ok(false)
127    }
128
129    fn transport_parameters(&self) -> Result<Option<TransportParameters>, TransportError> {
130        match self.inner.quic_transport_parameters() {
131            None => Ok(None),
132            Some(buf) => match TransportParameters::read(self.side(), &mut io::Cursor::new(buf)) {
133                Ok(params) => Ok(Some(params)),
134                Err(e) => Err(e.into()),
135            },
136        }
137    }
138
139    fn write_handshake(&mut self, buf: &mut Vec<u8>) -> Option<Keys> {
140        let keys = match self.inner.write_hs(buf)? {
141            KeyChange::Handshake { keys } => keys,
142            KeyChange::OneRtt { keys, next } => {
143                self.next_secrets = Some(next);
144                keys
145            }
146        };
147
148        Some(Keys {
149            header: KeyPair {
150                local: Box::new(keys.local.header),
151                remote: Box::new(keys.remote.header),
152            },
153            packet: KeyPair {
154                local: Box::new(keys.local.packet),
155                remote: Box::new(keys.remote.packet),
156            },
157        })
158    }
159
160    fn next_1rtt_keys(&mut self) -> Option<KeyPair<Box<dyn crypto::PacketKey>>> {
161        let secrets = self.next_secrets.as_mut()?;
162        let keys = secrets.next_packet_keys();
163        Some(KeyPair {
164            local: Box::new(keys.local),
165            remote: Box::new(keys.remote),
166        })
167    }
168
169    fn is_valid_retry(&self, orig_dst_cid: ConnectionId, header: &[u8], payload: &[u8]) -> bool {
170        if payload.len() < 16 {
171            return false;
172        }
173
174        let mut pseudo_packet =
175            Vec::with_capacity(header.len() + payload.len() + orig_dst_cid.len() + 1);
176        pseudo_packet.push(orig_dst_cid.len() as u8);
177        pseudo_packet.extend_from_slice(&orig_dst_cid);
178        pseudo_packet.extend_from_slice(header);
179        pseudo_packet.extend_from_slice(payload);
180
181        let (nonce, key) = match self.version {
182            Version::V1 => (&RETRY_INTEGRITY_NONCE_V1, &RETRY_INTEGRITY_KEY_V1),
183            Version::V1Draft => (&RETRY_INTEGRITY_NONCE_DRAFT, &RETRY_INTEGRITY_KEY_DRAFT),
184            _ => unreachable!(),
185        };
186
187        let Some((aad, tag)) = pseudo_packet.split_last_chunk::<16>() else {
188            return false; // But length is actually already checked above.
189        };
190
191        // This implements https://www.rfc-editor.org/rfc/rfc9001#name-retry-packet-integrity
192        let key = aes_gcm::Key::<aes_gcm::Aes128Gcm>::from_slice(key);
193        let nonce = aes_gcm::Nonce::from_slice(nonce);
194        let tag = aes_gcm::Tag::from_slice(tag);
195        aes_gcm::Aes128Gcm::new(key)
196            .decrypt_in_place_detached(nonce, aad, &mut [], tag)
197            .is_ok()
198    }
199
200    fn export_keying_material(
201        &self,
202        output: &mut [u8],
203        label: &[u8],
204        context: &[u8],
205    ) -> Result<(), ExportKeyingMaterialError> {
206        self.inner
207            .export_keying_material(output, label, Some(context))
208            .map_err(|_| ExportKeyingMaterialError)?;
209        Ok(())
210    }
211}
212
213const RETRY_INTEGRITY_KEY_DRAFT: [u8; 16] = [
214    0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1,
215];
216const RETRY_INTEGRITY_NONCE_DRAFT: [u8; 12] = [
217    0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c,
218];
219
220const RETRY_INTEGRITY_KEY_V1: [u8; 16] = [
221    0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e,
222];
223const RETRY_INTEGRITY_NONCE_V1: [u8; 12] = [
224    0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb,
225];
226
227impl crypto::HeaderKey for Box<dyn HeaderProtectionKey> {
228    fn decrypt(&self, pn_offset: usize, packet: &mut [u8]) {
229        let (header, sample) = packet.split_at_mut(pn_offset + 4);
230        let (first, rest) = header.split_at_mut(1);
231        let pn_end = Ord::min(pn_offset + 3, rest.len());
232        self.decrypt_in_place(
233            &sample[..self.sample_size()],
234            &mut first[0],
235            &mut rest[pn_offset - 1..pn_end],
236        )
237        .unwrap();
238    }
239
240    fn encrypt(&self, pn_offset: usize, packet: &mut [u8]) {
241        let (header, sample) = packet.split_at_mut(pn_offset + 4);
242        let (first, rest) = header.split_at_mut(1);
243        let pn_end = Ord::min(pn_offset + 3, rest.len());
244        self.encrypt_in_place(
245            &sample[..self.sample_size()],
246            &mut first[0],
247            &mut rest[pn_offset - 1..pn_end],
248        )
249        .unwrap();
250    }
251
252    fn sample_size(&self) -> usize {
253        self.sample_len()
254    }
255}
256
257/// Authentication data for (rustls) TLS session
258pub struct HandshakeData {
259    /// The negotiated application protocol, if ALPN is in use
260    ///
261    /// Guaranteed to be set if a nonempty list of protocols was specified for this connection.
262    pub protocol: Option<Vec<u8>>,
263    /// The server name specified by the client, if any
264    ///
265    /// Always `None` for outgoing connections
266    pub server_name: Option<String>,
267    /// The key exchange group negotiated with the peer
268    #[cfg(feature = "__rustls-post-quantum-test")]
269    pub negotiated_key_exchange_group: rustls::NamedGroup,
270}
271
272/// A QUIC-compatible TLS client configuration
273///
274/// noq implicitly constructs a `QuicClientConfig` with reasonable defaults within
275/// [`ClientConfig::with_root_certificates()`][root_certs] and [`ClientConfig::try_with_platform_verifier()`][platform].
276/// Alternatively, `QuicClientConfig`'s [`TryFrom`] implementation can be used to wrap around a
277/// custom [`rustls::ClientConfig`], in which case care should be taken around certain points:
278///
279/// - If `enable_early_data` is not set to true, then sending 0-RTT data will not be possible on
280///   outgoing connections.
281/// - The [`rustls::ClientConfig`] must have TLS 1.3 support enabled for conversion to succeed.
282///
283/// The object in the `resumption` field of the inner [`rustls::ClientConfig`] determines whether
284/// calling `into_0rtt` on outgoing connections returns `Ok` or `Err`. It typically allows
285/// `into_0rtt` to proceed if it recognizes the server name, and defaults to an in-memory cache of
286/// 256 server names.
287///
288/// [root_certs]: crate::config::ClientConfig::with_root_certificates()
289/// [platform]: crate::config::ClientConfig::try_with_platform_verifier()
290#[derive(Clone)] // cheap clone: Only one arc clone and some copied pointers
291pub struct QuicClientConfig {
292    pub(crate) inner: Arc<rustls::ClientConfig>,
293    initial: Suite,
294}
295
296impl QuicClientConfig {
297    #[cfg(all(
298        feature = "platform-verifier",
299        any(feature = "aws-lc-rs", feature = "ring")
300    ))]
301    pub(crate) fn with_platform_verifier() -> Result<Self, Error> {
302        use rustls_platform_verifier::BuilderVerifierExt;
303
304        // Keep in sync with `inner()` below
305        let mut inner = rustls::ClientConfig::builder_with_provider(configured_provider())
306            .with_protocol_versions(&[&rustls::version::TLS13])
307            .unwrap() // The default providers support TLS 1.3
308            .with_platform_verifier()?
309            .with_no_client_auth();
310
311        inner.enable_early_data = true;
312        Ok(Self {
313            // We're confident that the *ring* default provider contains TLS13_AES_128_GCM_SHA256
314            initial: initial_suite_from_provider(inner.crypto_provider())
315                .expect("no initial cipher suite found"),
316            inner: Arc::new(inner),
317        })
318    }
319
320    /// Initialize a sane QUIC-compatible TLS client configuration
321    ///
322    /// QUIC requires that TLS 1.3 be enabled. Advanced users can use any [`rustls::ClientConfig`] that
323    /// satisfies this requirement.
324    #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
325    pub(crate) fn new(verifier: Arc<dyn ServerCertVerifier>) -> Self {
326        let inner = Self::inner(verifier);
327        Self {
328            // We're confident that the *ring* default provider contains TLS13_AES_128_GCM_SHA256
329            initial: initial_suite_from_provider(inner.crypto_provider())
330                .expect("no initial cipher suite found"),
331            inner: Arc::new(inner),
332        }
333    }
334
335    /// Initialize a QUIC-compatible TLS client configuration with a separate initial cipher suite
336    ///
337    /// This is useful if you want to avoid the initial cipher suite for traffic encryption.
338    pub fn with_initial(
339        inner: Arc<rustls::ClientConfig>,
340        initial: Suite,
341    ) -> Result<Self, NoInitialCipherSuite> {
342        match initial.suite.common.suite {
343            CipherSuite::TLS13_AES_128_GCM_SHA256 => Ok(Self { inner, initial }),
344            _ => Err(NoInitialCipherSuite { specific: true }),
345        }
346    }
347
348    /// Updates the set of ALPN protocols configured in the client config.
349    pub fn set_alpn_protocols(&mut self, alpn_protocols: Vec<Vec<u8>>) {
350        let config = Arc::make_mut(&mut self.inner);
351        config.alpn_protocols = alpn_protocols;
352    }
353
354    #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
355    pub(crate) fn inner(verifier: Arc<dyn ServerCertVerifier>) -> rustls::ClientConfig {
356        // Keep in sync with `with_platform_verifier()` above
357        let mut config = rustls::ClientConfig::builder_with_provider(configured_provider())
358            .with_protocol_versions(&[&rustls::version::TLS13])
359            .unwrap() // The default providers support TLS 1.3
360            .dangerous()
361            .with_custom_certificate_verifier(verifier)
362            .with_no_client_auth();
363
364        config.enable_early_data = true;
365        config
366    }
367}
368
369impl crypto::ClientConfig for QuicClientConfig {
370    fn start_session(
371        &self,
372        version: u32,
373        server_name: &str,
374        params: &TransportParameters,
375    ) -> Result<Box<dyn crypto::Session>, ConnectError> {
376        let version = interpret_version(version)?;
377        Ok(Box::new(TlsSession {
378            version,
379            got_handshake_data: false,
380            next_secrets: None,
381            inner: rustls::quic::Connection::Client(
382                rustls::quic::ClientConnection::new(
383                    self.inner.clone(),
384                    version,
385                    ServerName::try_from(server_name)
386                        .map_err(|_| ConnectError::InvalidServerName(server_name.into()))?
387                        .to_owned(),
388                    to_vec(params),
389                )
390                .unwrap(),
391            ),
392            suite: self.initial,
393        }))
394    }
395}
396
397impl TryFrom<rustls::ClientConfig> for QuicClientConfig {
398    type Error = NoInitialCipherSuite;
399
400    fn try_from(inner: rustls::ClientConfig) -> Result<Self, Self::Error> {
401        Arc::new(inner).try_into()
402    }
403}
404
405impl TryFrom<Arc<rustls::ClientConfig>> for QuicClientConfig {
406    type Error = NoInitialCipherSuite;
407
408    fn try_from(inner: Arc<rustls::ClientConfig>) -> Result<Self, Self::Error> {
409        Ok(Self {
410            initial: initial_suite_from_provider(inner.crypto_provider())
411                .ok_or(NoInitialCipherSuite { specific: false })?,
412            inner,
413        })
414    }
415}
416
417/// The initial cipher suite (AES-128-GCM-SHA256) is not available
418///
419/// When the cipher suite is supplied `with_initial()`, it must be
420/// [`CipherSuite::TLS13_AES_128_GCM_SHA256`]. When the cipher suite is derived from a config's
421/// [`CryptoProvider`][provider], that provider must reference a cipher suite with the same ID.
422///
423/// [provider]: rustls::crypto::CryptoProvider
424#[derive(Clone, Debug)]
425pub struct NoInitialCipherSuite {
426    /// Whether the initial cipher suite was supplied by the caller
427    specific: bool,
428}
429
430impl std::fmt::Display for NoInitialCipherSuite {
431    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
432        f.write_str(match self.specific {
433            true => "invalid cipher suite specified",
434            false => "no initial cipher suite found",
435        })
436    }
437}
438
439impl std::error::Error for NoInitialCipherSuite {}
440
441/// A QUIC-compatible TLS server configuration
442///
443/// noq implicitly constructs a `QuicServerConfig` with reasonable defaults within
444/// [`ServerConfig::with_single_cert()`][single]. Alternatively, `QuicServerConfig`'s [`TryFrom`]
445/// implementation or `with_initial` method can be used to wrap around a custom
446/// [`rustls::ServerConfig`], in which case care should be taken around certain points:
447///
448/// - If `max_early_data_size` is not set to `u32::MAX`, the server will not be able to accept
449///   incoming 0-RTT data. QUIC prohibits `max_early_data_size` values other than 0 or `u32::MAX`.
450/// - The `rustls::ServerConfig` must have TLS 1.3 support enabled for conversion to succeed.
451///
452/// [single]: crate::config::ServerConfig::with_single_cert()
453#[derive(Clone)] // clone is cheap: Just an Arc clone and some copied pointers
454pub struct QuicServerConfig {
455    inner: Arc<rustls::ServerConfig>,
456    initial: Suite,
457}
458
459impl QuicServerConfig {
460    #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
461    pub(crate) fn new(
462        cert_chain: Vec<CertificateDer<'static>>,
463        key: PrivateKeyDer<'static>,
464    ) -> Result<Self, rustls::Error> {
465        let inner = Self::inner(cert_chain, key)?;
466        Ok(Self {
467            // We're confident that the *ring* default provider contains TLS13_AES_128_GCM_SHA256
468            initial: initial_suite_from_provider(inner.crypto_provider())
469                .expect("no initial cipher suite found"),
470            inner: Arc::new(inner),
471        })
472    }
473
474    /// Initialize a QUIC-compatible TLS client configuration with a separate initial cipher suite
475    ///
476    /// This is useful if you want to avoid the initial cipher suite for traffic encryption.
477    pub fn with_initial(
478        inner: Arc<rustls::ServerConfig>,
479        initial: Suite,
480    ) -> Result<Self, NoInitialCipherSuite> {
481        match initial.suite.common.suite {
482            CipherSuite::TLS13_AES_128_GCM_SHA256 => Ok(Self { inner, initial }),
483            _ => Err(NoInitialCipherSuite { specific: true }),
484        }
485    }
486
487    /// Updates the set of ALPN protocols configured in the server config.
488    pub fn set_alpn_protocols(&mut self, alpn_protocols: Vec<Vec<u8>>) {
489        let config = Arc::make_mut(&mut self.inner);
490        config.alpn_protocols = alpn_protocols;
491    }
492
493    /// Initialize a sane QUIC-compatible TLS server configuration
494    ///
495    /// QUIC requires that TLS 1.3 be enabled, and that the maximum early data size is either 0 or
496    /// `u32::MAX`. Advanced users can use any [`rustls::ServerConfig`] that satisfies these
497    /// requirements.
498    #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
499    pub(crate) fn inner(
500        cert_chain: Vec<CertificateDer<'static>>,
501        key: PrivateKeyDer<'static>,
502    ) -> Result<rustls::ServerConfig, rustls::Error> {
503        let mut inner = rustls::ServerConfig::builder_with_provider(configured_provider())
504            .with_protocol_versions(&[&rustls::version::TLS13])
505            .unwrap() // The *ring* default provider supports TLS 1.3
506            .with_no_client_auth()
507            .with_single_cert(cert_chain, key)?;
508
509        inner.max_early_data_size = u32::MAX;
510        Ok(inner)
511    }
512}
513
514impl TryFrom<rustls::ServerConfig> for QuicServerConfig {
515    type Error = NoInitialCipherSuite;
516
517    fn try_from(inner: rustls::ServerConfig) -> Result<Self, Self::Error> {
518        Arc::new(inner).try_into()
519    }
520}
521
522impl TryFrom<Arc<rustls::ServerConfig>> for QuicServerConfig {
523    type Error = NoInitialCipherSuite;
524
525    fn try_from(inner: Arc<rustls::ServerConfig>) -> Result<Self, Self::Error> {
526        Ok(Self {
527            initial: initial_suite_from_provider(inner.crypto_provider())
528                .ok_or(NoInitialCipherSuite { specific: false })?,
529            inner,
530        })
531    }
532}
533
534impl crypto::ServerConfig for QuicServerConfig {
535    fn start_session(
536        &self,
537        version: u32,
538        params: &TransportParameters,
539    ) -> Box<dyn crypto::Session> {
540        // Safe: `start_session()` is never called if `initial_keys()` rejected `version`
541        let version = interpret_version(version).unwrap();
542        Box::new(TlsSession {
543            version,
544            got_handshake_data: false,
545            next_secrets: None,
546            inner: rustls::quic::Connection::Server(
547                rustls::quic::ServerConnection::new(self.inner.clone(), version, to_vec(params))
548                    .unwrap(),
549            ),
550            suite: self.initial,
551        })
552    }
553
554    fn initial_keys(
555        &self,
556        version: u32,
557        dst_cid: ConnectionId,
558    ) -> Result<Keys, UnsupportedVersion> {
559        let version = interpret_version(version)?;
560        Ok(initial_keys(version, dst_cid, Side::Server, &self.initial))
561    }
562
563    fn retry_tag(&self, version: u32, orig_dst_cid: ConnectionId, packet: &[u8]) -> [u8; 16] {
564        // Safe: `start_session()` is never called if `initial_keys()` rejected `version`
565        let version = interpret_version(version).unwrap();
566        let (nonce, key) = match version {
567            Version::V1 => (&RETRY_INTEGRITY_NONCE_V1, &RETRY_INTEGRITY_KEY_V1),
568            Version::V1Draft => (&RETRY_INTEGRITY_NONCE_DRAFT, &RETRY_INTEGRITY_KEY_DRAFT),
569            _ => unreachable!(),
570        };
571
572        let mut pseudo_packet = Vec::with_capacity(packet.len() + orig_dst_cid.len() + 1);
573        pseudo_packet.push(orig_dst_cid.len() as u8);
574        pseudo_packet.extend_from_slice(&orig_dst_cid);
575        pseudo_packet.extend_from_slice(packet);
576
577        let nonce = aes_gcm::Nonce::from_slice(nonce);
578        let key = aes_gcm::Key::<aes_gcm::Aes128Gcm>::from_slice(key);
579        let tag = aes_gcm::Aes128Gcm::new(key)
580            .encrypt_in_place_detached(nonce, &pseudo_packet, &mut [])
581            .unwrap();
582        tag.into()
583    }
584}
585
586pub(crate) fn initial_suite_from_provider(
587    provider: &Arc<rustls::crypto::CryptoProvider>,
588) -> Option<Suite> {
589    provider
590        .cipher_suites
591        .iter()
592        .find_map(|cs| match (cs.suite(), cs.tls13()) {
593            (rustls::CipherSuite::TLS13_AES_128_GCM_SHA256, Some(suite)) => {
594                Some(suite.quic_suite())
595            }
596            _ => None,
597        })
598        .flatten()
599}
600
601#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
602pub(crate) fn configured_provider() -> Arc<rustls::crypto::CryptoProvider> {
603    Arc::new(rustls::crypto::aws_lc_rs::default_provider())
604}
605
606#[cfg(feature = "ring")]
607pub(crate) fn configured_provider() -> Arc<rustls::crypto::CryptoProvider> {
608    Arc::new(rustls::crypto::ring::default_provider())
609}
610
611fn to_vec(params: &TransportParameters) -> Vec<u8> {
612    let mut bytes = Vec::new();
613    params.write(&mut bytes);
614    bytes
615}
616
617pub(crate) fn initial_keys(
618    version: Version,
619    dst_cid: ConnectionId,
620    side: Side,
621    suite: &Suite,
622) -> Keys {
623    let keys = suite.keys(&dst_cid, side.into(), version);
624    Keys {
625        header: KeyPair {
626            local: Box::new(keys.local.header),
627            remote: Box::new(keys.remote.header),
628        },
629        packet: KeyPair {
630            local: Box::new(keys.local.packet),
631            remote: Box::new(keys.remote.packet),
632        },
633    }
634}
635
636impl crypto::PacketKey for Box<dyn PacketKey> {
637    fn encrypt(&self, path_id: PathId, packet: u64, buf: &mut [u8], header_len: usize) {
638        let (header, payload_tag) = buf.split_at_mut(header_len);
639        let (payload, tag_storage) = payload_tag.split_at_mut(payload_tag.len() - self.tag_len());
640        let tag = self
641            .encrypt_in_place_for_path(path_id.as_u32(), packet, &*header, payload)
642            .unwrap();
643        tag_storage.copy_from_slice(tag.as_ref());
644    }
645
646    fn decrypt(
647        &self,
648        path_id: PathId,
649        packet: u64,
650        header: &[u8],
651        payload: &mut BytesMut,
652    ) -> Result<(), CryptoError> {
653        let plain = self
654            .decrypt_in_place_for_path(path_id.as_u32(), packet, header, payload.as_mut())
655            .map_err(|_| CryptoError)?;
656        let plain_len = plain.len();
657        payload.truncate(plain_len);
658        Ok(())
659    }
660
661    fn tag_len(&self) -> usize {
662        (**self).tag_len()
663    }
664
665    fn confidentiality_limit(&self) -> u64 {
666        (**self).confidentiality_limit()
667    }
668
669    fn integrity_limit(&self) -> u64 {
670        (**self).integrity_limit()
671    }
672}
673
674fn interpret_version(version: u32) -> Result<Version, UnsupportedVersion> {
675    match version {
676        0xff00_001d..=0xff00_0020 => Ok(Version::V1Draft),
677        0x0000_0001 | 0xff00_0021..=0xff00_0022 => Ok(Version::V1),
678        _ => Err(UnsupportedVersion),
679    }
680}