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