1use anyhow::{Context, Result};
4use rustls::pki_types::pem::PemObject;
5use rustls::pki_types::CertificateDer;
6use rustls::{ClientConfig, RootCertStore};
7use serde::{Deserialize, Serialize};
8use std::path::Path;
9use std::sync::Arc;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "lowercase")]
14pub enum Security {
15 None,
17 #[serde(rename = "starttls")]
19 StartTls,
20 #[serde(rename = "ssl")]
22 Implicit,
23}
24
25impl Security {
26 pub fn as_str(self) -> &'static str {
27 match self {
28 Security::None => "none",
29 Security::StartTls => "starttls",
30 Security::Implicit => "ssl",
31 }
32 }
33}
34
35pub fn build_client_config(ca_file: Option<&Path>, insecure: bool) -> Result<Arc<ClientConfig>> {
39 let mut roots = RootCertStore::empty();
40 roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
41
42 if let Some(path) = ca_file {
43 let certs: Vec<CertificateDer<'static>> = CertificateDer::pem_file_iter(path)
48 .with_context(|| format!("opening CA bundle {}", path.display()))?
49 .collect::<std::result::Result<Vec<_>, _>>()
50 .with_context(|| format!("parsing CA PEM {}", path.display()))?;
51 for cert in certs {
52 roots.add(cert).context("adding user CA to root store")?;
53 }
54 }
55
56 let config = if insecure {
57 let mut cfg = ClientConfig::builder()
59 .with_root_certificates(roots)
60 .with_no_client_auth();
61 cfg.dangerous()
62 .set_certificate_verifier(Arc::new(danger::AcceptAnyCert));
63 cfg
64 } else {
65 ClientConfig::builder()
66 .with_root_certificates(roots)
67 .with_no_client_auth()
68 };
69
70 Ok(Arc::new(config))
71}
72
73mod danger {
75 use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
76 use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
77 use rustls::{DigitallySignedStruct, Error, SignatureScheme};
78
79 #[derive(Debug)]
80 pub struct AcceptAnyCert;
81
82 impl ServerCertVerifier for AcceptAnyCert {
83 fn verify_server_cert(
84 &self,
85 _end: &CertificateDer<'_>,
86 _ints: &[CertificateDer<'_>],
87 _sn: &ServerName<'_>,
88 _ocsp: &[u8],
89 _now: UnixTime,
90 ) -> Result<ServerCertVerified, Error> {
91 Ok(ServerCertVerified::assertion())
92 }
93
94 fn verify_tls12_signature(
95 &self,
96 _m: &[u8],
97 _c: &CertificateDer<'_>,
98 _d: &DigitallySignedStruct,
99 ) -> Result<HandshakeSignatureValid, Error> {
100 Ok(HandshakeSignatureValid::assertion())
101 }
102
103 fn verify_tls13_signature(
104 &self,
105 _m: &[u8],
106 _c: &CertificateDer<'_>,
107 _d: &DigitallySignedStruct,
108 ) -> Result<HandshakeSignatureValid, Error> {
109 Ok(HandshakeSignatureValid::assertion())
110 }
111
112 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
113 vec![
114 SignatureScheme::RSA_PKCS1_SHA256,
115 SignatureScheme::RSA_PKCS1_SHA384,
116 SignatureScheme::RSA_PKCS1_SHA512,
117 SignatureScheme::ECDSA_NISTP256_SHA256,
118 SignatureScheme::ECDSA_NISTP384_SHA384,
119 SignatureScheme::RSA_PSS_SHA256,
120 SignatureScheme::RSA_PSS_SHA384,
121 SignatureScheme::RSA_PSS_SHA512,
122 SignatureScheme::ED25519,
123 ]
124 }
125 }
126}