diff options
author | Alex Auvolat <alex@adnab.me> | 2021-12-14 11:31:22 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2021-12-14 11:31:22 +0100 |
commit | d13066b12bc03e49c233a065294595c2da3b1f3d (patch) | |
tree | 365e00a90ecf079d28defd9de050dad6e9041c9b /src | |
parent | 7488d8e907dadc3e91c8c8920fdc38f42c455b50 (diff) | |
download | tricot-d13066b12bc03e49c233a065294595c2da3b1f3d.tar.gz tricot-d13066b12bc03e49c233a065294595c2da3b1f3d.zip |
Implement basic domain accesibility check before asking for certificatedocker-25
Diffstat (limited to 'src')
-rw-r--r-- | src/cert_store.rs | 46 |
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)?; |