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