use std::sync::Arc;
use rustls::ClientConfig;
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
pub enum TrustAnchors {
SystemPlusAdditional(Vec<CertificateDer<'static>>),
ExplicitOnly(Vec<CertificateDer<'static>>),
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum TlsVersion {
Tls12,
#[default]
Tls13,
}
pub struct TlsConfig {
pub trust_anchors: TrustAnchors,
pub client_cert: Option<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)>,
pub min_tls_version: TlsVersion,
#[cfg(feature = "danger-disable-verify")]
pub danger_disable_verification: bool,
}
impl Default for TlsConfig {
fn default() -> Self {
Self {
trust_anchors: TrustAnchors::SystemPlusAdditional(Vec::new()),
client_cert: None,
min_tls_version: TlsVersion::default(),
#[cfg(feature = "danger-disable-verify")]
danger_disable_verification: false,
}
}
}
impl TlsConfig {
pub fn build(self) -> Result<Arc<ClientConfig>, rustls::Error> {
#[cfg(feature = "danger-disable-verify")]
if self.danger_disable_verification {
let config = crate::conn::danger_no_verify_tls_config();
return Ok(Arc::new(config));
}
let root_store = match self.trust_anchors {
TrustAnchors::SystemPlusAdditional(extra) => {
let mut store = rustls::RootCertStore::from_iter(
webpki_roots::TLS_SERVER_ROOTS.iter().cloned(),
);
for cert in extra {
store.add(cert)?;
}
store
}
TrustAnchors::ExplicitOnly(certs) => {
let mut store = rustls::RootCertStore::empty();
for cert in certs {
store.add(cert)?;
}
store
}
};
let versions: &[&rustls::SupportedProtocolVersion] = match self.min_tls_version {
TlsVersion::Tls13 => &[&rustls::version::TLS13],
TlsVersion::Tls12 => &[&rustls::version::TLS12, &rustls::version::TLS13],
};
let builder = ClientConfig::builder_with_protocol_versions(versions)
.with_root_certificates(root_store);
let config = match self.client_cert {
Some((certs, key)) => builder.with_client_auth_cert(certs, key)?,
None => builder.with_no_client_auth(),
};
Ok(Arc::new(config))
}
}