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(
21 docsrs,
22 doc(cfg(all(
23 feature = "native-tls",
24 any(feature = "tokio", feature = "async-std", feature = "smol")
25 )))
26)]
27#[derive(Default, Clone)]
28#[non_exhaustive]
29pub struct NativeTlsProvider {}
30
31impl<S> CertifiedConn for async_native_tls::TlsStream<S>
32where
33 S: AsyncRead + AsyncWrite + Unpin,
34{
35 fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
36 let cert = self.peer_certificate();
37 match cert {
38 Ok(Some(c)) => {
39 let der = c.to_der().map_err(IoError::other)?;
40 Ok(Some(Cow::from(der)))
41 }
42 Ok(None) => Ok(None),
43 Err(e) => Err(IoError::other(e)),
44 }
45 }
46
47 fn export_keying_material(
48 &self,
49 _len: usize,
50 _label: &[u8],
51 _context: Option<&[u8]>,
52 ) -> IoResult<Vec<u8>> {
53 Err(std::io::Error::new(
54 std::io::ErrorKind::Unsupported,
55 tor_error::bad_api_usage!("native-tls does not support exporting keying material"),
56 ))
57 }
58
59 fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
60 Ok(None)
66 }
67}
68
69impl<S: AsyncRead + AsyncWrite + StreamOps + Unpin> StreamOps for async_native_tls::TlsStream<S> {
70 fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
71 self.get_ref().set_tcp_notsent_lowat(notsent_lowat)
72 }
73
74 fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
75 self.get_ref().new_handle()
76 }
77}
78
79pub struct NativeTlsConnector<S> {
81 connector: async_native_tls::TlsConnector,
83 _phantom: std::marker::PhantomData<fn(S) -> S>,
85}
86
87#[async_trait]
88impl<S> TlsConnector<S> for NativeTlsConnector<S>
89where
90 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
91{
92 type Conn = async_native_tls::TlsStream<S>;
93
94 #[instrument(skip_all, level = "trace")]
95 async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
96 let conn = self
97 .connector
98 .connect(sni_hostname, stream)
99 .await
100 .map_err(IoError::other)?;
101 Ok(conn)
102 }
103}
104
105impl<S> TlsProvider<S> for NativeTlsProvider
106where
107 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
108{
109 type Connector = NativeTlsConnector<S>;
110
111 type TlsStream = async_native_tls::TlsStream<S>;
112
113 type Acceptor = UnimplementedTls;
114 type TlsServerStream = UnimplementedTls;
115
116 fn tls_connector(&self) -> Self::Connector {
117 let mut builder = native_tls::TlsConnector::builder();
118 builder
123 .danger_accept_invalid_certs(true)
124 .danger_accept_invalid_hostnames(true);
125
126 builder.disable_built_in_roots(true);
129
130 let connector = builder.into();
131
132 NativeTlsConnector {
133 connector,
134 _phantom: std::marker::PhantomData,
135 }
136 }
137
138 fn tls_acceptor(&self, _settings: TlsAcceptorSettings) -> IoResult<Self::Acceptor> {
139 Err(crate::tls::TlsServerUnsupported {}.into())
142 }
143
144 fn supports_keying_material_export(&self) -> bool {
145 false
146 }
147}