mail_send/smtp/
tls.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7use 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    /// Upgrade the connection to TLS.
20    pub async fn start_tls(
21        mut self,
22        tls_connector: &TlsConnector,
23        hostname: &str,
24    ) -> crate::Result<SmtpClient<TlsStream<TcpStream>>> {
25        // Send STARTTLS command
26        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}