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! {
63static RUSTLS_CACHE: LruCacheWithTtl<RustlsCacheKey, Arc<ClientConfig>>::new("rfc5321_rustls_config", 32);
64}
65
66impl RustlsCacheKey {
67    fn get(&self) -> Option<Arc<ClientConfig>> {
68        RUSTLS_CACHE.get(self)
69    }
70
71    async fn set(self, value: Arc<ClientConfig>) {
72        RUSTLS_CACHE
73            .insert(
74                self,
75                value,
76                // We allow the state to be cached for up to 15 minutes at
77                // a time so that we have an opportunity to reload the
78                // system certificates within a reasonable time frame
79                // as/when they are updated by the system.
80                Instant::now() + Duration::from_secs(15 * 60),
81            )
82            .await;
83    }
84}
85
86#[derive(Debug, Clone, Default)]
87pub struct TlsOptions {
88    pub insecure: bool,
89    pub alt_name: Option<String>,
90    pub dane_tlsa: Vec<TLSA>,
91    pub prefer_openssl: bool,
92    pub certificate_from_pem: Option<Arc<Box<[u8]>>>,
93    pub private_key_from_pem: Option<Arc<Box<[u8]>>>,
94    pub openssl_cipher_list: Option<String>,
95    pub openssl_cipher_suites: Option<String>,
96    pub openssl_options: Option<SslOptions>,
97    pub rustls_cipher_suites: Vec<SupportedCipherSuite>,
98}
99
100impl TlsOptions {
101    /// Produce a TlsConnector for this set of TlsOptions.
102    /// We need to employ a cache around the verifier as loading
103    /// the system certificate store can be a non-trivial operation
104    /// and not be something we want to do repeatedly in a hot code
105    /// path.  The cache does unfortunately complicate some of the
106    /// internals here.
107    pub async fn build_tls_connector(&self) -> anyhow::Result<TlsConnector> {
108        let key = RustlsCacheKey {
109            insecure: self.insecure,
110            rustls_cipher_suites: self.rustls_cipher_suites.clone(),
111            certificate_from_pem: self.certificate_from_pem.clone(),
112            private_key_from_pem: self.private_key_from_pem.clone(),
113        };
114        if let Some(config) = key.get() {
115            return Ok(TlsConnector::from(config));
116        }
117        let cipher_suites = if self.rustls_cipher_suites.is_empty() {
118            provider::DEFAULT_CIPHER_SUITES
119        } else {
120            &self.rustls_cipher_suites
121        };
122
123        let provider = Arc::new(CryptoProvider {
124            cipher_suites: cipher_suites.to_vec(),
125            ..provider::default_provider()
126        });
127
128        let verifier: Arc<dyn ServerCertVerifier> = if self.insecure {
129            Arc::new(danger::NoCertificateVerification::new(provider.clone()))
130        } else {
131            Arc::new(rustls_platform_verifier::Verifier::new().with_provider(provider.clone()))
132        };
133
134        let rustls_certificate = self.load_tls_cert().await?;
135        let rustls_private_key = self.load_private_key().await?;
136
137        let builder = ClientConfig::builder_with_provider(provider.clone())
138            .with_protocol_versions(tokio_rustls::rustls::DEFAULT_VERSIONS)
139            .expect("inconsistent cipher-suite/versions selected")
140            .dangerous()
141            .with_custom_certificate_verifier(verifier.clone());
142        let config = match (&rustls_certificate, &rustls_private_key) {
143            (Some(certs), Some(key)) => builder
144                .clone()
145                .with_client_auth_cert(certs.as_ref().clone(), key.as_ref().clone_key()),
146            _ => Ok(builder.with_no_client_auth()),
147        }?;
148
149        let config = Arc::new(config);
150        key.set(config.clone()).await;
151
152        Ok(TlsConnector::from(config))
153    }
154
155    async fn load_tls_cert(&self) -> std::io::Result<Option<Arc<Vec<CertificateDer<'static>>>>> {
156        match &self.certificate_from_pem {
157            Some(pem) => {
158                let data = pem.as_ref().clone().into_vec();
159                let mut reader = BufReader::new(data.as_slice());
160                let certs = certs(&mut reader)
161                    .into_iter()
162                    .map(|r| r.map(CertificateDer::into_owned))
163                    .collect::<Result<Vec<CertificateDer<'static>>, std::io::Error>>()?;
164                Ok(Some(Arc::new(certs)))
165            }
166            None => return Ok(None),
167        }
168    }
169
170    async fn load_private_key(&self) -> std::io::Result<Option<Arc<PrivateKeyDer<'static>>>> {
171        match &self.private_key_from_pem {
172            Some(pem) => {
173                let data = pem.as_ref().clone().into_vec();
174
175                // Try to parse as PKCS#8
176                let pkcs8_keys: Vec<PrivateKeyDer<'static>> = {
177                    let mut reader = BufReader::new(data.as_slice());
178                    rustls_pemfile::pkcs8_private_keys(&mut reader)
179                        .into_iter()
180                        .map(|r| r.map(PrivateKeyDer::Pkcs8))
181                        .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
182                };
183
184                if !pkcs8_keys.is_empty() {
185                    return Ok(pkcs8_keys.into_iter().next().map(Arc::new));
186                }
187
188                // Reset reader and try as RSA PKCS#1
189                let rsa_keys: Vec<PrivateKeyDer<'static>> = {
190                    let mut reader = BufReader::new(data.as_slice());
191                    rustls_pemfile::rsa_private_keys(&mut reader)
192                        .into_iter()
193                        .map(|r| r.map(PrivateKeyDer::Pkcs1))
194                        .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
195                };
196
197                if !rsa_keys.is_empty() {
198                    return Ok(rsa_keys.into_iter().next().map(Arc::new));
199                }
200
201                // Reset reader and try as EC Sec1
202                let ec_keys: Vec<PrivateKeyDer<'static>> = {
203                    let mut reader = BufReader::new(data.as_slice());
204                    rustls_pemfile::ec_private_keys(&mut reader)
205                        .into_iter()
206                        .map(|r| r.map(PrivateKeyDer::Sec1))
207                        .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
208                };
209
210                if !ec_keys.is_empty() {
211                    return Ok(ec_keys.into_iter().next().map(Arc::new));
212                }
213
214                Err(std::io::Error::new(
215                    std::io::ErrorKind::InvalidData,
216                    "No private key found in PEM file",
217                ))
218            }
219            None => return Ok(None),
220        }
221    }
222}
223
224mod danger {
225    use std::sync::Arc;
226    use tokio_rustls::rustls::client::danger::{
227        HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier,
228    };
229    use tokio_rustls::rustls::crypto::{
230        verify_tls12_signature, verify_tls13_signature, CryptoProvider,
231    };
232    use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime};
233    use tokio_rustls::rustls::DigitallySignedStruct;
234
235    #[derive(Debug)]
236    pub struct NoCertificateVerification(Arc<CryptoProvider>);
237
238    impl NoCertificateVerification {
239        pub fn new(provider: Arc<CryptoProvider>) -> Self {
240            Self(provider)
241        }
242    }
243
244    impl ServerCertVerifier for NoCertificateVerification {
245        fn verify_server_cert(
246            &self,
247            _end_entity: &CertificateDer<'_>,
248            _intermediates: &[CertificateDer<'_>],
249            _server_name: &ServerName<'_>,
250            _ocsp: &[u8],
251            _now: UnixTime,
252        ) -> Result<ServerCertVerified, tokio_rustls::rustls::Error> {
253            Ok(ServerCertVerified::assertion())
254        }
255
256        fn verify_tls12_signature(
257            &self,
258            message: &[u8],
259            cert: &CertificateDer<'_>,
260            dss: &DigitallySignedStruct,
261        ) -> Result<HandshakeSignatureValid, tokio_rustls::rustls::Error> {
262            verify_tls12_signature(
263                message,
264                cert,
265                dss,
266                &self.0.signature_verification_algorithms,
267            )
268        }
269
270        fn verify_tls13_signature(
271            &self,
272            message: &[u8],
273            cert: &CertificateDer<'_>,
274            dss: &DigitallySignedStruct,
275        ) -> Result<HandshakeSignatureValid, tokio_rustls::rustls::Error> {
276            verify_tls13_signature(
277                message,
278                cert,
279                dss,
280                &self.0.signature_verification_algorithms,
281            )
282        }
283
284        fn supported_verify_schemes(&self) -> Vec<tokio_rustls::rustls::SignatureScheme> {
285            self.0.signature_verification_algorithms.supported_schemes()
286        }
287    }
288}