ferron/
acme.rs

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::{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::tls_util::load_host_resolver;
36use ferron_common::dns::DnsProvider;
37
38pub const ACME_TLS_ALPN_NAME: &[u8] = b"acme-tls/1";
39const SECONDS_BEFORE_RENEWAL: u64 = 86400; // 1 day before expiration
40
41pub type TlsAlpn01DataLock = Arc<RwLock<Option<(Arc<CertifiedKey>, String)>>>;
42pub type Http01DataLock = Arc<RwLock<Option<(String, String)>>>;
43
44/// Represents the configuration for the ACME client.
45pub struct AcmeConfig {
46  /// The Rustls client configuration to use for ACME communication.
47  pub rustls_client_config: ClientConfig,
48  /// The domains for which to request certificates.
49  pub domains: Vec<String>,
50  /// The type of challenge to use for ACME certificate issuance.
51  pub challenge_type: ChallengeType,
52  /// The contact information for the ACME account.
53  pub contact: Vec<String>,
54  /// The directory URL for the ACME server.
55  pub directory: String,
56  /// The optional EAB key
57  pub eab_key: Option<Arc<ExternalAccountKey>>,
58  /// The optional ACME profile name
59  pub profile: Option<String>,
60  /// The cache for storing ACME account information.
61  pub account_cache: AcmeCache,
62  /// The cache for storing ACME certificate information.
63  pub certificate_cache: AcmeCache,
64  /// The lock for managing the certified key.
65  pub certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
66  /// The lock for managing the TLS-ALPN-01 data.
67  pub tls_alpn_01_data_lock: TlsAlpn01DataLock,
68  /// The lock for managing the HTTP-01 data.
69  pub http_01_data_lock: Http01DataLock,
70  /// The ACME DNS provider.
71  pub dns_provider: Option<Arc<dyn DnsProvider + Send + Sync>>,
72  /// The certificate renewal information.
73  pub renewal_info: Option<(RenewalInfo, Instant)>,
74  /// The ACME account information
75  pub account: Option<Account>,
76}
77
78/// Represents the type of cache to use for storing ACME data.
79pub enum AcmeCache {
80  /// Use an in-memory cache.
81  Memory(Arc<RwLock<HashMap<String, Vec<u8>>>>),
82  /// Use a file-based cache.
83  File(PathBuf),
84}
85
86#[derive(Serialize, Deserialize)]
87struct CertificateCacheData {
88  certificate_chain_pem: String,
89  private_key_pem: String,
90}
91
92/// Gets data from the cache.
93async fn get_from_cache(cache: &AcmeCache, key: &str) -> Option<Vec<u8>> {
94  match cache {
95    AcmeCache::Memory(cache) => cache.read().await.get(key).cloned(),
96    AcmeCache::File(path) => tokio::fs::read(path.join(key)).await.ok(),
97  }
98}
99
100/// Represents the on-demand configuration for the ACME client.
101pub struct AcmeOnDemandConfig {
102  /// The Rustls client configuration to use for ACME communication.
103  pub rustls_client_config: ClientConfig,
104  /// The type of challenge to use for ACME certificate issuance.
105  pub challenge_type: ChallengeType,
106  /// The contact information for the ACME account.
107  pub contact: Vec<String>,
108  /// The directory URL for the ACME server.
109  pub directory: String,
110  /// The optional EAB key
111  pub eab_key: Option<Arc<ExternalAccountKey>>,
112  /// The optional ACME profile name
113  pub profile: Option<String>,
114  /// The path to the cache directory for storing ACME information.
115  pub cache_path: Option<PathBuf>,
116  /// The lock for managing the SNI resolver.
117  #[allow(clippy::type_complexity)]
118  pub sni_resolver_lock: Arc<RwLock<Vec<(String, Arc<dyn ResolvesServerCert>)>>>,
119  /// The lock for managing the TLS-ALPN-01 resolver.
120  pub tls_alpn_01_resolver_lock: Arc<RwLock<Vec<TlsAlpn01DataLock>>>,
121  /// The lock for managing the HTTP-01 resolver.
122  pub http_01_resolver_lock: Arc<RwLock<Vec<Http01DataLock>>>,
123  /// The ACME DNS provider.
124  pub dns_provider: Option<Arc<dyn DnsProvider + Send + Sync>>,
125  /// The SNI hostname.
126  pub sni_hostname: Option<String>,
127  /// The port to use for ACME communication.
128  pub port: u16,
129}
130
131/// Sets data in the cache.
132async fn set_in_cache(cache: &AcmeCache, key: &str, value: Vec<u8>) -> Result<(), Box<dyn Error + Send + Sync>> {
133  match cache {
134    AcmeCache::Memory(cache) => {
135      cache.write().await.insert(key.to_string(), value);
136      Ok(())
137    }
138    AcmeCache::File(path) => {
139      tokio::fs::create_dir_all(path).await.unwrap_or_default();
140      let mut open_options = tokio::fs::OpenOptions::new();
141      open_options.write(true).create(true);
142
143      #[cfg(unix)]
144      open_options.mode(0o600); // Don't allow others to read or write
145
146      let mut file = open_options.open(path.join(key)).await?;
147      file.write_all(&value).await?;
148      file.flush().await.unwrap_or_default();
149
150      Ok(())
151    }
152  }
153}
154
155/// Removes data from the cache.
156async fn remove_from_cache(cache: &AcmeCache, key: &str) {
157  match cache {
158    AcmeCache::Memory(cache) => {
159      cache.write().await.remove(key);
160    }
161    AcmeCache::File(path) => {
162      let _ = tokio::fs::remove_file(path.join(key)).await;
163    }
164  }
165}
166
167/// Checks if the TLS certificate is valid
168fn check_certificate_validity(
169  certificate: &CertificateDer,
170  renewal_info: Option<&RenewalInfo>,
171) -> Result<bool, Box<dyn Error + Send + Sync>> {
172  if let Some(renewal_info) = renewal_info {
173    return Ok(SystemTime::now() < renewal_info.suggested_window.start);
174  }
175  let (_, x509_certificate) = X509Certificate::from_der(certificate)?;
176  let validity = x509_certificate.validity();
177  if let Some(time_to_expiration) = validity.time_to_expiration() {
178    let time_before_expiration = if let Some(valid_duration) = validity.not_after.sub(validity.not_before) {
179      (valid_duration.whole_seconds().unsigned_abs() / 2).min(SECONDS_BEFORE_RENEWAL)
180    } else {
181      SECONDS_BEFORE_RENEWAL
182    };
183    if time_to_expiration >= Duration::from_secs(time_before_expiration) {
184      return Ok(true);
185    }
186  }
187  Ok(false)
188}
189
190/// Determines the account cache key
191fn get_account_cache_key(config: &AcmeConfig) -> String {
192  format!(
193    "account_{}",
194    base64::engine::general_purpose::URL_SAFE_NO_PAD
195      .encode(xxh3_128(format!("{};{}", &config.contact.join(","), &config.directory).as_bytes()).to_be_bytes())
196  )
197}
198
199/// Determines the certificate cache key
200fn get_certificate_cache_key(config: &AcmeConfig) -> String {
201  format!(
202    "certificate_{}",
203    base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(
204      xxh3_128(
205        format!(
206          "{}{}",
207          config.domains.join(","),
208          config.profile.as_ref().map_or("".to_string(), |p| format!(";{p}"))
209        )
210        .as_bytes()
211      )
212      .to_be_bytes()
213    )
214  )
215}
216
217/// Determines the account cache key
218fn get_hostname_cache_key(config: &AcmeOnDemandConfig) -> String {
219  format!(
220    "hostname_{}",
221    base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(
222      xxh3_128(
223        format!(
224          "{}{}",
225          &config.port,
226          config.sni_hostname.as_ref().map_or("".to_string(), |h| format!(";{h}"))
227        )
228        .as_bytes()
229      )
230      .to_be_bytes()
231    )
232  )
233}
234
235/// Checks if the TLS certificate (cached or live) is valid. If cached certificate is valid, installs the cached certificate
236pub async fn check_certificate_validity_or_install_cached(
237  config: &mut AcmeConfig,
238  acme_account: Option<&Account>,
239) -> Result<bool, Box<dyn Error + Send + Sync>> {
240  if let Some(certified_key) = config.certified_key_lock.read().await.as_deref() {
241    if let Some(certificate) = certified_key.cert.first() {
242      if let Some(acme_account) = acme_account {
243        if config
244          .renewal_info
245          .as_ref()
246          .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
247        {
248          if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
249            if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
250              let mut renewal_instant = Instant::now();
251              renewal_instant += renewal_info.1;
252              config.renewal_info = Some((renewal_info.0, renewal_instant));
253            }
254          }
255        }
256      }
257      if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
258        return Ok(true);
259      }
260    }
261  }
262
263  let certificate_cache_key = get_certificate_cache_key(config);
264
265  if let Some(serialized_certificate_cache_data) =
266    get_from_cache(&config.certificate_cache, &certificate_cache_key).await
267  {
268    let certificate_data = serde_json::from_slice::<CertificateCacheData>(&serialized_certificate_cache_data)?;
269    let certs = rustls_pemfile::certs(&mut std::io::Cursor::new(
270      certificate_data.certificate_chain_pem.as_bytes(),
271    ))
272    .collect::<Result<Vec<_>, _>>()?;
273    if let Some(certificate) = certs.first() {
274      if let Some(acme_account) = acme_account {
275        if config
276          .renewal_info
277          .as_ref()
278          .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
279        {
280          if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
281            if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
282              let mut renewal_instant = Instant::now();
283              renewal_instant -= renewal_info.1;
284              config.renewal_info = Some((renewal_info.0, renewal_instant));
285            }
286          }
287        }
288      }
289      if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
290        let private_key =
291          (match rustls_pemfile::private_key(&mut std::io::Cursor::new(certificate_data.private_key_pem.as_bytes())) {
292            Ok(Some(private_key)) => Ok(private_key),
293            Ok(None) => Err(std::io::Error::new(
294              std::io::ErrorKind::InvalidData,
295              "Invalid private key",
296            )),
297            Err(err) => Err(err),
298          })?;
299
300        let signing_key = CryptoProvider::get_default()
301          .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
302          .key_provider
303          .load_private_key(private_key)?;
304
305        *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
306
307        return Ok(true);
308      }
309    }
310  }
311
312  Ok(false)
313}
314
315/// Provisions TLS certificates using the ACME protocol.
316pub async fn provision_certificate(config: &mut AcmeConfig) -> Result<(), Box<dyn Error + Send + Sync>> {
317  let account_cache_key = get_account_cache_key(config);
318  let certificate_cache_key = get_certificate_cache_key(config);
319
320  let acme_account = if let Some(acme_account) = config.account.take() {
321    acme_account
322  } else {
323    let acme_account_builder =
324      Account::builder_with_http(Box::new(HttpsClientForAcme::new(config.rustls_client_config.clone())));
325
326    if let Some(account_credentials_serialized) = get_from_cache(&config.account_cache, &account_cache_key).await {
327      let account_credentials = serde_json::from_slice::<AccountCredentials>(&account_credentials_serialized)?;
328      acme_account_builder.from_credentials(account_credentials).await?
329    } else {
330      let (account, account_credentials) = acme_account_builder
331        .create(
332          &NewAccount {
333            contact: config.contact.iter().map(|s| s.deref()).collect::<Vec<_>>().as_slice(),
334            terms_of_service_agreed: true,
335            only_return_existing: false,
336          },
337          config.directory.clone(),
338          config.eab_key.as_deref(),
339        )
340        .await?;
341
342      set_in_cache(
343        &config.account_cache,
344        &account_cache_key,
345        serde_json::to_vec(&account_credentials)?,
346      )
347      .await?;
348      account
349    }
350  };
351
352  if check_certificate_validity_or_install_cached(config, Some(&acme_account)).await? {
353    // Certificate is still valid, no need to renew
354    config.account.replace(acme_account);
355    return Ok(());
356  }
357
358  let acme_identifiers_vec = config
359    .domains
360    .iter()
361    .map(|s| {
362      if let Ok(ip) = s.parse::<IpAddr>() {
363        Identifier::Ip(ip)
364      } else {
365        Identifier::Dns(s.to_string())
366      }
367    })
368    .collect::<Vec<_>>();
369
370  let mut acme_new_order = NewOrder::new(&acme_identifiers_vec);
371  if let Some(profile) = &config.profile {
372    acme_new_order = acme_new_order.profile(profile);
373  }
374
375  let mut acme_order = match acme_account.new_order(&acme_new_order).await {
376    Ok(order) => order,
377    Err(instant_acme::Error::Api(problem)) => {
378      if problem.r#type.as_deref() == Some("urn:ietf:params:acme:error:accountDoesNotExist") {
379        // Remove non-existent account from the cache
380        remove_from_cache(&config.account_cache, &account_cache_key).await;
381      }
382      Err(instant_acme::Error::Api(problem))?
383    }
384    Err(err) => Err(err)?,
385  };
386  let mut dns_01_identifiers = Vec::new();
387  let mut acme_authorizations = acme_order.authorizations();
388  while let Some(acme_authorization) = acme_authorizations.next().await {
389    let mut acme_authorization = acme_authorization?;
390    match acme_authorization.status {
391      AuthorizationStatus::Pending => {}
392      AuthorizationStatus::Valid => continue,
393      _ => Err(anyhow::anyhow!("Invalid ACME authorization status"))?,
394    }
395
396    let mut challenge = acme_authorization
397      .challenge(config.challenge_type.clone())
398      .ok_or(anyhow::anyhow!(
399        "The ACME server doesn't support the requested challenge type"
400      ))?;
401
402    let identifier = match challenge.identifier().identifier {
403      Identifier::Dns(identifier) => identifier.to_string(),
404      Identifier::Ip(ip) => ip.to_string(),
405      _ => Err(anyhow::anyhow!("Unsupported ACME identifier type",))?,
406    };
407
408    let key_authorization = challenge.key_authorization();
409    match config.challenge_type {
410      ChallengeType::TlsAlpn01 => {
411        let mut params = CertificateParams::new(vec![identifier.clone()])?;
412        params.custom_extensions.push(CustomExtension::new_acme_identifier(
413          key_authorization.digest().as_ref(),
414        ));
415        let key_pair = KeyPair::generate()?;
416        let certificate = params.self_signed(&key_pair)?;
417        let private_key = PrivateKeyDer::try_from(key_pair.serialize_der())?;
418
419        let signing_key = CryptoProvider::get_default()
420          .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
421          .key_provider
422          .load_private_key(private_key)?;
423
424        *config.tls_alpn_01_data_lock.write().await = Some((
425          Arc::new(CertifiedKey::new(vec![certificate.der().to_owned()], signing_key)),
426          identifier.clone(),
427        ));
428      }
429      ChallengeType::Http01 => {
430        let key_auth_value = key_authorization.as_str();
431        *config.http_01_data_lock.write().await = Some((challenge.token.clone(), key_auth_value.to_string()));
432      }
433      ChallengeType::Dns01 => {
434        if let Some(dns_provider) = &config.dns_provider {
435          dns_provider
436            .remove_acme_txt_record(&identifier)
437            .await
438            .unwrap_or_default();
439          dns_provider
440            .set_acme_txt_record(&identifier, &key_authorization.dns_value())
441            .await?;
442          // Wait for DNS propagation
443          tokio::time::sleep(Duration::from_secs(60)).await;
444          dns_01_identifiers.push(identifier.clone());
445        } else {
446          Err(anyhow::anyhow!("No DNS provider configured."))?;
447        }
448      }
449      _ => (),
450    }
451
452    challenge.set_ready().await?;
453  }
454
455  let acme_order_status = acme_order.poll_ready(&RetryPolicy::default()).await?;
456  if acme_order_status != OrderStatus::Ready {
457    Err(anyhow::anyhow!("ACME order is not ready",))?;
458  }
459
460  let finalize_closure = async {
461    let private_key_pem = acme_order.finalize().await?;
462    let certificate_chain_pem = acme_order.poll_certificate(&RetryPolicy::default()).await?;
463
464    let certificate_cache_data = CertificateCacheData {
465      certificate_chain_pem: certificate_chain_pem.clone(),
466      private_key_pem: private_key_pem.clone(),
467    };
468
469    set_in_cache(
470      &config.certificate_cache,
471      &certificate_cache_key,
472      serde_json::to_vec(&certificate_cache_data)?,
473    )
474    .await?;
475
476    let certs = rustls_pemfile::certs(&mut std::io::Cursor::new(certificate_chain_pem.as_bytes()))
477      .collect::<Result<Vec<_>, _>>()?;
478    let private_key = (match rustls_pemfile::private_key(&mut std::io::Cursor::new(private_key_pem.as_bytes())) {
479      Ok(Some(private_key)) => Ok(private_key),
480      Ok(None) => Err(std::io::Error::new(
481        std::io::ErrorKind::InvalidData,
482        "Invalid private key",
483      )),
484      Err(err) => Err(err),
485    })?;
486
487    let signing_key = CryptoProvider::get_default()
488      .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
489      .key_provider
490      .load_private_key(private_key)?;
491
492    config.account.replace(acme_account);
493
494    *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
495
496    Ok::<_, Box<dyn Error + Send + Sync>>(())
497  };
498
499  let result = finalize_closure.await;
500
501  // Cleanup
502  if let Some(dns_provider) = &config.dns_provider {
503    for identifier in dns_01_identifiers {
504      dns_provider
505        .remove_acme_txt_record(&identifier)
506        .await
507        .unwrap_or_default();
508    }
509  }
510
511  result?;
512
513  Ok(())
514}
515
516/// Obtains the list of domains for which `AcmeOnDemandConfig` was converted into `AcmeConfig` from cache.
517pub async fn get_cached_domains(config: &AcmeOnDemandConfig) -> Vec<String> {
518  if let Some(pathbuf) = config.cache_path.clone() {
519    let hostname_cache_key = get_hostname_cache_key(config);
520    let hostname_cache = AcmeCache::File(pathbuf);
521    let cache_data = get_from_cache(&hostname_cache, &hostname_cache_key).await;
522    if let Some(data) = cache_data {
523      serde_json::from_slice(&data).unwrap_or_default()
524    } else {
525      Vec::new()
526    }
527  } else {
528    Vec::new()
529  }
530}
531
532/// Adds the domain to the cache.
533pub async fn add_domain_to_cache(
534  config: &AcmeOnDemandConfig,
535  domain: &str,
536) -> Result<(), Box<dyn Error + Send + Sync>> {
537  if let Some(pathbuf) = config.cache_path.clone() {
538    let hostname_cache_key = get_hostname_cache_key(config);
539    let hostname_cache = AcmeCache::File(pathbuf);
540    let mut cached_domains = get_cached_domains(config).await;
541    cached_domains.push(domain.to_string());
542    let data = serde_json::to_vec(&cached_domains)?;
543    set_in_cache(&hostname_cache, &hostname_cache_key, data).await?;
544  }
545  Ok(())
546}
547
548/// Converts a `AcmeOnDemandConfig` into an `AcmeConfig`
549pub async fn convert_on_demand_config(
550  config: &AcmeOnDemandConfig,
551  sni_hostname: String,
552  memory_acme_account_cache_data: Arc<RwLock<HashMap<String, Vec<u8>>>>,
553) -> AcmeConfig {
554  let (account_cache_path, cert_cache_path) = if let Some(mut pathbuf) = config.cache_path.clone() {
555    let base_pathbuf = pathbuf.clone();
556    let append_hash = base64::engine::general_purpose::URL_SAFE_NO_PAD
557      .encode(xxh3_128(format!("{}-{sni_hostname}", config.port).as_bytes()).to_be_bytes());
558    pathbuf.push(append_hash);
559    (Some(base_pathbuf), Some(pathbuf))
560  } else {
561    (None, None)
562  };
563
564  let certified_key_lock = Arc::new(tokio::sync::RwLock::new(None));
565  let tls_alpn_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
566  let http_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
567
568  // Insert new locked data
569  load_host_resolver(
570    &mut *config.sni_resolver_lock.write().await,
571    &sni_hostname,
572    Arc::new(AcmeResolver::new(certified_key_lock.clone())),
573  );
574  match config.challenge_type {
575    ChallengeType::TlsAlpn01 => {
576      config
577        .tls_alpn_01_resolver_lock
578        .write()
579        .await
580        .push(tls_alpn_01_data_lock.clone());
581    }
582    ChallengeType::Http01 => {
583      config
584        .http_01_resolver_lock
585        .write()
586        .await
587        .push(http_01_data_lock.clone());
588    }
589    _ => (),
590  };
591
592  AcmeConfig {
593    rustls_client_config: config.rustls_client_config.clone(),
594    domains: vec![sni_hostname],
595    challenge_type: config.challenge_type.clone(),
596    contact: config.contact.clone(),
597    directory: config.directory.clone(),
598    eab_key: config.eab_key.clone(),
599    profile: config.profile.clone(),
600    account_cache: if let Some(account_cache_path) = account_cache_path {
601      AcmeCache::File(account_cache_path)
602    } else {
603      AcmeCache::Memory(memory_acme_account_cache_data.clone())
604    },
605    certificate_cache: if let Some(cert_cache_path) = cert_cache_path {
606      AcmeCache::File(cert_cache_path)
607    } else {
608      AcmeCache::Memory(Arc::new(tokio::sync::RwLock::new(HashMap::new())))
609    },
610    certified_key_lock: certified_key_lock.clone(),
611    tls_alpn_01_data_lock: tls_alpn_01_data_lock.clone(),
612    http_01_data_lock: http_01_data_lock.clone(),
613    dns_provider: config.dns_provider.clone(),
614    renewal_info: None,
615    account: None,
616  }
617}
618
619/// An ACME resolver resolving one certified key
620#[derive(Debug)]
621pub struct AcmeResolver {
622  certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
623}
624
625impl AcmeResolver {
626  /// Creates an ACME resolver
627  pub fn new(certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>) -> Self {
628    Self { certified_key_lock }
629  }
630}
631
632impl ResolvesServerCert for AcmeResolver {
633  fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
634    self.certified_key_lock.blocking_read().clone()
635  }
636}
637
638struct HttpsClientForAcme(HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, BodyWrapper<Bytes>>);
639
640impl HttpsClientForAcme {
641  fn new(tls_config: ClientConfig) -> Self {
642    Self(
643      HyperClient::builder(TokioExecutor::new()).build(
644        hyper_rustls::HttpsConnectorBuilder::new()
645          .with_tls_config(tls_config)
646          .https_or_http()
647          .enable_http1()
648          .enable_http2()
649          .build(),
650      ),
651    )
652  }
653}
654
655impl HttpClient for HttpsClientForAcme {
656  fn request(
657    &self,
658    req: Request<BodyWrapper<Bytes>>,
659  ) -> Pin<Box<dyn Future<Output = Result<BytesResponse, instant_acme::Error>> + Send>> {
660    HttpClient::request(&self.0, req)
661  }
662}
663
664/// The TLS-ALPN-01 ACME challenge certificate resolver
665#[derive(Debug)]
666pub struct TlsAlpn01Resolver {
667  resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>,
668}
669
670impl TlsAlpn01Resolver {
671  /// Creates a TLS-ALPN-01 resolver
672  #[allow(dead_code)]
673  pub fn new() -> Self {
674    Self {
675      resolvers: Arc::new(tokio::sync::RwLock::new(Vec::new())),
676    }
677  }
678
679  /// Creates a TLS-ALPN-01 resolver with provided resolver list lock
680  pub fn with_resolvers(resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>) -> Self {
681    Self { resolvers }
682  }
683
684  /// Loads a certificate resolver lock
685  pub fn load_resolver(&self, resolver: TlsAlpn01DataLock) {
686    self.resolvers.blocking_write().push(resolver);
687  }
688}
689
690impl ResolvesServerCert for TlsAlpn01Resolver {
691  fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
692    let hostname = client_hello.server_name().map(|hn| hn.strip_suffix('.').unwrap_or(hn));
693
694    // If blocking_read() method is used when only Tokio is used, the program would panic on resolving a TLS certificate.
695    #[cfg(feature = "runtime-monoio")]
696    let resolver_locks = self.resolvers.blocking_read();
697    #[cfg(feature = "runtime-tokio")]
698    let resolver_locks = futures_executor::block_on(async { self.resolvers.read().await });
699
700    for resolver_lock in &*resolver_locks {
701      if let Some(hostname) = hostname {
702        #[cfg(feature = "runtime-monoio")]
703        let resolver_data = resolver_lock.blocking_read().clone();
704        #[cfg(feature = "runtime-tokio")]
705        let resolver_data = futures_executor::block_on(async { resolver_lock.read().await }).clone();
706        if let Some(resolver_data) = resolver_data {
707          let (cert, host) = resolver_data;
708          if host == hostname {
709            return Some(cert);
710          }
711        }
712      }
713    }
714    None
715  }
716}