1mod traits;
7
8pub use traits::*;
9
10use hickory_proto::rr::rdata::tlsa::{CertUsage, Matching, Selector};
11use hickory_proto::rr::rdata::TLSA;
12use openssl::pkey::PKey;
13use openssl::ssl::{DaneMatchType, DaneSelector, DaneUsage, SslOptions};
14use openssl::x509::X509;
15use rustls::pki_types::{CertificateDer, PrivateKeyDer};
16use rustls_pemfile::certs;
17use std::io::BufReader;
18use std::sync::Arc;
19use thiserror::Error;
20use tokio::time::{Duration, Instant};
21use tokio_rustls::rustls::client::danger::ServerCertVerifier;
22use tokio_rustls::rustls::crypto::{aws_lc_rs as provider, CryptoProvider};
23use tokio_rustls::rustls::{ClientConfig, SupportedCipherSuite};
24use tokio_rustls::TlsConnector;
25
26#[derive(Error, Debug, Clone)]
28pub enum OpensslConnectorError {
29 #[error("SSL Error: {0}")]
30 SslErrorStack(String),
31 #[error("No usable DANE TLSA records for {hostname}: {tlsa:?}")]
32 NoUsableDaneTlsa { hostname: String, tlsa: Vec<TLSA> },
33}
34
35impl From<openssl::error::ErrorStack> for OpensslConnectorError {
36 fn from(err: openssl::error::ErrorStack) -> Self {
37 OpensslConnectorError::SslErrorStack(err.to_string())
38 }
39}
40
41#[derive(Clone, Debug)]
42struct RustlsCacheKey {
43 insecure: bool,
44 certificate_from_pem: Option<Arc<Box<[u8]>>>,
45 private_key_from_pem: Option<Arc<Box<[u8]>>>,
46 rustls_cipher_suites: Vec<SupportedCipherSuite>,
47}
48
49impl std::cmp::PartialEq for RustlsCacheKey {
58 fn eq(&self, other: &RustlsCacheKey) -> bool {
59 if self.insecure != other.insecure {
60 return false;
61 }
62 self.rustls_cipher_suites
63 .iter()
64 .map(|s| s.suite())
65 .eq(other.rustls_cipher_suites.iter().map(|s| s.suite()))
66 }
67}
68
69impl std::cmp::Eq for RustlsCacheKey {}
70
71impl std::hash::Hash for RustlsCacheKey {
72 fn hash<H>(&self, hasher: &mut H)
73 where
74 H: std::hash::Hasher,
75 {
76 self.insecure.hash(hasher);
77 for suite in &self.rustls_cipher_suites {
78 suite.suite().as_str().hash(hasher);
79 }
80 if let Some(pem) = &self.certificate_from_pem {
81 pem.as_ref().clone().into_vec().hash(hasher);
82 }
83 if let Some(pem) = &self.private_key_from_pem {
84 pem.as_ref().clone().into_vec().hash(hasher);
85 }
86 }
87}
88
89lruttl::declare_cache! {
90static RUSTLS_CACHE: LruCacheWithTtl<RustlsCacheKey, Arc<ClientConfig>>::new("rustls_client_config", 32);
92}
93
94impl RustlsCacheKey {
95 fn get(&self) -> Option<Arc<ClientConfig>> {
96 RUSTLS_CACHE.get(self)
97 }
98
99 async fn set(self, value: Arc<ClientConfig>) {
100 RUSTLS_CACHE
101 .insert(
102 self,
103 value,
104 Instant::now() + Duration::from_secs(15 * 60),
109 )
110 .await;
111 }
112}
113
114#[derive(Debug, Clone, Default)]
115pub struct TlsOptions {
116 pub insecure: bool,
117 pub alt_name: Option<String>,
118 pub dane_tlsa: Vec<TLSA>,
119 pub prefer_openssl: bool,
120 pub certificate_from_pem: Option<Arc<Box<[u8]>>>,
121 pub private_key_from_pem: Option<Arc<Box<[u8]>>>,
122 pub openssl_cipher_list: Option<String>,
123 pub openssl_cipher_suites: Option<String>,
124 pub openssl_options: Option<SslOptions>,
125 pub rustls_cipher_suites: Vec<SupportedCipherSuite>,
126}
127
128impl TlsOptions {
129 pub async fn build_tls_connector(&self) -> anyhow::Result<TlsConnector> {
136 let key = RustlsCacheKey {
137 insecure: self.insecure,
138 rustls_cipher_suites: self.rustls_cipher_suites.clone(),
139 certificate_from_pem: self.certificate_from_pem.clone(),
140 private_key_from_pem: self.private_key_from_pem.clone(),
141 };
142 if let Some(config) = key.get() {
143 return Ok(TlsConnector::from(config));
144 }
145 let cipher_suites = if self.rustls_cipher_suites.is_empty() {
146 provider::DEFAULT_CIPHER_SUITES
147 } else {
148 &self.rustls_cipher_suites
149 };
150
151 let provider = Arc::new(CryptoProvider {
152 cipher_suites: cipher_suites.to_vec(),
153 ..provider::default_provider()
154 });
155
156 let verifier: Arc<dyn ServerCertVerifier> = if self.insecure {
157 Arc::new(danger::NoCertificateVerification::new(provider.clone()))
158 } else {
159 Arc::new(rustls_platform_verifier::Verifier::new().with_provider(provider.clone()))
160 };
161
162 let rustls_certificate = self.load_tls_cert().await?;
163 let rustls_private_key = self.load_private_key().await?;
164
165 let builder = ClientConfig::builder_with_provider(provider.clone())
166 .with_protocol_versions(tokio_rustls::rustls::DEFAULT_VERSIONS)
167 .expect("inconsistent cipher-suite/versions selected")
168 .dangerous()
169 .with_custom_certificate_verifier(verifier.clone());
170 let config = match (&rustls_certificate, &rustls_private_key) {
171 (Some(certs), Some(key)) => builder
172 .clone()
173 .with_client_auth_cert(certs.as_ref().clone(), key.as_ref().clone_key()),
174 _ => Ok(builder.with_no_client_auth()),
175 }?;
176
177 let config = Arc::new(config);
178 key.set(config.clone()).await;
179
180 Ok(TlsConnector::from(config))
181 }
182
183 async fn load_tls_cert(&self) -> std::io::Result<Option<Arc<Vec<CertificateDer<'static>>>>> {
184 match &self.certificate_from_pem {
185 Some(pem) => {
186 let data = pem.as_ref().clone().into_vec();
187 let mut reader = BufReader::new(data.as_slice());
188 let certs = certs(&mut reader)
189 .map(|r| r.map(CertificateDer::into_owned))
190 .collect::<Result<Vec<CertificateDer<'static>>, std::io::Error>>()?;
191 Ok(Some(Arc::new(certs)))
192 }
193 None => return Ok(None),
194 }
195 }
196
197 async fn load_private_key(&self) -> std::io::Result<Option<Arc<PrivateKeyDer<'static>>>> {
198 match &self.private_key_from_pem {
199 Some(pem) => {
200 let data = pem.as_ref().clone().into_vec();
201
202 let pkcs8_keys: Vec<PrivateKeyDer<'static>> = {
204 let mut reader = BufReader::new(data.as_slice());
205 rustls_pemfile::pkcs8_private_keys(&mut reader)
206 .map(|r| r.map(PrivateKeyDer::Pkcs8))
207 .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
208 };
209
210 if !pkcs8_keys.is_empty() {
211 return Ok(pkcs8_keys.into_iter().next().map(Arc::new));
212 }
213
214 let rsa_keys: Vec<PrivateKeyDer<'static>> = {
216 let mut reader = BufReader::new(data.as_slice());
217 rustls_pemfile::rsa_private_keys(&mut reader)
218 .map(|r| r.map(PrivateKeyDer::Pkcs1))
219 .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
220 };
221
222 if !rsa_keys.is_empty() {
223 return Ok(rsa_keys.into_iter().next().map(Arc::new));
224 }
225
226 let ec_keys: Vec<PrivateKeyDer<'static>> = {
228 let mut reader = BufReader::new(data.as_slice());
229 rustls_pemfile::ec_private_keys(&mut reader)
230 .map(|r| r.map(PrivateKeyDer::Sec1))
231 .collect::<Result<Vec<PrivateKeyDer<'static>>, std::io::Error>>()?
232 };
233
234 if !ec_keys.is_empty() {
235 return Ok(ec_keys.into_iter().next().map(Arc::new));
236 }
237
238 Err(std::io::Error::new(
239 std::io::ErrorKind::InvalidData,
240 "No private key found in PEM file",
241 ))
242 }
243 None => return Ok(None),
244 }
245 }
246
247 pub fn build_openssl_connector(
250 &self,
251 hostname: &str,
252 ) -> Result<openssl::ssl::ConnectConfiguration, OpensslConnectorError> {
253 tracing::trace!("build_openssl_connector for {hostname}");
254 let mut builder =
255 openssl::ssl::SslConnector::builder(openssl::ssl::SslMethod::tls_client())?;
256
257 if let (Some(cert_data), Some(key_data)) =
258 (&self.certificate_from_pem, &self.private_key_from_pem)
259 {
260 let certs = X509::stack_from_pem(cert_data)?;
261 let Some(leaf) = certs.first().cloned() else {
262 return Err(OpensslConnectorError::SslErrorStack(
263 "certificate PEM data is empty".to_string(),
264 ));
265 };
266 builder.set_certificate(&leaf)?;
267
268 for cert in certs.iter().skip(1) {
270 builder.add_extra_chain_cert(cert.clone())?;
271 }
272
273 let key = PKey::private_key_from_pem(key_data)?;
274 builder.set_private_key(&key)?;
275
276 builder.check_private_key()?;
277 }
278
279 if let Some(list) = &self.openssl_cipher_list {
280 builder.set_cipher_list(list)?;
281 }
282
283 if let Some(suites) = &self.openssl_cipher_suites {
284 builder.set_ciphersuites(suites)?;
285 }
286
287 if let Some(options) = &self.openssl_options {
288 builder.clear_options(SslOptions::all());
289 builder.set_options(*options);
290 }
291
292 if self.insecure {
293 builder.set_verify(openssl::ssl::SslVerifyMode::NONE);
294 }
295
296 if !self.dane_tlsa.is_empty() {
297 builder.dane_enable()?;
298 builder.set_no_dane_ee_namechecks();
299 }
300
301 let connector = builder.build();
302
303 let mut config = connector.configure()?;
304
305 if !self.dane_tlsa.is_empty() {
306 config.dane_enable(hostname)?;
307 let mut any_usable = false;
308 for tlsa in &self.dane_tlsa {
309 let usable = config.dane_tlsa_add(
310 match tlsa.cert_usage {
311 CertUsage::PkixTa => DaneUsage::PKIX_TA,
312 CertUsage::PkixEe => DaneUsage::PKIX_EE,
313 CertUsage::DaneTa => DaneUsage::DANE_TA,
314 CertUsage::DaneEe => DaneUsage::DANE_EE,
315 CertUsage::Unassigned(n) => DaneUsage::from_raw(n),
316 CertUsage::Private => DaneUsage::PRIV_CERT,
317 },
318 match tlsa.selector {
319 Selector::Full => DaneSelector::CERT,
320 Selector::Spki => DaneSelector::SPKI,
321 Selector::Unassigned(n) => DaneSelector::from_raw(n),
322 Selector::Private => DaneSelector::PRIV_SEL,
323 },
324 match tlsa.matching {
325 Matching::Raw => DaneMatchType::FULL,
326 Matching::Sha256 => DaneMatchType::SHA2_256,
327 Matching::Sha512 => DaneMatchType::SHA2_512,
328 Matching::Unassigned(n) => DaneMatchType::from_raw(n),
329 Matching::Private => DaneMatchType::PRIV_MATCH,
330 },
331 &tlsa.cert_data,
332 )?;
333
334 tracing::trace!("build_dane_connector usable={usable} {tlsa:?}");
335 if usable {
336 any_usable = true;
337 }
338 }
339
340 if !any_usable {
341 return Err(OpensslConnectorError::NoUsableDaneTlsa {
342 hostname: hostname.to_string(),
343 tlsa: self.dane_tlsa.clone(),
344 });
345 }
346 }
347
348 Ok(config)
349 }
350}
351
352mod danger {
353 use std::sync::Arc;
354 use tokio_rustls::rustls::client::danger::{
355 HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier,
356 };
357 use tokio_rustls::rustls::crypto::{
358 verify_tls12_signature, verify_tls13_signature, CryptoProvider,
359 };
360 use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime};
361 use tokio_rustls::rustls::DigitallySignedStruct;
362
363 #[derive(Debug)]
364 pub struct NoCertificateVerification(Arc<CryptoProvider>);
365
366 impl NoCertificateVerification {
367 pub fn new(provider: Arc<CryptoProvider>) -> Self {
368 Self(provider)
369 }
370 }
371
372 impl ServerCertVerifier for NoCertificateVerification {
373 fn verify_server_cert(
374 &self,
375 _end_entity: &CertificateDer<'_>,
376 _intermediates: &[CertificateDer<'_>],
377 _server_name: &ServerName<'_>,
378 _ocsp: &[u8],
379 _now: UnixTime,
380 ) -> Result<ServerCertVerified, tokio_rustls::rustls::Error> {
381 Ok(ServerCertVerified::assertion())
382 }
383
384 fn verify_tls12_signature(
385 &self,
386 message: &[u8],
387 cert: &CertificateDer<'_>,
388 dss: &DigitallySignedStruct,
389 ) -> Result<HandshakeSignatureValid, tokio_rustls::rustls::Error> {
390 verify_tls12_signature(
391 message,
392 cert,
393 dss,
394 &self.0.signature_verification_algorithms,
395 )
396 }
397
398 fn verify_tls13_signature(
399 &self,
400 message: &[u8],
401 cert: &CertificateDer<'_>,
402 dss: &DigitallySignedStruct,
403 ) -> Result<HandshakeSignatureValid, tokio_rustls::rustls::Error> {
404 verify_tls13_signature(
405 message,
406 cert,
407 dss,
408 &self.0.signature_verification_algorithms,
409 )
410 }
411
412 fn supported_verify_schemes(&self) -> Vec<tokio_rustls::rustls::SignatureScheme> {
413 self.0.signature_verification_algorithms.supported_schemes()
414 }
415 }
416}