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::{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; // 1 day before expiration
41
42pub type TlsAlpn01DataLock = Arc<RwLock<Option<(Arc<CertifiedKey>, String)>>>;
43pub type Http01DataLock = Arc<RwLock<Option<(String, String)>>>;
44
45/// Represents the configuration for the ACME client.
46pub struct AcmeConfig {
47  /// The Rustls client configuration to use for ACME communication.
48  pub rustls_client_config: ClientConfig,
49  /// The domains for which to request certificates.
50  pub domains: Vec<String>,
51  /// The type of challenge to use for ACME certificate issuance.
52  pub challenge_type: ChallengeType,
53  /// The contact information for the ACME account.
54  pub contact: Vec<String>,
55  /// The directory URL for the ACME server.
56  pub directory: String,
57  /// The optional EAB key
58  pub eab_key: Option<Arc<ExternalAccountKey>>,
59  /// The optional ACME profile name
60  pub profile: Option<String>,
61  /// The cache for storing ACME account information.
62  pub account_cache: AcmeCache,
63  /// The cache for storing ACME certificate information.
64  pub certificate_cache: AcmeCache,
65  /// The lock for managing the certified key.
66  pub certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
67  /// The lock for managing the TLS-ALPN-01 data.
68  pub tls_alpn_01_data_lock: TlsAlpn01DataLock,
69  /// The lock for managing the HTTP-01 data.
70  pub http_01_data_lock: Http01DataLock,
71  /// The ACME DNS provider.
72  pub dns_provider: Option<Arc<dyn DnsProvider + Send + Sync>>,
73  /// The certificate renewal information.
74  pub renewal_info: Option<(RenewalInfo, Instant)>,
75  /// The ACME account information
76  pub account: Option<Account>,
77}
78
79/// Represents the type of cache to use for storing ACME data.
80pub enum AcmeCache {
81  /// Use an in-memory cache.
82  Memory(Arc<RwLock<HashMap<String, Vec<u8>>>>),
83  /// Use a file-based cache.
84  File(PathBuf),
85}
86
87#[derive(Serialize, Deserialize)]
88struct CertificateCacheData {
89  certificate_chain_pem: String,
90  private_key_pem: String,
91}
92
93/// Gets data from the cache.
94async 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
101/// Represents the on-demand configuration for the ACME client.
102pub struct AcmeOnDemandConfig {
103  /// The Rustls client configuration to use for ACME communication.
104  pub rustls_client_config: ClientConfig,
105  /// The type of challenge to use for ACME certificate issuance.
106  pub challenge_type: ChallengeType,
107  /// The contact information for the ACME account.
108  pub contact: Vec<String>,
109  /// The directory URL for the ACME server.
110  pub directory: String,
111  /// The optional EAB key
112  pub eab_key: Option<Arc<ExternalAccountKey>>,
113  /// The optional ACME profile name
114  pub profile: Option<String>,
115  /// The path to the cache directory for storing ACME information.
116  pub cache_path: Option<PathBuf>,
117  /// The lock for managing the SNI resolver.
118  #[allow(clippy::type_complexity)]
119  pub sni_resolver_lock: Arc<RwLock<Vec<(String, Arc<dyn ResolvesServerCert>)>>>,
120  /// The lock for managing the TLS-ALPN-01 resolver.
121  pub tls_alpn_01_resolver_lock: Arc<RwLock<Vec<TlsAlpn01DataLock>>>,
122  /// The lock for managing the HTTP-01 resolver.
123  pub http_01_resolver_lock: Arc<RwLock<Vec<Http01DataLock>>>,
124  /// The ACME DNS provider.
125  pub dns_provider: Option<Arc<dyn DnsProvider + Send + Sync>>,
126  /// The SNI hostname.
127  pub sni_hostname: Option<String>,
128  /// The port to use for ACME communication.
129  pub port: u16,
130}
131
132/// Sets data in the cache.
133async 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); // Don't allow others to read or write
146
147      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
156/// Removes data from the cache.
157async 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
168/// Checks if the TLS certificate is valid
169fn 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
191/// Determines the account cache key
192fn 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
200/// Determines the certificate cache key
201fn 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
221/// Determines the account cache key
222fn 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
239/// Checks if the TLS certificate (cached or live) is valid. If cached certificate is valid, installs the cached certificate
240pub 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      // Corrupted certificates would be skipped
274      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            // Corrupted private key would be skipped
295            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
314/// Provisions TLS certificates using the ACME protocol.
315pub 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    // Certificate is still valid, no need to renew
371    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 non-existent account from the cache
397        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          // Wait for DNS propagation
460          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 => (), // It's alright!
475    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  // Cleanup
533  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
558/// Obtains the list of domains for which `AcmeOnDemandConfig` was converted into `AcmeConfig` from cache.
559pub 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
574/// Adds the domain to the cache.
575pub 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
590/// Converts a `AcmeOnDemandConfig` into an `AcmeConfig`
591pub 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  // Insert new locked data
611  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/// An ACME resolver resolving one certified key
662#[derive(Debug)]
663pub struct AcmeResolver {
664  certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
665}
666
667impl AcmeResolver {
668  /// Creates an ACME resolver
669  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/// The TLS-ALPN-01 ACME challenge certificate resolver
707#[derive(Debug)]
708pub struct TlsAlpn01Resolver {
709  resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>,
710}
711
712impl TlsAlpn01Resolver {
713  /// Creates a TLS-ALPN-01 resolver
714  #[allow(dead_code)]
715  pub fn new() -> Self {
716    Self {
717      resolvers: Arc::new(tokio::sync::RwLock::new(Vec::new())),
718    }
719  }
720
721  /// Creates a TLS-ALPN-01 resolver with provided resolver list lock
722  pub fn with_resolvers(resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>) -> Self {
723    Self { resolvers }
724  }
725
726  /// Loads a certificate resolver lock
727  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    // If blocking_read() method is used when only Tokio is used, the program would panic on resolving a TLS certificate.
737    #[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}