1use alloc::vec::Vec;
2use core::marker::PhantomData;
3
4use pki_types::{CertificateDer, PrivateKeyDer};
5
6use super::client_conn::Resumption;
7use crate::builder::{ConfigBuilder, WantsVerifier};
8use crate::client::{ClientConfig, EchMode, ResolvesClientCert, handy};
9use crate::enums::ProtocolVersion;
10use crate::error::Error;
11use crate::key_log::NoKeyLog;
12use crate::sign::{CertifiedKey, SingleCertAndKey};
13use crate::sync::Arc;
14use crate::webpki::{self, WebPkiServerVerifier};
15use crate::{compress, verify};
16
17impl ConfigBuilder<ClientConfig, WantsVerifier> {
18 pub fn with_ech(mut self, mode: EchMode) -> Self {
29 self.state.client_ech_mode = Some(mode);
30 self
31 }
32}
33
34impl ConfigBuilder<ClientConfig, WantsVerifier> {
35 pub fn with_root_certificates(
49 self,
50 root_store: impl Into<Arc<webpki::RootCertStore>>,
51 ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
52 let algorithms = self
53 .provider
54 .signature_verification_algorithms;
55 self.with_webpki_verifier(
56 WebPkiServerVerifier::new_without_revocation(root_store, algorithms).into(),
57 )
58 }
59
60 pub fn with_webpki_verifier(
65 self,
66 verifier: Arc<WebPkiServerVerifier>,
67 ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
68 ConfigBuilder {
69 state: WantsClientCert {
70 verifier,
71 client_ech_mode: self.state.client_ech_mode,
72 },
73 provider: self.provider,
74 time_provider: self.time_provider,
75 side: PhantomData,
76 }
77 }
78
79 pub fn dangerous(self) -> danger::DangerousClientConfigBuilder {
82 danger::DangerousClientConfigBuilder { cfg: self }
83 }
84}
85
86pub(super) mod danger {
88 use core::marker::PhantomData;
89
90 use crate::client::WantsClientCert;
91 use crate::sync::Arc;
92 use crate::{ClientConfig, ConfigBuilder, WantsVerifier, verify};
93
94 #[derive(Debug)]
96 pub struct DangerousClientConfigBuilder {
97 pub(super) cfg: ConfigBuilder<ClientConfig, WantsVerifier>,
99 }
100
101 impl DangerousClientConfigBuilder {
102 pub fn with_custom_certificate_verifier(
104 self,
105 verifier: Arc<dyn verify::ServerCertVerifier>,
106 ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
107 ConfigBuilder {
108 state: WantsClientCert {
109 verifier,
110 client_ech_mode: self.cfg.state.client_ech_mode,
111 },
112 provider: self.cfg.provider,
113 time_provider: self.cfg.time_provider,
114 side: PhantomData,
115 }
116 }
117 }
118}
119
120#[derive(Clone)]
125pub struct WantsClientCert {
126 verifier: Arc<dyn verify::ServerCertVerifier>,
127 client_ech_mode: Option<EchMode>,
128}
129
130impl ConfigBuilder<ClientConfig, WantsClientCert> {
131 pub fn with_client_auth_cert(
141 self,
142 cert_chain: Vec<CertificateDer<'static>>,
143 key_der: PrivateKeyDer<'static>,
144 ) -> Result<ClientConfig, Error> {
145 let certified_key = CertifiedKey::from_der(cert_chain, key_der, &self.provider)?;
146 self.with_client_cert_resolver(Arc::new(SingleCertAndKey::from(certified_key)))
147 }
148
149 pub fn with_no_client_auth(self) -> Result<ClientConfig, Error> {
151 self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {}))
152 }
153
154 pub fn with_client_cert_resolver(
156 self,
157 client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
158 ) -> Result<ClientConfig, Error> {
159 self.provider.consistency_check()?;
160
161 if self.state.client_ech_mode.is_some() {
162 if !self
163 .provider
164 .cipher_suites
165 .iter()
166 .any(|cs| cs.version().version() == ProtocolVersion::TLSv1_3)
167 {
168 return Err(Error::General("ECH requires TLS1.3 support".into()));
169 }
170
171 if self
172 .provider
173 .cipher_suites
174 .iter()
175 .any(|cs| cs.version().version() == ProtocolVersion::TLSv1_2)
176 {
177 return Err(Error::General("ECH forbids TLS1.2 support".into()));
178 }
179 }
180
181 Ok(ClientConfig {
182 provider: self.provider,
183 alpn_protocols: Vec::new(),
184 resumption: Resumption::default(),
185 max_fragment_size: None,
186 client_auth_cert_resolver,
187 enable_sni: true,
188 verifier: self.state.verifier,
189 key_log: Arc::new(NoKeyLog {}),
190 enable_secret_extraction: false,
191 enable_early_data: false,
192 require_ems: cfg!(feature = "fips"),
193 time_provider: self.time_provider,
194 cert_compressors: compress::default_cert_compressors().to_vec(),
195 cert_compression_cache: Arc::new(compress::CompressionCache::default()),
196 cert_decompressors: compress::default_cert_decompressors().to_vec(),
197 ech_mode: self.state.client_ech_mode,
198 })
199 }
200}