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
22impl 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 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 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 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 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 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}