Browse Source

Merge branch 'feature/whitelist-self-signed' into 'master'

add a config value to trust certificates from certain domains

See merge request famedly/conduit!55
merge-requests/55/merge
Aiden McClelland 4 years ago
parent
commit
e1701af15a
  1. 17
      conduit-example.toml
  2. 12
      src/database.rs
  3. 20
      src/database/globals.rs
  4. 32
      src/database/proxy.rs

17
conduit-example.toml

@ -41,7 +41,20 @@ trusted_servers = ["matrix.org"]
address = "127.0.0.1" # This makes sure Conduit can only be reached using the reverse proxy address = "127.0.0.1" # This makes sure Conduit can only be reached using the reverse proxy
proxy = "none" # more examples can be found at src/database/proxy.rs:6
# The total amount of memory that the database will use. # The total amount of memory that the database will use.
#db_cache_capacity_mb = 200 #db_cache_capacity_mb = 200
# proxy = "none" # more examples can be found at src/database/proxy.rs:6
# [trust_certificates]
# include = ["*.onion] # do not validate certificates from this domain (NOTE: this should *ONLY* be done for protocols that are self-authenticating such as Tor hidden services)
# To enable Tor federation, uncomment below:
#
# [[proxy.by_domain]]
# url = "socks5h://localhost:9050"
# include = ["*.onion"]
#
# [trust_certificates]
# include = ["*.onion"]

12
src/database.rs

