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