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);
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 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 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 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 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 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}