aggligator_wrapper_tls/
lib.rs

1#![warn(missing_docs)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/surban/aggligator/master/.misc/aggligator.png",
5    html_favicon_url = "https://raw.githubusercontent.com/surban/aggligator/master/.misc/aggligator.png",
6    issue_tracker_base_url = "https://github.com/surban/aggligator/issues/"
7)]
8
9//! [Aggligator](aggligator) transport wrapper using TLS
10//!
11//! This provides connection security by wrapping Aggligator links
12//! in TLS.
13
14use async_trait::async_trait;
15use std::{io::Result, sync::Arc};
16use tokio::io::split;
17use tokio_rustls::{TlsAcceptor, TlsConnector};
18
19#[doc(no_inline)]
20pub use rustls::{pki_types::ServerName, ClientConfig, RootCertStore, ServerConfig};
21
22use aggligator::{
23    io::{IoBox, StreamBox},
24    transport::{AcceptingWrapper, ConnectingWrapper},
25};
26
27static NAME: &str = "tls";
28
29/// TLS outgoing connection wrapper.
30///
31/// Only IO-based streams are supported.
32///
33/// Pass this to [`Connector::wrapped`](aggligator::transport::Connector::wrapped) to apply TLS
34/// encryption to each outgoing link.
35///
36/// # Panics
37/// Panics if a packet-based stream is supplied.
38#[derive(Debug)]
39#[must_use = "you must pass this wrapper to the connector"]
40pub struct TlsClient {
41    server_name: ServerName<'static>,
42    client_cfg: Arc<ClientConfig>,
43}
44
45impl TlsClient {
46    /// Creates a new TLS outgoing connection wrapper.
47    ///
48    /// The identity of the server is verified using TLS against `server_name`.
49    /// The outgoing link is encrypted using TLS with the configuration specified
50    /// in `client_cfg`.
51    pub fn new(client_cfg: Arc<ClientConfig>, server_name: ServerName<'static>) -> Self {
52        Self { server_name, client_cfg }
53    }
54}
55
56#[async_trait]
57impl ConnectingWrapper for TlsClient {
58    fn name(&self) -> &str {
59        NAME
60    }
61
62    async fn wrap(&self, stream: StreamBox) -> Result<StreamBox> {
63        let StreamBox::Io(io) = stream else { panic!("TlsClient only supports IO-based streams") };
64        let connector = TlsConnector::from(self.client_cfg.clone());
65        let tls = connector.connect(self.server_name.clone(), io).await?;
66        let (rh, wh) = split(tls);
67        Ok(IoBox::new(rh, wh).into())
68    }
69}
70
71/// TLS incoming connection wrapper.
72///
73/// Only IO-based streams are supported.
74///
75/// # Panics
76/// Panics if a packet-based stream is supplied.
77#[derive(Debug)]
78#[must_use = "you must pass this wrapper to the acceptor"]
79pub struct TlsServer {
80    server_cfg: Arc<ServerConfig>,
81}
82
83impl TlsServer {
84    /// Creates a new TLS incoming connection wrapper.
85    ///
86    /// Incoming links are encrypted using TLS with the configuration specified
87    /// in `server_cfg`.
88    pub fn new(server_cfg: Arc<ServerConfig>) -> Self {
89        Self { server_cfg }
90    }
91}
92
93#[async_trait]
94impl AcceptingWrapper for TlsServer {
95    fn name(&self) -> &str {
96        NAME
97    }
98
99    async fn wrap(&self, stream: StreamBox) -> Result<StreamBox> {
100        let StreamBox::Io(io) = stream else { panic!("TlsServer only supports IO-based streams") };
101        let acceptor = TlsAcceptor::from(self.server_cfg.clone());
102        let tls = acceptor.accept(io).await?;
103        let (rh, wh) = split(tls);
104        Ok(IoBox::new(rh, wh).into())
105    }
106}