tor_rtcompat/impls/
native_tls.rs1use crate::{
4 tls::{TlsAcceptorSettings, UnimplementedTls},
5 traits::{CertifiedConn, StreamOps, TlsConnector, TlsProvider},
6};
7
8use async_trait::async_trait;
9use futures::{AsyncRead, AsyncWrite};
10use native_tls_crate as native_tls;
11use std::{
12 borrow::Cow,
13 io::{Error as IoError, Result as IoResult},
14};
15use tracing::instrument;
16
17#[cfg_attr(
31 docsrs,
32 doc(cfg(all(
33 feature = "native-tls",
34 any(feature = "tokio", feature = "async-std", feature = "smol")
35 )))
36)]
37#[derive(Default, Clone)]
38#[non_exhaustive]
39pub struct NativeTlsProvider {}
40
41impl<S> CertifiedConn for async_native_tls::TlsStream<S>
42where
43 S: AsyncRead + AsyncWrite + Unpin,
44{
45 fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
46 let cert = self.peer_certificate();
47 match cert {
48 Ok(Some(c)) => {
49 let der = c.to_der().map_err(IoError::other)?;
50 Ok(Some(Cow::from(der)))
51 }
52 Ok(None) => Ok(None),
53 Err(e) => Err(IoError::other(e)),
54 }
55 }
56
57 fn export_keying_material(
58 &self,
59 _len: usize,
60 _label: &[u8],
61 _context: Option<&[u8]>,
62 ) -> IoResult<Vec<u8>> {
63 Err(std::io::Error::new(
64 std::io::ErrorKind::Unsupported,
65 tor_error::bad_api_usage!("native-tls does not support exporting keying material"),
66 ))
67 }
68
69 fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
70 Ok(None)
76 }
77}
78
79impl<S: AsyncRead + AsyncWrite + StreamOps + Unpin> StreamOps for async_native_tls::TlsStream<S> {
80 fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
81 self.get_ref().set_tcp_notsent_lowat(notsent_lowat)
82 }
83
84 fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
85 self.get_ref().new_handle()
86 }
87}
88
89pub struct NativeTlsConnector<S> {
91 connector: async_native_tls::TlsConnector,
93 _phantom: std::marker::PhantomData<fn(S) -> S>,
95}
96
97#[async_trait]
98impl<S> TlsConnector<S> for NativeTlsConnector<S>
99where
100 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
101{
102 type Conn = async_native_tls::TlsStream<S>;
103
104 #[instrument(skip_all, level = "trace")]
105 async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
106 let conn = self
107 .connector
108 .connect(sni_hostname, stream)
109 .await
110 .map_err(IoError::other)?;
111 Ok(conn)
112 }
113}
114
115impl<S> TlsProvider<S> for NativeTlsProvider
116where
117 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
118{
119 type Connector = NativeTlsConnector<S>;
120
121 type TlsStream = async_native_tls::TlsStream<S>;
122
123 type Acceptor = UnimplementedTls;
124 type TlsServerStream = UnimplementedTls;
125
126 fn tls_connector(&self) -> Self::Connector {
127 let mut builder = native_tls::TlsConnector::builder();
128 builder
133 .danger_accept_invalid_certs(true)
134 .danger_accept_invalid_hostnames(true);
135
136 builder.disable_built_in_roots(true);
139
140 let connector = builder.into();
144
145 NativeTlsConnector {
146 connector,
147 _phantom: std::marker::PhantomData,
148 }
149 }
150
151 fn tls_acceptor(&self, _settings: TlsAcceptorSettings) -> IoResult<Self::Acceptor> {
152 Err(crate::tls::TlsServerUnsupported {}.into())
155 }
156
157 fn supports_keying_material_export(&self) -> bool {
158 false
159 }
160}