diff --git a/src/transport/smtp/client/async_connection.rs b/src/transport/smtp/client/async_connection.rs index e170b52..194c638 100644 --- a/src/transport/smtp/client/async_connection.rs +++ b/src/transport/smtp/client/async_connection.rs @@ -373,6 +373,22 @@ impl AsyncSmtpConnection { self.stream.get_ref().peer_certificate() } + /// Currently this is only avaialable when using Boring TLS and + /// returns the result of the verification of the TLS certificate + /// presented by the peer, if any. Only the last error encountered + /// during verification is presented. + /// It can be useful when you don't want to fail outright the TLS + /// negotiation, for example when a self-signed certificate is + /// encountered, but still want to record metrics or log the fact. + /// When using DANE verification, the PKI root of trust moves from + /// the CAs to DNS, so self-signed certificates are permitted as long + /// as the TLSA records match the leaf or issuer certificates. + /// It cannot be called on non Boring TLS streams. + #[cfg(feature = "boring-tls")] + pub fn tls_verify_result(&self) -> Result<(), Error> { + self.stream.get_ref().tls_verify_result() + } + /// All the X509 certificates of the chain (DER encoded) #[cfg(any(feature = "rustls-tls", feature = "boring-tls"))] pub fn certificate_chain(&self) -> Result>, Error> { diff --git a/src/transport/smtp/client/async_net.rs b/src/transport/smtp/client/async_net.rs index 7343387..ed5c984 100644 --- a/src/transport/smtp/client/async_net.rs +++ b/src/transport/smtp/client/async_net.rs @@ -429,6 +429,30 @@ impl AsyncNetworkStream { } } + #[cfg(feature = "boring-tls")] + pub fn tls_verify_result(&self) -> Result<(), Error> { + match &self.inner { + #[cfg(feature = "tokio1")] + InnerAsyncNetworkStream::Tokio1Tcp(_) => { + Err(error::client("Connection is not encrypted")) + } + #[cfg(feature = "tokio1-native-tls")] + InnerAsyncNetworkStream::Tokio1NativeTls(_) => panic!("Unsupported"), + #[cfg(feature = "tokio1-rustls-tls")] + InnerAsyncNetworkStream::Tokio1RustlsTls(_) => panic!("Unsupported"), + #[cfg(feature = "tokio1-boring-tls")] + InnerAsyncNetworkStream::Tokio1BoringTls(stream) => { + stream.ssl().verify_result().map_err(error::tls) + } + #[cfg(feature = "async-std1")] + InnerAsyncNetworkStream::AsyncStd1Tcp(_) => { + Err(error::client("Connection is not encrypted")) + } + #[cfg(feature = "async-std1-rustls-tls")] + InnerAsyncNetworkStream::AsyncStd1RustlsTls(_) => panic!("Unsupported"), + InnerAsyncNetworkStream::None => panic!("InnerNetworkStream::None must never be built"), + } + } pub fn certificate_chain(&self) -> Result>, Error> { match &self.inner { #[cfg(feature = "tokio1")] diff --git a/src/transport/smtp/client/connection.rs b/src/transport/smtp/client/connection.rs index 0e6ebdb..76f778f 100644 --- a/src/transport/smtp/client/connection.rs +++ b/src/transport/smtp/client/connection.rs @@ -308,6 +308,22 @@ impl SmtpConnection { self.stream.get_ref().peer_certificate() } + /// Currently this is only avaialable when using Boring TLS and + /// returns the result of the verification of the TLS certificate + /// presented by the peer, if any. Only the last error encountered + /// during verification is presented. + /// It can be useful when you don't want to fail outright the TLS + /// negotiation, for example when a self-signed certificate is + /// encountered, but still want to record metrics or log the fact. + /// When using DANE verification, the PKI root of trust moves from + /// the CAs to DNS, so self-signed certificates are permitted as long + /// as the TLSA records match the leaf or issuer certificates. + /// It cannot be called on non Boring TLS streams. + #[cfg(feature = "boring-tls")] + pub fn tls_verify_result(&self) -> Result<(), Error> { + self.stream.get_ref().tls_verify_result() + } + /// All the X509 certificates of the chain (DER encoded) #[cfg(any(feature = "rustls-tls", feature = "boring-tls"))] pub fn certificate_chain(&self) -> Result>, Error> { diff --git a/src/transport/smtp/client/net.rs b/src/transport/smtp/client/net.rs index 4e7fae3..6be0a99 100644 --- a/src/transport/smtp/client/net.rs +++ b/src/transport/smtp/client/net.rs @@ -222,6 +222,22 @@ impl NetworkStream { } } + #[cfg(feature = "boring-tls")] + pub fn tls_verify_result(&self) -> Result<(), Error> { + match &self.inner { + InnerNetworkStream::Tcp(_) => Err(error::client("Connection is not encrypted")), + #[cfg(feature = "native-tls")] + InnerNetworkStream::NativeTls(_) => panic!("Unsupported"), + #[cfg(feature = "rustls-tls")] + InnerNetworkStream::RustlsTls(_) => panic!("Unsupported"), + #[cfg(feature = "boring-tls")] + InnerNetworkStream::BoringTls(stream) => { + stream.ssl().verify_result().map_err(error::tls) + } + InnerNetworkStream::None => panic!("InnerNetworkStream::None must never be built"), + } + } + #[cfg(any(feature = "rustls-tls", feature = "boring-tls"))] pub fn certificate_chain(&self) -> Result>, Error> { match &self.inner {