diff --git a/src/net/tls.rs b/src/net/tls.rs index 0745b32608..0013f23bea 100644 --- a/src/net/tls.rs +++ b/src/net/tls.rs @@ -10,6 +10,9 @@ use crate::net::session::SessionStream; use tokio_rustls::rustls; use tokio_rustls::rustls::client::ClientSessionStore; +mod danger; +use danger::NoCertificateVerification; + pub async fn wrap_tls<'a>( strict_tls: bool, hostname: &str, @@ -124,6 +127,18 @@ pub async fn wrap_rustls<'a>( config.resumption = resumption; config.enable_sni = use_sni; + // Do not verify certificates for hostnames starting with `_`. + // They are used for servers with self-signed certificates, e.g. for local testing. + // Hostnames starting with `_` can have only self-signed TLS certificates or wildcard certificates. + // It is not possible to get valid non-wildcard TLS certificates because CA/Browser Forum requirements + // explicitly state that domains should start with a letter, digit or hyphen: + // https://github.com/cabforum/servercert/blob/24f38fd4765e019db8bb1a8c56bf63c7115ce0b0/docs/BR.md + if hostname.starts_with("_") { + config + .dangerous() + .set_certificate_verifier(Arc::new(NoCertificateVerification::new())); + } + let tls = tokio_rustls::TlsConnector::from(Arc::new(config)); let name = tokio_rustls::rustls::pki_types::ServerName::try_from(hostname)?.to_owned(); let tls_stream = tls.connect(name, stream).await?; diff --git a/src/net/tls/danger.rs b/src/net/tls/danger.rs new file mode 100644 index 0000000000..bd0267ddc0 --- /dev/null +++ b/src/net/tls/danger.rs @@ -0,0 +1,55 @@ +//! Dangerous TLS implementation of accepting invalid certificates for Rustls. + +use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; +use tokio_rustls::rustls; + +#[derive(Debug)] +pub(super) struct NoCertificateVerification(); + +impl NoCertificateVerification { + pub(super) fn new() -> Self { + Self() + } +} + +impl rustls::client::danger::ServerCertVerifier for NoCertificateVerification { + fn verify_server_cert( + &self, + _end_entity: &CertificateDer<'_>, + _intermediates: &[CertificateDer<'_>], + _server_name: &ServerName<'_>, + _ocsp_response: &[u8], + _now: UnixTime, + ) -> Result { + Ok(rustls::client::danger::ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + let provider = rustls::crypto::ring::default_provider(); + let supported_schemes = &provider.signature_verification_algorithms; + rustls::crypto::verify_tls12_signature(message, cert, dss, supported_schemes) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + let provider = rustls::crypto::ring::default_provider(); + let supported_schemes = &provider.signature_verification_algorithms; + rustls::crypto::verify_tls13_signature(message, cert, dss, supported_schemes) + } + + fn supported_verify_schemes(&self) -> Vec { + let provider = rustls::crypto::ring::default_provider(); + provider + .signature_verification_algorithms + .supported_schemes() + } +}