diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index 694897a80..c376c3d00 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -35,6 +35,7 @@ transport = [ ] tls = ["transport", "tokio-rustls"] tls-roots = ["tls", "rustls-native-certs"] +tls-dangerous = ["rustls", "webpki"] # [[bench]] # name = "bench_main" @@ -42,7 +43,7 @@ tls-roots = ["tls", "rustls-native-certs"] [dependencies] bytes = "0.5" -futures-core = { version = "0.3", default-features = false } +futures-core = { version = "0.3", default-features = false } futures-util = { version = "0.3", default-features = false } tracing = "0.1" http = "0.2" @@ -74,6 +75,8 @@ tracing-futures = { version = "0.2", optional = true } # rustls tokio-rustls = { version = "0.12", optional = true } rustls-native-certs = { version = "0.1", optional = true } +rustls = { version = "0.16", features = ["dangerous_configuration"], optional = true } +webpki = { version = "0.21", optional = true } [dev-dependencies] tokio = { version = "0.2", features = ["rt-core", "macros"] } @@ -88,4 +91,3 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "decode" harness = false - diff --git a/tonic/src/transport/channel/tls.rs b/tonic/src/transport/channel/tls.rs index 33d8f83c5..1aab36071 100644 --- a/tonic/src/transport/channel/tls.rs +++ b/tonic/src/transport/channel/tls.rs @@ -15,6 +15,8 @@ pub struct ClientTlsConfig { cert: Option, identity: Option, rustls_raw: Option, + #[cfg(feature = "tls-dangerous")] + certs_validation: bool, } #[cfg(feature = "tls")] @@ -37,6 +39,8 @@ impl ClientTlsConfig { cert: None, identity: None, rustls_raw: None, + #[cfg(feature = "tls-dangerous")] + certs_validation: true, } } @@ -80,6 +84,28 @@ impl ClientTlsConfig { } } + /// Disables certificate validation. + /// + /// # Warning + /// + /// You should think very carefully before using this method. If + /// invalid certificates are trusted, *any* certificate for *any* site + /// will be trusted for use. This includes expired certificates. This + /// introduces significant vulnerabilities, and should only be used + /// as a last resort. + /// + /// # Optional + /// + /// This requires the optional `tls` and `tls-dangerous` features to be enabled. + #[cfg(feature = "tls-dangerous")] + #[cfg_attr(docsrs, doc(cfg(feature = "tls-dangerous")))] + pub fn danger_accept_invalid_certs(self) -> Self { + ClientTlsConfig { + certs_validation: false, + ..self + } + } + pub(crate) fn tls_connector(&self, uri: Uri) -> Result { let domain = match &self.domain { None => uri.host().ok_or(Error::new_invalid_uri())?.to_string(), @@ -87,7 +113,23 @@ impl ClientTlsConfig { }; match &self.rustls_raw { None => { - TlsConnector::new_with_rustls_cert(self.cert.clone(), self.identity.clone(), domain) + let certs_validation = { + #[cfg(feature = "tls-dangerous")] + { + self.certs_validation + } + #[cfg(not(feature = "tls-dangerous"))] + { + true + } + }; + + TlsConnector::new_with_rustls_cert( + self.cert.clone(), + self.identity.clone(), + certs_validation, + domain, + ) } Some(c) => TlsConnector::new_with_rustls_raw(c.clone(), domain), } diff --git a/tonic/src/transport/service/tls.rs b/tonic/src/transport/service/tls.rs index e6cd2d8b4..056b80792 100644 --- a/tonic/src/transport/service/tls.rs +++ b/tonic/src/transport/service/tls.rs @@ -43,6 +43,7 @@ impl TlsConnector { pub(crate) fn new_with_rustls_cert( ca_cert: Option, identity: Option, + _certs_validation: bool, domain: String, ) -> Result { let mut config = ClientConfig::new(); @@ -63,6 +64,14 @@ impl TlsConnector { config.root_store.add_pem_file(&mut buf).unwrap(); } + #[cfg(feature = "tls-dangerous")] + { + if !_certs_validation { + config.dangerous() + .set_certificate_verifier(std::sync::Arc::new(NoCertsValidation)); + } + } + Ok(Self { config: Arc::new(config), domain: Arc::new(domain), @@ -245,3 +254,19 @@ mod rustls_keys { Ok((cert, key)) } } + +#[cfg(feature = "tls-dangerous")] +struct NoCertsValidation; + +#[cfg(feature = "tls-dangerous")] +impl rustls::ServerCertVerifier for NoCertsValidation { + fn verify_server_cert( + &self, + _roots: &rustls::RootCertStore, + _presented_certs: &[rustls::Certificate], + _dns_name: webpki::DNSNameRef<'_>, + _ocsp_response: &[u8], + ) -> Result { + Ok(rustls::ServerCertVerified::assertion()) + } +}