diff options
Diffstat (limited to 'vendor/rustls/src/crypto/mod.rs')
| -rw-r--r-- | vendor/rustls/src/crypto/mod.rs | 756 |
1 files changed, 0 insertions, 756 deletions
diff --git a/vendor/rustls/src/crypto/mod.rs b/vendor/rustls/src/crypto/mod.rs deleted file mode 100644 index 3ce026b9..00000000 --- a/vendor/rustls/src/crypto/mod.rs +++ /dev/null @@ -1,756 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt::Debug; - -use pki_types::PrivateKeyDer; -use zeroize::Zeroize; - -#[cfg(all(doc, feature = "tls12"))] -use crate::Tls12CipherSuite; -use crate::msgs::ffdhe_groups::FfdheGroup; -use crate::sign::SigningKey; -use crate::sync::Arc; -pub use crate::webpki::{ - WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature, - verify_tls13_signature_with_raw_key, -}; -#[cfg(doc)] -use crate::{ - ClientConfig, ConfigBuilder, ServerConfig, SupportedCipherSuite, Tls13CipherSuite, client, - crypto, server, sign, -}; -use crate::{Error, NamedGroup, ProtocolVersion, SupportedProtocolVersion, suites}; - -/// *ring* based CryptoProvider. -#[cfg(feature = "ring")] -pub mod ring; - -/// aws-lc-rs-based CryptoProvider. -#[cfg(feature = "aws_lc_rs")] -pub mod aws_lc_rs; - -/// TLS message encryption/decryption interfaces. -pub mod cipher; - -/// Hashing interfaces. -pub mod hash; - -/// HMAC interfaces. -pub mod hmac; - -#[cfg(feature = "tls12")] -/// Cryptography specific to TLS1.2. -pub mod tls12; - -/// Cryptography specific to TLS1.3. -pub mod tls13; - -/// Hybrid public key encryption (RFC 9180). -pub mod hpke; - -// Message signing interfaces. Re-exported under rustls::sign. Kept crate-internal here to -// avoid having two import paths to the same types. -pub(crate) mod signer; - -pub use crate::msgs::handshake::KeyExchangeAlgorithm; -pub use crate::rand::GetRandomFailed; -pub use crate::suites::CipherSuiteCommon; - -/// Controls core cryptography used by rustls. -/// -/// This crate comes with two built-in options, provided as -/// `CryptoProvider` structures: -/// -/// - [`crypto::aws_lc_rs::default_provider`]: (behind the `aws_lc_rs` crate feature, -/// which is enabled by default). This provider uses the [aws-lc-rs](https://github.com/aws/aws-lc-rs) -/// crate. The `fips` crate feature makes this option use FIPS140-3-approved cryptography. -/// - [`crypto::ring::default_provider`]: (behind the `ring` crate feature, which -/// is optional). This provider uses the [*ring*](https://github.com/briansmith/ring) -/// crate. -/// -/// This structure provides defaults. Everything in it can be overridden at -/// runtime by replacing field values as needed. -/// -/// # Using the per-process default `CryptoProvider` -/// -/// There is the concept of an implicit default provider, configured at run-time once in -/// a given process. -/// -/// It is used for functions like [`ClientConfig::builder()`] and [`ServerConfig::builder()`]. -/// -/// The intention is that an application can specify the [`CryptoProvider`] they wish to use -/// once, and have that apply to the variety of places where their application does TLS -/// (which may be wrapped inside other libraries). -/// They should do this by calling [`CryptoProvider::install_default()`] early on. -/// -/// To achieve this goal: -/// -/// - _libraries_ should use [`ClientConfig::builder()`]/[`ServerConfig::builder()`] -/// or otherwise rely on the [`CryptoProvider::get_default()`] provider. -/// - _applications_ should call [`CryptoProvider::install_default()`] early -/// in their `fn main()`. If _applications_ uses a custom provider based on the one built-in, -/// they can activate the `custom-provider` feature to ensure its usage. -/// -/// # Using a specific `CryptoProvider` -/// -/// Supply the provider when constructing your [`ClientConfig`] or [`ServerConfig`]: -/// -/// - [`ClientConfig::builder_with_provider()`] -/// - [`ServerConfig::builder_with_provider()`] -/// -/// When creating and configuring a webpki-backed client or server certificate verifier, a choice of -/// provider is also needed to start the configuration process: -/// -/// - [`client::WebPkiServerVerifier::builder_with_provider()`] -/// - [`server::WebPkiClientVerifier::builder_with_provider()`] -/// -/// If you install a custom provider and want to avoid any accidental use of a built-in provider, the feature -/// `custom-provider` can be activated to ensure your custom provider is used everywhere -/// and not a built-in one. This will disable any implicit use of a built-in provider. -/// -/// # Making a custom `CryptoProvider` -/// -/// Your goal will be to populate an instance of this `CryptoProvider` struct. -/// -/// ## Which elements are required? -/// -/// There is no requirement that the individual elements ([`SupportedCipherSuite`], [`SupportedKxGroup`], -/// [`SigningKey`], etc.) come from the same crate. It is allowed and expected that uninteresting -/// elements would be delegated back to one of the default providers (statically) or a parent -/// provider (dynamically). -/// -/// For example, if we want to make a provider that just overrides key loading in the config builder -/// API (with [`ConfigBuilder::with_single_cert`], etc.), it might look like this: -/// -/// ``` -/// # #[cfg(feature = "aws_lc_rs")] { -/// # use std::sync::Arc; -/// # mod fictious_hsm_api { pub fn load_private_key(key_der: pki_types::PrivateKeyDer<'static>) -> ! { unreachable!(); } } -/// use rustls::crypto::aws_lc_rs; -/// -/// pub fn provider() -> rustls::crypto::CryptoProvider { -/// rustls::crypto::CryptoProvider{ -/// key_provider: &HsmKeyLoader, -/// ..aws_lc_rs::default_provider() -/// } -/// } -/// -/// #[derive(Debug)] -/// struct HsmKeyLoader; -/// -/// impl rustls::crypto::KeyProvider for HsmKeyLoader { -/// fn load_private_key(&self, key_der: pki_types::PrivateKeyDer<'static>) -> Result<Arc<dyn rustls::sign::SigningKey>, rustls::Error> { -/// fictious_hsm_api::load_private_key(key_der) -/// } -/// } -/// # } -/// ``` -/// -/// ## References to the individual elements -/// -/// The elements are documented separately: -/// -/// - **Random** - see [`crypto::SecureRandom::fill()`]. -/// - **Cipher suites** - see [`SupportedCipherSuite`], [`Tls12CipherSuite`], and -/// [`Tls13CipherSuite`]. -/// - **Key exchange groups** - see [`crypto::SupportedKxGroup`]. -/// - **Signature verification algorithms** - see [`crypto::WebPkiSupportedAlgorithms`]. -/// - **Authentication key loading** - see [`crypto::KeyProvider::load_private_key()`] and -/// [`sign::SigningKey`]. -/// -/// # Example code -/// -/// See custom [`provider-example/`] for a full client and server example that uses -/// cryptography from the [`RustCrypto`] and [`dalek-cryptography`] projects. -/// -/// ```shell -/// $ cargo run --example client | head -3 -/// Current ciphersuite: TLS13_CHACHA20_POLY1305_SHA256 -/// HTTP/1.1 200 OK -/// Content-Type: text/html; charset=utf-8 -/// Content-Length: 19899 -/// ``` -/// -/// [`provider-example/`]: https://github.com/rustls/rustls/tree/main/provider-example/ -/// [`RustCrypto`]: https://github.com/RustCrypto -/// [`dalek-cryptography`]: https://github.com/dalek-cryptography -/// -/// # FIPS-approved cryptography -/// The `fips` crate feature enables use of the `aws-lc-rs` crate in FIPS mode. -/// -/// You can verify the configuration at runtime by checking -/// [`ServerConfig::fips()`]/[`ClientConfig::fips()`] return `true`. -#[derive(Debug, Clone)] -pub struct CryptoProvider { - /// List of supported ciphersuites, in preference order -- the first element - /// is the highest priority. - /// - /// The `SupportedCipherSuite` type carries both configuration and implementation. - /// - /// A valid `CryptoProvider` must ensure that all cipher suites are accompanied by at least - /// one matching key exchange group in [`CryptoProvider::kx_groups`]. - pub cipher_suites: Vec<suites::SupportedCipherSuite>, - - /// List of supported key exchange groups, in preference order -- the - /// first element is the highest priority. - /// - /// The first element in this list is the _default key share algorithm_, - /// and in TLS1.3 a key share for it is sent in the client hello. - /// - /// The `SupportedKxGroup` type carries both configuration and implementation. - pub kx_groups: Vec<&'static dyn SupportedKxGroup>, - - /// List of signature verification algorithms for use with webpki. - /// - /// These are used for both certificate chain verification and handshake signature verification. - /// - /// This is called by [`ConfigBuilder::with_root_certificates()`], - /// [`server::WebPkiClientVerifier::builder_with_provider()`] and - /// [`client::WebPkiServerVerifier::builder_with_provider()`]. - pub signature_verification_algorithms: WebPkiSupportedAlgorithms, - - /// Source of cryptographically secure random numbers. - pub secure_random: &'static dyn SecureRandom, - - /// Provider for loading private [`SigningKey`]s from [`PrivateKeyDer`]. - pub key_provider: &'static dyn KeyProvider, -} - -impl CryptoProvider { - /// Sets this `CryptoProvider` as the default for this process. - /// - /// This can be called successfully at most once in any process execution. - /// - /// Call this early in your process to configure which provider is used for - /// the provider. The configuration should happen before any use of - /// [`ClientConfig::builder()`] or [`ServerConfig::builder()`]. - pub fn install_default(self) -> Result<(), Arc<Self>> { - static_default::install_default(self) - } - - /// Returns the default `CryptoProvider` for this process. - /// - /// This will be `None` if no default has been set yet. - pub fn get_default() -> Option<&'static Arc<Self>> { - static_default::get_default() - } - - /// An internal function that: - /// - /// - gets the pre-installed default, or - /// - installs one `from_crate_features()`, or else - /// - panics about the need to call [`CryptoProvider::install_default()`] - pub(crate) fn get_default_or_install_from_crate_features() -> &'static Arc<Self> { - if let Some(provider) = Self::get_default() { - return provider; - } - - let provider = Self::from_crate_features() - .expect("no process-level CryptoProvider available -- call CryptoProvider::install_default() before this point"); - // Ignore the error resulting from us losing a race, and accept the outcome. - let _ = provider.install_default(); - Self::get_default().unwrap() - } - - /// Returns a provider named unambiguously by rustls crate features. - /// - /// This function returns `None` if the crate features are ambiguous (ie, specify two - /// providers), or specify no providers, or the feature `custom-provider` is activated. - /// In all cases the application should explicitly specify the provider to use - /// with [`CryptoProvider::install_default`]. - fn from_crate_features() -> Option<Self> { - #[cfg(all( - feature = "ring", - not(feature = "aws_lc_rs"), - not(feature = "custom-provider") - ))] - { - return Some(ring::default_provider()); - } - - #[cfg(all( - feature = "aws_lc_rs", - not(feature = "ring"), - not(feature = "custom-provider") - ))] - { - return Some(aws_lc_rs::default_provider()); - } - - #[allow(unreachable_code)] - None - } - - /// Returns `true` if this `CryptoProvider` is operating in FIPS mode. - /// - /// This covers only the cryptographic parts of FIPS approval. There are - /// also TLS protocol-level recommendations made by NIST. You should - /// prefer to call [`ClientConfig::fips()`] or [`ServerConfig::fips()`] - /// which take these into account. - pub fn fips(&self) -> bool { - let Self { - cipher_suites, - kx_groups, - signature_verification_algorithms, - secure_random, - key_provider, - } = self; - cipher_suites.iter().all(|cs| cs.fips()) - && kx_groups.iter().all(|kx| kx.fips()) - && signature_verification_algorithms.fips() - && secure_random.fips() - && key_provider.fips() - } -} - -/// A source of cryptographically secure randomness. -pub trait SecureRandom: Send + Sync + Debug { - /// Fill the given buffer with random bytes. - /// - /// The bytes must be sourced from a cryptographically secure random number - /// generator seeded with good quality, secret entropy. - /// - /// This is used for all randomness required by rustls, but not necessarily - /// randomness required by the underlying cryptography library. For example: - /// [`SupportedKxGroup::start()`] requires random material to generate - /// an ephemeral key exchange key, but this is not included in the interface with - /// rustls: it is assumed that the cryptography library provides for this itself. - fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed>; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -/// A mechanism for loading private [`SigningKey`]s from [`PrivateKeyDer`]. -/// -/// This trait is intended to be used with private key material that is sourced from DER, -/// such as a private-key that may be present on-disk. It is not intended to be used with -/// keys held in hardware security modules (HSMs) or physical tokens. For these use-cases -/// see the Rustls manual section on [customizing private key usage]. -/// -/// [customizing private key usage]: <https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#customising-private-key-usage> -pub trait KeyProvider: Send + Sync + Debug { - /// Decode and validate a private signing key from `key_der`. - /// - /// This is used by [`ConfigBuilder::with_client_auth_cert()`], [`ConfigBuilder::with_single_cert()`], - /// and [`ConfigBuilder::with_single_cert_with_ocsp()`]. The key types and formats supported by this - /// function directly defines the key types and formats supported in those APIs. - /// - /// Return an error if the key type encoding is not supported, or if the key fails validation. - fn load_private_key( - &self, - key_der: PrivateKeyDer<'static>, - ) -> Result<Arc<dyn SigningKey>, Error>; - - /// Return `true` if this is backed by a FIPS-approved implementation. - /// - /// If this returns `true`, that must be the case for all possible key types - /// supported by [`KeyProvider::load_private_key()`]. - fn fips(&self) -> bool { - false - } -} - -/// A supported key exchange group. -/// -/// This type carries both configuration and implementation. Specifically, -/// it has a TLS-level name expressed using the [`NamedGroup`] enum, and -/// a function which produces a [`ActiveKeyExchange`]. -/// -/// Compare with [`NamedGroup`], which carries solely a protocol identifier. -pub trait SupportedKxGroup: Send + Sync + Debug { - /// Start a key exchange. - /// - /// This will prepare an ephemeral secret key in the supported group, and a corresponding - /// public key. The key exchange can be completed by calling [ActiveKeyExchange#complete] - /// or discarded. - /// - /// # Errors - /// - /// This can fail if the random source fails during ephemeral key generation. - fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error>; - - /// Start and complete a key exchange, in one operation. - /// - /// The default implementation for this calls `start()` and then calls - /// `complete()` on the result. This is suitable for Diffie-Hellman-like - /// key exchange algorithms, where there is not a data dependency between - /// our key share (named "pub_key" in this API) and the peer's (`peer_pub_key`). - /// - /// If there is such a data dependency (like key encapsulation mechanisms), this - /// function should be implemented. - fn start_and_complete(&self, peer_pub_key: &[u8]) -> Result<CompletedKeyExchange, Error> { - let kx = self.start()?; - - Ok(CompletedKeyExchange { - group: kx.group(), - pub_key: kx.pub_key().to_vec(), - secret: kx.complete(peer_pub_key)?, - }) - } - - /// FFDHE group the `SupportedKxGroup` operates in. - /// - /// Return `None` if this group is not a FFDHE one. - /// - /// The default implementation calls `FfdheGroup::from_named_group`: this function - /// is extremely linker-unfriendly so it is recommended all key exchange implementers - /// provide this function. - /// - /// `rustls::ffdhe_groups` contains suitable values to return from this, - /// for example [`rustls::ffdhe_groups::FFDHE2048`][crate::ffdhe_groups::FFDHE2048]. - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - #[allow(deprecated)] - FfdheGroup::from_named_group(self.name()) - } - - /// Named group the SupportedKxGroup operates in. - /// - /// If the `NamedGroup` enum does not have a name for the algorithm you are implementing, - /// you can use [`NamedGroup::Unknown`]. - fn name(&self) -> NamedGroup; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } - - /// Return `true` if this should be offered/selected with the given version. - /// - /// The default implementation returns true for all versions. - fn usable_for_version(&self, _version: ProtocolVersion) -> bool { - true - } -} - -/// An in-progress key exchange originating from a [`SupportedKxGroup`]. -pub trait ActiveKeyExchange: Send + Sync { - /// Completes the key exchange, given the peer's public key. - /// - /// This method must return an error if `peer_pub_key` is invalid: either - /// mis-encoded, or an invalid public key (such as, but not limited to, being - /// in a small order subgroup). - /// - /// If the key exchange algorithm is FFDHE, the result must be left-padded with zeros, - /// as required by [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446#section-7.4.1) - /// (see [`complete_for_tls_version()`](Self::complete_for_tls_version) for more details). - /// - /// The shared secret is returned as a [`SharedSecret`] which can be constructed - /// from a `&[u8]`. - /// - /// This consumes and so terminates the [`ActiveKeyExchange`]. - fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error>; - - /// Completes the key exchange for the given TLS version, given the peer's public key. - /// - /// Note that finite-field Diffie–Hellman key exchange has different requirements for the derived - /// shared secret in TLS 1.2 and TLS 1.3 (ECDHE key exchange is the same in TLS 1.2 and TLS 1.3): - /// - /// In TLS 1.2, the calculated secret is required to be stripped of leading zeros - /// [(RFC 5246)](https://www.rfc-editor.org/rfc/rfc5246#section-8.1.2). - /// - /// In TLS 1.3, the calculated secret is required to be padded with leading zeros to be the same - /// byte-length as the group modulus [(RFC 8446)](https://www.rfc-editor.org/rfc/rfc8446#section-7.4.1). - /// - /// The default implementation of this method delegates to [`complete()`](Self::complete) assuming it is - /// implemented for TLS 1.3 (i.e., for FFDHE KX, removes padding as needed). Implementers of this trait - /// are encouraged to just implement [`complete()`](Self::complete) assuming TLS 1.3, and let the default - /// implementation of this method handle TLS 1.2-specific requirements. - /// - /// This method must return an error if `peer_pub_key` is invalid: either - /// mis-encoded, or an invalid public key (such as, but not limited to, being - /// in a small order subgroup). - /// - /// The shared secret is returned as a [`SharedSecret`] which can be constructed - /// from a `&[u8]`. - /// - /// This consumes and so terminates the [`ActiveKeyExchange`]. - fn complete_for_tls_version( - self: Box<Self>, - peer_pub_key: &[u8], - tls_version: &SupportedProtocolVersion, - ) -> Result<SharedSecret, Error> { - if tls_version.version != ProtocolVersion::TLSv1_2 { - return self.complete(peer_pub_key); - } - - let group = self.group(); - let mut complete_res = self.complete(peer_pub_key)?; - if group.key_exchange_algorithm() == KeyExchangeAlgorithm::DHE { - complete_res.strip_leading_zeros(); - } - Ok(complete_res) - } - - /// For hybrid key exchanges, returns the [`NamedGroup`] and key share - /// for the classical half of this key exchange. - /// - /// There is no requirement for a hybrid scheme (or any other!) to implement - /// `hybrid_component()`. It only enables an optimization; described below. - /// - /// "Hybrid" means a key exchange algorithm which is constructed from two - /// (or more) independent component algorithms. Usually one is post-quantum-secure, - /// and the other is "classical". See - /// <https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/11/> - /// - /// # Background - /// Rustls always sends a presumptive key share in its `ClientHello`, using - /// (absent any other information) the first item in [`CryptoProvider::kx_groups`]. - /// If the server accepts the client's selection, it can complete the handshake - /// using that key share. If not, the server sends a `HelloRetryRequest` instructing - /// the client to send a different key share instead. - /// - /// This request costs an extra round trip, and wastes the key exchange computation - /// (in [`SupportedKxGroup::start()`]) the client already did. We would - /// like to avoid those wastes if possible. - /// - /// It is early days for post-quantum-secure hybrid key exchange deployment. - /// This means (commonly) continuing to offer both the hybrid and classical - /// key exchanges, so the handshake can be completed without a `HelloRetryRequest` - /// for servers that support the offered hybrid or classical schemes. - /// - /// Implementing `hybrid_component()` enables two optimizations: - /// - /// 1. Sending both the hybrid and classical key shares in the `ClientHello`. - /// - /// 2. Performing the classical key exchange setup only once. This is important - /// because the classical key exchange setup is relatively expensive. - /// This optimization is permitted and described in - /// <https://www.ietf.org/archive/id/draft-ietf-tls-hybrid-design-11.html#section-3.2> - /// - /// Both of these only happen if the classical algorithm appears separately in - /// the client's [`CryptoProvider::kx_groups`], and if the hybrid algorithm appears - /// first in that list. - /// - /// # How it works - /// This function is only called by rustls for clients. It is called when - /// constructing the initial `ClientHello`. rustls follows these steps: - /// - /// 1. If the return value is `None`, nothing further happens. - /// 2. If the given [`NamedGroup`] does not appear in - /// [`CryptoProvider::kx_groups`], nothing further happens. - /// 3. The given key share is added to the `ClientHello`, after the hybrid entry. - /// - /// Then, one of three things may happen when the server replies to the `ClientHello`: - /// - /// 1. The server sends a `HelloRetryRequest`. Everything is thrown away and - /// we start again. - /// 2. The server agrees to our hybrid key exchange: rustls calls - /// [`ActiveKeyExchange::complete()`] consuming `self`. - /// 3. The server agrees to our classical key exchange: rustls calls - /// [`ActiveKeyExchange::complete_hybrid_component()`] which - /// discards the hybrid key data, and completes just the classical key exchange. - fn hybrid_component(&self) -> Option<(NamedGroup, &[u8])> { - None - } - - /// Completes the classical component of the key exchange, given the peer's public key. - /// - /// This is only called if `hybrid_component` returns `Some(_)`. - /// - /// This method must return an error if `peer_pub_key` is invalid: either - /// mis-encoded, or an invalid public key (such as, but not limited to, being - /// in a small order subgroup). - /// - /// The shared secret is returned as a [`SharedSecret`] which can be constructed - /// from a `&[u8]`. - /// - /// See the documentation on [`Self::hybrid_component()`] for explanation. - fn complete_hybrid_component( - self: Box<Self>, - _peer_pub_key: &[u8], - ) -> Result<SharedSecret, Error> { - unreachable!("only called if `hybrid_component()` implemented") - } - - /// Return the public key being used. - /// - /// For ECDHE, the encoding required is defined in - /// [RFC8446 section 4.2.8.2](https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2). - /// - /// For FFDHE, the encoding required is defined in - /// [RFC8446 section 4.2.8.1](https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.1). - fn pub_key(&self) -> &[u8]; - - /// FFDHE group the `ActiveKeyExchange` is operating in. - /// - /// Return `None` if this group is not a FFDHE one. - /// - /// The default implementation calls `FfdheGroup::from_named_group`: this function - /// is extremely linker-unfriendly so it is recommended all key exchange implementers - /// provide this function. - /// - /// `rustls::ffdhe_groups` contains suitable values to return from this, - /// for example [`rustls::ffdhe_groups::FFDHE2048`][crate::ffdhe_groups::FFDHE2048]. - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - #[allow(deprecated)] - FfdheGroup::from_named_group(self.group()) - } - - /// Return the group being used. - fn group(&self) -> NamedGroup; -} - -/// The result from [`SupportedKxGroup::start_and_complete()`]. -pub struct CompletedKeyExchange { - /// Which group was used. - pub group: NamedGroup, - - /// Our key share (sometimes a public key). - pub pub_key: Vec<u8>, - - /// The computed shared secret. - pub secret: SharedSecret, -} - -/// The result from [`ActiveKeyExchange::complete`] or [`ActiveKeyExchange::complete_hybrid_component`]. -pub struct SharedSecret { - buf: Vec<u8>, - offset: usize, -} - -impl SharedSecret { - /// Returns the shared secret as a slice of bytes. - pub fn secret_bytes(&self) -> &[u8] { - &self.buf[self.offset..] - } - - /// Removes leading zeros from `secret_bytes()` by adjusting the `offset`. - /// - /// This function does not re-allocate. - fn strip_leading_zeros(&mut self) { - let start = self - .secret_bytes() - .iter() - .enumerate() - .find(|(_i, x)| **x != 0) - .map(|(i, _x)| i) - .unwrap_or(self.secret_bytes().len()); - self.offset += start; - } -} - -impl Drop for SharedSecret { - fn drop(&mut self) { - self.buf.zeroize(); - } -} - -impl From<&[u8]> for SharedSecret { - fn from(source: &[u8]) -> Self { - Self { - buf: source.to_vec(), - offset: 0, - } - } -} - -impl From<Vec<u8>> for SharedSecret { - fn from(buf: Vec<u8>) -> Self { - Self { buf, offset: 0 } - } -} - -/// This function returns a [`CryptoProvider`] that uses -/// FIPS140-3-approved cryptography. -/// -/// Using this function expresses in your code that you require -/// FIPS-approved cryptography, and will not compile if you make -/// a mistake with cargo features. -/// -/// See our [FIPS documentation](crate::manual::_06_fips) for -/// more detail. -/// -/// Install this as the process-default provider, like: -/// -/// ```rust -/// # #[cfg(feature = "fips")] { -/// rustls::crypto::default_fips_provider().install_default() -/// .expect("default provider already set elsewhere"); -/// # } -/// ``` -/// -/// You can also use this explicitly, like: -/// -/// ```rust -/// # #[cfg(feature = "fips")] { -/// # let root_store = rustls::RootCertStore::empty(); -/// let config = rustls::ClientConfig::builder_with_provider( -/// rustls::crypto::default_fips_provider().into() -/// ) -/// .with_safe_default_protocol_versions() -/// .unwrap() -/// .with_root_certificates(root_store) -/// .with_no_client_auth(); -/// # } -/// ``` -#[cfg(all(feature = "aws_lc_rs", any(feature = "fips", docsrs)))] -#[cfg_attr(docsrs, doc(cfg(feature = "fips")))] -pub fn default_fips_provider() -> CryptoProvider { - aws_lc_rs::default_provider() -} - -mod static_default { - #[cfg(not(feature = "std"))] - use alloc::boxed::Box; - #[cfg(feature = "std")] - use std::sync::OnceLock; - - #[cfg(not(feature = "std"))] - use once_cell::race::OnceBox; - - use super::CryptoProvider; - use crate::sync::Arc; - - #[cfg(feature = "std")] - pub(crate) fn install_default( - default_provider: CryptoProvider, - ) -> Result<(), Arc<CryptoProvider>> { - PROCESS_DEFAULT_PROVIDER.set(Arc::new(default_provider)) - } - - #[cfg(not(feature = "std"))] - pub(crate) fn install_default( - default_provider: CryptoProvider, - ) -> Result<(), Arc<CryptoProvider>> { - PROCESS_DEFAULT_PROVIDER - .set(Box::new(Arc::new(default_provider))) - .map_err(|e| *e) - } - - pub(crate) fn get_default() -> Option<&'static Arc<CryptoProvider>> { - PROCESS_DEFAULT_PROVIDER.get() - } - - #[cfg(feature = "std")] - static PROCESS_DEFAULT_PROVIDER: OnceLock<Arc<CryptoProvider>> = OnceLock::new(); - #[cfg(not(feature = "std"))] - static PROCESS_DEFAULT_PROVIDER: OnceBox<Arc<CryptoProvider>> = OnceBox::new(); -} - -#[cfg(test)] -mod tests { - use std::vec; - - use super::SharedSecret; - - #[test] - fn test_shared_secret_strip_leading_zeros() { - let test_cases = [ - (vec![0, 1], vec![1]), - (vec![1], vec![1]), - (vec![1, 0, 2], vec![1, 0, 2]), - (vec![0, 0, 1, 2], vec![1, 2]), - (vec![0, 0, 0], vec![]), - (vec![], vec![]), - ]; - for (buf, expected) in test_cases { - let mut secret = SharedSecret::from(&buf[..]); - assert_eq!(secret.secret_bytes(), buf); - secret.strip_leading_zeros(); - assert_eq!(secret.secret_bytes(), expected); - } - } -} |
