Skip to main content

tonic/transport/channel/
tls.rs

1use super::service::TlsConnector;
2use crate::transport::{
3    Error,
4    tls::{Certificate, Identity},
5};
6use http::Uri;
7use std::sync::Arc;
8use std::time::Duration;
9use tokio_rustls::rustls::client::danger::ServerCertVerifier;
10use tokio_rustls::rustls::pki_types::TrustAnchor;
11
12/// Configures TLS settings for endpoints.
13#[derive(Debug, Clone, Default)]
14pub struct ClientTlsConfig {
15    domain: Option<String>,
16    certs: Vec<Certificate>,
17    trust_anchors: Vec<TrustAnchor<'static>>,
18    identity: Option<Identity>,
19    assume_http2: bool,
20    #[cfg(feature = "tls-native-roots")]
21    with_native_roots: bool,
22    #[cfg(feature = "tls-webpki-roots")]
23    with_webpki_roots: bool,
24    use_key_log: bool,
25    timeout: Option<Duration>,
26}
27
28impl ClientTlsConfig {
29    /// Creates a new `ClientTlsConfig` using Rustls.
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    /// Sets the domain name against which to verify the server's TLS certificate.
35    pub fn domain_name(self, domain_name: impl Into<String>) -> Self {
36        ClientTlsConfig {
37            domain: Some(domain_name.into()),
38            ..self
39        }
40    }
41
42    /// Adds the CA Certificate against which to verify the server's TLS certificate.
43    pub fn ca_certificate(self, ca_certificate: Certificate) -> Self {
44        let mut certs = self.certs;
45        certs.push(ca_certificate);
46        ClientTlsConfig { certs, ..self }
47    }
48
49    /// Adds the multiple CA Certificates against which to verify the server's TLS certificate.
50    pub fn ca_certificates(self, ca_certificates: impl IntoIterator<Item = Certificate>) -> Self {
51        let mut certs = self.certs;
52        certs.extend(ca_certificates);
53        ClientTlsConfig { certs, ..self }
54    }
55
56    /// Adds the trust anchor which to verify the server's TLS certificate.
57    pub fn trust_anchor(self, trust_anchor: TrustAnchor<'static>) -> Self {
58        let mut trust_anchors = self.trust_anchors;
59        trust_anchors.push(trust_anchor);
60        ClientTlsConfig {
61            trust_anchors,
62            ..self
63        }
64    }
65
66    /// Adds the multiple trust anchors which to verify the server's TLS certificate.
67    pub fn trust_anchors(
68        mut self,
69        trust_anchors: impl IntoIterator<Item = TrustAnchor<'static>>,
70    ) -> Self {
71        self.trust_anchors.extend(trust_anchors);
72        self
73    }
74
75    /// Sets the client identity to present to the server.
76    pub fn identity(self, identity: Identity) -> Self {
77        ClientTlsConfig {
78            identity: Some(identity),
79            ..self
80        }
81    }
82
83    /// If true, the connector should assume that the server supports HTTP/2,
84    /// even if it doesn't provide protocol negotiation via ALPN.
85    pub fn assume_http2(self, assume_http2: bool) -> Self {
86        ClientTlsConfig {
87            assume_http2,
88            ..self
89        }
90    }
91
92    /// Use key log as specified by the `SSLKEYLOGFILE` environment variable.
93    pub fn use_key_log(self) -> Self {
94        ClientTlsConfig {
95            use_key_log: true,
96            ..self
97        }
98    }
99
100    /// Enables the platform's trusted certs.
101    #[cfg(feature = "tls-native-roots")]
102    pub fn with_native_roots(self) -> Self {
103        ClientTlsConfig {
104            with_native_roots: true,
105            ..self
106        }
107    }
108
109    /// Enables the webpki roots.
110    #[cfg(feature = "tls-webpki-roots")]
111    pub fn with_webpki_roots(self) -> Self {
112        ClientTlsConfig {
113            with_webpki_roots: true,
114            ..self
115        }
116    }
117
118    /// Activates all TLS roots enabled through `tls-*-roots` feature flags
119    pub fn with_enabled_roots(self) -> Self {
120        let config = self;
121
122        #[cfg(feature = "tls-native-roots")]
123        let config = config.with_native_roots();
124        #[cfg(feature = "tls-webpki-roots")]
125        let config = config.with_webpki_roots();
126
127        config
128    }
129
130    /// Sets the timeout for the TLS handshake.
131    pub fn timeout(self, timeout: Duration) -> Self {
132        ClientTlsConfig {
133            timeout: Some(timeout),
134            ..self
135        }
136    }
137
138    pub(crate) fn into_tls_connector(self, uri: &Uri) -> Result<TlsConnector, crate::BoxError> {
139        self.build_tls_connector(uri, None)
140    }
141
142    pub(crate) fn into_tls_connector_with_verifier(
143        self,
144        uri: &Uri,
145        verifier: Arc<dyn ServerCertVerifier>,
146    ) -> Result<TlsConnector, crate::BoxError> {
147        self.build_tls_connector(uri, Some(verifier))
148    }
149
150    fn build_tls_connector(
151        self,
152        uri: &Uri,
153        server_cert_verifier: Option<Arc<dyn ServerCertVerifier>>,
154    ) -> Result<TlsConnector, crate::BoxError> {
155        let domain = match &self.domain {
156            Some(domain) => domain,
157            None => uri.host().ok_or_else(Error::new_invalid_uri)?,
158        };
159        TlsConnector::new(
160            self.certs,
161            self.trust_anchors,
162            self.identity,
163            server_cert_verifier,
164            domain,
165            self.assume_http2,
166            self.use_key_log,
167            self.timeout,
168            #[cfg(feature = "tls-native-roots")]
169            self.with_native_roots,
170            #[cfg(feature = "tls-webpki-roots")]
171            self.with_webpki_roots,
172        )
173    }
174}