use std::sync::Arc;
use rustls::crypto::CryptoProvider;
pub(crate) fn client_config() -> Result<rustls::ClientConfig, String> {
let mut roots = rustls::RootCertStore::empty();
roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
let provider = select_provider(CryptoProvider::get_default(), builtin_provider)?;
client_config_with(provider, roots)
}
pub(crate) fn client_config_with(
provider: Arc<CryptoProvider>,
roots: rustls::RootCertStore,
) -> Result<rustls::ClientConfig, String> {
Ok(rustls::ClientConfig::builder_with_provider(provider)
.with_safe_default_protocol_versions()
.map_err(|e| format!("the rustls crypto provider cannot do TLS 1.2 or 1.3: {e}"))?
.with_root_certificates(roots)
.with_no_client_auth())
}
fn select_provider(
installed: Option<&Arc<CryptoProvider>>,
builtin: impl FnOnce() -> Option<CryptoProvider>,
) -> Result<Arc<CryptoProvider>, String> {
if let Some(installed) = installed {
return Ok(Arc::clone(installed));
}
builtin().map(Arc::new).ok_or_else(|| {
"the outbound HTTP client needs a rustls crypto provider: enable the \
`rust_crypto` or `aws_lc_rs` feature, or install one with \
`rustls::crypto::CryptoProvider::install_default` before building the proxy"
.to_string()
})
}
#[cfg(feature = "aws_lc_rs")]
fn builtin_provider() -> Option<CryptoProvider> {
Some(rustls::crypto::aws_lc_rs::default_provider())
}
#[cfg(all(feature = "rust_crypto", not(feature = "aws_lc_rs")))]
fn builtin_provider() -> Option<CryptoProvider> {
Some(rustls_rustcrypto::provider())
}
#[cfg(not(any(feature = "rust_crypto", feature = "aws_lc_rs")))]
fn builtin_provider() -> Option<CryptoProvider> {
None
}
#[cfg(test)]
mod tests;