mail_send/smtp/
tls.rs

1/*
2 * Copyright Stalwart Labs Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7 * option. This file may not be copied, modified, or distributed
8 * except according to those terms.
9 */
10
11use 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    /// Upgrade the connection to TLS.
27    pub async fn start_tls(
28        mut self,
29        tls_connector: &TlsConnector,
30        hostname: &str,
31    ) -> crate::Result<SmtpClient<TlsStream<TcpStream>>> {
32        // Send STARTTLS command
33        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}