rustls/crypto/mod.rs
1use alloc::borrow::Cow;
2use alloc::boxed::Box;
3use alloc::vec::Vec;
4use core::borrow::Borrow;
5use core::fmt::{self, Debug};
6use core::hash::{Hash, Hasher};
7use core::time::Duration;
8
9use pki_types::{FipsStatus, PrivateKeyDer, SignatureVerificationAlgorithm};
10
11use crate::crypto::kx::KeyExchangeAlgorithm;
12use crate::enums::ProtocolVersion;
13#[cfg(feature = "webpki")]
14use crate::error::PeerMisbehaved;
15use crate::error::{ApiMisuse, Error};
16use crate::msgs::ALL_KEY_EXCHANGE_ALGORITHMS;
17use crate::sync::Arc;
18#[cfg(feature = "webpki")]
19pub use crate::webpki::{verify_tls12_signature, verify_tls13_signature};
20#[cfg(doc)]
21use crate::{ClientConfig, ConfigBuilder, ServerConfig, client, crypto, server};
22use crate::{SupportedCipherSuite, Tls12CipherSuite, Tls13CipherSuite};
23
24/// TLS message encryption/decryption interfaces.
25pub mod cipher;
26
27mod enums;
28pub use enums::{CipherSuite, HashAlgorithm, SignatureAlgorithm, SignatureScheme};
29
30/// Hashing interfaces.
31pub mod hash;
32
33/// HMAC interfaces.
34pub mod hmac;
35
36/// Key exchange interfaces.
37pub mod kx;
38use kx::{NamedGroup, SupportedKxGroup};
39
40/// Cryptography specific to TLS1.2.
41pub mod tls12;
42
43/// Cryptography specific to TLS1.3.
44pub mod tls13;
45
46/// Hybrid public key encryption (RFC 9180).
47pub mod hpke;
48
49#[cfg(any(doc, test))]
50pub(crate) mod test_provider;
51#[cfg(test)]
52pub(crate) use test_provider::TEST_PROVIDER;
53#[cfg(doc)]
54#[doc(hidden)]
55pub use test_provider::TEST_PROVIDER;
56#[cfg(all(test, any(target_arch = "aarch64", target_arch = "x86_64")))]
57pub(crate) use test_provider::TLS13_TEST_SUITE;
58
59// Message signing interfaces.
60mod signer;
61pub use signer::{
62 CertificateIdentity, Credentials, Identity, InconsistentKeys, SelectedCredential, Signer,
63 SigningKey, SingleCredential, VerifiedIdentity, public_key_to_spki,
64};
65
66pub use crate::suites::CipherSuiteCommon;
67
68/// Controls core cryptography used by rustls.
69///
70/// This structure provides defaults. Everything in it can be overridden at
71/// runtime by replacing field values as needed.
72///
73/// # Using a specific `CryptoProvider`
74///
75/// Supply the provider when constructing your [`ClientConfig`] or [`ServerConfig`]:
76///
77/// - [`ClientConfig::builder()`][crate::ClientConfig::builder()]
78/// - [`ServerConfig::builder()`][crate::ServerConfig::builder()]
79///
80/// When creating and configuring a webpki-backed client or server certificate verifier, a choice of
81/// provider is also needed to start the configuration process:
82///
83/// - [`WebPkiServerVerifier::builder()`][crate::client::WebPkiServerVerifier::builder()]
84/// - [`WebPkiClientVerifier::builder()`][crate::server::WebPkiClientVerifier::builder()]
85///
86/// # Making a custom `CryptoProvider`
87///
88/// Your goal will be to populate an instance of this `CryptoProvider` struct.
89///
90/// ## Which elements are required?
91///
92/// There is no requirement that the individual elements ([`SupportedCipherSuite`], [`SupportedKxGroup`],
93/// [`SigningKey`], etc.) come from the same crate. It is allowed and expected that uninteresting
94/// elements would be delegated back to one of the default providers (statically) or a parent
95/// provider (dynamically).
96///
97/// For example, if we want to make a provider that just overrides key loading in the config builder
98/// API (with [`ConfigBuilder::with_single_cert`], etc.), it might look like this:
99///
100/// ```
101/// # use std::sync::Arc;
102/// # mod fictitious_hsm_api { pub fn load_private_key(key_der: pki_types::PrivateKeyDer<'static>) -> ! { unreachable!(); } }
103///
104/// pub fn provider() -> rustls::crypto::CryptoProvider {
105/// # let DEFAULT_PROVIDER = panic!();
106/// rustls::crypto::CryptoProvider {
107/// key_provider: &HsmKeyLoader,
108/// ..DEFAULT_PROVIDER
109/// }
110/// }
111///
112/// #[derive(Debug)]
113/// struct HsmKeyLoader;
114///
115/// impl rustls::crypto::KeyProvider for HsmKeyLoader {
116/// fn load_private_key(&self, key_der: pki_types::PrivateKeyDer<'static>) -> Result<Box<dyn rustls::crypto::SigningKey>, rustls::Error> {
117/// fictitious_hsm_api::load_private_key(key_der)
118/// }
119/// }
120/// ```
121///
122/// ## References to the individual elements
123///
124/// The elements are documented separately:
125///
126/// - **Random** - see [`SecureRandom::fill()`].
127/// - **Cipher suites** - see [`SupportedCipherSuite`], [`Tls12CipherSuite`], and
128/// [`Tls13CipherSuite`].
129/// - **Key exchange groups** - see [`SupportedKxGroup`].
130/// - **Signature verification algorithms** - see [`WebPkiSupportedAlgorithms`].
131/// - **Authentication key loading** - see [`KeyProvider::load_private_key()`] and
132/// [`SigningKey`].
133///
134/// # FIPS-approved cryptography
135///
136/// Each element of a `CryptoProvider` may be implemented using FIPS-approved cryptography,
137/// and the FIPS status of the overall provider is derived from the status of its elements.
138/// Call [`CryptoProvider::fips()`] to determine the FIPS status of a given provider.
139///
140/// You can verify the configuration at runtime by checking
141/// [`ServerConfig::fips()`]/[`ClientConfig::fips()`].
142#[expect(clippy::exhaustive_structs)]
143#[derive(Debug, Clone)]
144pub struct CryptoProvider {
145 /// List of supported TLS1.2 cipher suites, in preference order -- the first element
146 /// is the highest priority.
147 ///
148 /// Note that the protocol version is negotiated before the cipher suite.
149 ///
150 /// The `Tls12CipherSuite` type carries both configuration and implementation.
151 ///
152 /// A valid `CryptoProvider` must ensure that all cipher suites are accompanied by at least
153 /// one matching key exchange group in [`CryptoProvider::kx_groups`].
154 pub tls12_cipher_suites: Cow<'static, [&'static Tls12CipherSuite]>,
155
156 /// List of supported TLS1.3 cipher suites, in preference order -- the first element
157 /// is the highest priority.
158 ///
159 /// Note that the protocol version is negotiated before the cipher suite.
160 ///
161 /// The `Tls13CipherSuite` type carries both configuration and implementation.
162 pub tls13_cipher_suites: Cow<'static, [&'static Tls13CipherSuite]>,
163
164 /// List of supported key exchange groups, in preference order -- the
165 /// first element is the highest priority.
166 ///
167 /// The first element in this list is the _default key share algorithm_,
168 /// and in TLS1.3 a key share for it is sent in the client hello.
169 ///
170 /// The `SupportedKxGroup` type carries both configuration and implementation.
171 pub kx_groups: Cow<'static, [&'static dyn SupportedKxGroup]>,
172
173 /// List of signature verification algorithms for use with webpki.
174 ///
175 /// These are used for both certificate chain verification and handshake signature verification.
176 ///
177 /// This is called by [`ConfigBuilder::with_root_certificates()`],
178 /// [`server::WebPkiClientVerifier::builder()`] and
179 /// [`client::WebPkiServerVerifier::builder()`].
180 pub signature_verification_algorithms: WebPkiSupportedAlgorithms,
181
182 /// Source of cryptographically secure random numbers.
183 pub secure_random: &'static dyn SecureRandom,
184
185 /// Provider for loading private [`SigningKey`]s from [`PrivateKeyDer`].
186 pub key_provider: &'static dyn KeyProvider,
187
188 /// Provider for creating [`TicketProducer`]s for stateless session resumption.
189 pub ticketer_factory: &'static dyn TicketerFactory,
190}
191
192impl CryptoProvider {
193 /// Return the FIPS validation status for this `CryptoProvider`.
194 ///
195 /// This covers only the cryptographic parts of FIPS approval. There are
196 /// also TLS protocol-level recommendations made by NIST. You should
197 /// prefer to call [`ClientConfig::fips()`] or [`ServerConfig::fips()`]
198 /// which take these into account.
199 pub fn fips(&self) -> FipsStatus {
200 let Self {
201 tls12_cipher_suites,
202 tls13_cipher_suites,
203 kx_groups,
204 signature_verification_algorithms,
205 secure_random,
206 key_provider,
207 ticketer_factory,
208 } = self;
209
210 let mut status = Ord::min(
211 signature_verification_algorithms.fips(),
212 secure_random.fips(),
213 );
214 status = Ord::min(status, key_provider.fips());
215 status = Ord::min(status, ticketer_factory.fips());
216 for cs in tls12_cipher_suites.iter() {
217 status = Ord::min(status, cs.fips());
218 }
219 for cs in tls13_cipher_suites.iter() {
220 status = Ord::min(status, cs.fips());
221 }
222 for kx in kx_groups.iter() {
223 status = Ord::min(status, kx.fips());
224 }
225
226 status
227 }
228
229 pub(crate) fn consistency_check(&self) -> Result<(), Error> {
230 if self.tls12_cipher_suites.is_empty() && self.tls13_cipher_suites.is_empty() {
231 return Err(ApiMisuse::NoCipherSuitesConfigured.into());
232 }
233
234 if self.kx_groups.is_empty() {
235 return Err(ApiMisuse::NoKeyExchangeGroupsConfigured.into());
236 }
237
238 // verifying DHE kx groups return their actual group
239 for group in self.kx_groups.iter() {
240 if group.name().key_exchange_algorithm() == KeyExchangeAlgorithm::DHE
241 && group.ffdhe_group().is_none()
242 {
243 return Err(Error::General(alloc::format!(
244 "SupportedKxGroup {group:?} must return Some() from `ffdhe_group()`"
245 )));
246 }
247 }
248
249 // verifying cipher suites have matching kx groups
250 let mut supported_kx_algos = Vec::with_capacity(ALL_KEY_EXCHANGE_ALGORITHMS.len());
251 for group in self.kx_groups.iter() {
252 let kx = group.name().key_exchange_algorithm();
253 if !supported_kx_algos.contains(&kx) {
254 supported_kx_algos.push(kx);
255 }
256 // Small optimization. We don't need to go over other key exchange groups
257 // if we already cover all supported key exchange algorithms
258 if supported_kx_algos.len() == ALL_KEY_EXCHANGE_ALGORITHMS.len() {
259 break;
260 }
261 }
262
263 for cs in self.tls12_cipher_suites.iter() {
264 if supported_kx_algos.contains(&cs.kx) {
265 continue;
266 }
267 let suite_name = cs.common.suite;
268 return Err(Error::General(alloc::format!(
269 "TLS1.2 cipher suite {suite_name:?} requires {0:?} key exchange, but no {0:?}-compatible \
270 key exchange groups were present in `CryptoProvider`'s `kx_groups` field",
271 cs.kx,
272 )));
273 }
274
275 Ok(())
276 }
277
278 pub(crate) fn iter_cipher_suites(&self) -> impl Iterator<Item = SupportedCipherSuite> + '_ {
279 self.tls13_cipher_suites
280 .iter()
281 .copied()
282 .map(SupportedCipherSuite::Tls13)
283 .chain(
284 self.tls12_cipher_suites
285 .iter()
286 .copied()
287 .map(SupportedCipherSuite::Tls12),
288 )
289 }
290
291 /// We support a given TLS version if at least one ciphersuite for the version
292 /// is available.
293 pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool {
294 match v {
295 ProtocolVersion::TLSv1_2 => !self.tls12_cipher_suites.is_empty(),
296 ProtocolVersion::TLSv1_3 => !self.tls13_cipher_suites.is_empty(),
297 _ => false,
298 }
299 }
300
301 pub(crate) fn find_kx_group(
302 &self,
303 name: NamedGroup,
304 version: ProtocolVersion,
305 ) -> Option<&'static dyn SupportedKxGroup> {
306 if !name.usable_for_version(version) {
307 return None;
308 }
309 self.kx_groups
310 .iter()
311 .find(|skxg| skxg.name() == name)
312 .copied()
313 }
314}
315
316impl Borrow<[&'static Tls12CipherSuite]> for CryptoProvider {
317 fn borrow(&self) -> &[&'static Tls12CipherSuite] {
318 &self.tls12_cipher_suites
319 }
320}
321
322impl Borrow<[&'static Tls13CipherSuite]> for CryptoProvider {
323 fn borrow(&self) -> &[&'static Tls13CipherSuite] {
324 &self.tls13_cipher_suites
325 }
326}
327
328/// Describes which `webpki` signature verification algorithms are supported and
329/// how they map to TLS [`SignatureScheme`]s.
330///
331/// Create one with [`WebPkiSupportedAlgorithms::new`], which can be done in const-context.
332#[derive(Clone, Copy)]
333pub struct WebPkiSupportedAlgorithms {
334 /// A list of all supported signature verification algorithms.
335 ///
336 /// Used for verifying certificate chains.
337 ///
338 /// The order of this list is not significant. It may be empty, but the default
339 /// certificate verifier will reject all certificates so a custom verifier will be required.
340 pub(crate) all: &'static [&'static dyn SignatureVerificationAlgorithm],
341
342 /// A mapping from TLS `SignatureScheme`s to matching webpki signature verification algorithms.
343 ///
344 /// This field has invariants enforced by [`Self::new()`]:
345 ///
346 /// - The mappings must be non-empty.
347 /// - The list of verification algorithms for each mapping must be non-empty.
348 ///
349 /// This is one (`SignatureScheme`) to many ([`SignatureVerificationAlgorithm`]) because
350 /// (depending on the protocol version) there is not necessary a 1-to-1 mapping.
351 ///
352 /// For TLS1.2, all `SignatureVerificationAlgorithm`s are tried in sequence.
353 ///
354 /// For TLS1.3, only the first is tried.
355 ///
356 /// The supported schemes in this mapping is communicated to the peer and the order is significant.
357 /// The first mapping is our highest preference.
358 pub(crate) mapping: &'static [(
359 SignatureScheme,
360 &'static [&'static dyn SignatureVerificationAlgorithm],
361 )],
362}
363
364impl WebPkiSupportedAlgorithms {
365 /// Creating a `WebPkiSupportedAlgorithms` and checking its consistency.
366 ///
367 /// This is intended to only be called in const context, so the panics are
368 /// compile-time.
369 pub const fn new(
370 all: &'static [&'static dyn SignatureVerificationAlgorithm],
371 mapping: &'static [(
372 SignatureScheme,
373 &'static [&'static dyn SignatureVerificationAlgorithm],
374 )],
375 ) -> Result<Self, ApiMisuse> {
376 let s = Self { all, mapping };
377 if mapping.is_empty() {
378 return Err(ApiMisuse::NoSignatureVerificationAlgorithms);
379 }
380
381 // TODO: rewrite when feature(const_iter) and feature(const_for) are available
382 let mut i = 0;
383 while i < s.mapping.len() {
384 if s.mapping[i].1.is_empty() {
385 return Err(ApiMisuse::NoSignatureVerificationAlgorithms);
386 }
387 assert!(!s.mapping[i].1.is_empty());
388 i += 1;
389 }
390
391 Ok(s)
392 }
393
394 /// Return all the `scheme` items in `mapping`, maintaining order.
395 pub fn supported_schemes(&self) -> Vec<SignatureScheme> {
396 self.mapping
397 .iter()
398 .map(|item| item.0)
399 .collect()
400 }
401
402 /// Return the FIPS validation status of this implementation.
403 pub fn fips(&self) -> FipsStatus {
404 let algs = self
405 .all
406 .iter()
407 .map(|alg| alg.fips_status())
408 .min();
409 let mapped = self
410 .mapping
411 .iter()
412 .flat_map(|(_, algs)| algs.iter().map(|alg| alg.fips_status()))
413 .min();
414
415 match (algs, mapped) {
416 (Some(algs), Some(mapped)) => Ord::min(algs, mapped),
417 (Some(status), None) | (None, Some(status)) => status,
418 (None, None) => FipsStatus::Unvalidated,
419 }
420 }
421
422 /// Accessor for the `mapping` field.
423 pub fn mapping(
424 &self,
425 ) -> &'static [(
426 SignatureScheme,
427 &'static [&'static dyn SignatureVerificationAlgorithm],
428 )] {
429 self.mapping
430 }
431
432 /// Return the first item in `mapping` that matches `scheme`.
433 #[cfg(feature = "webpki")]
434 pub(crate) fn convert_scheme(
435 &self,
436 scheme: SignatureScheme,
437 ) -> Result<&[&'static dyn SignatureVerificationAlgorithm], Error> {
438 self.mapping
439 .iter()
440 .filter_map(|item| if item.0 == scheme { Some(item.1) } else { None })
441 .next()
442 .ok_or_else(|| PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into())
443 }
444}
445
446impl Debug for WebPkiSupportedAlgorithms {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 write!(f, "WebPkiSupportedAlgorithms {{ all: [ .. ], mapping: ")?;
449 f.debug_list()
450 .entries(self.mapping.iter().map(|item| item.0))
451 .finish()?;
452 write!(f, " }}")
453 }
454}
455
456impl Hash for WebPkiSupportedAlgorithms {
457 fn hash<H: Hasher>(&self, state: &mut H) {
458 let Self { all, mapping } = self;
459
460 write_algs(state, all);
461 state.write_usize(mapping.len());
462 for (scheme, algs) in *mapping {
463 state.write_u16(u16::from(*scheme));
464 write_algs(state, algs);
465 }
466
467 fn write_algs<H: Hasher>(
468 state: &mut H,
469 algs: &[&'static dyn SignatureVerificationAlgorithm],
470 ) {
471 state.write_usize(algs.len());
472 for alg in algs {
473 state.write(alg.public_key_alg_id().as_ref());
474 state.write(alg.signature_alg_id().as_ref());
475 }
476 }
477 }
478}
479
480pub(crate) mod rand {
481 use super::{GetRandomFailed, SecureRandom};
482
483 /// Make an array of size `N` containing random material.
484 pub(crate) fn random_array<const N: usize>(
485 secure_random: &dyn SecureRandom,
486 ) -> Result<[u8; N], GetRandomFailed> {
487 let mut v = [0; N];
488 secure_random.fill(&mut v)?;
489 Ok(v)
490 }
491
492 /// Return a uniformly random [`u32`].
493 pub(crate) fn random_u32(secure_random: &dyn SecureRandom) -> Result<u32, GetRandomFailed> {
494 Ok(u32::from_be_bytes(random_array(secure_random)?))
495 }
496
497 /// Return a uniformly random [`u16`].
498 pub(crate) fn random_u16(secure_random: &dyn SecureRandom) -> Result<u16, GetRandomFailed> {
499 Ok(u16::from_be_bytes(random_array(secure_random)?))
500 }
501}
502
503/// Random material generation failed.
504#[expect(clippy::exhaustive_structs)]
505#[derive(Debug)]
506pub struct GetRandomFailed;
507
508/// A source of cryptographically secure randomness.
509pub trait SecureRandom: Send + Sync + Debug {
510 /// Fill the given buffer with random bytes.
511 ///
512 /// The bytes must be sourced from a cryptographically secure random number
513 /// generator seeded with good quality, secret entropy.
514 ///
515 /// This is used for all randomness required by rustls, but not necessarily
516 /// randomness required by the underlying cryptography library. For example:
517 /// [`SupportedKxGroup::start()`] requires random material to generate
518 /// an ephemeral key exchange key, but this is not included in the interface with
519 /// rustls: it is assumed that the cryptography library provides for this itself.
520 fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed>;
521
522 /// Return the FIPS validation status of this implementation.
523 fn fips(&self) -> FipsStatus {
524 FipsStatus::Unvalidated
525 }
526}
527
528/// A mechanism for loading private [`SigningKey`]s from [`PrivateKeyDer`].
529///
530/// This trait is intended to be used with private key material that is sourced from DER,
531/// such as a private-key that may be present on-disk. It is not intended to be used with
532/// keys held in hardware security modules (HSMs) or physical tokens. For these use-cases
533/// see the Rustls manual section on [customizing private key usage].
534///
535/// [customizing private key usage]: <https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#customising-private-key-usage>
536pub trait KeyProvider: Send + Sync + Debug {
537 /// Decode and validate a private signing key from `key_der`.
538 ///
539 /// This is used by [`ConfigBuilder::with_client_auth_cert()`], [`ConfigBuilder::with_single_cert()`],
540 /// and [`ConfigBuilder::with_single_cert_with_ocsp()`]. The key types and formats supported by this
541 /// function directly defines the key types and formats supported in those APIs.
542 ///
543 /// Return an error if the key type encoding is not supported, or if the key fails validation.
544 fn load_private_key(
545 &self,
546 key_der: PrivateKeyDer<'static>,
547 ) -> Result<Box<dyn SigningKey>, Error>;
548
549 /// Return the FIPS validation status for this key provider.
550 ///
551 /// The returned status must cover all possible key types supported by
552 /// [`KeyProvider::load_private_key()`].
553 fn fips(&self) -> FipsStatus {
554 FipsStatus::Unvalidated
555 }
556}
557
558/// A factory that builds [`TicketProducer`]s.
559///
560/// These can be used in [`ServerConfig::ticketer`] to enable stateless resumption.
561///
562/// [`ServerConfig::ticketer`]: crate::server::ServerConfig::ticketer
563pub trait TicketerFactory: Debug + Send + Sync {
564 /// Build a new `TicketProducer`.
565 fn ticketer(&self) -> Result<Arc<dyn TicketProducer>, Error>;
566
567 /// Return the FIPS validation status of ticketers produced from here.
568 fn fips(&self) -> FipsStatus {
569 FipsStatus::Unvalidated
570 }
571}
572
573/// A trait for the ability to encrypt and decrypt tickets.
574pub trait TicketProducer: Debug + Send + Sync {
575 /// Encrypt and authenticate `plain`, returning the resulting
576 /// ticket. Return None if `plain` cannot be encrypted for
577 /// some reason: an empty ticket will be sent and the connection
578 /// will continue.
579 fn encrypt(&self, plain: &[u8]) -> Option<Vec<u8>>;
580
581 /// Decrypt `cipher`, validating its authenticity protection
582 /// and recovering the plaintext. `cipher` is fully attacker
583 /// controlled, so this decryption must be side-channel free,
584 /// panic-proof, and otherwise bullet-proof. If the decryption
585 /// fails, return None.
586 fn decrypt(&self, cipher: &[u8]) -> Option<Vec<u8>>;
587
588 /// Returns the lifetime of tickets produced now.
589 /// The lifetime is provided as a hint to clients that the
590 /// ticket will not be useful after the given time.
591 ///
592 /// This lifetime must be implemented by key rolling and
593 /// erasure, *not* by storing a lifetime in the ticket.
594 ///
595 /// The objective is to limit damage to forward secrecy caused
596 /// by tickets, not just limiting their lifetime.
597 fn lifetime(&self) -> Duration;
598}
599
600#[cfg(test)]
601#[track_caller]
602pub(crate) fn tls13_suite(
603 suite: CipherSuite,
604 provider: &CryptoProvider,
605) -> &'static Tls13CipherSuite {
606 provider
607 .tls13_cipher_suites
608 .iter()
609 .find(|cs| cs.common.suite == suite)
610 .unwrap()
611}
612
613#[cfg(test)]
614#[track_caller]
615pub(crate) fn tls12_suite(
616 suite: CipherSuite,
617 provider: &CryptoProvider,
618) -> &'static Tls12CipherSuite {
619 provider
620 .tls12_cipher_suites
621 .iter()
622 .find(|cs| cs.common.suite == suite)
623 .unwrap()
624}
625
626#[cfg(test)]
627#[track_caller]
628pub(crate) fn tls13_only(provider: CryptoProvider) -> CryptoProvider {
629 CryptoProvider {
630 tls12_cipher_suites: Cow::default(),
631 ..provider
632 }
633}
634
635#[cfg(test)]
636#[track_caller]
637pub(crate) fn tls12_only(provider: CryptoProvider) -> CryptoProvider {
638 CryptoProvider {
639 tls13_cipher_suites: Cow::default(),
640 ..provider
641 }
642}