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::SniResolverLock;
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 pub save_paths: Option<(PathBuf, PathBuf)>,
79 pub post_obtain_command: Option<String>,
82}
83
84pub enum AcmeCache {
86 Memory(Arc<RwLock<HashMap<String, Vec<u8>>>>),
88 File(PathBuf),
90}
91
92impl AcmeCache {
93 async fn get(&self, key: &str) -> Option<Vec<u8>> {
95 match self {
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 async fn set(&self, key: &str, value: Vec<u8>) -> Result<(), std::io::Error> {
103 match self {
104 AcmeCache::Memory(cache) => {
105 cache.write().await.insert(key.to_string(), value);
106 Ok(())
107 }
108 AcmeCache::File(path) => {
109 tokio::fs::create_dir_all(path).await.unwrap_or_default();
110 let mut open_options = tokio::fs::OpenOptions::new();
111 open_options.write(true).create(true).truncate(true);
112
113 #[cfg(unix)]
114 open_options.mode(0o600); let mut file = open_options.open(path.join(key)).await?;
117 file.write_all(&value).await?;
118 file.flush().await.unwrap_or_default();
119
120 Ok(())
121 }
122 }
123 }
124
125 async fn remove(&self, key: &str) {
127 match self {
128 AcmeCache::Memory(cache) => {
129 cache.write().await.remove(key);
130 }
131 AcmeCache::File(path) => {
132 let _ = tokio::fs::remove_file(path.join(key)).await;
133 }
134 }
135 }
136}
137
138#[derive(Serialize, Deserialize)]
139struct CertificateCacheData {
140 certificate_chain_pem: String,
141 private_key_pem: String,
142}
143
144pub struct AcmeOnDemandConfig {
146 pub rustls_client_config: ClientConfig,
148 pub challenge_type: ChallengeType,
150 pub contact: Vec<String>,
152 pub directory: String,
154 pub eab_key: Option<Arc<ExternalAccountKey>>,
156 pub profile: Option<String>,
158 pub cache_path: Option<PathBuf>,
160 pub sni_resolver_lock: SniResolverLock,
162 pub tls_alpn_01_resolver_lock: Arc<RwLock<Vec<TlsAlpn01DataLock>>>,
164 pub http_01_resolver_lock: Arc<RwLock<Vec<Http01DataLock>>>,
166 pub dns_provider: Option<Arc<dyn DnsProvider + Send + Sync>>,
168 pub sni_hostname: Option<String>,
170 pub port: u16,
172}
173
174fn check_certificate_validity(
176 certificate: &CertificateDer,
177 renewal_info: Option<&RenewalInfo>,
178) -> Result<bool, Box<dyn Error + Send + Sync>> {
179 if let Some(renewal_info) = renewal_info {
180 return Ok(SystemTime::now() < renewal_info.suggested_window.start);
181 }
182 let (_, x509_certificate) = X509Certificate::from_der(certificate)?;
183 let validity = x509_certificate.validity();
184 if let Some(time_to_expiration) = validity.time_to_expiration() {
185 let time_before_expiration = if let Some(valid_duration) = validity.not_after.sub(validity.not_before) {
186 (valid_duration.whole_seconds().unsigned_abs() / 2).min(SECONDS_BEFORE_RENEWAL)
187 } else {
188 SECONDS_BEFORE_RENEWAL
189 };
190 if time_to_expiration >= Duration::from_secs(time_before_expiration) {
191 return Ok(true);
192 }
193 }
194 Ok(false)
195}
196
197fn get_account_cache_key(config: &AcmeConfig) -> String {
199 format!(
200 "account_{}",
201 base64::engine::general_purpose::URL_SAFE_NO_PAD
202 .encode(xxh3_128(format!("{};{}", &config.contact.join(","), &config.directory).as_bytes()).to_be_bytes())
203 )
204}
205
206fn get_certificate_cache_key(config: &AcmeConfig) -> String {
208 let mut domains = config.domains.clone();
209 domains.sort_unstable();
210 let domains_joined = domains.join(",");
211 format!(
212 "certificate_{}",
213 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(
214 xxh3_128(
215 format!(
216 "{}{}",
217 domains_joined,
218 config.profile.as_ref().map_or("".to_string(), |p| format!(";{p}"))
219 )
220 .as_bytes()
221 )
222 .to_be_bytes()
223 )
224 )
225}
226
227fn get_hostname_cache_key(config: &AcmeOnDemandConfig) -> String {
229 format!(
230 "hostname_{}",
231 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(
232 xxh3_128(
233 format!(
234 "{}{}",
235 &config.port,
236 config.sni_hostname.as_ref().map_or("".to_string(), |h| format!(";{h}"))
237 )
238 .as_bytes()
239 )
240 .to_be_bytes()
241 )
242 )
243}
244
245async fn post_process_obtained_certificate(
247 config: &AcmeConfig,
248 certificate_pem: &str,
249 private_key_pem: &str,
250) -> Result<(), Box<dyn Error + Send + Sync>> {
251 if let Some((cert_path, key_path)) = &config.save_paths {
252 tokio::fs::write(cert_path, certificate_pem).await?;
253
254 let mut open_options = tokio::fs::OpenOptions::new();
255 open_options.write(true).create(true).truncate(true);
256
257 #[cfg(unix)]
258 open_options.mode(0o600); let mut file = open_options.open(key_path).await?;
261 file.write_all(private_key_pem.as_bytes()).await?;
262 file.flush().await.unwrap_or_default();
263
264 if let Some(command) = &config.post_obtain_command {
265 tokio::process::Command::new(command)
266 .env("FERRON_ACME_DOMAIN", config.domains.join(","))
267 .env("FERRON_ACME_CERT_PATH", cert_path)
268 .env("FERRON_ACME_KEY_PATH", key_path)
269 .stdin(std::process::Stdio::null())
270 .stdout(std::process::Stdio::null())
271 .stderr(std::process::Stdio::null())
272 .spawn()?;
273 }
274 }
275
276 Ok(())
277}
278
279pub async fn check_certificate_validity_or_install_cached(
281 config: &mut AcmeConfig,
282 acme_account: Option<&Account>,
283) -> Result<bool, Box<dyn Error + Send + Sync>> {
284 if let Some(certified_key) = config.certified_key_lock.read().await.as_deref() {
285 if let Some(certificate) = certified_key.cert.first() {
286 if let Some(acme_account) = acme_account {
287 if config
288 .renewal_info
289 .as_ref()
290 .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
291 {
292 if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
293 if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
294 let mut renewal_instant = Instant::now();
295 renewal_instant += renewal_info.1;
296 config.renewal_info = Some((renewal_info.0, renewal_instant));
297 }
298 }
299 }
300 }
301 if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
302 return Ok(true);
303 }
304 }
305 }
306
307 let certificate_cache_key = get_certificate_cache_key(config);
308
309 if let Some(serialized_certificate_cache_data) = config.certificate_cache.get(&certificate_cache_key).await {
310 if let Ok(certificate_data) = serde_json::from_slice::<CertificateCacheData>(&serialized_certificate_cache_data) {
311 if let Ok(certs) =
313 CertificateDer::pem_slice_iter(certificate_data.certificate_chain_pem.as_bytes()).collect::<Result<Vec<_>, _>>()
314 {
315 if let Some(certificate) = certs.first() {
316 if let Some(acme_account) = acme_account {
317 if config
318 .renewal_info
319 .as_ref()
320 .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
321 {
322 if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
323 if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
324 let mut renewal_instant = Instant::now();
325 renewal_instant += renewal_info.1;
326 config.renewal_info = Some((renewal_info.0, renewal_instant));
327 }
328 }
329 }
330 }
331 if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
332 if let Ok(private_key) = PrivateKeyDer::from_pem_slice(certificate_data.private_key_pem.as_bytes()) {
334 let signing_key = CryptoProvider::get_default()
335 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
336 .key_provider
337 .load_private_key(private_key)?;
338
339 *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
340
341 let _ = post_process_obtained_certificate(
342 config,
343 &certificate_data.certificate_chain_pem,
344 &certificate_data.private_key_pem,
345 )
346 .await;
347
348 return Ok(true);
349 }
350 }
351 }
352 }
353 }
354 }
355
356 Ok(false)
357}
358
359pub async fn provision_certificate(
361 config: &mut AcmeConfig,
362 error_logger: &ErrorLogger,
363) -> Result<(), Box<dyn Error + Send + Sync>> {
364 let account_cache_key = get_account_cache_key(config);
365 let certificate_cache_key = get_certificate_cache_key(config);
366 let mut had_cache_error = false;
367
368 let acme_account = if let Some(acme_account) = config.account.take() {
369 acme_account
370 } else {
371 let acme_account_builder =
372 Account::builder_with_http(Box::new(HttpsClientForAcme::new(config.rustls_client_config.clone())));
373
374 if let Some(account_credentials) = config
375 .account_cache
376 .get(&account_cache_key)
377 .await
378 .and_then(|c| serde_json::from_slice::<AccountCredentials>(&c).ok())
379 {
380 acme_account_builder.from_credentials(account_credentials).await?
381 } else {
382 let (account, account_credentials) = acme_account_builder
383 .create(
384 &NewAccount {
385 contact: config.contact.iter().map(|s| s.deref()).collect::<Vec<_>>().as_slice(),
386 terms_of_service_agreed: true,
387 only_return_existing: false,
388 },
389 config.directory.clone(),
390 config.eab_key.as_deref(),
391 )
392 .await?;
393
394 if let Err(err) = config
395 .account_cache
396 .set(&account_cache_key, serde_json::to_vec(&account_credentials)?)
397 .await
398 {
399 if !had_cache_error {
400 error_logger
401 .log(&format!(
402 "Failed to access the ACME cache: {}. Ferron can't use ACME caching",
403 err
404 ))
405 .await;
406 had_cache_error = true;
407 }
408 }
409
410 account
411 }
412 };
413
414 if check_certificate_validity_or_install_cached(config, Some(&acme_account)).await? {
415 config.account.replace(acme_account);
417 return Ok(());
418 }
419
420 let acme_identifiers_vec = config
421 .domains
422 .iter()
423 .map(|s| {
424 if let Ok(ip) = s.parse::<IpAddr>() {
425 Identifier::Ip(ip)
426 } else {
427 Identifier::Dns(s.to_string())
428 }
429 })
430 .collect::<Vec<_>>();
431
432 let mut acme_new_order = NewOrder::new(&acme_identifiers_vec);
433 if let Some(profile) = &config.profile {
434 acme_new_order = acme_new_order.profile(profile);
435 }
436
437 let mut acme_order = match acme_account.new_order(&acme_new_order).await {
438 Ok(order) => order,
439 Err(instant_acme::Error::Api(problem)) => {
440 if problem.r#type.as_deref() == Some("urn:ietf:params:acme:error:accountDoesNotExist") {
441 config.account_cache.remove(&account_cache_key).await;
443 }
444 Err(instant_acme::Error::Api(problem))?
445 }
446 Err(err) => Err(err)?,
447 };
448 let mut dns_01_identifiers = Vec::new();
449 let mut acme_authorizations = acme_order.authorizations();
450 while let Some(acme_authorization) = acme_authorizations.next().await {
451 let mut acme_authorization = acme_authorization?;
452 match acme_authorization.status {
453 AuthorizationStatus::Pending => {}
454 AuthorizationStatus::Valid => continue,
455 _ => Err(anyhow::anyhow!("Invalid ACME authorization status"))?,
456 }
457
458 let mut challenge = acme_authorization
459 .challenge(config.challenge_type.clone())
460 .ok_or(anyhow::anyhow!(
461 "The ACME server doesn't support the requested challenge type"
462 ))?;
463
464 let identifier = match challenge.identifier().identifier {
465 Identifier::Dns(identifier) => identifier.to_string(),
466 Identifier::Ip(ip) => ip.to_string(),
467 _ => Err(anyhow::anyhow!("Unsupported ACME identifier type",))?,
468 };
469
470 let key_authorization = challenge.key_authorization();
471 match config.challenge_type {
472 ChallengeType::TlsAlpn01 => {
473 let mut params = CertificateParams::new(vec![identifier.clone()])?;
474 params.custom_extensions.push(CustomExtension::new_acme_identifier(
475 key_authorization.digest().as_ref(),
476 ));
477 let key_pair = KeyPair::generate()?;
478 let certificate = params.self_signed(&key_pair)?;
479 let private_key = PrivateKeyDer::try_from(key_pair.serialize_der())?;
480
481 let signing_key = CryptoProvider::get_default()
482 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
483 .key_provider
484 .load_private_key(private_key)?;
485
486 *config.tls_alpn_01_data_lock.write().await = Some((
487 Arc::new(CertifiedKey::new(vec![certificate.der().to_owned()], signing_key)),
488 identifier.clone(),
489 ));
490 }
491 ChallengeType::Http01 => {
492 let key_auth_value = key_authorization.as_str();
493 *config.http_01_data_lock.write().await = Some((challenge.token.clone(), key_auth_value.to_string()));
494 }
495 ChallengeType::Dns01 => {
496 if let Some(dns_provider) = &config.dns_provider {
497 dns_provider
498 .remove_acme_txt_record(&identifier)
499 .await
500 .unwrap_or_default();
501 dns_provider
502 .set_acme_txt_record(&identifier, &key_authorization.dns_value())
503 .await?;
504 tokio::time::sleep(Duration::from_secs(60)).await;
506 dns_01_identifiers.push(identifier.clone());
507 } else {
508 Err(anyhow::anyhow!("No DNS provider configured."))?;
509 }
510 }
511 _ => (),
512 }
513
514 challenge.set_ready().await?;
515 }
516
517 let acme_order_status = acme_order.poll_ready(&RetryPolicy::default()).await?;
518 match acme_order_status {
519 OrderStatus::Ready => (), OrderStatus::Invalid => Err(anyhow::anyhow!("ACME order is invalid"))?,
521 _ => Err(anyhow::anyhow!("ACME order is not ready"))?,
522 }
523
524 let finalize_closure = async {
525 let private_key_pem = acme_order.finalize().await?;
526 let certificate_chain_pem = acme_order.poll_certificate(&RetryPolicy::default()).await?;
527
528 if let Err(err) = post_process_obtained_certificate(config, &certificate_chain_pem, &private_key_pem).await {
529 error_logger
530 .log(&format!(
531 "Failed to save or post-process the obtained certificate: {}",
532 err
533 ))
534 .await;
535 }
536
537 let certificate_cache_data = CertificateCacheData {
538 certificate_chain_pem: certificate_chain_pem.clone(),
539 private_key_pem: private_key_pem.clone(),
540 };
541
542 if let Err(err) = config
543 .certificate_cache
544 .set(&certificate_cache_key, serde_json::to_vec(&certificate_cache_data)?)
545 .await
546 {
547 if !had_cache_error {
548 error_logger
549 .log(&format!(
550 "Failed to access the ACME cache: {}. Ferron can't use ACME caching",
551 err
552 ))
553 .await;
554 had_cache_error = true;
555 }
556 }
557
558 let certs = CertificateDer::pem_slice_iter(certificate_chain_pem.as_bytes())
559 .collect::<Result<Vec<_>, _>>()
560 .map_err(|e| match e {
561 rustls_pki_types::pem::Error::Io(err) => err,
562 err => std::io::Error::other(err),
563 })?;
564 let private_key = (match PrivateKeyDer::from_pem_slice(private_key_pem.as_bytes()) {
565 Ok(private_key) => Ok(private_key),
566 Err(rustls_pki_types::pem::Error::Io(err)) => Err(err),
567 Err(err) => Err(std::io::Error::other(err)),
568 })?;
569
570 let signing_key = CryptoProvider::get_default()
571 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
572 .key_provider
573 .load_private_key(private_key)?;
574
575 config.account.replace(acme_account);
576
577 *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
578
579 Ok::<_, Box<dyn Error + Send + Sync>>(())
580 };
581
582 let result = finalize_closure.await;
583
584 match config.challenge_type {
586 ChallengeType::TlsAlpn01 => {
587 *config.tls_alpn_01_data_lock.write().await = None;
588 }
589 ChallengeType::Http01 => {
590 *config.http_01_data_lock.write().await = None;
591 }
592 ChallengeType::Dns01 => {
593 if let Some(dns_provider) = &config.dns_provider {
594 for identifier in dns_01_identifiers {
595 dns_provider
596 .remove_acme_txt_record(&identifier)
597 .await
598 .unwrap_or_default();
599 }
600 }
601 }
602 _ => {}
603 };
604
605 result?;
606
607 Ok(())
608}
609
610pub async fn get_cached_domains(config: &AcmeOnDemandConfig) -> Vec<String> {
612 if let Some(pathbuf) = config.cache_path.clone() {
613 let hostname_cache_key = get_hostname_cache_key(config);
614 let hostname_cache = AcmeCache::File(pathbuf);
615 let cache_data = hostname_cache.get(&hostname_cache_key).await;
616 if let Some(data) = cache_data {
617 serde_json::from_slice(&data).unwrap_or_default()
618 } else {
619 Vec::new()
620 }
621 } else {
622 Vec::new()
623 }
624}
625
626pub async fn add_domain_to_cache(
628 config: &AcmeOnDemandConfig,
629 domain: &str,
630) -> Result<(), Box<dyn Error + Send + Sync>> {
631 if let Some(pathbuf) = config.cache_path.clone() {
632 let hostname_cache_key = get_hostname_cache_key(config);
633 let hostname_cache = AcmeCache::File(pathbuf);
634 let mut cached_domains = get_cached_domains(config).await;
635 cached_domains.push(domain.to_string());
636 let data = serde_json::to_vec(&cached_domains)?;
637 hostname_cache.set(&hostname_cache_key, data).await?;
638 }
639 Ok(())
640}
641
642pub async fn convert_on_demand_config(
644 config: &AcmeOnDemandConfig,
645 sni_hostname: String,
646 memory_acme_account_cache_data: Arc<RwLock<HashMap<String, Vec<u8>>>>,
647) -> AcmeConfig {
648 let (account_cache_path, cert_cache_path) = if let Some(mut pathbuf) = config.cache_path.clone() {
649 let base_pathbuf = pathbuf.clone();
650 let append_hash = base64::engine::general_purpose::URL_SAFE_NO_PAD
651 .encode(xxh3_128(format!("{}-{sni_hostname}", config.port).as_bytes()).to_be_bytes());
652 pathbuf.push(append_hash);
653 (Some(base_pathbuf), Some(pathbuf))
654 } else {
655 (None, None)
656 };
657
658 let certified_key_lock = Arc::new(tokio::sync::RwLock::new(None));
659 let tls_alpn_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
660 let http_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
661
662 config.sni_resolver_lock.write().await.insert(
664 sni_hostname.clone(),
665 Arc::new(AcmeResolver::new(certified_key_lock.clone())),
666 );
667 match config.challenge_type {
668 ChallengeType::TlsAlpn01 => {
669 config
670 .tls_alpn_01_resolver_lock
671 .write()
672 .await
673 .push(tls_alpn_01_data_lock.clone());
674 }
675 ChallengeType::Http01 => {
676 config
677 .http_01_resolver_lock
678 .write()
679 .await
680 .push(http_01_data_lock.clone());
681 }
682 _ => (),
683 };
684
685 AcmeConfig {
686 rustls_client_config: config.rustls_client_config.clone(),
687 domains: vec![sni_hostname],
688 challenge_type: config.challenge_type.clone(),
689 contact: config.contact.clone(),
690 directory: config.directory.clone(),
691 eab_key: config.eab_key.clone(),
692 profile: config.profile.clone(),
693 account_cache: if let Some(account_cache_path) = account_cache_path {
694 AcmeCache::File(account_cache_path)
695 } else {
696 AcmeCache::Memory(memory_acme_account_cache_data.clone())
697 },
698 certificate_cache: if let Some(cert_cache_path) = cert_cache_path {
699 AcmeCache::File(cert_cache_path)
700 } else {
701 AcmeCache::Memory(Arc::new(tokio::sync::RwLock::new(HashMap::new())))
702 },
703 certified_key_lock: certified_key_lock.clone(),
704 tls_alpn_01_data_lock: tls_alpn_01_data_lock.clone(),
705 http_01_data_lock: http_01_data_lock.clone(),
706 dns_provider: config.dns_provider.clone(),
707 renewal_info: None,
708 account: None,
709 save_paths: None,
710 post_obtain_command: None,
711 }
712}
713
714#[derive(Debug)]
716pub struct AcmeResolver {
717 certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
718}
719
720impl AcmeResolver {
721 pub fn new(certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>) -> Self {
723 Self { certified_key_lock }
724 }
725}
726
727impl ResolvesServerCert for AcmeResolver {
728 fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
729 self.certified_key_lock.blocking_read().clone()
730 }
731}
732
733struct HttpsClientForAcme(HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, BodyWrapper<Bytes>>);
734
735impl HttpsClientForAcme {
736 fn new(tls_config: ClientConfig) -> Self {
737 Self(
738 HyperClient::builder(TokioExecutor::new()).build(
739 hyper_rustls::HttpsConnectorBuilder::new()
740 .with_tls_config(tls_config)
741 .https_or_http()
742 .enable_http1()
743 .enable_http2()
744 .build(),
745 ),
746 )
747 }
748}
749
750impl HttpClient for HttpsClientForAcme {
751 fn request(
752 &self,
753 req: Request<BodyWrapper<Bytes>>,
754 ) -> Pin<Box<dyn Future<Output = Result<BytesResponse, instant_acme::Error>> + Send>> {
755 HttpClient::request(&self.0, req)
756 }
757}
758
759#[derive(Debug)]
761pub struct TlsAlpn01Resolver {
762 resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>,
763}
764
765impl TlsAlpn01Resolver {
766 #[allow(dead_code)]
768 pub fn new() -> Self {
769 Self {
770 resolvers: Arc::new(tokio::sync::RwLock::new(Vec::new())),
771 }
772 }
773
774 pub fn with_resolvers(resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>) -> Self {
776 Self { resolvers }
777 }
778
779 pub fn load_resolver(&self, resolver: TlsAlpn01DataLock) {
781 self.resolvers.blocking_write().push(resolver);
782 }
783}
784
785impl ResolvesServerCert for TlsAlpn01Resolver {
786 fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
787 let hostname = client_hello.server_name().map(|hn| hn.strip_suffix('.').unwrap_or(hn));
788
789 #[cfg(feature = "runtime-monoio")]
791 let resolver_locks = self.resolvers.blocking_read();
792 #[cfg(feature = "runtime-tokio")]
793 let resolver_locks = futures_executor::block_on(async { self.resolvers.read().await });
794
795 for resolver_lock in &*resolver_locks {
796 if let Some(hostname) = hostname {
797 #[cfg(feature = "runtime-monoio")]
798 let resolver_data = resolver_lock.blocking_read().clone();
799 #[cfg(feature = "runtime-tokio")]
800 let resolver_data = futures_executor::block_on(async { resolver_lock.read().await }).clone();
801 if let Some(resolver_data) = resolver_data {
802 let (cert, host) = resolver_data;
803 if host == hostname {
804 return Some(cert);
805 }
806 }
807 }
808 }
809 None
810 }
811}