rfc5321/
tls.rs

1#![cfg(feature = "client")]
2use hickory_proto::rr::rdata::TLSA;
3use openssl::ssl::SslOptions;
4use rustls::pki_types::{CertificateDer, PrivateKeyDer};
5use rustls_pemfile::certs;
6use std::io::BufReader;
7use std::sync::Arc;
8use tokio::time::{Duration, Instant};
9use tokio_rustls::rustls::client::danger::ServerCertVerifier;
10use tokio_rustls::rustls::crypto::{aws_lc_rs as provider, CryptoProvider};
11use tokio_rustls::rustls::{ClientConfig, SupportedCipherSuite};
12use tokio_rustls::TlsConnector;
13
14#[derive(Clone, Debug)]
15struct RustlsCacheKey {
16    insecure: bool,
17    certificate_from_pem: Option<Arc<Box<[u8]>>>,
18    private_key_from_pem: Option<Arc<Box<[u8]>>>,
19    rustls_cipher_suites: Vec<SupportedCipherSuite>,
20}
21
22// SupportedCipherSuite has a PartialEq impl but not an Eq impl.
23// Since we need RustlsCacheKey to be Hash we cannot simply derive
24// PartialEq and then add an explicit impl for Eq on RustlsCacheKey
25// because we don't know the implementation details of the underlying
26// PartialEq impl. So we define our own here where we explicitly compare
27// the suite names. This may not be strictly necessary, but it seems
28// wise to be robust to possible future weirdness in that type, and
29// to be certain that our Hash impl is consistent with the Eq impl.
30impl std::cmp::PartialEq for RustlsCacheKey {
31    fn eq(&self, other: &RustlsCacheKey) -> bool {
32        if self.insecure != other.insecure {
33            return false;
34        }
35        self.rustls_cipher_suites
36            .iter()
37            .map(|s| s.suite())
38            .eq(other.rustls_cipher_suites.iter().map(|s| s.suite()))
39    }
40}
41
42impl std::cmp::Eq for RustlsCacheKey {}
43
44impl std::hash::Hash for RustlsCacheKey {
45    fn hash<H>(&self, hasher: &mut H)
46    where
47        H: std::hash::Hasher,
48    {
49        self.insecure.hash(hasher);
50        for suite in &self.rustls_cipher_suites {
51            suite.suite().as_str().hash(hasher);
52        }
53        if let Some(pem) = &self.certificate_from_pem {
54            pem.as_ref().clone().into_vec().hash(hasher);
55        }
56        if let Some(pem) = &self.private_key_from_pem {
57            pem.as_ref().clone().into_vec().hash(hasher);
58        }
59    }
60}
61
62lruttl::declare_cache! {
63/// Caches TLS connector information for the RFC5321 SMTP client
64static RUSTLS_CACHE: LruCacheWithTtl<RustlsCacheKey, Arc<ClientConfig>>::new("rfc5321_rustls_config", 32);
65}
66
67impl RustlsCacheKey {
68    fn get(&self) -> Option<Arc<ClientConfig>> {
69        RUSTLS_CACHE.get(self)
70    }
71
72    async fn set(self, value: Arc<ClientConfig>) {
73        RUSTLS_CACHE
74            .insert(
75                self,
76                value,
77                // We allow the state to be cached for up to 15 minutes at
78                // a time so that we have an opportunity to reload the
79                // system certificates within a reasonable time frame
80                // as/when they are updated by the system.
81                Instant::now() + Duration::from_secs(15 * 60),
82            )
83            .await;
84    }
85}
86
87#[derive(Debug, Clone, Default)]
88pub struct TlsOptions {
89    pub insecure: bool,
90    pub alt_name: Option<String>,
91    pub dane_tlsa: Vec<TLSA>,
92    pub prefer_openssl: bool,
93    pub certificate_from_pem: Option<Arc<Box<[u8]>>>,
94    pub private_key_from_pem: Option<Arc<Box<[u8]>>>,
95    pub openssl_cipher_list: Option<String>,
96    pub openssl_cipher_suites: Option<String>,
97    pub openssl_options: Option<SslOptions>,
98    pub rustls_cipher_suites: Vec<SupportedCipherSuite>,
99}
100
101impl TlsOptions {
102    /// Produce a TlsConnector for this set of TlsOptions.
103    /// We need to employ a cache around the verifier as loading
104    /// the system certificate store can be a non-trivial operation
105    /// and not be something we want to do repeatedly in a hot code
106    /// path.  The cache does unfortunately complicate some of the
107    /// internals here.
108    pub async fn build_tls_connector(&self) -> anyhow::Result<TlsConnector> {
109        let key = RustlsCacheKey {
110            insecure: self.insecure,
111            rustls_cipher_suites: self.rustls_cipher_suites.clone(),
112            certificate_from_pem: self.certificate_from_pem.clone(),
113            private_key_from_pem: self.private_key_from_pem.clone(),
114        };
115        if let Some(config) = key.get() {
116            return Ok(TlsConnector::from(config));
117        }
118        let cipher_suites = if self.rustls_cipher_suites.is_empty() {
119            provider::DEFAULT_CIPHER_SUITES
120        } else {
121            &self.rustls_cipher_suites
122        };
123
124        let provider = Arc::new(CryptoProvider {
125            cipher_suites: cipher_suites.to_vec(),
126            ..provider::default_provider()
127        });
128
129        let verifier: Arc<dyn ServerCertVerifier> = if self.insecure {
130            Arc::new(danger::NoCertificateVerification::new(provider.clone()))
131        } else {
132            Arc::new(rustls_platform_verifier::Verifier::new().with_provider(provider.clone()))
133        };
134
135        let rustls_certificate = self.load_tls_cert().await?;
136        let rustls_private_key = self.load_private_key().await?;
137
138        let builder = ClientConfig::builder_with_provider(provider.clone())
139            .with_protocol_versions(tokio_rustls::rustls::DEFAULT_VERSIONS)
140            .expect("inconsistent cipher-suite/versions selected")
141            .dangerous()
142            .with_custom_certificate_verifier(verifier.clone());
143        let config = match (&rustls_certificate, &rustls_private_key) {
144            (Some(certs), Some(key)) => builder
145                .clone()
146                .with_client_auth_cert(certs.as_ref().clone(), key.as_ref().clone_key()),
147            _ => Ok(builder.with_no_client_auth()),
148        }?;
149
150        let config = Arc::new(config);
151        key.set(config.clone()).await;
152
153        Ok(TlsConnector::from(config))
154    }
155
156    async fn load_tls_cert(&self) -> std::io::Result<Option<Arc<Vec<CertificateDer<'static>>>>> {
157        match &self.certificate_from_pem {
158            Some(pem) => {
159                let data = pem.as_ref().clone().into_vec();
160                let mut reader = BufReader::new(data.as_slice());
161                let certs = certs(&mut reader)
162                    .into_iter()
163                    .map(|r| r.map(CertificateDer::into_owned))
164                    .collect::<Result<Vec<CertificateDer<'static>>, std::io::Error>>()?;
165                Ok(Some(Arc::new(certs)))
166            }
167            None => return Ok(None),
168        }
169    }
170
171    async fn load_private_key(&self) -> std::io::Result<Option<Arc<PrivateKeyDer<'static>>>> {
172        match &self.private_key_from_pem {
173            Some(pem) => {
174                let data = pem.as_ref().clone().into_vec();
175
176                // Try to parse as PKCS#8
177                let pkcs8_keys: Vec<PrivateKeyDer<'static>> = {
178                    let mut reader = BufReader::new(data.as_slice());
179                    rustls_pemfile::pkcs8_private_keys(&mut reader)
180                        .into_iter()
181                        .map(|r| r.map(PrivateKeyDer::Pkcs8))
182                        .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
183                };
184
185                if !pkcs8_keys.is_empty() {
186                    return Ok(pkcs8_keys.into_iter().next().map(Arc::new));
187                }
188
189                // Reset reader and try as RSA PKCS#1
190                let rsa_keys: Vec<PrivateKeyDer<'static>> = {
191                    let mut reader = BufReader::new(data.as_slice());
192                    rustls_pemfile::rsa_private_keys(&mut reader)
193                        .into_iter()
194                        .map(|r| r.map(PrivateKeyDer::Pkcs1))
195                        .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
196                };
197
198                if !rsa_keys.is_empty() {
199                    return Ok(rsa_keys.into_iter().next().map(Arc::new));
200                }
201
202                // Reset reader and try as EC Sec1
203                let ec_keys: Vec<PrivateKeyDer<'static>> = {
204                    let mut reader = BufReader::new(data.as_slice());
205                    rustls_pemfile::ec_private_keys(&mut reader)
206                        .into_iter()
207                        .map(|r| r.map(PrivateKeyDer::Sec1))
208                        .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
209                };
210
211                if !ec_keys.is_empty() {
212                    return Ok(ec_keys.into_iter().next().map(Arc::new));
213                }
214
215                Err(std::io::Error::new(
216                    std::io::ErrorKind::InvalidData,
217                    "No private key found in PEM file",
218                ))
219            }
220            None => return Ok(None),
221        }
222    }
223}
224
225mod danger {
226    use std::sync::Arc;
227    use tokio_rustls::rustls::client::danger::{
228        HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier,
229    };
230    use tokio_rustls::rustls::crypto::{
231        verify_tls12_signature, verify_tls13_signature, CryptoProvider,
232    };
233    use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime};
234    use tokio_rustls::rustls::DigitallySignedStruct;
235
236    #[derive(Debug)]
237    pub struct NoCertificateVerification(Arc<CryptoProvider>);
238
239    impl NoCertificateVerification {
240        pub fn new(provider: Arc<CryptoProvider>) -> Self {
241            Self(provider)
242        }
243    }
244
245    impl ServerCertVerifier for NoCertificateVerification {
246        fn verify_server_cert(
247            &self,
248            _end_entity: &CertificateDer<'_>,
249            _intermediates: &[CertificateDer<'_>],
250            _server_name: &ServerName<'_>,
251            _ocsp: &[u8],
252            _now: UnixTime,
253        ) -> Result<ServerCertVerified, tokio_rustls::rustls::Error> {
254            Ok(ServerCertVerified::assertion())
255        }
256
257        fn verify_tls12_signature(
258            &self,
259            message: &[u8],
260            cert: &CertificateDer<'_>,
261            dss: &DigitallySignedStruct,
262        ) -> Result<HandshakeSignatureValid, tokio_rustls::rustls::Error> {
263            verify_tls12_signature(
264                message,
265                cert,
266                dss,
267                &self.0.signature_verification_algorithms,
268            )
269        }
270
271        fn verify_tls13_signature(
272            &self,
273            message: &[u8],
274            cert: &CertificateDer<'_>,
275            dss: &DigitallySignedStruct,
276        ) -> Result<HandshakeSignatureValid, tokio_rustls::rustls::Error> {
277            verify_tls13_signature(
278                message,
279                cert,
280                dss,
281                &self.0.signature_verification_algorithms,
282            )
283        }
284
285        fn supported_verify_schemes(&self) -> Vec<tokio_rustls::rustls::SignatureScheme> {
286            self.0.signature_verification_algorithms.supported_schemes()
287        }
288    }
289}