1use std::{future::Future, io, sync::Arc};
2
3use compio_net::ToSocketAddrsAsync;
4use quinn_proto::{
5 ClientConfig, ServerConfig,
6 crypto::rustls::{QuicClientConfig, QuicServerConfig},
7};
8
9use crate::{Endpoint, endpoint};
10
11#[derive(Debug)]
17pub struct ClientBuilder<T>(T);
18
19impl ClientBuilder<rustls::RootCertStore> {
20 pub fn new_with_empty_roots() -> Self {
22 ClientBuilder(rustls::RootCertStore::empty())
23 }
24
25 #[cfg(feature = "native-certs")]
27 pub fn new_with_native_certs() -> io::Result<Self> {
28 let mut roots = rustls::RootCertStore::empty();
29 let mut certs = rustls_native_certs::load_native_certs();
30 if certs.certs.is_empty() {
31 return Err(io::Error::other(
32 certs
33 .errors
34 .pop()
35 .expect("certs and errors should not be both empty"),
36 ));
37 }
38 roots.add_parsable_certificates(certs.certs);
39 Ok(ClientBuilder(roots))
40 }
41
42 #[cfg(feature = "webpki-roots")]
44 pub fn new_with_webpki_roots() -> Self {
45 let roots =
46 rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
47 ClientBuilder(roots)
48 }
49
50 pub fn with_custom_certificate(
52 mut self,
53 der: rustls::pki_types::CertificateDer,
54 ) -> Result<Self, rustls::Error> {
55 self.0.add(der)?;
56 Ok(self)
57 }
58
59 pub fn with_no_crls(self) -> ClientBuilder<rustls::ClientConfig> {
61 ClientBuilder::new_with_root_certificates(self.0)
62 }
63
64 pub fn with_crls(
67 self,
68 crls: impl IntoIterator<Item = rustls::pki_types::CertificateRevocationListDer<'static>>,
69 ) -> Result<ClientBuilder<rustls::ClientConfig>, rustls::client::VerifierBuilderError> {
70 let verifier = rustls::client::WebPkiServerVerifier::builder(Arc::new(self.0))
71 .with_crls(crls)
72 .build()?;
73 Ok(ClientBuilder::new_with_webpki_verifier(verifier))
74 }
75}
76
77impl ClientBuilder<rustls::ClientConfig> {
78 pub fn new_with_rustls_client_config(
80 client_config: rustls::ClientConfig,
81 ) -> ClientBuilder<rustls::ClientConfig> {
82 ClientBuilder(client_config)
83 }
84
85 pub fn new_with_no_server_verification() -> ClientBuilder<rustls::ClientConfig> {
88 ClientBuilder(
89 rustls::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS13])
90 .dangerous()
91 .with_custom_certificate_verifier(Arc::new(verifier::SkipServerVerification::new()))
92 .with_no_client_auth(),
93 )
94 }
95
96 #[cfg(feature = "platform-verifier")]
98 pub fn new_with_platform_verifier() -> Result<ClientBuilder<rustls::ClientConfig>, rustls::Error>
99 {
100 use rustls_platform_verifier::BuilderVerifierExt;
101
102 Ok(ClientBuilder(
103 rustls::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS13])
104 .with_platform_verifier()?
105 .with_no_client_auth(),
106 ))
107 }
108
109 pub fn new_with_root_certificates(
111 roots: rustls::RootCertStore,
112 ) -> ClientBuilder<rustls::ClientConfig> {
113 ClientBuilder(
114 rustls::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS13])
115 .with_root_certificates(roots)
116 .with_no_client_auth(),
117 )
118 }
119
120 pub fn new_with_webpki_verifier(
122 verifier: Arc<rustls::client::WebPkiServerVerifier>,
123 ) -> ClientBuilder<rustls::ClientConfig> {
124 ClientBuilder(
125 rustls::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS13])
126 .with_webpki_verifier(verifier)
127 .with_no_client_auth(),
128 )
129 }
130
131 pub fn with_alpn_protocols(mut self, protocols: &[&str]) -> Self {
133 self.0.alpn_protocols = protocols.iter().map(|p| p.as_bytes().to_vec()).collect();
134 self
135 }
136
137 pub fn with_key_log(mut self) -> Self {
143 self.0.key_log = Arc::new(rustls::KeyLogFile::new());
144 self
145 }
146
147 pub fn build(mut self) -> ClientConfig {
149 self.0.enable_early_data = true;
150 ClientConfig::new(Arc::new(
151 QuicClientConfig::try_from(self.0).expect("should support TLS13_AES_128_GCM_SHA256"),
152 ))
153 }
154
155 #[track_caller]
159 pub fn bind(self, addr: impl ToSocketAddrsAsync) -> impl Future<Output = io::Result<Endpoint>> {
160 let meta = endpoint::worker_meta();
161 async move {
162 let mut endpoint = Endpoint::client_at(addr, meta).await?;
163 endpoint.default_client_config = Some(self.build());
164 Ok(endpoint)
165 }
166 }
167}
168
169#[derive(Debug)]
175pub struct ServerBuilder<T>(T);
176
177impl ServerBuilder<rustls::ServerConfig> {
178 pub fn new_with_rustls_server_config(server_config: rustls::ServerConfig) -> Self {
180 Self(server_config)
181 }
182
183 pub fn new_with_single_cert(
187 cert_chain: Vec<rustls::pki_types::CertificateDer<'static>>,
188 key_der: rustls::pki_types::PrivateKeyDer<'static>,
189 ) -> Result<Self, rustls::Error> {
190 let server_config =
191 rustls::ServerConfig::builder_with_protocol_versions(&[&rustls::version::TLS13])
192 .with_no_client_auth()
193 .with_single_cert(cert_chain, key_der)?;
194 Ok(Self::new_with_rustls_server_config(server_config))
195 }
196
197 pub fn with_alpn_protocols(mut self, protocols: &[&str]) -> Self {
199 self.0.alpn_protocols = protocols.iter().map(|p| p.as_bytes().to_vec()).collect();
200 self
201 }
202
203 pub fn with_key_log(mut self) -> Self {
209 self.0.key_log = Arc::new(rustls::KeyLogFile::new());
210 self
211 }
212
213 pub fn build(mut self) -> ServerConfig {
215 self.0.max_early_data_size = u32::MAX;
216 ServerConfig::with_crypto(Arc::new(
217 QuicServerConfig::try_from(self.0).expect("should support TLS13_AES_128_GCM_SHA256"),
218 ))
219 }
220
221 #[track_caller]
225 pub fn bind(self, addr: impl ToSocketAddrsAsync) -> impl Future<Output = io::Result<Endpoint>> {
226 Endpoint::server_at(addr, self.build(), endpoint::worker_meta())
227 }
228}
229
230mod verifier {
231 use rustls::{
232 DigitallySignedStruct, Error, SignatureScheme,
233 client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
234 crypto::WebPkiSupportedAlgorithms,
235 pki_types::{CertificateDer, ServerName, UnixTime},
236 };
237
238 #[derive(Debug)]
239 pub struct SkipServerVerification(WebPkiSupportedAlgorithms);
240
241 impl SkipServerVerification {
242 pub fn new() -> Self {
243 Self(
244 rustls::crypto::CryptoProvider::get_default()
245 .map(|provider| provider.signature_verification_algorithms)
246 .unwrap_or_else(|| {
247 #[cfg(feature = "ring")]
248 use rustls::crypto::ring::default_provider;
249 default_provider().signature_verification_algorithms
250 }),
251 )
252 }
253 }
254
255 impl ServerCertVerifier for SkipServerVerification {
256 fn verify_server_cert(
257 &self,
258 _end_entity: &CertificateDer<'_>,
259 _intermediates: &[CertificateDer<'_>],
260 _server_name: &ServerName<'_>,
261 _ocsp: &[u8],
262 _now: UnixTime,
263 ) -> Result<ServerCertVerified, Error> {
264 Ok(ServerCertVerified::assertion())
265 }
266
267 fn verify_tls12_signature(
268 &self,
269 message: &[u8],
270 cert: &CertificateDer<'_>,
271 dss: &DigitallySignedStruct,
272 ) -> Result<HandshakeSignatureValid, Error> {
273 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.0)
274 }
275
276 fn verify_tls13_signature(
277 &self,
278 message: &[u8],
279 cert: &CertificateDer<'_>,
280 dss: &DigitallySignedStruct,
281 ) -> Result<HandshakeSignatureValid, Error> {
282 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.0)
283 }
284
285 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
286 self.0.supported_schemes()
287 }
288 }
289}