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 let mut command_shlex = shlex::Shlex::new(command);
266 let Some(command) = command_shlex.next() else {
267 Err(anyhow::anyhow!("Invalid post-obtain command"))?
268 };
269 let mut command = tokio::process::Command::new(command);
270 for arg in command_shlex {
271 command.arg(arg);
272 }
273 command
274 .env("FERRON_ACME_DOMAIN", config.domains.join(","))
275 .env("FERRON_ACME_CERT_PATH", cert_path)
276 .env("FERRON_ACME_KEY_PATH", key_path)
277 .stdin(std::process::Stdio::null())
278 .stdout(std::process::Stdio::null())
279 .stderr(std::process::Stdio::null())
280 .spawn()?;
281 }
282 }
283
284 Ok(())
285}
286
287pub async fn check_certificate_validity_or_install_cached(
289 config: &mut AcmeConfig,
290 acme_account: Option<&Account>,
291) -> Result<bool, Box<dyn Error + Send + Sync>> {
292 if let Some(certified_key) = config.certified_key_lock.read().await.as_deref() {
293 if let Some(certificate) = certified_key.cert.first() {
294 if let Some(acme_account) = acme_account {
295 if config
296 .renewal_info
297 .as_ref()
298 .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
299 {
300 if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
301 if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
302 let mut renewal_instant = Instant::now();
303 renewal_instant += renewal_info.1;
304 config.renewal_info = Some((renewal_info.0, renewal_instant));
305 }
306 }
307 }
308 }
309 if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
310 return Ok(true);
311 }
312 }
313 }
314
315 let certificate_cache_key = get_certificate_cache_key(config);
316
317 if let Some(serialized_certificate_cache_data) = config.certificate_cache.get(&certificate_cache_key).await {
318 if let Ok(certificate_data) = serde_json::from_slice::<CertificateCacheData>(&serialized_certificate_cache_data) {
319 if let Ok(certs) =
321 CertificateDer::pem_slice_iter(certificate_data.certificate_chain_pem.as_bytes()).collect::<Result<Vec<_>, _>>()
322 {
323 if let Some(certificate) = certs.first() {
324 if let Some(acme_account) = acme_account {
325 if config
326 .renewal_info
327 .as_ref()
328 .is_none_or(|v| v.1.elapsed() > Duration::ZERO)
329 {
330 if let Ok(certificate_id) = CertificateIdentifier::try_from(certificate) {
331 if let Ok(renewal_info) = acme_account.renewal_info(&certificate_id).await {
332 let mut renewal_instant = Instant::now();
333 renewal_instant += renewal_info.1;
334 config.renewal_info = Some((renewal_info.0, renewal_instant));
335 }
336 }
337 }
338 }
339 if check_certificate_validity(certificate, config.renewal_info.as_ref().map(|i| &i.0))? {
340 if let Ok(private_key) = PrivateKeyDer::from_pem_slice(certificate_data.private_key_pem.as_bytes()) {
342 let signing_key = CryptoProvider::get_default()
343 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
344 .key_provider
345 .load_private_key(private_key)?;
346
347 *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
348
349 let _ = post_process_obtained_certificate(
350 config,
351 &certificate_data.certificate_chain_pem,
352 &certificate_data.private_key_pem,
353 )
354 .await;
355
356 return Ok(true);
357 }
358 }
359 }
360 }
361 }
362 }
363
364 Ok(false)
365}
366
367pub async fn provision_certificate(
369 config: &mut AcmeConfig,
370 error_logger: &ErrorLogger,
371) -> Result<(), Box<dyn Error + Send + Sync>> {
372 let account_cache_key = get_account_cache_key(config);
373 let certificate_cache_key = get_certificate_cache_key(config);
374 let mut had_cache_error = false;
375
376 let acme_account = if let Some(acme_account) = config.account.take() {
377 acme_account
378 } else {
379 let acme_account_builder =
380 Account::builder_with_http(Box::new(HttpsClientForAcme::new(config.rustls_client_config.clone())));
381
382 if let Some(account_credentials) = config
383 .account_cache
384 .get(&account_cache_key)
385 .await
386 .and_then(|c| serde_json::from_slice::<AccountCredentials>(&c).ok())
387 {
388 acme_account_builder.from_credentials(account_credentials).await?
389 } else {
390 let (account, account_credentials) = acme_account_builder
391 .create(
392 &NewAccount {
393 contact: config.contact.iter().map(|s| s.deref()).collect::<Vec<_>>().as_slice(),
394 terms_of_service_agreed: true,
395 only_return_existing: false,
396 },
397 config.directory.clone(),
398 config.eab_key.as_deref(),
399 )
400 .await?;
401
402 if let Err(err) = config
403 .account_cache
404 .set(&account_cache_key, serde_json::to_vec(&account_credentials)?)
405 .await
406 {
407 if !had_cache_error {
408 error_logger
409 .log(&format!(
410 "Failed to access the ACME cache: {}. Ferron can't use ACME caching",
411 err
412 ))
413 .await;
414 had_cache_error = true;
415 }
416 }
417
418 account
419 }
420 };
421
422 if check_certificate_validity_or_install_cached(config, Some(&acme_account)).await? {
423 config.account.replace(acme_account);
425 return Ok(());
426 }
427
428 let acme_identifiers_vec = config
429 .domains
430 .iter()
431 .map(|s| {
432 if let Ok(ip) = s.parse::<IpAddr>() {
433 Identifier::Ip(ip)
434 } else {
435 Identifier::Dns(s.to_string())
436 }
437 })
438 .collect::<Vec<_>>();
439
440 let mut acme_new_order = NewOrder::new(&acme_identifiers_vec);
441 if let Some(profile) = &config.profile {
442 acme_new_order = acme_new_order.profile(profile);
443 }
444
445 let mut acme_order = match acme_account.new_order(&acme_new_order).await {
446 Ok(order) => order,
447 Err(instant_acme::Error::Api(problem)) => {
448 if problem.r#type.as_deref() == Some("urn:ietf:params:acme:error:accountDoesNotExist") {
449 config.account_cache.remove(&account_cache_key).await;
451 }
452 Err(instant_acme::Error::Api(problem))?
453 }
454 Err(err) => Err(err)?,
455 };
456 let mut dns_01_identifiers = Vec::new();
457 let mut acme_authorizations = acme_order.authorizations();
458 while let Some(acme_authorization) = acme_authorizations.next().await {
459 let mut acme_authorization = acme_authorization?;
460 match acme_authorization.status {
461 AuthorizationStatus::Pending => {}
462 AuthorizationStatus::Valid => continue,
463 _ => Err(anyhow::anyhow!("Invalid ACME authorization status"))?,
464 }
465
466 let mut challenge = acme_authorization
467 .challenge(config.challenge_type.clone())
468 .ok_or(anyhow::anyhow!(
469 "The ACME server doesn't support the requested challenge type"
470 ))?;
471
472 let identifier = match challenge.identifier().identifier {
473 Identifier::Dns(identifier) => identifier.to_string(),
474 Identifier::Ip(ip) => ip.to_string(),
475 _ => Err(anyhow::anyhow!("Unsupported ACME identifier type",))?,
476 };
477
478 let key_authorization = challenge.key_authorization();
479 match config.challenge_type {
480 ChallengeType::TlsAlpn01 => {
481 let mut params = CertificateParams::new(vec![identifier.clone()])?;
482 params.custom_extensions.push(CustomExtension::new_acme_identifier(
483 key_authorization.digest().as_ref(),
484 ));
485 let key_pair = KeyPair::generate()?;
486 let certificate = params.self_signed(&key_pair)?;
487 let private_key = PrivateKeyDer::try_from(key_pair.serialize_der())?;
488
489 let signing_key = CryptoProvider::get_default()
490 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
491 .key_provider
492 .load_private_key(private_key)?;
493
494 *config.tls_alpn_01_data_lock.write().await = Some((
495 Arc::new(CertifiedKey::new(vec![certificate.der().to_owned()], signing_key)),
496 identifier.clone(),
497 ));
498 }
499 ChallengeType::Http01 => {
500 let key_auth_value = key_authorization.as_str();
501 *config.http_01_data_lock.write().await = Some((challenge.token.clone(), key_auth_value.to_string()));
502 }
503 ChallengeType::Dns01 => {
504 if let Some(dns_provider) = &config.dns_provider {
505 dns_provider
506 .remove_acme_txt_record(&identifier)
507 .await
508 .unwrap_or_default();
509 dns_provider
510 .set_acme_txt_record(&identifier, &key_authorization.dns_value())
511 .await?;
512 tokio::time::sleep(Duration::from_secs(60)).await;
514 dns_01_identifiers.push(identifier.clone());
515 } else {
516 Err(anyhow::anyhow!("No DNS provider configured."))?;
517 }
518 }
519 _ => (),
520 }
521
522 challenge.set_ready().await?;
523 }
524
525 let acme_order_status = acme_order.poll_ready(&RetryPolicy::default()).await?;
526 match acme_order_status {
527 OrderStatus::Ready => (), OrderStatus::Invalid => Err(anyhow::anyhow!("ACME order is invalid"))?,
529 _ => Err(anyhow::anyhow!("ACME order is not ready"))?,
530 }
531
532 let finalize_closure = async {
533 let private_key_pem = acme_order.finalize().await?;
534 let certificate_chain_pem = acme_order.poll_certificate(&RetryPolicy::default()).await?;
535
536 if let Err(err) = post_process_obtained_certificate(config, &certificate_chain_pem, &private_key_pem).await {
537 error_logger
538 .log(&format!(
539 "Failed to save or post-process the obtained certificate: {}",
540 err
541 ))
542 .await;
543 }
544
545 let certificate_cache_data = CertificateCacheData {
546 certificate_chain_pem: certificate_chain_pem.clone(),
547 private_key_pem: private_key_pem.clone(),
548 };
549
550 if let Err(err) = config
551 .certificate_cache
552 .set(&certificate_cache_key, serde_json::to_vec(&certificate_cache_data)?)
553 .await
554 {
555 if !had_cache_error {
556 error_logger
557 .log(&format!(
558 "Failed to access the ACME cache: {}. Ferron can't use ACME caching",
559 err
560 ))
561 .await;
562 had_cache_error = true;
563 }
564 }
565
566 let certs = CertificateDer::pem_slice_iter(certificate_chain_pem.as_bytes())
567 .collect::<Result<Vec<_>, _>>()
568 .map_err(|e| match e {
569 rustls_pki_types::pem::Error::Io(err) => err,
570 err => std::io::Error::other(err),
571 })?;
572 let private_key = (match PrivateKeyDer::from_pem_slice(private_key_pem.as_bytes()) {
573 Ok(private_key) => Ok(private_key),
574 Err(rustls_pki_types::pem::Error::Io(err)) => Err(err),
575 Err(err) => Err(std::io::Error::other(err)),
576 })?;
577
578 let signing_key = CryptoProvider::get_default()
579 .ok_or(anyhow::anyhow!("Cannot get default crypto provider"))?
580 .key_provider
581 .load_private_key(private_key)?;
582
583 config.account.replace(acme_account);
584
585 *config.certified_key_lock.write().await = Some(Arc::new(CertifiedKey::new(certs, signing_key)));
586
587 Ok::<_, Box<dyn Error + Send + Sync>>(())
588 };
589
590 let result = finalize_closure.await;
591
592 match config.challenge_type {
594 ChallengeType::TlsAlpn01 => {
595 *config.tls_alpn_01_data_lock.write().await = None;
596 }
597 ChallengeType::Http01 => {
598 *config.http_01_data_lock.write().await = None;
599 }
600 ChallengeType::Dns01 => {
601 if let Some(dns_provider) = &config.dns_provider {
602 for identifier in dns_01_identifiers {
603 dns_provider
604 .remove_acme_txt_record(&identifier)
605 .await
606 .unwrap_or_default();
607 }
608 }
609 }
610 _ => {}
611 };
612
613 result?;
614
615 Ok(())
616}
617
618pub async fn get_cached_domains(config: &AcmeOnDemandConfig) -> Vec<String> {
620 if let Some(pathbuf) = config.cache_path.clone() {
621 let hostname_cache_key = get_hostname_cache_key(config);
622 let hostname_cache = AcmeCache::File(pathbuf);
623 let cache_data = hostname_cache.get(&hostname_cache_key).await;
624 if let Some(data) = cache_data {
625 serde_json::from_slice(&data).unwrap_or_default()
626 } else {
627 Vec::new()
628 }
629 } else {
630 Vec::new()
631 }
632}
633
634pub async fn add_domain_to_cache(
636 config: &AcmeOnDemandConfig,
637 domain: &str,
638) -> Result<(), Box<dyn Error + Send + Sync>> {
639 if let Some(pathbuf) = config.cache_path.clone() {
640 let hostname_cache_key = get_hostname_cache_key(config);
641 let hostname_cache = AcmeCache::File(pathbuf);
642 let mut cached_domains = get_cached_domains(config).await;
643 cached_domains.push(domain.to_string());
644 let data = serde_json::to_vec(&cached_domains)?;
645 hostname_cache.set(&hostname_cache_key, data).await?;
646 }
647 Ok(())
648}
649
650pub async fn convert_on_demand_config(
652 config: &AcmeOnDemandConfig,
653 sni_hostname: String,
654 memory_acme_account_cache_data: Arc<RwLock<HashMap<String, Vec<u8>>>>,
655) -> AcmeConfig {
656 let (account_cache_path, cert_cache_path) = if let Some(mut pathbuf) = config.cache_path.clone() {
657 let base_pathbuf = pathbuf.clone();
658 let append_hash = base64::engine::general_purpose::URL_SAFE_NO_PAD
659 .encode(xxh3_128(format!("{}-{sni_hostname}", config.port).as_bytes()).to_be_bytes());
660 pathbuf.push(append_hash);
661 (Some(base_pathbuf), Some(pathbuf))
662 } else {
663 (None, None)
664 };
665
666 let certified_key_lock = Arc::new(tokio::sync::RwLock::new(None));
667 let tls_alpn_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
668 let http_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
669
670 config.sni_resolver_lock.write().await.insert(
672 sni_hostname.clone(),
673 Arc::new(AcmeResolver::new(certified_key_lock.clone())),
674 );
675 match config.challenge_type {
676 ChallengeType::TlsAlpn01 => {
677 config
678 .tls_alpn_01_resolver_lock
679 .write()
680 .await
681 .push(tls_alpn_01_data_lock.clone());
682 }
683 ChallengeType::Http01 => {
684 config
685 .http_01_resolver_lock
686 .write()
687 .await
688 .push(http_01_data_lock.clone());
689 }
690 _ => (),
691 };
692
693 AcmeConfig {
694 rustls_client_config: config.rustls_client_config.clone(),
695 domains: vec![sni_hostname],
696 challenge_type: config.challenge_type.clone(),
697 contact: config.contact.clone(),
698 directory: config.directory.clone(),
699 eab_key: config.eab_key.clone(),
700 profile: config.profile.clone(),
701 account_cache: if let Some(account_cache_path) = account_cache_path {
702 AcmeCache::File(account_cache_path)
703 } else {
704 AcmeCache::Memory(memory_acme_account_cache_data.clone())
705 },
706 certificate_cache: if let Some(cert_cache_path) = cert_cache_path {
707 AcmeCache::File(cert_cache_path)
708 } else {
709 AcmeCache::Memory(Arc::new(tokio::sync::RwLock::new(HashMap::new())))
710 },
711 certified_key_lock: certified_key_lock.clone(),
712 tls_alpn_01_data_lock: tls_alpn_01_data_lock.clone(),
713 http_01_data_lock: http_01_data_lock.clone(),
714 dns_provider: config.dns_provider.clone(),
715 renewal_info: None,
716 account: None,
717 save_paths: None,
718 post_obtain_command: None,
719 }
720}
721
722#[derive(Debug)]
724pub struct AcmeResolver {
725 certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>,
726}
727
728impl AcmeResolver {
729 pub fn new(certified_key_lock: Arc<RwLock<Option<Arc<CertifiedKey>>>>) -> Self {
731 Self { certified_key_lock }
732 }
733}
734
735impl ResolvesServerCert for AcmeResolver {
736 fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
737 self.certified_key_lock.blocking_read().clone()
738 }
739}
740
741struct HttpsClientForAcme(HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, BodyWrapper<Bytes>>);
742
743impl HttpsClientForAcme {
744 fn new(tls_config: ClientConfig) -> Self {
745 Self(
746 HyperClient::builder(TokioExecutor::new()).build(
747 hyper_rustls::HttpsConnectorBuilder::new()
748 .with_tls_config(tls_config)
749 .https_or_http()
750 .enable_http1()
751 .enable_http2()
752 .build(),
753 ),
754 )
755 }
756}
757
758impl HttpClient for HttpsClientForAcme {
759 fn request(
760 &self,
761 req: Request<BodyWrapper<Bytes>>,
762 ) -> Pin<Box<dyn Future<Output = Result<BytesResponse, instant_acme::Error>> + Send>> {
763 HttpClient::request(&self.0, req)
764 }
765}
766
767#[derive(Debug)]
769pub struct TlsAlpn01Resolver {
770 resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>,
771}
772
773impl TlsAlpn01Resolver {
774 #[allow(dead_code)]
776 pub fn new() -> Self {
777 Self {
778 resolvers: Arc::new(tokio::sync::RwLock::new(Vec::new())),
779 }
780 }
781
782 pub fn with_resolvers(resolvers: Arc<tokio::sync::RwLock<Vec<TlsAlpn01DataLock>>>) -> Self {
784 Self { resolvers }
785 }
786
787 pub fn load_resolver(&self, resolver: TlsAlpn01DataLock) {
789 self.resolvers.blocking_write().push(resolver);
790 }
791}
792
793impl ResolvesServerCert for TlsAlpn01Resolver {
794 fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
795 let hostname = client_hello.server_name().map(|hn| hn.strip_suffix('.').unwrap_or(hn));
796
797 #[cfg(any(feature = "runtime-vibeio", feature = "runtime-monoio"))]
799 let resolver_locks = self.resolvers.blocking_read();
800 #[cfg(feature = "runtime-tokio")]
801 let resolver_locks = futures_executor::block_on(async { self.resolvers.read().await });
802
803 for resolver_lock in &*resolver_locks {
804 if let Some(hostname) = hostname {
805 #[cfg(any(feature = "runtime-vibeio", feature = "runtime-monoio"))]
806 let resolver_data = resolver_lock.blocking_read().clone();
807 #[cfg(feature = "runtime-tokio")]
808 let resolver_data = futures_executor::block_on(async { resolver_lock.read().await }).clone();
809 if let Some(resolver_data) = resolver_data {
810 let (cert, host) = resolver_data;
811 if host.parse::<IpAddr>().is_ok() || host == hostname {
812 return Some(cert);
813 }
814 }
815 }
816 }
817 None
818 }
819}