use std::fmt;
use std::sync::Arc;
mod cert;
pub use cert::{parse_pem, Certificate, PemItem, PrivateKey};
#[cfg(feature = "_rustls")]
pub(crate) mod rustls;
#[cfg(feature = "native-tls")]
pub(crate) mod native_tls;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum TlsProvider {
Rustls,
NativeTls,
}
impl TlsProvider {
pub(crate) fn is_feature_enabled(&self) -> bool {
match self {
TlsProvider::Rustls => {
cfg!(feature = "_rustls")
}
TlsProvider::NativeTls => {
cfg!(feature = "native-tls")
}
}
}
pub(crate) fn feature_name(&self) -> &'static str {
match self {
TlsProvider::Rustls => "rustls",
TlsProvider::NativeTls => "native-tls",
}
}
}
#[derive(Clone)]
pub struct TlsConfig {
provider: TlsProvider,
client_cert: Option<ClientCert>,
root_certs: RootCerts,
use_sni: bool,
disable_verification: bool,
#[cfg(feature = "_rustls")]
rustls_crypto_provider: Option<Arc<::rustls::crypto::CryptoProvider>>,
}
impl TlsConfig {
pub fn builder() -> TlsConfigBuilder {
TlsConfigBuilder {
config: TlsConfig::default(),
}
}
}
impl TlsConfig {
pub fn provider(&self) -> TlsProvider {
self.provider
}
pub fn client_cert(&self) -> Option<&ClientCert> {
self.client_cert.as_ref()
}
pub fn root_certs(&self) -> &RootCerts {
&self.root_certs
}
pub fn use_sni(&self) -> bool {
self.use_sni
}
pub fn disable_verification(&self) -> bool {
self.disable_verification
}
#[cfg(feature = "_rustls")]
pub fn unversioned_rustls_crypto_provider(
&self,
) -> &Option<Arc<::rustls::crypto::CryptoProvider>> {
&self.rustls_crypto_provider
}
}
pub struct TlsConfigBuilder {
config: TlsConfig,
}
impl TlsConfigBuilder {
pub fn provider(mut self, v: TlsProvider) -> Self {
self.config.provider = v;
self
}
pub fn client_cert(mut self, v: Option<ClientCert>) -> Self {
self.config.client_cert = v;
self
}
pub fn root_certs(mut self, v: RootCerts) -> Self {
self.config.root_certs = v;
self
}
pub fn use_sni(mut self, v: bool) -> Self {
self.config.use_sni = v;
self
}
pub fn disable_verification(mut self, v: bool) -> Self {
self.config.disable_verification = v;
self
}
#[cfg(feature = "_rustls")]
pub fn unversioned_rustls_crypto_provider(
mut self,
v: Arc<::rustls::crypto::CryptoProvider>,
) -> Self {
self.config.rustls_crypto_provider = Some(v);
self
}
pub fn build(self) -> TlsConfig {
self.config
}
}
#[derive(Debug, Clone)]
pub struct ClientCert(Arc<(Vec<Certificate<'static>>, PrivateKey<'static>)>);
impl ClientCert {
pub fn new_with_certs(chain: &[Certificate<'static>], key: PrivateKey<'static>) -> Self {
Self(Arc::new((chain.to_vec(), key)))
}
pub fn certs(&self) -> &[Certificate<'static>] {
&self.0 .0
}
pub fn private_key(&self) -> &PrivateKey<'static> {
&self.0 .1
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum RootCerts {
Specific(Arc<Vec<Certificate<'static>>>),
PlatformVerifier,
WebPki,
}
impl RootCerts {
pub fn new_with_certs(certs: &[Certificate<'static>]) -> Self {
certs.iter().cloned().into()
}
}
impl<I: IntoIterator<Item = Certificate<'static>>> From<I> for RootCerts {
fn from(value: I) -> Self {
RootCerts::Specific(Arc::new(value.into_iter().collect()))
}
}
impl Default for TlsConfig {
fn default() -> Self {
let provider = TlsProvider::default();
Self {
provider,
client_cert: None,
root_certs: RootCerts::WebPki,
use_sni: true,
disable_verification: false,
#[cfg(feature = "_rustls")]
rustls_crypto_provider: None,
}
}
}
impl Default for TlsProvider {
fn default() -> Self {
Self::Rustls
}
}
impl fmt::Debug for TlsConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TlsConfig")
.field("provider", &self.provider)
.field("client_cert", &self.client_cert)
.field("root_certs", &self.root_certs)
.field("use_sni", &self.use_sni)
.field("disable_verification", &self.disable_verification)
.finish()
}
}
#[cfg(test)]
mod test {
use super::*;
use assert_no_alloc::*;
#[test]
fn tls_config_clone_does_not_allocate() {
let c = TlsConfig::default();
assert_no_alloc(|| c.clone());
}
}