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