1use alloc::vec::Vec;
2use core::marker::PhantomData;
3
4use pki_types::PrivateKeyDer;
5
6use super::client_conn::Resumption;
7use crate::builder::{ConfigBuilder, WantsVerifier};
8use crate::client::{ClientConfig, ClientCredentialResolver, EchMode, handy};
9use crate::crypto::{Credentials, Identity, SingleCredential};
10use crate::error::{ApiMisuse, Error};
11use crate::key_log::NoKeyLog;
12use crate::sync::Arc;
13use crate::webpki::{self, WebPkiServerVerifier};
14use crate::{compress, verify};
15
16impl ConfigBuilder<ClientConfig, WantsVerifier> {
17 pub fn with_ech(mut self, mode: EchMode) -> Self {
28 self.state.client_ech_mode = Some(mode);
29 self
30 }
31}
32
33impl ConfigBuilder<ClientConfig, WantsVerifier> {
34 pub fn with_root_certificates(
48 self,
49 root_store: impl Into<Arc<webpki::RootCertStore>>,
50 ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
51 let algorithms = self
52 .provider
53 .signature_verification_algorithms;
54 self.with_webpki_verifier(
55 WebPkiServerVerifier::new_without_revocation(root_store, algorithms).into(),
56 )
57 }
58
59 pub fn with_webpki_verifier(
64 self,
65 verifier: Arc<WebPkiServerVerifier>,
66 ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
67 ConfigBuilder {
68 state: WantsClientCert {
69 verifier,
70 client_ech_mode: self.state.client_ech_mode,
71 },
72 provider: self.provider,
73 time_provider: self.time_provider,
74 side: PhantomData,
75 }
76 }
77
78 pub fn dangerous(self) -> danger::DangerousClientConfigBuilder {
81 danger::DangerousClientConfigBuilder { cfg: self }
82 }
83}
84
85pub(super) mod danger {
87 use core::marker::PhantomData;
88
89 use crate::client::WantsClientCert;
90 use crate::sync::Arc;
91 use crate::{ClientConfig, ConfigBuilder, WantsVerifier, verify};
92
93 #[derive(Debug)]
95 pub struct DangerousClientConfigBuilder {
96 pub(super) cfg: ConfigBuilder<ClientConfig, WantsVerifier>,
98 }
99
100 impl DangerousClientConfigBuilder {
101 pub fn with_custom_certificate_verifier(
103 self,
104 verifier: Arc<dyn verify::ServerVerifier>,
105 ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
106 ConfigBuilder {
107 state: WantsClientCert {
108 verifier,
109 client_ech_mode: self.cfg.state.client_ech_mode,
110 },
111 provider: self.cfg.provider,
112 time_provider: self.cfg.time_provider,
113 side: PhantomData,
114 }
115 }
116 }
117}
118
119#[derive(Clone)]
124pub struct WantsClientCert {
125 verifier: Arc<dyn verify::ServerVerifier>,
126 client_ech_mode: Option<EchMode>,
127}
128
129impl ConfigBuilder<ClientConfig, WantsClientCert> {
130 pub fn with_client_auth_cert(
140 self,
141 identity: Arc<Identity<'static>>,
142 key_der: PrivateKeyDer<'static>,
143 ) -> Result<ClientConfig, Error> {
144 let credentials = Credentials::from_der(identity, key_der, &self.provider)?;
145 self.with_client_credential_resolver(Arc::new(SingleCredential::from(credentials)))
146 }
147
148 pub fn with_no_client_auth(self) -> Result<ClientConfig, Error> {
150 self.with_client_credential_resolver(Arc::new(handy::FailResolveClientCert {}))
151 }
152
153 pub fn with_client_credential_resolver(
155 self,
156 client_auth_cert_resolver: Arc<dyn ClientCredentialResolver>,
157 ) -> Result<ClientConfig, Error> {
158 self.provider.consistency_check()?;
159
160 if self.state.client_ech_mode.is_some() {
161 match (
162 self.provider
163 .tls12_cipher_suites
164 .is_empty(),
165 self.provider
166 .tls13_cipher_suites
167 .is_empty(),
168 ) {
169 (_, true) => return Err(ApiMisuse::EchRequiresTls13Support.into()),
170 (false, _) => return Err(ApiMisuse::EchForbidsTls12Support.into()),
171 (true, false) => {}
172 };
173 }
174
175 Ok(ClientConfig {
176 provider: self.provider,
177 alpn_protocols: Vec::new(),
178 resumption: Resumption::default(),
179 max_fragment_size: None,
180 client_auth_cert_resolver,
181 enable_sni: true,
182 verifier: self.state.verifier,
183 key_log: Arc::new(NoKeyLog {}),
184 enable_secret_extraction: false,
185 enable_early_data: false,
186 require_ems: cfg!(feature = "fips"),
187 time_provider: self.time_provider,
188 cert_compressors: compress::default_cert_compressors().to_vec(),
189 cert_compression_cache: Arc::new(compress::CompressionCache::default()),
190 cert_decompressors: compress::default_cert_decompressors().to_vec(),
191 ech_mode: self.state.client_ech_mode,
192 })
193 }
194}