1use std::{
2 collections::HashMap,
3 error::Error,
4 future::Future,
5 net::IpAddr,
6 ops::{Deref, Sub},
7 path::PathBuf,
8 pin::Pin,
9 sync::Arc,
10 time::{Duration, SystemTime},
11};
12
13use base64::Engine;
14use bytes::Bytes;
15use hyper::Request;
16use hyper_util::client::legacy::Client as HyperClient;
17use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
18use instant_acme::{
19 Account, AccountCredentials, AuthorizationStatus, BodyWrapper, BytesResponse, CertificateIdentifier, ChallengeType,
20 ExternalAccountKey, HttpClient, Identifier, NewAccount, NewOrder, OrderStatus, RenewalInfo, RetryPolicy,
21};
22use rcgen::{CertificateParams, CustomExtension, KeyPair};
23use rustls::{
24 crypto::CryptoProvider,
25 server::{ClientHello, ResolvesServerCert},
26 sign::CertifiedKey,
27 ClientConfig,
28};
29use rustls_pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer};
30use serde::{Deserialize, Serialize};
31use tokio::{io::AsyncWriteExt, sync::RwLock, time::Instant};
32use x509_parser::prelude::{FromDer, X509Certificate};
33use xxhash_rust::xxh3::xxh3_128;
34
35use crate::util::load_host_resolver;
36use ferron_common::dns::DnsProvider;
37use ferron_common::logging::ErrorLogger;
38
39pub const ACME_TLS_ALPN_NAME: &[u8] = b"acme-tls/1";
40const SECONDS_BEFORE_RENEWAL: u64 = 86400; pub type TlsAlpn01DataLock = Arc<RwLock<Option<(Arc<CertifiedKey>, String)>>>;
43pub type Http01DataLock = Arc<RwLock<Option<(String, String)>>>;
44
45pub struct AcmeConfig {
47 pub rustls_client_config: ClientConfig,
49 pub domains: Vec<String>,
51 pub challenge_type: ChallengeType,
53 pub contact: Vec<String>,
55 pub directory: String,
57 pub eab_key: Option<Arc<ExternalAccountKey>>,
59 pub profile: Option<String>,
61 pub account_cache: AcmeCache,
63 pub certificate_cache: AcmeCache,
65 pub certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
67 pub tls_alpn_01_data_lock: TlsAlpn01DataLock,
69 pub http_01_data_lock: Http01DataLock,
71 pub dns_provider: Option<Arc<dyn DnsProvider + Send + Sync>>,
73 pub renewal_info: Option<(RenewalInfo, Instant)>,
75 pub account: Option<Account>,
77}
78
79pub enum AcmeCache {
81 Memory(Arc<RwLock<HashMap<String, Vec<u8>>>>),
83 File(PathBuf),
85}
86
87#[derive(Serialize, Deserialize)]
88struct CertificateCacheData {
89 certificate_chain_pem: String,
90 private_key_pem: String,
91}
92
93async fn get_from_cache(cache: &AcmeCache, key: &str) -> Option<Vec<u8>> {
95 match cache {
96 AcmeCache::Memory(cache) => cache.read().await.get(key).cloned(),
97 AcmeCache::File(path) => tokio::fs::read(path.join(key)).await.ok(),
98 }
99}
100
101pub struct AcmeOnDemandConfig {
103 pub rustls_client_config: ClientConfig,
105 pub challenge_type: ChallengeType,
107 pub contact: Vec<String>,
109 pub directory: String,
111 pub eab_key: Option<Arc<ExternalAccountKey>>,
113 pub profile: Option<String>,
115 pub cache_path: Option<PathBuf>,
117 #[allow(clippy::type_complexity)]
119 pub sni_resolver_lock: Arc<RwLock<Vec<(String, Arc<dyn ResolvesServerCert>)>>>,
120 pub tls_alpn_01_resolver_lock: Arc<RwLock<Vec<TlsAlpn01DataLock>>>,
122 pub http_01_resolver_lock: Arc<RwLock<Vec<Http01DataLock>>>,
124 pub dns_provider: Option<Arc<dyn DnsProvider + Send + Sync>>,
126 pub sni_hostname: Option<String>,
128 pub port: u16,
130}
131
132async fn set_in_cache(cache: &AcmeCache, key: &str, value: Vec<u8>) -> Result<(), Box<dyn Error + Send + Sync>> {
134 match cache {
135 AcmeCache::Memory(cache) => {
136 cache.write().await.insert(key.to_string(), value);
137 Ok(())
138 }
139 AcmeCache::File(path) => {
140 tokio::fs::create_dir_all(path).await.unwrap_or_default();
141 let mut open_options = tokio::fs::OpenOptions::new();
142 open_options.write(true).create(true).truncate(true);
143
144 #[cfg(unix)]
145 open_options.mode(0o600); let mut file = open_options.open(path.join(key)).await?;
148 file.write_all(&value).await?;
149 file.flush().await.unwrap_or_default();
150
151 Ok(())
152 }
153 }
154}
155
156async fn remove_from_cache(cache: &AcmeCache, key: &str) {
158 match cache {
159 AcmeCache::Memory(cache) => {
160 cache.write().await.remove(key);
161 }
162 AcmeCache::File(path) => {
163 let _ = tokio::fs::remove_file(path.join(key)).await;
164 }
165 }
166}
167
168fn check_certificate_validity(
170 certificate: &CertificateDer,
171 renewal_info: Option<&RenewalInfo>,
172) -> Result<bool, Box<dyn Error + Send + Sync>> {
173 if let Some(renewal_info) = renewal_info {
174 return Ok(SystemTime::now() < renewal_info.suggested_window.start);
175 }
176 let (_, x509_certificate) = X509Certificate::from_der(certificate)?;
177 let validity = x509_certificate.validity();
178 if let Some(time_to_expiration) = validity.time_to_expiration() {
179 let time_before_expiration = if let Some(valid_duration) = validity.not_after.sub(validity.not_before) {
180 (valid_duration.whole_seconds().unsigned_abs() / 2).min(SECONDS_BEFORE_RENEWAL)
181 } else {
182 SECONDS_BEFORE_RENEWAL
183 };
184 if time_to_expiration >= Duration::from_secs(time_before_expiration) {
185 return Ok(true);
186 }
187 }
188 Ok(false)
189}
190
191fn get_account_cache_key(config: &AcmeConfig) -> String {
193 format!(
194 "account_{}",
195 base64::engine::general_purpose::URL_SAFE_NO_PAD
196 .encode(xxh3_128(format!("{};{}", &config.contact.join(","), &config.directory).as_bytes()).to_be_bytes())
197 )
198}
199
200fn get_certificate_cache_key(config: &AcmeConfig) -> String {
202 let mut domains = config.domains.clone();
203 domains.sort_unstable();
204 let domains_joined = domains.join(",");
205 format!(
206 "certificate_{}",
207 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(
208 xxh3_128(
209 format!(
210 "{}{}",
211 domains_joined,
212 config.profile.as_ref().map_or("".to_string(), |p| format!(";{p}"))
213 )
214 .as_bytes()
215 )
216 .to_be_bytes()
217 )
218 )
219}
220
221fn get_hostname_cache_key(config: &AcmeOnDemandConfig) -> String {
223 format!(
224 "hostname_{}",
225 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(
226 xxh3_128(
227 format!(
228 "{}{}",
229 &config.port,
230 config.sni_hostname.as_ref().map_or("".to_string(), |h| format!(";{h}"))
231 )
232 .as_bytes()
233 )
234 .to_be_bytes()
235 )
236 )
237}
238
239pub async fn check_certificate_validity_or_install_cached(
241 config: &mut AcmeConfig,
242 acme_account: Option<&Account>,
243) -> Result<bool, Box<dyn Error + Send + Sync>> {
244 if let Some(certified_key) = config.certified_key_lock.read().await.as_deref() {
245 if let Some(certificate) = certified_key.cert.first() {
246 if let Some(acme_account) = acme_account {
247 if config
248 .renewal_info
249 .as_ref()
250 .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
251 {
252 if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
253 if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
254 let mut renewal_instant = Instant::now();
255 renewal_instant += renewal_info.1;
256 config.renewal_info = Some((renewal_info.0, renewal_instant));
257 }
258 }
259 }
260 }
261 if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
262 return Ok(true);
263 }
264 }
265 }
266
267 let certificate_cache_key = get_certificate_cache_key(config);
268
269 if let Some(serialized_certificate_cache_data) =
270 get_from_cache(&config.certificate_cache, &certificate_cache_key).await
271 {
272 if let Ok(certificate_data) = serde_json::from_slice::<CertificateCacheData>(&serialized_certificate_cache_data) {
273 if let Ok(certs) =
275 CertificateDer::pem_slice_iter(certificate_data.certificate_chain_pem.as_bytes()).collect::<Result<Vec<_>, _>>()
276 {
277 if let Some(certificate) = certs.first() {
278 if let Some(acme_account) = acme_account {
279 if config
280 .renewal_info
281 .as_ref()
282 .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
283 {
284 if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
285 if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
286 let mut renewal_instant = Instant::now();
287 renewal_instant += renewal_info.1;
288 config.renewal_info = Some((renewal_info.0, renewal_instant));
289 }
290 }
291 }
292 }
293 if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
294 if let Ok(private_key) = PrivateKeyDer::from_pem_slice(certificate_data.private_key_pem.as_bytes()) {
296 let signing_key = CryptoProvider::get_default()
297 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
298 .key_provider
299 .load_private_key(private_key)?;
300
301 *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
302
303 return Ok(true);
304 }
305 }
306 }
307 }
308 }
309 }
310
311 Ok(false)
312}
313
314pub async fn provision_certificate(
316 config: &mut AcmeConfig,
317 error_logger: &ErrorLogger,
318) -> Result<(), Box<dyn Error + Send + Sync>> {
319 let account_cache_key = get_account_cache_key(config);
320 let certificate_cache_key = get_certificate_cache_key(config);
321 let mut had_cache_error = false;
322
323 let acme_account = if let Some(acme_account) = config.account.take() {
324 acme_account
325 } else {
326 let acme_account_builder =
327 Account::builder_with_http(Box::new(HttpsClientForAcme::new(config.rustls_client_config.clone())));
328
329 if let Some(account_credentials) = get_from_cache(&config.account_cache, &account_cache_key)
330 .await
331 .and_then(|c| serde_json::from_slice::<AccountCredentials>(&c).ok())
332 {
333 acme_account_builder.from_credentials(account_credentials).await?
334 } else {
335 let (account, account_credentials) = acme_account_builder
336 .create(
337 &NewAccount {
338 contact: config.contact.iter().map(|s| s.deref()).collect::<Vec<_>>().as_slice(),
339 terms_of_service_agreed: true,
340 only_return_existing: false,
341 },
342 config.directory.clone(),
343 config.eab_key.as_deref(),
344 )
345 .await?;
346
347 if let Err(err) = set_in_cache(
348 &config.account_cache,
349 &account_cache_key,
350 serde_json::to_vec(&account_credentials)?,
351 )
352 .await
353 {
354 if !had_cache_error {
355 error_logger
356 .log(&format!(
357 "Failed to access the ACME cache: {}. Ferron can't use ACME caching",
358 err
359 ))
360 .await;
361 had_cache_error = true;
362 }
363 }
364
365 account
366 }
367 };
368
369 if check_certificate_validity_or_install_cached(config, Some(&acme_account)).await? {
370 config.account.replace(acme_account);
372 return Ok(());
373 }
374
375 let acme_identifiers_vec = config
376 .domains
377 .iter()
378 .map(|s| {
379 if let Ok(ip) = s.parse::<IpAddr>() {
380 Identifier::Ip(ip)
381 } else {
382 Identifier::Dns(s.to_string())
383 }
384 })
385 .collect::<Vec<_>>();
386
387 let mut acme_new_order = NewOrder::new(&acme_identifiers_vec);
388 if let Some(profile) = &config.profile {
389 acme_new_order = acme_new_order.profile(profile);
390 }
391
392 let mut acme_order = match acme_account.new_order(&acme_new_order).await {
393 Ok(order) => order,
394 Err(instant_acme::Error::Api(problem)) => {
395 if problem.r#type.as_deref() == Some("urn:ietf:params:acme:error:accountDoesNotExist") {
396 remove_from_cache(&config.account_cache, &account_cache_key).await;
398 }
399 Err(instant_acme::Error::Api(problem))?
400 }
401 Err(err) => Err(err)?,
402 };
403 let mut dns_01_identifiers = Vec::new();
404 let mut acme_authorizations = acme_order.authorizations();
405 while let Some(acme_authorization) = acme_authorizations.next().await {
406 let mut acme_authorization = acme_authorization?;
407 match acme_authorization.status {
408 AuthorizationStatus::Pending => {}
409 AuthorizationStatus::Valid => continue,
410 _ => Err(anyhow::anyhow!("Invalid ACME authorization status"))?,
411 }
412
413 let mut challenge = acme_authorization
414 .challenge(config.challenge_type.clone())
415 .ok_or(anyhow::anyhow!(
416 "The ACME server doesn't support the requested challenge type"
417 ))?;
418
419 let identifier = match challenge.identifier().identifier {
420 Identifier::Dns(identifier) => identifier.to_string(),
421 Identifier::Ip(ip) => ip.to_string(),
422 _ => Err(anyhow::anyhow!("Unsupported ACME identifier type",))?,
423 };
424
425 let key_authorization = challenge.key_authorization();
426 match config.challenge_type {
427 ChallengeType::TlsAlpn01 => {
428 let mut params = CertificateParams::new(vec![identifier.clone()])?;
429 params.custom_extensions.push(CustomExtension::new_acme_identifier(
430 key_authorization.digest().as_ref(),
431 ));
432 let key_pair = KeyPair::generate()?;
433 let certificate = params.self_signed(&key_pair)?;
434 let private_key = PrivateKeyDer::try_from(key_pair.serialize_der())?;
435
436 let signing_key = CryptoProvider::get_default()
437 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
438 .key_provider
439 .load_private_key(private_key)?;
440
441 *config.tls_alpn_01_data_lock.write().await = Some((
442 Arc::new(CertifiedKey::new(vec![certificate.der().to_owned()], signing_key)),
443 identifier.clone(),
444 ));
445 }
446 ChallengeType::Http01 => {
447 let key_auth_value = key_authorization.as_str();
448 *config.http_01_data_lock.write().await = Some((challenge.token.clone(), key_auth_value.to_string()));
449 }
450 ChallengeType::Dns01 => {
451 if let Some(dns_provider) = &config.dns_provider {
452 dns_provider
453 .remove_acme_txt_record(&identifier)
454 .await
455 .unwrap_or_default();
456 dns_provider
457 .set_acme_txt_record(&identifier, &key_authorization.dns_value())
458 .await?;
459 tokio::time::sleep(Duration::from_secs(60)).await;
461 dns_01_identifiers.push(identifier.clone());
462 } else {
463 Err(anyhow::anyhow!("No DNS provider configured."))?;
464 }
465 }
466 _ => (),
467 }
468
469 challenge.set_ready().await?;
470 }
471
472 let acme_order_status = acme_order.poll_ready(&RetryPolicy::default()).await?;
473 match acme_order_status {
474 OrderStatus::Ready => (), OrderStatus::Invalid => Err(anyhow::anyhow!("ACME order is invalid"))?,
476 _ => Err(anyhow::anyhow!("ACME order is not ready"))?,
477 }
478
479 let finalize_closure = async {
480 let private_key_pem = acme_order.finalize().await?;
481 let certificate_chain_pem = acme_order.poll_certificate(&RetryPolicy::default()).await?;
482
483 let certificate_cache_data = CertificateCacheData {
484 certificate_chain_pem: certificate_chain_pem.clone(),
485 private_key_pem: private_key_pem.clone(),
486 };
487
488 if let Err(err) = set_in_cache(
489 &config.certificate_cache,
490 &certificate_cache_key,
491 serde_json::to_vec(&certificate_cache_data)?,
492 )
493 .await
494 {
495 if !had_cache_error {
496 error_logger
497 .log(&format!(
498 "Failed to access the ACME cache: {}. Ferron can't use ACME caching",
499 err
500 ))
501 .await;
502 had_cache_error = true;
503 }
504 }
505
506 let certs = CertificateDer::pem_slice_iter(certificate_chain_pem.as_bytes())
507 .collect::<Result<Vec<_>, _>>()
508 .map_err(|e| match e {
509 rustls_pki_types::pem::Error::Io(err) => err,
510 err => std::io::Error::other(err),
511 })?;
512 let private_key = (match PrivateKeyDer::from_pem_slice(private_key_pem.as_bytes()) {
513 Ok(private_key) => Ok(private_key),
514 Err(rustls_pki_types::pem::Error::Io(err)) => Err(err),
515 Err(err) => Err(std::io::Error::other(err)),
516 })?;
517
518 let signing_key = CryptoProvider::get_default()
519 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
520 .key_provider
521 .load_private_key(private_key)?;
522
523 config.account.replace(acme_account);
524
525 *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
526
527 Ok::<_, Box<dyn Error + Send + Sync>>(())
528 };
529
530 let result = finalize_closure.await;
531
532 match config.challenge_type {
534 ChallengeType::TlsAlpn01 => {
535 *config.tls_alpn_01_data_lock.write().await = None;
536 }
537 ChallengeType::Http01 => {
538 *config.http_01_data_lock.write().await = None;
539 }
540 ChallengeType::Dns01 => {
541 if let Some(dns_provider) = &config.dns_provider {
542 for identifier in dns_01_identifiers {
543 dns_provider
544 .remove_acme_txt_record(&identifier)
545 .await
546 .unwrap_or_default();
547 }
548 }
549 }
550 _ => {}
551 };
552
553 result?;
554
555 Ok(())
556}
557
558pub async fn get_cached_domains(config: &AcmeOnDemandConfig) -> Vec<String> {
560 if let Some(pathbuf) = config.cache_path.clone() {
561 let hostname_cache_key = get_hostname_cache_key(config);
562 let hostname_cache = AcmeCache::File(pathbuf);
563 let cache_data = get_from_cache(&hostname_cache, &hostname_cache_key).await;
564 if let Some(data) = cache_data {
565 serde_json::from_slice(&data).unwrap_or_default()
566 } else {
567 Vec::new()
568 }
569 } else {
570 Vec::new()
571 }
572}
573
574pub async fn add_domain_to_cache(
576 config: &AcmeOnDemandConfig,
577 domain: &str,
578) -> Result<(), Box<dyn Error + Send + Sync>> {
579 if let Some(pathbuf) = config.cache_path.clone() {
580 let hostname_cache_key = get_hostname_cache_key(config);
581 let hostname_cache = AcmeCache::File(pathbuf);
582 let mut cached_domains = get_cached_domains(config).await;
583 cached_domains.push(domain.to_string());
584 let data = serde_json::to_vec(&cached_domains)?;
585 set_in_cache(&hostname_cache, &hostname_cache_key, data).await?;
586 }
587 Ok(())
588}
589
590pub async fn convert_on_demand_config(
592 config: &AcmeOnDemandConfig,
593 sni_hostname: String,
594 memory_acme_account_cache_data: Arc<RwLock<HashMap<String, Vec<u8>>>>,
595) -> AcmeConfig {
596 let (account_cache_path, cert_cache_path) = if let Some(mut pathbuf) = config.cache_path.clone() {
597 let base_pathbuf = pathbuf.clone();
598 let append_hash = base64::engine::general_purpose::URL_SAFE_NO_PAD
599 .encode(xxh3_128(format!("{}-{sni_hostname}", config.port).as_bytes()).to_be_bytes());
600 pathbuf.push(append_hash);
601 (Some(base_pathbuf), Some(pathbuf))
602 } else {
603 (None, None)
604 };
605
606 let certified_key_lock = Arc::new(tokio::sync::RwLock::new(None));
607 let tls_alpn_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
608 let http_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
609
610 load_host_resolver(
612 &mut *config.sni_resolver_lock.write().await,
613 &sni_hostname,
614 Arc::new(AcmeResolver::new(certified_key_lock.clone())),
615 );
616 match config.challenge_type {
617 ChallengeType::TlsAlpn01 => {
618 config
619 .tls_alpn_01_resolver_lock
620 .write()
621 .await
622 .push(tls_alpn_01_data_lock.clone());
623 }
624 ChallengeType::Http01 => {
625 config
626 .http_01_resolver_lock
627 .write()
628 .await
629 .push(http_01_data_lock.clone());
630 }
631 _ => (),
632 };
633
634 AcmeConfig {
635 rustls_client_config: config.rustls_client_config.clone(),
636 domains: vec![sni_hostname],
637 challenge_type: config.challenge_type.clone(),
638 contact: config.contact.clone(),
639 directory: config.directory.clone(),
640 eab_key: config.eab_key.clone(),
641 profile: config.profile.clone(),
642 account_cache: if let Some(account_cache_path) = account_cache_path {
643 AcmeCache::File(account_cache_path)
644 } else {
645 AcmeCache::Memory(memory_acme_account_cache_data.clone())
646 },
647 certificate_cache: if let Some(cert_cache_path) = cert_cache_path {
648 AcmeCache::File(cert_cache_path)
649 } else {
650 AcmeCache::Memory(Arc::new(tokio::sync::RwLock::new(HashMap::new())))
651 },
652 certified_key_lock: certified_key_lock.clone(),
653 tls_alpn_01_data_lock: tls_alpn_01_data_lock.clone(),
654 http_01_data_lock: http_01_data_lock.clone(),
655 dns_provider: config.dns_provider.clone(),
656 renewal_info: None,
657 account: None,
658 }
659}
660
661#[derive(Debug)]
663pub struct AcmeResolver {
664 certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
665}
666
667impl AcmeResolver {
668 pub fn new(certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>) -> Self {
670 Self { certified_key_lock }
671 }
672}
673
674impl ResolvesServerCert for AcmeResolver {
675 fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
676 self.certified_key_lock.blocking_read().clone()
677 }
678}
679
680struct HttpsClientForAcme(HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, BodyWrapper<Bytes>>);
681
682impl HttpsClientForAcme {
683 fn new(tls_config: ClientConfig) -> Self {
684 Self(
685 HyperClient::builder(TokioExecutor::new()).build(
686 hyper_rustls::HttpsConnectorBuilder::new()
687 .with_tls_config(tls_config)
688 .https_or_http()
689 .enable_http1()
690 .enable_http2()
691 .build(),
692 ),
693 )
694 }
695}
696
697impl HttpClient for HttpsClientForAcme {
698 fn request(
699 &self,
700 req: Request<BodyWrapper<Bytes>>,
701 ) -> Pin<Box<dyn Future<Output = Result<BytesResponse, instant_acme::Error>> + Send>> {
702 HttpClient::request(&self.0, req)
703 }
704}
705
706#[derive(Debug)]
708pub struct TlsAlpn01Resolver {
709 resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>,
710}
711
712impl TlsAlpn01Resolver {
713 #[allow(dead_code)]
715 pub fn new() -> Self {
716 Self {
717 resolvers: Arc::new(tokio::sync::RwLock::new(Vec::new())),
718 }
719 }
720
721 pub fn with_resolvers(resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>) -> Self {
723 Self { resolvers }
724 }
725
726 pub fn load_resolver(&self, resolver: TlsAlpn01DataLock) {
728 self.resolvers.blocking_write().push(resolver);
729 }
730}
731
732impl ResolvesServerCert for TlsAlpn01Resolver {
733 fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
734 let hostname = client_hello.server_name().map(|hn| hn.strip_suffix('.').unwrap_or(hn));
735
736 #[cfg(feature = "runtime-monoio")]
738 let resolver_locks = self.resolvers.blocking_read();
739 #[cfg(feature = "runtime-tokio")]
740 let resolver_locks = futures_executor::block_on(async { self.resolvers.read().await });
741
742 for resolver_lock in &*resolver_locks {
743 if let Some(hostname) = hostname {
744 #[cfg(feature = "runtime-monoio")]
745 let resolver_data = resolver_lock.blocking_read().clone();
746 #[cfg(feature = "runtime-tokio")]
747 let resolver_data = futures_executor::block_on(async { resolver_lock.read().await }).clone();
748 if let Some(resolver_data) = resolver_data {
749 let (cert, host) = resolver_data;
750 if host == hostname {
751 return Some(cert);
752 }
753 }
754 }
755 }
756 None
757 }
758}