@ -39,7 +39,15 @@ use std::{
use tokio::sync::{OwnedRwLockReadGuard, RwLock as TokioRwLock, Semaphore}; use tokio::sync::{OwnedRwLockReadGuard, RwLock as TokioRwLock, Semaphore};
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
use self::proxy::ProxyConfig; use self::proxy::{IncludeExclude, ProxyConfig};
#[derive(Debug, Clone, Deserialize)]
pub struct CertificateTrustList(IncludeExclude);
impl CertificateTrustList {
pub fn contains(&self, domain: &str) -> bool {
self.0.includes(domain)
}
}
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
pub struct Config { pub struct Config {
@ -65,6 +73,8 @@ pub struct Config {
pub tracing_flame: bool, pub tracing_flame: bool,
#[serde(default)] #[serde(default)]
proxy: ProxyConfig, proxy: ProxyConfig,
#[serde(default)]
trust_certificates: Option<CertificateTrustList>,
jwt_secret: Option<String>, jwt_secret: Option<String>,
#[serde(default = "Vec::new")] #[serde(default = "Vec::new")]
trusted_servers: Vec<Box<ServerName>>, trusted_servers: Vec<Box<ServerName>>,

20
src/database/globals.rs

@ -19,7 +19,7 @@ use tokio::sync::{broadcast, watch::Receiver, Mutex as TokioMutex, Semaphore};
use tracing::{error, info}; use tracing::{error, info};
use trust_dns_resolver::TokioAsyncResolver; use trust_dns_resolver::TokioAsyncResolver;
use super::abstraction::Tree; use super::{abstraction::Tree, CertificateTrustList};
pub const COUNTER: &[u8] = b"c"; pub const COUNTER: &[u8] = b"c";
@ -53,6 +53,7 @@ pub struct Globals {
struct MatrixServerVerifier { struct MatrixServerVerifier {
inner: WebPKIVerifier, inner: WebPKIVerifier,
trust_list: Option<CertificateTrustList>,
tls_name_override: Arc<RwLock<TlsNameMap>>, tls_name_override: Arc<RwLock<TlsNameMap>>,
} }
@ -66,6 +67,14 @@ impl ServerCertVerifier for MatrixServerVerifier {
ocsp_response: &[u8], ocsp_response: &[u8],
) -> std::result::Result<rustls::ServerCertVerified, rustls::TLSError> { ) -> std::result::Result<rustls::ServerCertVerified, rustls::TLSError> {
if let Some(override_name) = self.tls_name_override.read().unwrap().get(dns_name.into()) { if let Some(override_name) = self.tls_name_override.read().unwrap().get(dns_name.into()) {
if self
.trust_list
.as_ref()
.map(|tl| tl.contains(override_name.as_ref().into()))
.unwrap_or_default()
{
return Ok(rustls::ServerCertVerified::assertion());
}
let result = self.inner.verify_server_cert( let result = self.inner.verify_server_cert(
roots, roots,
presented_certs, presented_certs,
@ -80,6 +89,14 @@ impl ServerCertVerifier for MatrixServerVerifier {
dns_name dns_name
); );
} }
if self
.trust_list
.as_ref()
.map(|tl| tl.contains(dns_name.into()))
.unwrap_or_default()
{
return Ok(rustls::ServerCertVerified::assertion());
}
self.inner self.inner
.verify_server_cert(roots, presented_certs, dns_name, ocsp_response) .verify_server_cert(roots, presented_certs, dns_name, ocsp_response)
} }
@ -164,6 +181,7 @@ impl Globals {
let tls_name_override = Arc::new(RwLock::new(TlsNameMap::new())); let tls_name_override = Arc::new(RwLock::new(TlsNameMap::new()));
let verifier = Arc::new(MatrixServerVerifier { let verifier = Arc::new(MatrixServerVerifier {
inner: WebPKIVerifier::new(), inner: WebPKIVerifier::new(),
trust_list: config.trust_certificates.clone(),
tls_name_override: tls_name_override.clone(), tls_name_override: tls_name_override.clone(),
}); });
let mut tlsconfig = rustls::ClientConfig::new(); let mut tlsconfig = rustls::ClientConfig::new();

32
src/database/proxy.rs

@ -58,14 +58,28 @@ impl Default for ProxyConfig {
pub struct PartialProxyConfig { pub struct PartialProxyConfig {
#[serde(deserialize_with = "crate::utils::deserialize_from_str")] #[serde(deserialize_with = "crate::utils::deserialize_from_str")]
url: Url, url: Url,
#[serde(flatten)]
include_exclude: IncludeExclude,
}
impl PartialProxyConfig {
pub fn for_url(&self, url: &Url) -> Option<&Url> {
if self.include_exclude.includes(url.domain()?) {
Some(&self.url)
} else {
None
}
}
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct IncludeExclude {
#[serde(default)] #[serde(default)]
include: Vec<WildCardedDomain>, include: Vec<WildCardedDomain>,
#[serde(default)] #[serde(default)]
exclude: Vec<WildCardedDomain>, exclude: Vec<WildCardedDomain>,
} }
impl PartialProxyConfig { impl IncludeExclude {
pub fn for_url(&self, url: &Url) -> Option<&Url> { pub fn includes(&self, domain: &str) -> bool {
let domain = url.domain()?;
let mut included_because = None; // most specific reason it was included let mut included_because = None; // most specific reason it was included
let mut excluded_because = None; // most specific reason it was excluded let mut excluded_because = None; // most specific reason it was excluded
if self.include.is_empty() { if self.include.is_empty() {
@ -89,9 +103,9 @@ impl PartialProxyConfig {
} }
} }
match (included_because, excluded_because) { match (included_because, excluded_because) {
(Some(a), Some(b)) if a.more_specific_than(b) => Some(&self.url), // included for a more specific reason than excluded (Some(a), Some(b)) if a.more_specific_than(b) => true, // included for a more specific reason than excluded
(Some(_), None) => Some(&self.url), (Some(_), None) => true,
_ => None, _ => false,
} }
} }
} }
@ -99,9 +113,9 @@ impl PartialProxyConfig {
/// A domain name, that optionally allows a * as its first subdomain. /// A domain name, that optionally allows a * as its first subdomain.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum WildCardedDomain { pub enum WildCardedDomain {
WildCard, WildCard, // *
WildCarded(String), WildCarded(String), // *.foo
Exact(String), Exact(String), // foo.bar
} }
impl WildCardedDomain { impl WildCardedDomain {
pub fn matches(&self, domain: &str) -> bool { pub fn matches(&self, domain: &str) -> bool {

Loading…
Cancel
Save