tor_rtcompat/impls/
rustls.rs1use crate::traits::{CertifiedConn, TlsConnector, TlsProvider};
4use crate::StreamOps;
5
6use async_trait::async_trait;
7use futures::{AsyncRead, AsyncWrite};
8use futures_rustls::rustls::client::WebPkiServerVerifier;
9use futures_rustls::rustls::{self, RootCertStore};
10use rustls::client::danger;
11use rustls::{CertificateError, Error as TLSError};
12use rustls_pki_types::{CertificateDer, ServerName};
13use webpki::EndEntityCert; use std::{
16 io::{self, Error as IoError, Result as IoResult},
17 sync::Arc,
18};
19
20#[cfg_attr(
28 docsrs,
29 doc(cfg(all(feature = "rustls", any(feature = "tokio", feature = "async-std"))))
30)]
31#[derive(Clone)]
32#[non_exhaustive]
33pub struct RustlsProvider {
34 config: Arc<futures_rustls::rustls::ClientConfig>,
36}
37
38impl<S> CertifiedConn for futures_rustls::client::TlsStream<S> {
39 fn peer_certificate(&self) -> IoResult<Option<Vec<u8>>> {
40 let (_, session) = self.get_ref();
41 Ok(session
42 .peer_certificates()
43 .and_then(|certs| certs.first().map(|c| Vec::from(c.as_ref()))))
44 }
45
46 fn export_keying_material(
47 &self,
48 len: usize,
49 label: &[u8],
50 context: Option<&[u8]>,
51 ) -> IoResult<Vec<u8>> {
52 let (_, session) = self.get_ref();
53 session
54 .export_keying_material(Vec::with_capacity(len), label, context)
55 .map_err(|e| IoError::new(io::ErrorKind::InvalidData, e))
56 }
57}
58
59impl<S: StreamOps> StreamOps for futures_rustls::client::TlsStream<S> {
60 fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
61 self.get_ref().0.set_tcp_notsent_lowat(notsent_lowat)
62 }
63
64 fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
65 self.get_ref().0.new_handle()
66 }
67}
68
69pub struct RustlsConnector<S> {
71 connector: futures_rustls::TlsConnector,
73 _phantom: std::marker::PhantomData<fn(S) -> S>,
75}
76
77#[async_trait]
78impl<S> TlsConnector<S> for RustlsConnector<S>
79where
80 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
81{
82 type Conn = futures_rustls::client::TlsStream<S>;
83
84 async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
85 let name: ServerName<'_> = sni_hostname
86 .try_into()
87 .map_err(|e| IoError::new(io::ErrorKind::InvalidInput, e))?;
88 self.connector.connect(name.to_owned(), stream).await
89 }
90}
91
92impl<S> TlsProvider<S> for RustlsProvider
93where
94 S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
95{
96 type Connector = RustlsConnector<S>;
97
98 type TlsStream = futures_rustls::client::TlsStream<S>;
99
100 fn tls_connector(&self) -> Self::Connector {
101 let connector = futures_rustls::TlsConnector::from(Arc::clone(&self.config));
102 RustlsConnector {
103 connector,
104 _phantom: std::marker::PhantomData,
105 }
106 }
107
108 fn supports_keying_material_export(&self) -> bool {
109 true
110 }
111}
112
113fn ensure_provider_installed() {
117 if futures_rustls::rustls::crypto::CryptoProvider::get_default().is_none() {
118 tracing::warn!(
122 "Creating a RustlsRuntime, but no CryptoProvider is installed. The application \
123 should call CryptoProvider::install_default()"
124 );
125 let _idempotent_ignore = futures_rustls::rustls::crypto::CryptoProvider::install_default(
126 futures_rustls::rustls::crypto::ring::default_provider(),
127 );
128 }
129}
130
131impl RustlsProvider {
132 pub(crate) fn new() -> Self {
134 ensure_provider_installed();
135
136 let config = futures_rustls::rustls::client::ClientConfig::builder()
145 .dangerous()
146 .with_custom_certificate_verifier(std::sync::Arc::new(Verifier::from_cert_der(
147 LETSENCRYPT_ROOT,
148 )))
149 .with_no_client_auth();
150
151 RustlsProvider {
152 config: Arc::new(config),
153 }
154 }
155}
156
157impl Default for RustlsProvider {
158 fn default() -> Self {
159 Self::new()
160 }
161}
162
163#[derive(Clone, Debug)]
171struct Verifier(Arc<WebPkiServerVerifier>);
172
173const LETSENCRYPT_ROOT: &[u8] = include_bytes!("letsencrypt-isrg-root-x2.der");
180
181impl Verifier {
182 fn from_cert_der(cert: &[u8]) -> Self {
188 let mut root_certs = RootCertStore::empty();
189 let der = CertificateDer::from_slice(cert);
190 root_certs
191 .add(der)
192 .expect("Unable to add dummy root-certificate for rustls.");
193 let bld = WebPkiServerVerifier::builder(Arc::new(root_certs));
194 Self(bld.build().expect("Could not build default verifier!"))
195 }
196}
197
198impl danger::ServerCertVerifier for Verifier {
199 fn verify_server_cert(
200 &self,
201 end_entity: &CertificateDer,
202 _roots: &[CertificateDer],
203 _server_name: &ServerName,
204 _ocsp_response: &[u8],
205 _now: rustls_pki_types::UnixTime,
206 ) -> Result<danger::ServerCertVerified, TLSError> {
207 let _cert: EndEntityCert<'_> = end_entity
219 .try_into()
220 .map_err(|_| TLSError::InvalidCertificate(CertificateError::BadEncoding))?;
221
222 Ok(danger::ServerCertVerified::assertion())
232 }
233
234 fn verify_tls12_signature(
235 &self,
236 message: &[u8],
237 cert: &CertificateDer,
238 dss: &rustls::DigitallySignedStruct,
239 ) -> Result<danger::HandshakeSignatureValid, TLSError> {
240 self.0.verify_tls12_signature(message, cert, dss)
241 }
242
243 fn verify_tls13_signature(
244 &self,
245 message: &[u8],
246 cert: &CertificateDer,
247 dss: &rustls::DigitallySignedStruct,
248 ) -> Result<danger::HandshakeSignatureValid, TLSError> {
249 self.0.verify_tls13_signature(message, cert, dss)
250 }
251
252 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
253 self.0.supported_verify_schemes()
254 }
255
256 fn root_hint_subjects(&self) -> Option<&[rustls::DistinguishedName]> {
257 None
260 }
261}
262
263#[cfg(test)]
264mod test {
265 #![allow(clippy::bool_assert_comparison)]
267 #![allow(clippy::clone_on_copy)]
268 #![allow(clippy::dbg_macro)]
269 #![allow(clippy::mixed_attributes_style)]
270 #![allow(clippy::print_stderr)]
271 #![allow(clippy::print_stdout)]
272 #![allow(clippy::single_char_pattern)]
273 #![allow(clippy::unwrap_used)]
274 #![allow(clippy::unchecked_duration_subtraction)]
275 #![allow(clippy::useless_vec)]
276 #![allow(clippy::needless_pass_by_value)]
277 use super::*;
279
280 const TOR_CERTIFICATE: &[u8] = include_bytes!("./tor-generated.der");
287
288 const EXPIRED_TOR_CERTIFICATE: &[u8] = include_bytes!("./tor-generated-expired.der");
293
294 #[test]
295 fn basic_tor_cert() {
296 ensure_provider_installed();
297 let der = CertificateDer::from_slice(TOR_CERTIFICATE);
298 let _cert = EndEntityCert::try_from(&der).unwrap();
299 }
300
301 #[test]
302 fn verifier_with_expired_root_cert() {
303 ensure_provider_installed();
304 let _verifier = Verifier::from_cert_der(EXPIRED_TOR_CERTIFICATE);
305 }
306}