aboutsummaryrefslogtreecommitdiff
path: root/src/cert_store.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cert_store.rs')
-rw-r--r--src/cert_store.rs46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/cert_store.rs b/src/cert_store.rs
index c272759..d561605 100644
--- a/src/cert_store.rs
+++ b/src/cert_store.rs
@@ -205,6 +205,12 @@ impl CertStore {
bail!("Lock is already taken, not renewing for now.");
}
+ // ---- Accessibility check ----
+ // We don't want to ask Let's encrypt for a domain that
+ // is not configured to point here. This can happen with wildcards: someone can send
+ // a fake SNI to a domain that is not ours. We have to detect it here.
+ self.check_domain_accessibility(domain, &session).await?;
+
// ---- Do let's encrypt stuff ----
let dir = Directory::from_url(DirectoryUrl::LetsEncrypt)?;
@@ -287,6 +293,46 @@ impl CertStore {
Ok(())
}
+ async fn check_domain_accessibility(&self, domain: &str, session: &str) -> Result<()> {
+ // Returns Ok(()) only if domain is a correct domain name that
+ // redirects to this server
+ let self_challenge_id = uuid::Uuid::new_v4().to_string();
+ let self_challenge_key = format!("challenge/{}", self_challenge_id);
+ let self_challenge_resp = uuid::Uuid::new_v4().to_string();
+
+ self.consul
+ .acquire(
+ &self_challenge_key,
+ self_challenge_resp.as_bytes().to_vec().into(),
+ session,
+ )
+ .await?;
+
+ let httpcli = reqwest::Client::new();
+ let chall_url = format!(
+ "http://{}/.well-known/acme-challenge/{}",
+ domain, self_challenge_id
+ );
+
+ for i in 1..=4 {
+ tokio::time::sleep(Duration::from_secs(2)).await;
+ info!("({}) Accessibility check {}/4", domain, i);
+
+ let httpresp = httpcli.get(&chall_url).send().await?;
+ if httpresp.status() == reqwest::StatusCode::OK
+ && httpresp.bytes().await? == self_challenge_resp.as_bytes()
+ {
+ // Challenge successfully validated
+ info!("({}) Accessibility check successfull", domain);
+ return Ok(());
+ }
+
+ tokio::time::sleep(Duration::from_secs(2)).await;
+ }
+
+ bail!("Unable to validate self-challenge for domain accessibility check");
+ }
+
fn gen_self_signed_certificate(&self, domain: &str) -> Result<Arc<Cert>> {
let subject_alt_names = vec![domain.to_string(), "localhost".to_string()];
let cert = rcgen::generate_simple_self_signed(subject_alt_names)?;