summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-08-19 03:14:34 +0200
committermetamuffin <metamuffin@disroot.org>2024-08-19 03:14:34 +0200
commitd06821468e9a6e0d62c4b1ced21b1290e7a5bc47 (patch)
tree0ef2cade2bfb6a24f2bb3e65b074df81afd5b5dd
parent6c3524c381467483a025eda5e7e5f0ded53094fa (diff)
downloadgnix-d06821468e9a6e0d62c4b1ced21b1290e7a5bc47.tar
gnix-d06821468e9a6e0d62c4b1ced21b1290e7a5bc47.tar.bz2
gnix-d06821468e9a6e0d62c4b1ced21b1290e7a5bc47.tar.zst
fallback cert
-rw-r--r--Cargo.toml4
-rw-r--r--readme.md3
-rw-r--r--src/certs.rs24
-rw-r--r--src/config.rs1
-rw-r--r--src/main.rs2
5 files changed, 29 insertions, 5 deletions
diff --git a/Cargo.toml b/Cargo.toml
index bc18ba9..fc77e7d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
# HTTP
-hyper = { version = "1.4.1", features = ["full"] }
+hyper = { version = "1.4.1", features = ["server", "client", "http1", "http2"] }
hyper-util = "0.1.7"
http-body-util = "0.1.2"
headers = "0.4.0"
@@ -52,4 +52,4 @@ bytes = "1.7.1"
anyhow = "1.0.86"
thiserror = "1.0.63"
regex = "1.10.6"
-users = "0.11.0" \ No newline at end of file
+users = "0.11.0"
diff --git a/readme.md b/readme.md
index 5cda4d6..348cafd 100644
--- a/readme.md
+++ b/readme.md
@@ -72,6 +72,9 @@ it will automatically be loaded and applied if valid.
`fullchain.pem` and `privkey.pem` files. The correct certificate is selected
automatically by subject (`CN`). Pointing this directly at
`/etc/letsencrypt/live` is possible. (string or list of strings)
+ - `cert_fallback`: Path to a single directory containing a key-cert pair that
+ is used when no other certificate seems appropriate. This is useful for
+ testing locally with a self-signed subjectless certificate. (optional string)
- **section `limits`**
- Note: Make sure you do not exceed the maximum file descriptor limit on your
diff --git a/src/certs.rs b/src/certs.rs
index 27aab51..84d0fca 100644
--- a/src/certs.rs
+++ b/src/certs.rs
@@ -19,6 +19,7 @@ use webpki::EndEntityCert;
pub struct CertPool {
provider: &'static Arc<CryptoProvider>,
domains: HashMap<String, Arc<CertifiedKey>>,
+ fallback: Option<Arc<CertifiedKey>>,
}
impl Default for CertPool {
@@ -26,16 +27,30 @@ impl Default for CertPool {
Self {
provider: CryptoProvider::get_default().unwrap(),
domains: Default::default(),
+ fallback: None,
}
}
}
impl CertPool {
- pub fn load(roots: &[PathBuf]) -> Result<Self> {
+ pub fn load(roots: &[PathBuf], fallback: Option<PathBuf>) -> Result<Self> {
let mut s = Self::default();
for r in roots {
s.load_recursive(&r)?;
}
+ if let Some(path) = fallback {
+ let keypath = path.join("privkey.pem");
+ let certpath = if path.join("fullchain.pem").exists() {
+ path.join("fullchain.pem")
+ } else {
+ path.join("cert.pem")
+ };
+ let certs = load_certs(&certpath)?;
+ let key = load_private_key(&keypath)?;
+ let skey = s.provider.key_provider.load_private_key(key)?;
+ let ck = CertifiedKey::new(certs.clone(), skey.clone());
+ s.fallback = Some(Arc::new(ck))
+ }
Ok(s)
}
@@ -74,7 +89,12 @@ impl CertPool {
impl ResolvesServerCert for CertPool {
fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
- Some(self.domains.get(client_hello.server_name()?)?.clone())
+ Some(
+ self.domains
+ .get(client_hello.server_name()?)
+ .or(self.fallback.as_ref())?
+ .clone(),
+ )
}
}
diff --git a/src/config.rs b/src/config.rs
index 6a22657..a6f7d1b 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -61,6 +61,7 @@ pub struct HttpsConfig {
pub bind: Vec<SocketAddr>,
#[serde(deserialize_with = "seq_or_not")]
pub cert_path: Vec<PathBuf>,
+ pub cert_fallback: Option<PathBuf>,
}
// try deser Vec<T> but fall back to deser T and putting that in Vec
diff --git a/src/main.rs b/src/main.rs
index 56a9b19..e286924 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -146,7 +146,7 @@ async fn serve_https(state: Arc<State>) -> Result<()> {
None => return Ok(()),
};
let tls_config = {
- let certs = CertPool::load(&https_config.cert_path)?;
+ let certs = CertPool::load(&https_config.cert_path, https_config.cert_fallback.clone())?;
let mut cfg = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_cert_resolver(Arc::new(certs));