1use crate::cert::{DeboaCertificate, DeboaIdentity};
4use deboa::{
5 errors::{ConnectionError, DeboaError},
6 Result,
7};
8use rustls::{
9 crypto::CryptoProvider,
10 pki_types::{CertificateDer, PrivateKeyDer},
11 ClientConfig,
12};
13
14pub(crate) fn default_provider() -> CryptoProvider {
15 #[cfg(feature = "__rustls_aws_lc_rs")]
16 return rustls::crypto::aws_lc_rs::default_provider();
17 #[cfg(feature = "__rustls_ring")]
18 return rustls::crypto::ring::default_provider();
19}
20
21#[inline]
22pub(crate) fn alpn() -> Vec<Vec<u8>> {
23 vec![
24 #[cfg(feature = "http3")]
25 b"h3".to_vec(),
26 #[cfg(feature = "http2")]
27 b"h2".to_vec(),
28 #[cfg(feature = "http1")]
29 b"http/1.1".to_vec(),
30 ]
31}
32
33pub struct TlsConnectionBuilder<'a> {
35 identity: Option<&'a DeboaIdentity>,
36 certificate: Option<&'a DeboaCertificate>,
37 skip_server_verification: bool,
38 alpn: Vec<Vec<u8>>,
39 provider: CryptoProvider,
40}
41
42impl Default for TlsConnectionBuilder<'_> {
43 fn default() -> Self {
44 Self {
45 identity: None,
46 certificate: None,
47 skip_server_verification: false,
48 alpn: alpn(),
49 provider: default_provider(),
50 }
51 }
52}
53
54impl<'a> TlsConnectionBuilder<'a> {
55 pub fn identity(mut self, identity: Option<&'a DeboaIdentity>) -> Self {
57 self.identity = identity;
58 self
59 }
60
61 pub fn certificate(mut self, certificate: Option<&'a DeboaCertificate>) -> Self {
63 self.certificate = certificate;
64 self
65 }
66
67 pub fn skip_server_verification(mut self, skip_server_verification: bool) -> Self {
69 self.skip_server_verification = skip_server_verification;
70 self
71 }
72
73 pub fn alpn(mut self, alpn: Vec<Vec<u8>>) -> Self {
75 self.alpn = alpn;
76 self
77 }
78
79 pub fn build_config(self) -> Result<ClientConfig> {
81 let client_config = {
82 if self.skip_server_verification {
83 ClientConfig::builder()
84 .dangerous()
85 .with_custom_certificate_verifier(verify::SkipServerVerification::new(
86 self.provider,
87 ))
88 .with_no_client_auth()
89 } else {
90 #[cfg(feature = "__webpki_rustls_verifier")]
91 let config = {
92 let config = ClientConfig::builder_with_provider(self.provider.into())
93 .with_protocol_versions(rustls::ALL_VERSIONS)
94 .map_err(|e| {
95 DeboaError::Connection(ConnectionError::Tls {
96 message: format!("Failed to set TLS version: {}", e),
97 })
98 })?;
99
100 let mut root_store =
101 rustls::RootCertStore { roots: webpki_roots::TLS_SERVER_ROOTS.to_vec() };
102 let config = if let Some(ca) = self.certificate {
103 let cert = ca
104 .try_into()
105 .map_err(|e| {
106 DeboaError::Connection(ConnectionError::Tls {
107 message: format!("Invalid CA certificate: {}", e),
108 })
109 })?;
110
111 root_store
112 .add(cert)
113 .map_err(|e| {
114 DeboaError::Connection(ConnectionError::Tls {
115 message: format!(
116 "Could not add CA certificate to the store: {}",
117 e
118 ),
119 })
120 })?;
121
122 config.with_root_certificates(root_store)
123 } else {
124 config.with_root_certificates(root_store)
125 };
126
127 config
128 };
129
130 #[cfg(feature = "__platform_rustls_verifier")]
131 let config = {
132 use rustls_platform_verifier::BuilderVerifierExt;
133 rustls::ClientConfig::builder_with_provider(default_provider())
134 .with_protocol_versions(rustls::ALL_VERSIONS)
135 .map_err(|e| {
136 DeboaError::Connection(ConnectionError::Tls {
137 message: format!("Failed to set TLS version: {}", e),
138 })
139 })?
140 .with_platform_verifier()
141 };
142
143 let mut config = if let Some(id) = self.identity {
144 let pair: (CertificateDer<'_>, PrivateKeyDer<'_>) = id
145 .try_into()
146 .map_err(|e| {
147 DeboaError::Connection(ConnectionError::Tls {
148 message: format!("Invalid client identity: {}", e),
149 })
150 })?;
151
152 config
153 .with_client_auth_cert(vec![pair.0], pair.1)
154 .map_err(|e| {
155 DeboaError::Connection(ConnectionError::Tls {
156 message: format!("Failed to set client identity: {}", e),
157 })
158 })?
159 } else {
160 config.with_no_client_auth()
161 };
162
163 config.enable_early_data = true;
164
165 config.alpn_protocols = self.alpn;
166
167 config
168 }
169 };
170
171 Ok(client_config)
172 }
173}
174
175#[cfg(any(feature = "http1", feature = "http2"))]
176pub mod tcp {
178 use compio::net::TcpStream;
179 use compio_tls::{TlsConnector, TlsStream};
180 use deboa::{
181 errors::{ConnectionError, DeboaError},
182 Result,
183 };
184 use rustls::ClientConfig;
185 use std::sync::Arc;
186
187 pub async fn connect(
189 config: ClientConfig,
190 inner_stream: TcpStream,
191 host: &str,
192 ) -> Result<TlsStream<TcpStream>> {
193 let connector = TlsConnector::from(Arc::new(config));
194
195 connector
196 .connect(host, inner_stream)
197 .await
198 .map_err(|e| {
199 DeboaError::Connection(ConnectionError::Tls {
200 message: format!("Could not connect to server: {}", e),
201 })
202 })
203 }
204}
205
206#[cfg(feature = "http3")]
207pub mod udp {
209 use compio_quic::{Connection, Endpoint};
210 use deboa::{
211 errors::{ConnectionError, DeboaError},
212 Result,
213 };
214 use rustls::ClientConfig;
215 use std::{net::SocketAddr, sync::Arc};
216
217 pub async fn connect(
219 config: ClientConfig,
220 endpoint: &mut Endpoint,
221 socket_addr: SocketAddr,
222 host: &str,
223 ) -> Result<Connection> {
224 let quic_config =
225 compio_quic::crypto::rustls::QuicClientConfig::try_from(config).map_err(|e| {
226 DeboaError::Connection(ConnectionError::Tls {
227 message: format!("Could not create QUIC client config: {}", e),
228 })
229 })?;
230
231 let client_config = compio_quic::ClientConfig::new(Arc::new(quic_config));
232
233 let conn = endpoint
234 .connect(socket_addr, host, Some(client_config))
235 .map_err(|e| {
236 DeboaError::Connection(ConnectionError::Udp {
237 message: format!("Could not connect to server: {}", e),
238 })
239 })?;
240
241 let conn = conn
242 .await
243 .map_err(|e| {
244 DeboaError::Connection(ConnectionError::Udp {
245 message: format!("Could not connect to server: {}", e),
246 })
247 })?;
248
249 Ok(conn)
250 }
251}
252
253pub(crate) mod verify {
254 use rustls::{
255 client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
256 crypto::CryptoProvider,
257 pki_types::{CertificateDer, ServerName, UnixTime},
258 };
259 use std::sync::Arc;
260
261 #[derive(Debug)]
262 pub(crate) struct SkipServerVerification(CryptoProvider);
263
264 impl SkipServerVerification {
265 pub(crate) fn new(provider: CryptoProvider) -> Arc<Self> {
266 Arc::new(Self(provider))
267 }
268 }
269
270 impl ServerCertVerifier for SkipServerVerification {
271 fn verify_server_cert(
272 &self,
273 _end_entity: &CertificateDer<'_>,
274 _intermediates: &[CertificateDer<'_>],
275 _server_name: &ServerName<'_>,
276 _ocsp: &[u8],
277 _now: UnixTime,
278 ) -> std::result::Result<ServerCertVerified, rustls::Error> {
279 Ok(ServerCertVerified::assertion())
280 }
281
282 fn verify_tls12_signature(
283 &self,
284 message: &[u8],
285 cert: &CertificateDer<'_>,
286 dss: &rustls::DigitallySignedStruct,
287 ) -> std::result::Result<HandshakeSignatureValid, rustls::Error> {
288 rustls::crypto::verify_tls12_signature(
289 message,
290 cert,
291 dss,
292 &self
293 .0
294 .signature_verification_algorithms,
295 )
296 }
297
298 fn verify_tls13_signature(
299 &self,
300 message: &[u8],
301 cert: &CertificateDer<'_>,
302 dss: &rustls::DigitallySignedStruct,
303 ) -> std::result::Result<HandshakeSignatureValid, rustls::Error> {
304 rustls::crypto::verify_tls13_signature(
305 message,
306 cert,
307 dss,
308 &self
309 .0
310 .signature_verification_algorithms,
311 )
312 }
313
314 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
315 self.0
316 .signature_verification_algorithms
317 .supported_schemes()
318 }
319 }
320}