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-rustls",
|
||||
"tokio-util",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2233,6 +2234,15 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
|
|
@ -34,3 +34,4 @@ rcgen = "0.8"
|
|||
accept-encoding-fork = "0.2.0-alpha.3"
|
||||
async-compression = { version = "0.3", features = ["tokio", "gzip", "zstd", "deflate", "brotli"] }
|
||||
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.");
|
||||
}
|
||||
|
||||
// ---- 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)?;
|
||||
|
|
Loading…
Reference in a new issue