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