tor_rtcompat/impls/
rustls.rs1#[cfg(feature = "tls-server")]
6pub(crate) mod rustls_server;
7
8use crate::StreamOps;
9use crate::tls::TlsAcceptorSettings;
10use crate::traits::{CertifiedConn, TlsConnector, TlsProvider};
11
12use async_trait::async_trait;
13use futures::{AsyncRead, AsyncWrite};
14use futures_rustls::rustls::{self, crypto::CryptoProvider};
15use rustls::client::danger;
16use rustls::crypto::{WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature};
17use rustls::{CertificateError, Error as TLSError};
18use rustls_pki_types::{CertificateDer, ServerName};
19use tracing::instrument;
20use webpki::EndEntityCert; use std::borrow::Cow;
23use std::{
24 io::{self, Error as IoError, Result as IoResult},
25 sync::Arc,
26};
27
28#[cfg_attr(
54 docsrs,
55 doc(cfg(all(
56 feature = "rustls",
57 any(feature = "tokio", feature = "async-std", feature = "smol")
58 )))
59)]
60#[derive(Clone)]
61#[non_exhaustive]
62pub struct RustlsProvider {
63 config: Arc<futures_rustls::rustls::ClientConfig>,
65}
66
67impl<S> CertifiedConn for futures_rustls::client::TlsStream<S> {
68 fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
69 let (_, session) = self.get_ref();
70 Ok(session
71 .peer_certificates()
72 .and_then(|certs| certs.first().map(|c| Cow::from(c.as_ref()))))
73 }
74
75 fn export_keying_material(
76 &self,
77 len: usize,
78 label: &[u8],
79 context: Option<&[u8]>,
80 ) -> IoResult<Vec<u8>> {
81 let (_, session) = self.get_ref();
82 session
83 .export_keying_material(vec![0_u8; len], label, context)
84 .map_err(|e| IoError::new(io::ErrorKind::InvalidData, e))
85 }
86
87 fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
88 Ok(None)
90 }
91}
92
93impl<S: StreamOps> StreamOps for futures_rustls::client::TlsStream<S> {
94 fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
95 self.get_ref().0.set_tcp_notsent_lowat(notsent_lowat)
96 }
97
98 fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
99 self.get_ref().0.new_handle()
100 }
101}
102
103pub struct RustlsConnector<S> {
105 connector: futures_rustls::TlsConnector,
107 _phantom: std::marker::PhantomData<fn(S) -> S>,
109}
110
111#[async_trait]
112impl<S> TlsConnector<S> for RustlsConnector<S>
113where
114 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
115{
116 type Conn = futures_rustls::client::TlsStream<S>;
117
118 #[instrument(skip_all, level = "trace")]
119 async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
120 let name: ServerName<'_> = sni_hostname
121 .try_into()
122 .map_err(|e| IoError::new(io::ErrorKind::InvalidInput, e))?;
123 self.connector.connect(name.to_owned(), stream).await
124 }
125}
126
127impl<S> TlsProvider<S> for RustlsProvider
128where
129 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
130{
131 type Connector = RustlsConnector<S>;
132
133 type TlsStream = futures_rustls::client::TlsStream<S>;
134
135 fn tls_connector(&self) -> Self::Connector {
136 let connector = futures_rustls::TlsConnector::from(Arc::clone(&self.config));
137 RustlsConnector {
138 connector,
139 _phantom: std::marker::PhantomData,
140 }
141 }
142
143 cfg_if::cfg_if! {
144 if #[cfg(feature = "tls-server")] {
145 type Acceptor = rustls_server::RustlsAcceptor<S>;
146 type TlsServerStream = rustls_server::RustlsServerStream<S>;
147 fn tls_acceptor(&self, settings: TlsAcceptorSettings) -> IoResult<Self::Acceptor> {
148 rustls_server::RustlsAcceptor::new(&settings)
149 }
150 } else {
151 type Acceptor = crate::tls::UnimplementedTls;
152 type TlsServerStream = crate::tls::UnimplementedTls;
153 fn tls_acceptor(&self, _settings: TlsAcceptorSettings) -> IoResult<Self::Acceptor> {
154 Err(crate::tls::TlsServerUnsupported{}.into())
155 }
156 }
157 }
158
159 fn supports_keying_material_export(&self) -> bool {
160 true
161 }
162}
163
164#[cfg(any(test, feature = "testing"))]
169fn ensure_testing_provider_installed() {
170 if CryptoProvider::get_default().is_none() {
171 tracing::warn!(
175 "Creating a RustlsRuntime, but no CryptoProvider is installed. The application \
176 should call CryptoProvider::install_default()"
177 );
178 let _idempotent_ignore = CryptoProvider::install_default(
179 futures_rustls::rustls::crypto::aws_lc_rs::default_provider(),
180 );
181 }
182}
183
184impl RustlsProvider {
185 pub(crate) fn new() -> Self {
187 #[cfg(any(test, feature = "testing"))]
188 ensure_testing_provider_installed();
189
190 let mut config = futures_rustls::rustls::client::ClientConfig::builder()
199 .dangerous()
200 .with_custom_certificate_verifier(Arc::new(Verifier(
201 CryptoProvider::get_default()
202 .expect("CryptoProvider not installed")
203 .signature_verification_algorithms,
204 )))
205 .with_no_client_auth();
206
207 config.resumption = futures_rustls::rustls::client::Resumption::disabled();
212
213 RustlsProvider {
214 config: Arc::new(config),
215 }
216 }
217}
218
219impl Default for RustlsProvider {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225#[derive(Clone, Debug)]
233struct Verifier(pub(crate) WebPkiSupportedAlgorithms);
234
235impl danger::ServerCertVerifier for Verifier {
236 fn verify_server_cert(
237 &self,
238 end_entity: &CertificateDer,
239 _roots: &[CertificateDer],
240 _server_name: &ServerName,
241 _ocsp_response: &[u8],
242 _now: rustls_pki_types::UnixTime,
243 ) -> Result<danger::ServerCertVerified, TLSError> {
244 let _cert: EndEntityCert<'_> = end_entity
256 .try_into()
257 .map_err(|_| TLSError::InvalidCertificate(CertificateError::BadEncoding))?;
258
259 Ok(danger::ServerCertVerified::assertion())
269 }
270
271 fn verify_tls12_signature(
272 &self,
273 message: &[u8],
274 cert: &CertificateDer,
275 dss: &rustls::DigitallySignedStruct,
276 ) -> Result<danger::HandshakeSignatureValid, TLSError> {
277 verify_tls12_signature(message, cert, dss, &self.0)
278 }
279
280 fn verify_tls13_signature(
281 &self,
282 message: &[u8],
283 cert: &CertificateDer,
284 dss: &rustls::DigitallySignedStruct,
285 ) -> Result<danger::HandshakeSignatureValid, TLSError> {
286 verify_tls13_signature(message, cert, dss, &self.0)
287 }
288
289 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
290 self.0.supported_schemes()
291 }
292
293 fn root_hint_subjects(&self) -> Option<&[rustls::DistinguishedName]> {
294 None
297 }
298}
299
300#[cfg(test)]
301mod test {
302 #![allow(clippy::bool_assert_comparison)]
304 #![allow(clippy::clone_on_copy)]
305 #![allow(clippy::dbg_macro)]
306 #![allow(clippy::mixed_attributes_style)]
307 #![allow(clippy::print_stderr)]
308 #![allow(clippy::print_stdout)]
309 #![allow(clippy::single_char_pattern)]
310 #![allow(clippy::unwrap_used)]
311 #![allow(clippy::unchecked_time_subtraction)]
312 #![allow(clippy::useless_vec)]
313 #![allow(clippy::needless_pass_by_value)]
314 use super::*;
316
317 const TOR_CERTIFICATE: &[u8] = include_bytes!("./tor-generated.der");
324
325 #[test]
326 fn basic_tor_cert() {
327 ensure_testing_provider_installed();
328 let der = CertificateDer::from_slice(TOR_CERTIFICATE);
329 let _cert = EndEntityCert::try_from(&der).unwrap();
330 }
331}