diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 87efd5d..b850440 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,11 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - + args: --no-default-features --features=native-tls + - uses: actions-rs/cargo@v1 + with: + command: test + check: name: Check runs-on: ubuntu-latest diff --git a/src/smtp/client/mod.rs b/src/smtp/client/mod.rs index 7c9a1d5..91b312a 100644 --- a/src/smtp/client/mod.rs +++ b/src/smtp/client/mod.rs @@ -109,8 +109,11 @@ impl InnerClient { } /// Upgrades the underlying connection to SSL/TLS - #[cfg(feature = "native-tls")] - pub fn upgrade_tls_stream(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()> { + #[cfg(any(feature = "native-tls", feature = "rustls"))] + pub fn upgrade_tls_stream( + &mut self, + tls_parameters: &ClientTlsParameters, + ) -> Result<(), Error> { match self.stream { Some(ref mut stream) => stream.get_mut().upgrade_tls(tls_parameters), None => Ok(()), diff --git a/src/smtp/client/net.rs b/src/smtp/client/net.rs index 9f3d4c6..7d151b8 100644 --- a/src/smtp/client/net.rs +++ b/src/smtp/client/net.rs @@ -19,12 +19,13 @@ use std::time::Duration; pub struct ClientTlsParameters { /// A connector from `native-tls` #[cfg(feature = "native-tls")] - pub connector: TlsConnector, + connector: TlsConnector, /// A client from `rustls` #[cfg(feature = "rustls")] - pub connector: ClientConfig, + // TODO use the same in all transports of the client + connector: Box, /// The domain name which is expected in the TLS certificate from the server - pub domain: String, + domain: String, } impl ClientTlsParameters { @@ -37,14 +38,18 @@ impl ClientTlsParameters { /// Creates a `ClientTlsParameters` #[cfg(feature = "rustls")] pub fn new(domain: String, connector: ClientConfig) -> Self { - ClientTlsParameters { connector, domain } + ClientTlsParameters { + connector: Box::new(connector), + domain, + } } } /// Accepted protocols by default. /// This removes TLS 1.0 and 1.1 compared to tls-native defaults. +/// This is also rustls' default behavior #[cfg(feature = "native-tls")] -pub const DEFAULT_TLS_MIN_PROTOCOL: Protocol = Protocol::Tlsv12; +const DEFAULT_TLS_MIN_PROTOCOL: Protocol = Protocol::Tlsv12; /// Represents the different types of underlying network streams pub enum NetworkStream { @@ -54,7 +59,7 @@ pub enum NetworkStream { #[cfg(feature = "native-tls")] Tls(Box>), #[cfg(feature = "rustls")] - Tls(rustls::StreamOwned), + Tls(Box>), /// Mock stream Mock(MockStream), } @@ -161,10 +166,10 @@ impl Connector for NetworkStream { Some(context) => { let domain = webpki::DNSNameRef::try_from_ascii_str(&context.domain)?; - Ok(NetworkStream::Tls(rustls::StreamOwned::new( - ClientSession::new(&Arc::new(context.connector.clone()), domain), + Ok(NetworkStream::Tls(Box::new(rustls::StreamOwned::new( + ClientSession::new(&Arc::new(*context.connector.clone()), domain), tcp_stream, - ))) + )))) } None => Ok(NetworkStream::Tcp(tcp_stream)), } @@ -184,10 +189,10 @@ impl Connector for NetworkStream { NetworkStream::Tcp(ref mut stream) => { let domain = webpki::DNSNameRef::try_from_ascii_str(&tls_parameters.domain)?; - NetworkStream::Tls(rustls::StreamOwned::new( - ClientSession::new(&Arc::new(tls_parameters.connector.clone()), domain), + NetworkStream::Tls(Box::new(rustls::StreamOwned::new( + ClientSession::new(&Arc::new(*tls_parameters.connector.clone()), domain), stream.try_clone().unwrap(), - )) + ))) } NetworkStream::Tls(_) | NetworkStream::Mock(_) => return Ok(()), }; diff --git a/src/smtp/mod.rs b/src/smtp/mod.rs index c78ba0a..0e46d7b 100644 --- a/src/smtp/mod.rs +++ b/src/smtp/mod.rs @@ -18,7 +18,6 @@ use crate::smtp::authentication::{ }; use crate::smtp::client::net::ClientTlsParameters; #[cfg(feature = "native-tls")] -// TODO RUSTLS use crate::smtp::client::net::DEFAULT_TLS_MIN_PROTOCOL; use crate::smtp::client::InnerClient; use crate::smtp::commands::*; @@ -306,7 +305,7 @@ impl<'a> SmtpTransport { (&ClientSecurity::Opportunistic(_), false) => (), (&ClientSecurity::None, _) => (), (&ClientSecurity::Wrapper(_), _) => (), - #[cfg(feature = "native-tls")] + #[cfg(any(feature = "native-tls", feature = "rustls"))] (&ClientSecurity::Opportunistic(ref tls_parameters), true) | (&ClientSecurity::Required(ref tls_parameters), true) => { try_smtp!(self.client.command(StarttlsCommand), self); @@ -315,10 +314,11 @@ impl<'a> SmtpTransport { // Send EHLO again self.ehlo()?; } - #[cfg(not(feature = "native-tls"))] + #[cfg(not(any(feature = "native-tls", feature = "rustls")))] (&ClientSecurity::Opportunistic(_), true) | (&ClientSecurity::Required(_), true) => { - // FIXME dedicated error variant - return Err(From::from("Encryption required but no TLS support enabled")); + // This should never happen as `ClientSecurity` can only be created + // when a TLS library is enabled + unreachable!("TLS support required but not supported"); } }