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};
#[cfg(feature = "ring")]
pub mod ring;
#[cfg(feature = "aws_lc_rs")]
pub mod aws_lc_rs;
pub mod cipher;
pub mod hash;
pub mod hmac;
#[cfg(feature = "tls12")]
pub mod tls12;
pub mod tls13;
pub mod hpke;
pub(crate) mod signer;
pub use crate::msgs::handshake::KeyExchangeAlgorithm;
pub use crate::rand::GetRandomFailed;
pub use crate::suites::CipherSuiteCommon;
#[derive(Debug, Clone)]
pub struct CryptoProvider {
pub cipher_suites: Vec<suites::SupportedCipherSuite>,
pub kx_groups: Vec<&'static dyn SupportedKxGroup>,
pub signature_verification_algorithms: WebPkiSupportedAlgorithms,
pub secure_random: &'static dyn SecureRandom,
pub key_provider: &'static dyn KeyProvider,
}
impl CryptoProvider {
pub fn install_default(self) -> Result<(), Arc<Self>> {
static_default::install_default(self)
}
pub fn get_default() -> Option<&'static Arc<Self>> {
static_default::get_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(r###"
Could not automatically determine the process-level CryptoProvider from Rustls crate features.
Call CryptoProvider::install_default() before this point to select a provider manually, or make sure exactly one of the 'aws-lc-rs' and 'ring' features is enabled.
See the documentation of the CryptoProvider type for more information.
"###);
let _ = provider.install_default();
Self::get_default().unwrap()
}
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
}
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()
}
}
pub trait SecureRandom: Send + Sync + Debug {
fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed>;
fn fips(&self) -> bool {
false
}
}
pub trait KeyProvider: Send + Sync + Debug {
fn load_private_key(
&self,
key_der: PrivateKeyDer<'static>,
) -> Result<Arc<dyn SigningKey>, Error>;
fn fips(&self) -> bool {
false
}
}
pub trait SupportedKxGroup: Send + Sync + Debug {
fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error>;
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)?,
})
}
fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> {
#[allow(deprecated)]
FfdheGroup::from_named_group(self.name())
}
fn name(&self) -> NamedGroup;
fn fips(&self) -> bool {
false
}
fn usable_for_version(&self, _version: ProtocolVersion) -> bool {
true
}
}
pub trait ActiveKeyExchange: Send + Sync {
fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error>;
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)
}
fn hybrid_component(&self) -> Option<(NamedGroup, &[u8])> {
None
}
fn complete_hybrid_component(
self: Box<Self>,
_peer_pub_key: &[u8],
) -> Result<SharedSecret, Error> {
unreachable!("only called if `hybrid_component()` implemented")
}
fn pub_key(&self) -> &[u8];
fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> {
#[allow(deprecated)]
FfdheGroup::from_named_group(self.group())
}
fn group(&self) -> NamedGroup;
}
pub struct CompletedKeyExchange {
pub group: NamedGroup,
pub pub_key: Vec<u8>,
pub secret: SharedSecret,
}
pub struct SharedSecret {
buf: Vec<u8>,
offset: usize,
}
impl SharedSecret {
pub fn secret_bytes(&self) -> &[u8] {
&self.buf[self.offset..]
}
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 }
}
}
#[cfg(all(feature = "aws_lc_rs", any(feature = "fips", rustls_docsrs)))]
#[cfg_attr(rustls_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);
}
}
}