use anyhow::{Context, Result};
use rustls::pki_types::pem::PemObject;
use rustls::pki_types::CertificateDer;
use rustls::{ClientConfig, RootCertStore};
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Security {
None,
#[serde(rename = "starttls")]
StartTls,
#[serde(rename = "ssl")]
Implicit,
}
impl Security {
pub fn as_str(self) -> &'static str {
match self {
Security::None => "none",
Security::StartTls => "starttls",
Security::Implicit => "ssl",
}
}
}
pub fn build_client_config(ca_file: Option<&Path>, insecure: bool) -> Result<Arc<ClientConfig>> {
let mut roots = RootCertStore::empty();
roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
if let Some(path) = ca_file {
let certs: Vec<CertificateDer<'static>> = CertificateDer::pem_file_iter(path)
.with_context(|| format!("opening CA bundle {}", path.display()))?
.collect::<std::result::Result<Vec<_>, _>>()
.with_context(|| format!("parsing CA PEM {}", path.display()))?;
for cert in certs {
roots.add(cert).context("adding user CA to root store")?;
}
}
let config = if insecure {
let mut cfg = ClientConfig::builder()
.with_root_certificates(roots)
.with_no_client_auth();
cfg.dangerous()
.set_certificate_verifier(Arc::new(danger::AcceptAnyCert));
cfg
} else {
ClientConfig::builder()
.with_root_certificates(roots)
.with_no_client_auth()
};
Ok(Arc::new(config))
}
mod danger {
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use rustls::{DigitallySignedStruct, Error, SignatureScheme};
#[derive(Debug)]
pub struct AcceptAnyCert;
impl ServerCertVerifier for AcceptAnyCert {
fn verify_server_cert(
&self,
_end: &CertificateDer<'_>,
_ints: &[CertificateDer<'_>],
_sn: &ServerName<'_>,
_ocsp: &[u8],
_now: UnixTime,
) -> Result<ServerCertVerified, Error> {
Ok(ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
_m: &[u8],
_c: &CertificateDer<'_>,
_d: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn verify_tls13_signature(
&self,
_m: &[u8],
_c: &CertificateDer<'_>,
_d: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
vec![
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::ED25519,
]
}
}
}