1 | use alloc::vec::Vec; |
2 | use core::marker::PhantomData; |
3 | |
4 | use pki_types::{CertificateDer, PrivateKeyDer}; |
5 | |
6 | use super::client_conn::Resumption; |
7 | use crate::builder::{ConfigBuilder, WantsVerifier}; |
8 | use crate::client::{ClientConfig, EchMode, ResolvesClientCert, handy}; |
9 | use crate::error::Error; |
10 | use crate::key_log::NoKeyLog; |
11 | use crate::sign::{CertifiedKey, SingleCertAndKey}; |
12 | use crate::sync::Arc; |
13 | use crate::versions::TLS13; |
14 | use crate::webpki::{self, WebPkiServerVerifier}; |
15 | use crate::{WantsVersions, compress, verify, versions}; |
16 | |
17 | impl ConfigBuilder<ClientConfig, WantsVersions> { |
18 | /// Enable Encrypted Client Hello (ECH) in the given mode. |
19 | /// |
20 | /// This implicitly selects TLS 1.3 as the only supported protocol version to meet the |
21 | /// requirement to support ECH. |
22 | /// |
23 | /// The `ClientConfig` that will be produced by this builder will be specific to the provided |
24 | /// [`crate::client::EchConfig`] and may not be appropriate for all connections made by the program. |
25 | /// In this case the configuration should only be shared by connections intended for domains |
26 | /// that offer the provided [`crate::client::EchConfig`] in their DNS zone. |
27 | pub fn with_ech( |
28 | self, |
29 | mode: EchMode, |
30 | ) -> Result<ConfigBuilder<ClientConfig, WantsVerifier>, Error> { |
31 | let mut res: ConfigBuilder = self.with_protocol_versions(&[&TLS13][..])?; |
32 | res.state.client_ech_mode = Some(mode); |
33 | Ok(res) |
34 | } |
35 | } |
36 | |
37 | impl ConfigBuilder<ClientConfig, WantsVerifier> { |
38 | /// Choose how to verify server certificates. |
39 | /// |
40 | /// Using this function does not configure revocation. If you wish to |
41 | /// configure revocation, instead use: |
42 | /// |
43 | /// ```diff |
44 | /// - .with_root_certificates(root_store) |
45 | /// + .with_webpki_verifier( |
46 | /// + WebPkiServerVerifier::builder_with_provider(root_store, crypto_provider) |
47 | /// + .with_crls(...) |
48 | /// + .build()? |
49 | /// + ) |
50 | /// ``` |
51 | pub fn with_root_certificates( |
52 | self, |
53 | root_store: impl Into<Arc<webpki::RootCertStore>>, |
54 | ) -> ConfigBuilder<ClientConfig, WantsClientCert> { |
55 | let algorithms = self |
56 | .provider |
57 | .signature_verification_algorithms; |
58 | self.with_webpki_verifier( |
59 | WebPkiServerVerifier::new_without_revocation(root_store, algorithms).into(), |
60 | ) |
61 | } |
62 | |
63 | /// Choose how to verify server certificates using a webpki verifier. |
64 | /// |
65 | /// See [`webpki::WebPkiServerVerifier::builder`] and |
66 | /// [`webpki::WebPkiServerVerifier::builder_with_provider`] for more information. |
67 | pub fn with_webpki_verifier( |
68 | self, |
69 | verifier: Arc<WebPkiServerVerifier>, |
70 | ) -> ConfigBuilder<ClientConfig, WantsClientCert> { |
71 | ConfigBuilder { |
72 | state: WantsClientCert { |
73 | versions: self.state.versions, |
74 | verifier, |
75 | client_ech_mode: self.state.client_ech_mode, |
76 | }, |
77 | provider: self.provider, |
78 | time_provider: self.time_provider, |
79 | side: PhantomData, |
80 | } |
81 | } |
82 | |
83 | /// Access configuration options whose use is dangerous and requires |
84 | /// extra care. |
85 | pub fn dangerous(self) -> danger::DangerousClientConfigBuilder { |
86 | danger::DangerousClientConfigBuilder { cfg: self } |
87 | } |
88 | } |
89 | |
90 | /// Container for unsafe APIs |
91 | pub(super) mod danger { |
92 | use core::marker::PhantomData; |
93 | |
94 | use crate::client::WantsClientCert; |
95 | use crate::sync::Arc; |
96 | use crate::{ClientConfig, ConfigBuilder, WantsVerifier, verify}; |
97 | |
98 | /// Accessor for dangerous configuration options. |
99 | #[derive (Debug)] |
100 | pub struct DangerousClientConfigBuilder { |
101 | /// The underlying ClientConfigBuilder |
102 | pub cfg: ConfigBuilder<ClientConfig, WantsVerifier>, |
103 | } |
104 | |
105 | impl DangerousClientConfigBuilder { |
106 | /// Set a custom certificate verifier. |
107 | pub fn with_custom_certificate_verifier( |
108 | self, |
109 | verifier: Arc<dyn verify::ServerCertVerifier>, |
110 | ) -> ConfigBuilder<ClientConfig, WantsClientCert> { |
111 | ConfigBuilder { |
112 | state: WantsClientCert { |
113 | versions: self.cfg.state.versions, |
114 | verifier, |
115 | client_ech_mode: self.cfg.state.client_ech_mode, |
116 | }, |
117 | provider: self.cfg.provider, |
118 | time_provider: self.cfg.time_provider, |
119 | side: PhantomData, |
120 | } |
121 | } |
122 | } |
123 | } |
124 | |
125 | /// A config builder state where the caller needs to supply whether and how to provide a client |
126 | /// certificate. |
127 | /// |
128 | /// For more information, see the [`ConfigBuilder`] documentation. |
129 | #[derive (Clone)] |
130 | pub struct WantsClientCert { |
131 | versions: versions::EnabledVersions, |
132 | verifier: Arc<dyn verify::ServerCertVerifier>, |
133 | client_ech_mode: Option<EchMode>, |
134 | } |
135 | |
136 | impl ConfigBuilder<ClientConfig, WantsClientCert> { |
137 | /// Sets a single certificate chain and matching private key for use |
138 | /// in client authentication. |
139 | /// |
140 | /// `cert_chain` is a vector of DER-encoded certificates. |
141 | /// `key_der` is a DER-encoded private key as PKCS#1, PKCS#8, or SEC1. The |
142 | /// `aws-lc-rs` and `ring` [`CryptoProvider`][crate::CryptoProvider]s support |
143 | /// all three encodings, but other `CryptoProviders` may not. |
144 | /// |
145 | /// This function fails if `key_der` is invalid. |
146 | pub fn with_client_auth_cert( |
147 | self, |
148 | cert_chain: Vec<CertificateDer<'static>>, |
149 | key_der: PrivateKeyDer<'static>, |
150 | ) -> Result<ClientConfig, Error> { |
151 | let certified_key = CertifiedKey::from_der(cert_chain, key_der, &self.provider)?; |
152 | Ok(self.with_client_cert_resolver(Arc::new(SingleCertAndKey::from(certified_key)))) |
153 | } |
154 | |
155 | /// Do not support client auth. |
156 | pub fn with_no_client_auth(self) -> ClientConfig { |
157 | self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {})) |
158 | } |
159 | |
160 | /// Sets a custom [`ResolvesClientCert`]. |
161 | pub fn with_client_cert_resolver( |
162 | self, |
163 | client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, |
164 | ) -> ClientConfig { |
165 | ClientConfig { |
166 | provider: self.provider, |
167 | alpn_protocols: Vec::new(), |
168 | resumption: Resumption::default(), |
169 | max_fragment_size: None, |
170 | client_auth_cert_resolver, |
171 | versions: self.state.versions, |
172 | enable_sni: true, |
173 | verifier: self.state.verifier, |
174 | key_log: Arc::new(NoKeyLog {}), |
175 | enable_secret_extraction: false, |
176 | enable_early_data: false, |
177 | #[cfg (feature = "tls12" )] |
178 | require_ems: cfg!(feature = "fips" ), |
179 | time_provider: self.time_provider, |
180 | cert_compressors: compress::default_cert_compressors().to_vec(), |
181 | cert_compression_cache: Arc::new(compress::CompressionCache::default()), |
182 | cert_decompressors: compress::default_cert_decompressors().to_vec(), |
183 | ech_mode: self.state.client_ech_mode, |
184 | } |
185 | } |
186 | } |
187 | |