Rename gencert.rs -> cert.rs, move in a bunch of certificate functions.
Make the cert.rs module private. Refactor refactor refactor!!! It's 5:14am and I HAVENT SLEPT THAT'S RIGHT IT'S INSOMNIA HOURS THEYDIES AND GENDERFUCKS!!!
This commit is contained in:
parent
dc71a2f2cf
commit
e55f5c675b
|
@ -6,16 +6,29 @@
|
||||||
//! methods on it or anything.
|
//! methods on it or anything.
|
||||||
//!
|
//!
|
||||||
//! [`Server::set_certificate_generation_mode()`]: crate::Server::set_certificate_generation_mode()
|
//! [`Server::set_certificate_generation_mode()`]: crate::Server::set_certificate_generation_mode()
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{anyhow, Context, Result, ensure};
|
||||||
|
#[cfg(feature = "certgen")]
|
||||||
|
use anyhow::bail;
|
||||||
|
|
||||||
use rustls::ServerConfig;
|
use rustls::ServerConfig;
|
||||||
|
|
||||||
use std::fs;
|
use std::{path::PathBuf, sync::Arc};
|
||||||
use std::io::{stdin, stdout, Write};
|
#[cfg(feature = "certgen")]
|
||||||
use std::path::Path;
|
use std::{
|
||||||
|
fs,
|
||||||
|
io::{stdin, stdout, Write},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
use rustls::internal::msgs::handshake::DigitallySignedStruct;
|
||||||
|
use tokio_rustls::rustls;
|
||||||
|
use rustls::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// The mode to use for determining the domains to use for a new certificate. Only
|
#[cfg(feature = "certgen")]
|
||||||
/// applies to [`CertGenMode::gencert()`].
|
/// The mode to use for determining the domains to use for a new certificate.
|
||||||
|
///
|
||||||
|
/// Used to configure a [`Server`] using [`Server::set_certificate_generation_mode()`]
|
||||||
pub enum CertGenMode {
|
pub enum CertGenMode {
|
||||||
|
|
||||||
/// Do not generate any certificates. Error if not available.
|
/// Do not generate any certificates. Error if not available.
|
||||||
|
@ -28,6 +41,7 @@ pub enum CertGenMode {
|
||||||
Interactive,
|
Interactive,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "certgen")]
|
||||||
impl CertGenMode {
|
impl CertGenMode {
|
||||||
/// Generate a new self-signed certificate
|
/// Generate a new self-signed certificate
|
||||||
///
|
///
|
||||||
|
@ -83,7 +97,7 @@ impl CertGenMode {
|
||||||
///
|
///
|
||||||
/// Returns an error if a certificate is not found **and** cannot be generated.
|
/// Returns an error if a certificate is not found **and** cannot be generated.
|
||||||
pub fn load_or_generate(self, to: &mut ServerConfig, cert: impl AsRef<Path>, key: impl AsRef<Path>) -> Result<()> {
|
pub fn load_or_generate(self, to: &mut ServerConfig, cert: impl AsRef<Path>, key: impl AsRef<Path>) -> Result<()> {
|
||||||
match (crate::load_cert_chain(&cert.as_ref().into()), crate::load_key(&key.as_ref().into())) {
|
match (load_cert_chain(&cert.as_ref().into()), load_key(&key.as_ref().into())) {
|
||||||
(Ok(cert_chain), Ok(key)) => {
|
(Ok(cert_chain), Ok(key)) => {
|
||||||
to.set_single_cert(cert_chain, key)
|
to.set_single_cert(cert_chain, key)
|
||||||
.context("Failed to use loaded TLS certificate")?;
|
.context("Failed to use loaded TLS certificate")?;
|
||||||
|
@ -101,6 +115,7 @@ impl CertGenMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "certgen")]
|
||||||
/// Attempt to get domains by prompting the user
|
/// Attempt to get domains by prompting the user
|
||||||
///
|
///
|
||||||
/// Guaranteed to return at least one domain. The user is provided `localhost` as a
|
/// Guaranteed to return at least one domain. The user is provided `localhost` as a
|
||||||
|
@ -108,7 +123,7 @@ impl CertGenMode {
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// ## Panics
|
||||||
/// Panics if reading from stdin or writing to stdout returns an error.
|
/// Panics if reading from stdin or writing to stdout returns an error.
|
||||||
pub fn prompt_domains() -> Vec<String> {
|
fn prompt_domains() -> Vec<String> {
|
||||||
let mut domains = Vec::with_capacity(1);
|
let mut domains = Vec::with_capacity(1);
|
||||||
let mut input = String::with_capacity(8);
|
let mut input = String::with_capacity(8);
|
||||||
println!("Now generating self-signed certificate...");
|
println!("Now generating self-signed certificate...");
|
||||||
|
@ -131,3 +146,107 @@ pub fn prompt_domains() -> Vec<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tls_config(
|
||||||
|
cert_path: &PathBuf,
|
||||||
|
key_path: &PathBuf,
|
||||||
|
#[cfg(feature = "certgen")]
|
||||||
|
mode: CertGenMode,
|
||||||
|
) -> Result<Arc<ServerConfig>> {
|
||||||
|
let mut config = ServerConfig::new(AllowAnonOrSelfsignedClient::new());
|
||||||
|
|
||||||
|
#[cfg(feature = "certgen")]
|
||||||
|
mode.load_or_generate(&mut config, cert_path, key_path)?;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "certgen"))] {
|
||||||
|
let cert_chain = load_cert_chain(cert_path)
|
||||||
|
.context("Failed to load TLS certificate")?;
|
||||||
|
let key = load_key(key_path)
|
||||||
|
.context("Failed to load TLS key")?;
|
||||||
|
config.set_single_cert(cert_chain, key)
|
||||||
|
.context("Failed to use loaded TLS certificate")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(config.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_cert_chain(cert_path: &PathBuf) -> Result<Vec<Certificate>> {
|
||||||
|
let certs = std::fs::File::open(cert_path)
|
||||||
|
.with_context(|| format!("Failed to open `{:?}`", cert_path))?;
|
||||||
|
let mut certs = std::io::BufReader::new(certs);
|
||||||
|
let certs = rustls::internal::pemfile::certs(&mut certs)
|
||||||
|
.map_err(|_| anyhow!("failed to load certs `{:?}`", cert_path))?;
|
||||||
|
|
||||||
|
Ok(certs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_key(key_path: &PathBuf) -> Result<PrivateKey> {
|
||||||
|
let keys = std::fs::File::open(key_path)
|
||||||
|
.with_context(|| format!("Failed to open `{:?}`", key_path))?;
|
||||||
|
let mut keys = std::io::BufReader::new(keys);
|
||||||
|
let mut keys = rustls::internal::pemfile::pkcs8_private_keys(&mut keys)
|
||||||
|
.map_err(|_| anyhow!("failed to load key `{:?}`", key_path))?;
|
||||||
|
|
||||||
|
ensure!(!keys.is_empty(), "no key found");
|
||||||
|
|
||||||
|
let key = keys.swap_remove(0);
|
||||||
|
|
||||||
|
Ok(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A client cert verifier that accepts all connections
|
||||||
|
///
|
||||||
|
/// Unfortunately, rustls doesn't provide a ClientCertVerifier that accepts self-signed
|
||||||
|
/// certificates, so we need to implement this ourselves.
|
||||||
|
struct AllowAnonOrSelfsignedClient { }
|
||||||
|
|
||||||
|
impl AllowAnonOrSelfsignedClient {
|
||||||
|
|
||||||
|
/// Create a new verifier
|
||||||
|
fn new() -> Arc<Self> {
|
||||||
|
Arc::new(Self {})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientCertVerifier for AllowAnonOrSelfsignedClient {
|
||||||
|
|
||||||
|
fn client_auth_root_subjects(
|
||||||
|
&self,
|
||||||
|
_: Option<&webpki::DNSName>
|
||||||
|
) -> Option<DistinguishedNames> {
|
||||||
|
Some(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_auth_mandatory(&self, _sni: Option<&webpki::DNSName>) -> Option<bool> {
|
||||||
|
Some(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the below methods are a hack until webpki doesn't break with certain certs
|
||||||
|
|
||||||
|
fn verify_client_cert(
|
||||||
|
&self,
|
||||||
|
_: &[Certificate],
|
||||||
|
_: Option<&webpki::DNSName>
|
||||||
|
) -> Result<ClientCertVerified, TLSError> {
|
||||||
|
Ok(ClientCertVerified::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_tls12_signature(
|
||||||
|
&self,
|
||||||
|
_message: &[u8],
|
||||||
|
_cert: &Certificate,
|
||||||
|
_dss: &DigitallySignedStruct,
|
||||||
|
) -> Result<HandshakeSignatureValid, TLSError> {
|
||||||
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_tls13_signature(
|
||||||
|
&self,
|
||||||
|
_message: &[u8],
|
||||||
|
_cert: &Certificate,
|
||||||
|
_dss: &DigitallySignedStruct,
|
||||||
|
) -> Result<HandshakeSignatureValid, TLSError> {
|
||||||
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
|
}
|
||||||
|
}
|
130
src/lib.rs
130
src/lib.rs
|
@ -102,19 +102,15 @@ use tokio::{
|
||||||
};
|
};
|
||||||
#[cfg(feature = "ratelimiting")]
|
#[cfg(feature = "ratelimiting")]
|
||||||
use tokio::time::interval;
|
use tokio::time::interval;
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
use rustls::ClientCertVerifier;
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
use rustls::internal::msgs::handshake::DigitallySignedStruct;
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
use tokio_rustls::{rustls, TlsAcceptor};
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
use rustls::*;
|
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use crate::util::opt_timeout;
|
use crate::util::opt_timeout;
|
||||||
use routing::RoutingNode;
|
use routing::RoutingNode;
|
||||||
#[cfg(feature = "ratelimiting")]
|
#[cfg(feature = "ratelimiting")]
|
||||||
use ratelimiting::RateLimiter;
|
use ratelimiting::RateLimiter;
|
||||||
|
#[cfg(feature = "gemini_srv")]
|
||||||
|
use tokio_rustls::TlsAcceptor;
|
||||||
|
#[cfg(feature = "gemini_srv")]
|
||||||
|
use rustls::Session;
|
||||||
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
@ -124,13 +120,13 @@ pub mod handling;
|
||||||
pub mod ratelimiting;
|
pub mod ratelimiting;
|
||||||
#[cfg(feature = "user_management")]
|
#[cfg(feature = "user_management")]
|
||||||
pub mod user_management;
|
pub mod user_management;
|
||||||
#[cfg(feature = "certgen")]
|
#[cfg(feature = "gemini_srv")]
|
||||||
pub mod gencert;
|
mod cert;
|
||||||
|
|
||||||
#[cfg(feature="user_management")]
|
#[cfg(feature="user_management")]
|
||||||
use user_management::UserManager;
|
use user_management::UserManager;
|
||||||
#[cfg(feature = "certgen")]
|
#[cfg(feature = "certgen")]
|
||||||
use gencert::CertGenMode;
|
pub use cert::CertGenMode;
|
||||||
|
|
||||||
pub use uriparse as uri;
|
pub use uriparse as uri;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
@ -723,7 +719,7 @@ impl Server {
|
||||||
|
|
||||||
fn build(mut self) -> Result<ServerInner> {
|
fn build(mut self) -> Result<ServerInner> {
|
||||||
#[cfg(feature = "gemini_srv")]
|
#[cfg(feature = "gemini_srv")]
|
||||||
let config = tls_config(
|
let config = cert::tls_config(
|
||||||
&self.cert_path,
|
&self.cert_path,
|
||||||
&self.key_path,
|
&self.key_path,
|
||||||
#[cfg(feature="certgen")]
|
#[cfg(feature="certgen")]
|
||||||
|
@ -825,115 +821,5 @@ async fn prune_ratelimit_log(rate_limits: Arc<RoutingNode<RateLimiter<IpAddr>>>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
fn tls_config(
|
|
||||||
cert_path: &PathBuf,
|
|
||||||
key_path: &PathBuf,
|
|
||||||
#[cfg(feature = "certgen")]
|
|
||||||
mode: CertGenMode,
|
|
||||||
) -> Result<Arc<ServerConfig>> {
|
|
||||||
let mut config = ServerConfig::new(AllowAnonOrSelfsignedClient::new());
|
|
||||||
|
|
||||||
#[cfg(feature = "certgen")]
|
|
||||||
mode.load_or_generate(&mut config, cert_path, key_path)?;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "certgen"))] {
|
|
||||||
let cert_chain = load_cert_chain(cert_path)
|
|
||||||
.context("Failed to load TLS certificate")?;
|
|
||||||
let key = load_key(key_path)
|
|
||||||
.context("Failed to load TLS key")?;
|
|
||||||
config.set_single_cert(cert_chain, key)
|
|
||||||
.context("Failed to use loaded TLS certificate")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(config.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
fn load_cert_chain(cert_path: &PathBuf) -> Result<Vec<Certificate>> {
|
|
||||||
let certs = std::fs::File::open(cert_path)
|
|
||||||
.with_context(|| format!("Failed to open `{:?}`", cert_path))?;
|
|
||||||
let mut certs = std::io::BufReader::new(certs);
|
|
||||||
let certs = rustls::internal::pemfile::certs(&mut certs)
|
|
||||||
.map_err(|_| anyhow!("failed to load certs `{:?}`", cert_path))?;
|
|
||||||
|
|
||||||
Ok(certs)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
fn load_key(key_path: &PathBuf) -> Result<PrivateKey> {
|
|
||||||
let keys = std::fs::File::open(key_path)
|
|
||||||
.with_context(|| format!("Failed to open `{:?}`", key_path))?;
|
|
||||||
let mut keys = std::io::BufReader::new(keys);
|
|
||||||
let mut keys = rustls::internal::pemfile::pkcs8_private_keys(&mut keys)
|
|
||||||
.map_err(|_| anyhow!("failed to load key `{:?}`", key_path))?;
|
|
||||||
|
|
||||||
ensure!(!keys.is_empty(), "no key found");
|
|
||||||
|
|
||||||
let key = keys.swap_remove(0);
|
|
||||||
|
|
||||||
Ok(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
/// A client cert verifier that accepts all connections
|
|
||||||
///
|
|
||||||
/// Unfortunately, rustls doesn't provide a ClientCertVerifier that accepts self-signed
|
|
||||||
/// certificates, so we need to implement this ourselves.
|
|
||||||
struct AllowAnonOrSelfsignedClient { }
|
|
||||||
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
impl AllowAnonOrSelfsignedClient {
|
|
||||||
|
|
||||||
/// Create a new verifier
|
|
||||||
fn new() -> Arc<Self> {
|
|
||||||
Arc::new(Self {})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gemini_srv")]
|
|
||||||
impl ClientCertVerifier for AllowAnonOrSelfsignedClient {
|
|
||||||
|
|
||||||
fn client_auth_root_subjects(
|
|
||||||
&self,
|
|
||||||
_: Option<&webpki::DNSName>
|
|
||||||
) -> Option<DistinguishedNames> {
|
|
||||||
Some(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn client_auth_mandatory(&self, _sni: Option<&webpki::DNSName>) -> Option<bool> {
|
|
||||||
Some(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the below methods are a hack until webpki doesn't break with certain certs
|
|
||||||
|
|
||||||
fn verify_client_cert(
|
|
||||||
&self,
|
|
||||||
_: &[Certificate],
|
|
||||||
_: Option<&webpki::DNSName>
|
|
||||||
) -> Result<ClientCertVerified, TLSError> {
|
|
||||||
Ok(ClientCertVerified::assertion())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn verify_tls12_signature(
|
|
||||||
&self,
|
|
||||||
_message: &[u8],
|
|
||||||
_cert: &Certificate,
|
|
||||||
_dss: &DigitallySignedStruct,
|
|
||||||
) -> Result<HandshakeSignatureValid, TLSError> {
|
|
||||||
Ok(HandshakeSignatureValid::assertion())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn verify_tls13_signature(
|
|
||||||
&self,
|
|
||||||
_message: &[u8],
|
|
||||||
_cert: &Certificate,
|
|
||||||
_dss: &DigitallySignedStruct,
|
|
||||||
) -> Result<HandshakeSignatureValid, TLSError> {
|
|
||||||
Ok(HandshakeSignatureValid::assertion())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ratelimiting")]
|
#[cfg(feature = "ratelimiting")]
|
||||||
enum Never {}
|
enum Never {}
|
||||||
|
|
Loading…
Reference in New Issue