1pub(super) mod conn;
6
7pub mod compress;
8pub mod keylog;
9pub mod session;
10pub mod trust;
11
12use std::borrow::Cow;
13
14pub use btls::ssl::{ExtensionType, KeyShare};
16use bytes::{BufMut, Bytes, BytesMut};
17use compress::CertificateCompressor;
18
19#[derive(Debug, Clone)]
22pub struct TlsInfo {
23 pub(crate) peer_certificate: Option<Bytes>,
24 pub(crate) peer_certificate_chain: Option<Vec<Bytes>>,
25}
26
27impl TlsInfo {
28 pub fn peer_certificate(&self) -> Option<&[u8]> {
30 self.peer_certificate.as_deref()
31 }
32
33 pub fn peer_certificate_chain(&self) -> Option<impl Iterator<Item = &[u8]>> {
37 self.peer_certificate_chain
38 .as_ref()
39 .map(|v| v.iter().map(|b| b.as_ref()))
40 }
41}
42
43#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
45pub struct TlsVersion(btls::ssl::SslVersion);
46
47impl TlsVersion {
48 pub const TLS_1_0: TlsVersion = TlsVersion(btls::ssl::SslVersion::TLS1);
50
51 pub const TLS_1_1: TlsVersion = TlsVersion(btls::ssl::SslVersion::TLS1_1);
53
54 pub const TLS_1_2: TlsVersion = TlsVersion(btls::ssl::SslVersion::TLS1_2);
56
57 pub const TLS_1_3: TlsVersion = TlsVersion(btls::ssl::SslVersion::TLS1_3);
59}
60
61#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
63pub struct AlpnProtocol(&'static [u8]);
64
65impl AlpnProtocol {
66 pub const HTTP1: AlpnProtocol = AlpnProtocol(b"http/1.1");
68
69 pub const HTTP2: AlpnProtocol = AlpnProtocol(b"h2");
71
72 pub const HTTP3: AlpnProtocol = AlpnProtocol(b"h3");
74
75 #[inline]
76 fn encode(self) -> Bytes {
77 Self::encode_sequence(std::iter::once(&self))
78 }
79
80 fn encode_sequence<'a, I>(items: I) -> Bytes
81 where
82 I: IntoIterator<Item = &'a AlpnProtocol>,
83 {
84 let mut buf = BytesMut::new();
85 for item in items {
86 buf.put_u8(item.0.len() as u8);
87 buf.extend_from_slice(item.0);
88 }
89 buf.freeze()
90 }
91}
92
93impl PartialEq<[u8]> for AlpnProtocol {
94 #[inline]
95 fn eq(&self, other: &[u8]) -> bool {
96 self.0 == other
97 }
98}
99
100#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
102pub struct AlpsProtocol(&'static [u8]);
103
104impl AlpsProtocol {
105 pub const HTTP1: AlpsProtocol = AlpsProtocol(b"http/1.1");
107
108 pub const HTTP2: AlpsProtocol = AlpsProtocol(b"h2");
110
111 pub const HTTP3: AlpsProtocol = AlpsProtocol(b"h3");
113}
114
115impl PartialEq<[u8]> for AlpsProtocol {
116 #[inline]
117 fn eq(&self, other: &[u8]) -> bool {
118 self.0 == other
119 }
120}
121
122#[must_use]
124#[derive(Debug, Clone)]
125pub struct TlsOptionsBuilder {
126 config: TlsOptions,
127}
128
129#[non_exhaustive]
140#[derive(Debug, Clone)]
141pub struct TlsOptions {
142 pub alpn_protocols: Option<Cow<'static, [AlpnProtocol]>>,
149
150 pub alps_protocols: Option<Cow<'static, [AlpsProtocol]>>,
157
158 pub alps_use_new_codepoint: bool,
164
165 pub session_ticket: bool,
171
172 pub min_tls_version: Option<TlsVersion>,
176
177 pub max_tls_version: Option<TlsVersion>,
181
182 pub pre_shared_key: bool,
188
189 pub enable_ech_grease: bool,
196
197 pub permute_extensions: Option<bool>,
201
202 pub grease_enabled: Option<bool>,
207
208 pub enable_ocsp_stapling: bool,
212
213 pub enable_signed_cert_timestamps: bool,
217
218 pub record_size_limit: Option<u16>,
222
223 pub psk_skip_session_ticket: bool,
227
228 pub key_shares: Option<Cow<'static, [KeyShare]>>,
232
233 pub psk_dhe_ke: bool,
237
238 pub renegotiation: bool,
242
243 pub delegated_credentials: Option<Cow<'static, str>>,
250
251 pub curves_list: Option<Cow<'static, str>>,
255
256 pub sigalgs_list: Option<Cow<'static, str>>,
260
261 pub cipher_list: Option<Cow<'static, str>>,
267
268 pub preserve_tls13_cipher_list: Option<bool>,
272
273 pub certificate_compressors: Option<Cow<'static, [&'static dyn CertificateCompressor]>>,
277
278 pub extension_permutation: Option<Cow<'static, [ExtensionType]>>,
282
283 pub aes_hw_override: Option<bool>,
287
288 pub random_aes_hw_override: bool,
292}
293
294impl TlsOptionsBuilder {
295 #[inline]
297 pub fn alpn_protocols<I>(mut self, alpn: I) -> Self
298 where
299 I: IntoIterator<Item = AlpnProtocol>,
300 {
301 self.config.alpn_protocols = Some(Cow::Owned(alpn.into_iter().collect()));
302 self
303 }
304
305 #[inline]
307 pub fn alps_protocols<I>(mut self, alps: I) -> Self
308 where
309 I: IntoIterator<Item = AlpsProtocol>,
310 {
311 self.config.alps_protocols = Some(Cow::Owned(alps.into_iter().collect()));
312 self
313 }
314
315 #[inline]
317 pub fn alps_use_new_codepoint(mut self, enabled: bool) -> Self {
318 self.config.alps_use_new_codepoint = enabled;
319 self
320 }
321 #[inline]
323 pub fn session_ticket(mut self, enabled: bool) -> Self {
324 self.config.session_ticket = enabled;
325 self
326 }
327
328 #[inline]
330 pub fn min_tls_version<T>(mut self, version: T) -> Self
331 where
332 T: Into<Option<TlsVersion>>,
333 {
334 self.config.min_tls_version = version.into();
335 self
336 }
337
338 #[inline]
340 pub fn max_tls_version<T>(mut self, version: T) -> Self
341 where
342 T: Into<Option<TlsVersion>>,
343 {
344 self.config.max_tls_version = version.into();
345 self
346 }
347
348 #[inline]
350 pub fn pre_shared_key(mut self, enabled: bool) -> Self {
351 self.config.pre_shared_key = enabled;
352 self
353 }
354
355 #[inline]
357 pub fn enable_ech_grease(mut self, enabled: bool) -> Self {
358 self.config.enable_ech_grease = enabled;
359 self
360 }
361
362 #[inline]
364 pub fn permute_extensions<T>(mut self, permute: T) -> Self
365 where
366 T: Into<Option<bool>>,
367 {
368 self.config.permute_extensions = permute.into();
369 self
370 }
371
372 #[inline]
374 pub fn grease_enabled<T>(mut self, enabled: T) -> Self
375 where
376 T: Into<Option<bool>>,
377 {
378 self.config.grease_enabled = enabled.into();
379 self
380 }
381
382 #[inline]
384 pub fn enable_ocsp_stapling(mut self, enabled: bool) -> Self {
385 self.config.enable_ocsp_stapling = enabled;
386 self
387 }
388
389 #[inline]
391 pub fn enable_signed_cert_timestamps(mut self, enabled: bool) -> Self {
392 self.config.enable_signed_cert_timestamps = enabled;
393 self
394 }
395
396 #[inline]
398 pub fn record_size_limit<U: Into<Option<u16>>>(mut self, limit: U) -> Self {
399 self.config.record_size_limit = limit.into();
400 self
401 }
402
403 #[inline]
405 pub fn psk_skip_session_ticket(mut self, skip: bool) -> Self {
406 self.config.psk_skip_session_ticket = skip;
407 self
408 }
409
410 #[inline]
412 pub fn psk_dhe_ke(mut self, enabled: bool) -> Self {
413 self.config.psk_dhe_ke = enabled;
414 self
415 }
416
417 #[inline]
419 pub fn renegotiation(mut self, enabled: bool) -> Self {
420 self.config.renegotiation = enabled;
421 self
422 }
423
424 #[inline]
426 pub fn delegated_credentials<T>(mut self, creds: T) -> Self
427 where
428 T: Into<Cow<'static, str>>,
429 {
430 self.config.delegated_credentials = Some(creds.into());
431 self
432 }
433
434 #[inline]
436 pub fn key_shares<T>(mut self, key_shares: T) -> Self
437 where
438 T: Into<Cow<'static, [KeyShare]>>,
439 {
440 self.config.key_shares = Some(key_shares.into());
441 self
442 }
443
444 #[inline]
446 pub fn curves_list<T>(mut self, curves: T) -> Self
447 where
448 T: Into<Cow<'static, str>>,
449 {
450 self.config.curves_list = Some(curves.into());
451 self
452 }
453
454 #[inline]
456 pub fn cipher_list<T>(mut self, ciphers: T) -> Self
457 where
458 T: Into<Cow<'static, str>>,
459 {
460 self.config.cipher_list = Some(ciphers.into());
461 self
462 }
463
464 #[inline]
466 pub fn sigalgs_list<T>(mut self, sigalgs: T) -> Self
467 where
468 T: Into<Cow<'static, str>>,
469 {
470 self.config.sigalgs_list = Some(sigalgs.into());
471 self
472 }
473
474 #[inline]
476 pub fn certificate_compressors<T>(mut self, algs: T) -> Self
477 where
478 T: Into<Cow<'static, [&'static dyn CertificateCompressor]>>,
479 {
480 self.config.certificate_compressors = Some(algs.into());
481 self
482 }
483
484 #[inline]
486 pub fn extension_permutation<T>(mut self, permutation: T) -> Self
487 where
488 T: Into<Cow<'static, [ExtensionType]>>,
489 {
490 self.config.extension_permutation = Some(permutation.into());
491 self
492 }
493
494 #[inline]
496 pub fn aes_hw_override<T>(mut self, enabled: T) -> Self
497 where
498 T: Into<Option<bool>>,
499 {
500 self.config.aes_hw_override = enabled.into();
501 self
502 }
503
504 #[inline]
506 pub fn random_aes_hw_override(mut self, enabled: bool) -> Self {
507 self.config.random_aes_hw_override = enabled;
508 self
509 }
510
511 #[inline]
524 pub fn preserve_tls13_cipher_list<T>(mut self, enabled: T) -> Self
525 where
526 T: Into<Option<bool>>,
527 {
528 self.config.preserve_tls13_cipher_list = enabled.into();
529 self
530 }
531
532 #[inline]
534 pub fn build(self) -> TlsOptions {
535 self.config
536 }
537}
538
539impl TlsOptions {
540 pub fn builder() -> TlsOptionsBuilder {
542 TlsOptionsBuilder {
543 config: TlsOptions::default(),
544 }
545 }
546}
547
548impl Default for TlsOptions {
549 fn default() -> Self {
550 TlsOptions {
551 alpn_protocols: Some(Cow::Borrowed(&[AlpnProtocol::HTTP2, AlpnProtocol::HTTP1])),
552 alps_protocols: None,
553 alps_use_new_codepoint: false,
554 session_ticket: true,
555 min_tls_version: None,
556 max_tls_version: None,
557 pre_shared_key: false,
558 enable_ech_grease: false,
559 permute_extensions: None,
560 grease_enabled: None,
561 enable_ocsp_stapling: false,
562 enable_signed_cert_timestamps: false,
563 record_size_limit: None,
564 psk_skip_session_ticket: false,
565 key_shares: None,
566 psk_dhe_ke: true,
567 renegotiation: true,
568 delegated_credentials: None,
569 curves_list: None,
570 cipher_list: None,
571 sigalgs_list: None,
572 certificate_compressors: None,
573 extension_permutation: None,
574 aes_hw_override: None,
575 preserve_tls13_cipher_list: None,
576 random_aes_hw_override: false,
577 }
578 }
579}
580
581#[cfg(test)]
582mod tests {
583 use super::*;
584
585 #[test]
586 fn alpn_protocol_encode() {
587 let alpn = AlpnProtocol::encode_sequence(&[AlpnProtocol::HTTP1, AlpnProtocol::HTTP2]);
588 assert_eq!(alpn, Bytes::from_static(b"\x08http/1.1\x02h2"));
589
590 let alpn = AlpnProtocol::encode_sequence(&[AlpnProtocol::HTTP3]);
591 assert_eq!(alpn, Bytes::from_static(b"\x02h3"));
592
593 let alpn = AlpnProtocol::encode_sequence(&[AlpnProtocol::HTTP1, AlpnProtocol::HTTP3]);
594 assert_eq!(alpn, Bytes::from_static(b"\x08http/1.1\x02h3"));
595
596 let alpn = AlpnProtocol::encode_sequence(&[AlpnProtocol::HTTP2, AlpnProtocol::HTTP3]);
597 assert_eq!(alpn, Bytes::from_static(b"\x02h2\x02h3"));
598
599 let alpn = AlpnProtocol::encode_sequence(&[
600 AlpnProtocol::HTTP1,
601 AlpnProtocol::HTTP2,
602 AlpnProtocol::HTTP3,
603 ]);
604 assert_eq!(alpn, Bytes::from_static(b"\x08http/1.1\x02h2\x02h3"));
605 }
606
607 #[test]
608 fn alpn_protocol_encode_single() {
609 let alpn = AlpnProtocol::HTTP1.encode();
610 assert_eq!(alpn, b"\x08http/1.1".as_ref());
611
612 let alpn = AlpnProtocol::HTTP2.encode();
613 assert_eq!(alpn, b"\x02h2".as_ref());
614
615 let alpn = AlpnProtocol::HTTP3.encode();
616 assert_eq!(alpn, b"\x02h3".as_ref());
617 }
618}