forked from Deuxfleurs/tricot
Implement basic domain accesibility check before asking for certificate
This commit is contained in:
parent
7488d8e907
commit
d13066b12b
3 changed files with 57 additions and 0 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -2146,6 +2146,7 @@ dependencies = [
|
||||||
"tokio 1.14.0",
|
"tokio 1.14.0",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2233,6 +2234,15 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|
|
@ -34,3 +34,4 @@ rcgen = "0.8"
|
||||||
accept-encoding-fork = "0.2.0-alpha.3"
|
accept-encoding-fork = "0.2.0-alpha.3"
|
||||||
async-compression = { version = "0.3", features = ["tokio", "gzip", "zstd", "deflate", "brotli"] }
|
async-compression = { version = "0.3", features = ["tokio", "gzip", "zstd", "deflate", "brotli"] }
|
||||||
tokio-util = { version = "0.6", features = ["io"] }
|
tokio-util = { version = "0.6", features = ["io"] }
|
||||||
|
uuid = { version = "0.8.2", features = ["v4"] }
|
||||||
|
|
|
@ -205,6 +205,12 @@ impl CertStore {
|
||||||
bail!("Lock is already taken, not renewing for now.");
|
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 ----
|
// ---- Do let's encrypt stuff ----
|
||||||
|
|
||||||
let dir = Directory::from_url(DirectoryUrl::LetsEncrypt)?;
|
let dir = Directory::from_url(DirectoryUrl::LetsEncrypt)?;
|
||||||
|
@ -287,6 +293,46 @@ impl CertStore {
|
||||||
Ok(())
|
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>> {
|
fn gen_self_signed_certificate(&self, domain: &str) -> Result<Arc<Cert>> {
|
||||||
let subject_alt_names = vec![domain.to_string(), "localhost".to_string()];
|
let subject_alt_names = vec![domain.to_string(), "localhost".to_string()];
|
||||||
let cert = rcgen::generate_simple_self_signed(subject_alt_names)?;
|
let cert = rcgen::generate_simple_self_signed(subject_alt_names)?;
|
||||||
|
|
Loading…
Reference in a new issue