1use super::AssertReply;
8use crate::{Error, SmtpClient};
9use rustls::{
10 ClientConfig, ClientConnection, SignatureScheme,
11 client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
12};
13use rustls_pki_types::ServerName;
14use rustls_platform_verifier::BuilderVerifierExt;
15use std::{convert::TryFrom, io, sync::Arc};
16use tokio::net::TcpStream;
17use tokio_rustls::{TlsConnector, client::TlsStream};
18
19impl SmtpClient<TcpStream> {
20 pub async fn start_tls(
22 mut self,
23 tls_connector: &TlsConnector,
24 hostname: &str,
25 ) -> crate::Result<SmtpClient<TlsStream<TcpStream>>> {
26 self.cmd(b"STARTTLS\r\n")
28 .await?
29 .assert_positive_completion()?;
30
31 self.into_tls(tls_connector, hostname).await
32 }
33
34 pub async fn into_tls(
35 self,
36 tls_connector: &TlsConnector,
37 hostname: &str,
38 ) -> crate::Result<SmtpClient<TlsStream<TcpStream>>> {
39 tokio::time::timeout(self.timeout, async {
40 Ok(SmtpClient {
41 stream: tls_connector
42 .connect(
43 ServerName::try_from(hostname)
44 .map_err(|_| crate::Error::InvalidTLSName)?
45 .to_owned(),
46 self.stream,
47 )
48 .await
49 .map_err(|err| {
50 let kind = err.kind();
51 if let Some(inner) = err.into_inner() {
52 match inner.downcast::<rustls::Error>() {
53 Ok(error) => Error::Tls(error),
54 Err(error) => Error::Io(io::Error::new(kind, error)),
55 }
56 } else {
57 Error::Io(io::Error::new(kind, "Unspecified"))
58 }
59 })?,
60 timeout: self.timeout,
61 })
62 })
63 .await
64 .map_err(|_| crate::Error::Timeout)?
65 }
66}
67
68impl SmtpClient<TlsStream<TcpStream>> {
69 pub fn tls_connection(&self) -> &ClientConnection {
70 self.stream.get_ref().1
71 }
72}
73
74pub fn build_tls_connector(allow_invalid_certs: bool) -> Result<TlsConnector, String> {
75 let config = if !allow_invalid_certs {
76 ClientConfig::builder()
77 .with_platform_verifier()
78 .map(|config| config.with_no_client_auth())
79 .map_err(|err| format!("Failed to build platform verifier: {err}"))?
80 } else {
81 ClientConfig::builder()
82 .dangerous()
83 .with_custom_certificate_verifier(Arc::new(DummyVerifier {}))
84 .with_no_client_auth()
85 };
86
87 Ok(TlsConnector::from(Arc::new(config)))
88}
89
90#[doc(hidden)]
91#[derive(Debug)]
92struct DummyVerifier;
93
94impl ServerCertVerifier for DummyVerifier {
95 fn verify_server_cert(
96 &self,
97 _end_entity: &rustls_pki_types::CertificateDer<'_>,
98 _intermediates: &[rustls_pki_types::CertificateDer<'_>],
99 _server_name: &rustls_pki_types::ServerName<'_>,
100 _ocsp_response: &[u8],
101 _now: rustls_pki_types::UnixTime,
102 ) -> Result<ServerCertVerified, rustls::Error> {
103 Ok(ServerCertVerified::assertion())
104 }
105
106 fn verify_tls12_signature(
107 &self,
108 _message: &[u8],
109 _cert: &rustls_pki_types::CertificateDer<'_>,
110 _dss: &rustls::DigitallySignedStruct,
111 ) -> Result<HandshakeSignatureValid, rustls::Error> {
112 Ok(HandshakeSignatureValid::assertion())
113 }
114
115 fn verify_tls13_signature(
116 &self,
117 _message: &[u8],
118 _cert: &rustls_pki_types::CertificateDer<'_>,
119 _dss: &rustls::DigitallySignedStruct,
120 ) -> Result<HandshakeSignatureValid, rustls::Error> {
121 Ok(HandshakeSignatureValid::assertion())
122 }
123
124 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
125 vec![
126 SignatureScheme::RSA_PKCS1_SHA1,
127 SignatureScheme::ECDSA_SHA1_Legacy,
128 SignatureScheme::RSA_PKCS1_SHA256,
129 SignatureScheme::ECDSA_NISTP256_SHA256,
130 SignatureScheme::RSA_PKCS1_SHA384,
131 SignatureScheme::ECDSA_NISTP384_SHA384,
132 SignatureScheme::RSA_PKCS1_SHA512,
133 SignatureScheme::ECDSA_NISTP521_SHA512,
134 SignatureScheme::RSA_PSS_SHA256,
135 SignatureScheme::RSA_PSS_SHA384,
136 SignatureScheme::RSA_PSS_SHA512,
137 SignatureScheme::ED25519,
138 SignatureScheme::ED448,
139 ]
140 }
141}