1 use crate::anchors;
2 use crate::builder::{ConfigBuilder, WantsVerifier};
3 use crate::client::handy;
4 use crate::client::{ClientConfig, ResolvesClientCert};
5 use crate::error::Error;
6 use crate::key;
7 use crate::keylog::NoKeyLog;
8 use crate::kx::SupportedKxGroup;
9 use crate::suites::SupportedCipherSuite;
10 use crate::verify::{self, CertificateTransparencyPolicy};
11 use crate::versions;
12 
13 use std::marker::PhantomData;
14 use std::sync::Arc;
15 use std::time::SystemTime;
16 
17 impl ConfigBuilder<ClientConfig, WantsVerifier> {
18     /// Choose how to verify client certificates.
with_root_certificates( self, root_store: anchors::RootCertStore, ) -> ConfigBuilder<ClientConfig, WantsTransparencyPolicyOrClientCert>19     pub fn with_root_certificates(
20         self,
21         root_store: anchors::RootCertStore,
22     ) -> ConfigBuilder<ClientConfig, WantsTransparencyPolicyOrClientCert> {
23         ConfigBuilder {
24             state: WantsTransparencyPolicyOrClientCert {
25                 cipher_suites: self.state.cipher_suites,
26                 kx_groups: self.state.kx_groups,
27                 versions: self.state.versions,
28                 root_store,
29             },
30             side: PhantomData::default(),
31         }
32     }
33 
34     #[cfg(feature = "dangerous_configuration")]
35     /// Set a custom certificate verifier.
with_custom_certificate_verifier( self, verifier: Arc<dyn verify::ServerCertVerifier>, ) -> ConfigBuilder<ClientConfig, WantsClientCert>36     pub fn with_custom_certificate_verifier(
37         self,
38         verifier: Arc<dyn verify::ServerCertVerifier>,
39     ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
40         ConfigBuilder {
41             state: WantsClientCert {
42                 cipher_suites: self.state.cipher_suites,
43                 kx_groups: self.state.kx_groups,
44                 versions: self.state.versions,
45                 verifier,
46             },
47             side: PhantomData::default(),
48         }
49     }
50 }
51 
52 /// A config builder state where the caller needs to supply a certificate transparency policy or
53 /// client certificate resolver.
54 ///
55 /// In this state, the caller can optionally enable certificate transparency, or ignore CT and
56 /// invoke one of the methods related to client certificates (as in the [`WantsClientCert`] state).
57 ///
58 /// For more information, see the [`ConfigBuilder`] documentation.
59 pub struct WantsTransparencyPolicyOrClientCert {
60     cipher_suites: Vec<SupportedCipherSuite>,
61     kx_groups: Vec<&'static SupportedKxGroup>,
62     versions: versions::EnabledVersions,
63     root_store: anchors::RootCertStore,
64 }
65 
66 impl ConfigBuilder<ClientConfig, WantsTransparencyPolicyOrClientCert> {
67     /// Set Certificate Transparency logs to use for server certificate validation.
68     ///
69     /// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or
70     /// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will
71     /// be validated against the configured CT logs until the deadline expires. After the deadline,
72     /// certificates will no longer be validated, and a warning message will be logged. The deadline
73     /// may vary depending on how often you deploy builds with updated dependencies.
with_certificate_transparency_logs( self, logs: &'static [&'static sct::Log], validation_deadline: SystemTime, ) -> ConfigBuilder<ClientConfig, WantsClientCert>74     pub fn with_certificate_transparency_logs(
75         self,
76         logs: &'static [&'static sct::Log],
77         validation_deadline: SystemTime,
78     ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
79         self.with_logs(Some(CertificateTransparencyPolicy::new(
80             logs,
81             validation_deadline,
82         )))
83     }
84 
85     /// Sets a single certificate chain and matching private key for use
86     /// in client authentication.
87     ///
88     /// `cert_chain` is a vector of DER-encoded certificates.
89     /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key.
90     ///
91     /// This function fails if `key_der` is invalid.
with_single_cert( self, cert_chain: Vec<key::Certificate>, key_der: key::PrivateKey, ) -> Result<ClientConfig, Error>92     pub fn with_single_cert(
93         self,
94         cert_chain: Vec<key::Certificate>,
95         key_der: key::PrivateKey,
96     ) -> Result<ClientConfig, Error> {
97         self.with_logs(None)
98             .with_single_cert(cert_chain, key_der)
99     }
100 
101     /// Do not support client auth.
with_no_client_auth(self) -> ClientConfig102     pub fn with_no_client_auth(self) -> ClientConfig {
103         self.with_logs(None)
104             .with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {}))
105     }
106 
107     /// Sets a custom [`ResolvesClientCert`].
with_client_cert_resolver( self, client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, ) -> ClientConfig108     pub fn with_client_cert_resolver(
109         self,
110         client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
111     ) -> ClientConfig {
112         self.with_logs(None)
113             .with_client_cert_resolver(client_auth_cert_resolver)
114     }
115 
with_logs( self, ct_policy: Option<CertificateTransparencyPolicy>, ) -> ConfigBuilder<ClientConfig, WantsClientCert>116     fn with_logs(
117         self,
118         ct_policy: Option<CertificateTransparencyPolicy>,
119     ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
120         ConfigBuilder {
121             state: WantsClientCert {
122                 cipher_suites: self.state.cipher_suites,
123                 kx_groups: self.state.kx_groups,
124                 versions: self.state.versions,
125                 verifier: Arc::new(verify::WebPkiVerifier::new(
126                     self.state.root_store,
127                     ct_policy,
128                 )),
129             },
130             side: PhantomData,
131         }
132     }
133 }
134 
135 /// A config builder state where the caller needs to supply whether and how to provide a client
136 /// certificate.
137 ///
138 /// For more information, see the [`ConfigBuilder`] documentation.
139 pub struct WantsClientCert {
140     cipher_suites: Vec<SupportedCipherSuite>,
141     kx_groups: Vec<&'static SupportedKxGroup>,
142     versions: versions::EnabledVersions,
143     verifier: Arc<dyn verify::ServerCertVerifier>,
144 }
145 
146 impl ConfigBuilder<ClientConfig, WantsClientCert> {
147     /// Sets a single certificate chain and matching private key for use
148     /// in client authentication.
149     ///
150     /// `cert_chain` is a vector of DER-encoded certificates.
151     /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key.
152     ///
153     /// This function fails if `key_der` is invalid.
with_single_cert( self, cert_chain: Vec<key::Certificate>, key_der: key::PrivateKey, ) -> Result<ClientConfig, Error>154     pub fn with_single_cert(
155         self,
156         cert_chain: Vec<key::Certificate>,
157         key_der: key::PrivateKey,
158     ) -> Result<ClientConfig, Error> {
159         let resolver = handy::AlwaysResolvesClientCert::new(cert_chain, &key_der)?;
160         Ok(self.with_client_cert_resolver(Arc::new(resolver)))
161     }
162 
163     /// Do not support client auth.
with_no_client_auth(self) -> ClientConfig164     pub fn with_no_client_auth(self) -> ClientConfig {
165         self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {}))
166     }
167 
168     /// Sets a custom [`ResolvesClientCert`].
with_client_cert_resolver( self, client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, ) -> ClientConfig169     pub fn with_client_cert_resolver(
170         self,
171         client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
172     ) -> ClientConfig {
173         ClientConfig {
174             cipher_suites: self.state.cipher_suites,
175             kx_groups: self.state.kx_groups,
176             alpn_protocols: Vec::new(),
177             session_storage: handy::ClientSessionMemoryCache::new(256),
178             max_fragment_size: None,
179             client_auth_cert_resolver,
180             enable_tickets: true,
181             versions: self.state.versions,
182             enable_sni: true,
183             verifier: self.state.verifier,
184             key_log: Arc::new(NoKeyLog {}),
185             enable_early_data: false,
186         }
187     }
188 }
189