1//! Implementation for using Rustls with a runtime.
23use crate::traits::{CertifiedConn, TlsConnector, TlsProvider};
4use crate::StreamOps;
56use 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; // this is actually rustls_webpki.
1415use std::{
16 io::{self, Error as IoError, Resultas IoResult},
17 sync::Arc,
18};
1920/// A [`TlsProvider`] that uses `rustls`.
21///
22/// It supports wrapping any reasonable stream type that implements `AsyncRead` + `AsyncWrite`.
23///
24/// The application is responsible for calling `CryptoProvider::install_default_provider()`
25/// before constructing one of these providers. If they do not, we will issue a warning,
26/// and install a default (ring) provider.
27#[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/// Inner `ClientConfig` logic used to create connectors.
35config: Arc<futures_rustls::rustls::ClientConfig>,
36}
3738impl<S> CertifiedConn for futures_rustls::client::TlsStream<S> {
39fn peer_certificate(&self) -> IoResult<Option<Vec<u8>>> {
40let (_, session) = self.get_ref();
41Ok(session
42 .peer_certificates()
43 .and_then(|certs| certs.first().map(|c| Vec::from(c.as_ref()))))
44 }
4546fn export_keying_material(
47&self,
48 len: usize,
49 label: &[u8],
50 context: Option<&[u8]>,
51 ) -> IoResult<Vec<u8>> {
52let (_, 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}
5859impl<S: StreamOps> StreamOps for futures_rustls::client::TlsStream<S> {
60fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
61self.get_ref().0.set_tcp_notsent_lowat(notsent_lowat)
62 }
6364fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
65self.get_ref().0.new_handle()
66 }
67}
6869/// An implementation of [`TlsConnector`] built with `rustls`.
70pub struct RustlsConnector<S> {
71/// The inner connector object.
72connector: futures_rustls::TlsConnector,
73/// Phantom data to ensure proper variance.
74_phantom: std::marker::PhantomData<fn(S) -> S>,
75}
7677#[async_trait]
78impl<S> TlsConnector<S> for RustlsConnector<S>
79where
80S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
81{
82type Conn = futures_rustls::client::TlsStream<S>;
8384async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
85let name: ServerName<'_> = sni_hostname
86 .try_into()
87 .map_err(|e| IoError::new(io::ErrorKind::InvalidInput, e))?;
88self.connector.connect(name.to_owned(), stream).await
89}
90}
9192impl<S> TlsProvider<S> for RustlsProvider
93where
94S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
95{
96type Connector = RustlsConnector<S>;
9798type TlsStream = futures_rustls::client::TlsStream<S>;
99100fn tls_connector(&self) -> Self::Connector {
101let connector = futures_rustls::TlsConnector::from(Arc::clone(&self.config));
102 RustlsConnector {
103 connector,
104 _phantom: std::marker::PhantomData,
105 }
106 }
107108fn supports_keying_material_export(&self) -> bool {
109true
110}
111}
112113/// Try to install a default crypto provider if none has been installed, so that Rustls can operate.
114///
115/// (Warns if we have to do this: the application should be responsible for choosing a provider.)
116fn ensure_provider_installed() {
117if futures_rustls::rustls::crypto::CryptoProvider::get_default().is_none() {
118// If we haven't installed a CryptoProvider at this point, we warn and install
119 // the `ring` provider. That isn't great, but the alternative would be to
120 // panic. Right now, that would cause many of our tests to fail.
121tracing::warn!(
122"Creating a RustlsRuntime, but no CryptoProvider is installed. The application \
123 should call CryptoProvider::install_default()"
124);
125let _idempotent_ignore = futures_rustls::rustls::crypto::CryptoProvider::install_default(
126 futures_rustls::rustls::crypto::ring::default_provider(),
127 );
128 }
129}
130131impl RustlsProvider {
132/// Construct a new [`RustlsProvider`.]
133pub(crate) fn new() -> Self {
134 ensure_provider_installed();
135136// Be afraid: we are overriding the default certificate verification and
137 // TLS signature checking code! See notes on `Verifier` below for
138 // details.
139 //
140 // Note that the `set_certificate_verifier` function is somewhat
141 // misnamed: it overrides not only how certificates are verified, but
142 // also how certificates are used to check the signatures in a TLS
143 // handshake.
144let 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();
150151 RustlsProvider {
152 config: Arc::new(config),
153 }
154 }
155}
156157impl Default for RustlsProvider {
158fn default() -> Self {
159Self::new()
160 }
161}
162163/// A [`rustls::client::danger::ServerCertVerifier`] based on the Rustls's [`WebPkiServerVerifier`].
164///
165/// This verifier is necessary since Tor relays doesn't participate in the web
166/// browser PKI, and as such their certificates won't check out as valid ones.
167///
168/// We enforce that the certificate itself has correctly authenticated the TLS
169/// connection, but nothing else.
170#[derive(Clone, Debug)]
171struct Verifier(Arc<WebPkiServerVerifier>);
172173/// Root certificate for Let's Encrypt, downloaded 27 February 2025.
174/// We don't actually use this certificate for anything here!
175/// We only have it here because the WebPkiServerVerifier
176/// requires that the RootCertStore is nonempty.
177///
178/// The presence of this certificate should be considered a kludge.
179const LETSENCRYPT_ROOT: &[u8] = include_bytes!("letsencrypt-isrg-root-x2.der");
180181impl Verifier {
182/// Construct a Verifier from a dummy root certificate, which will not actually be used.
183 ///
184 /// # Panics
185 ///
186 /// Panics if the certificate is not parseable.
187fn from_cert_der(cert: &[u8]) -> Self {
188let mut root_certs = RootCertStore::empty();
189let der = CertificateDer::from_slice(cert);
190 root_certs
191 .add(der)
192 .expect("Unable to add dummy root-certificate for rustls.");
193let bld = WebPkiServerVerifier::builder(Arc::new(root_certs));
194Self(bld.build().expect("Could not build default verifier!"))
195 }
196}
197198impl danger::ServerCertVerifier for Verifier {
199fn 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// We don't check anything about the certificate at this point other
208 // than making sure it is well-formed.
209 //
210 // When we make a channel, we'll check that it's authenticated by the
211 // other party's real identity key, inside the Tor handshake.
212 //
213 // In theory, we shouldn't have to do even this much: rustls should not
214 // allow a handshake without a certificate, and the certificate's
215 // well-formedness should get checked below in one of the
216 // verify_*_signature functions. But this check is cheap, so let's
217 // leave it in.
218let _cert: EndEntityCert<'_> = end_entity
219 .try_into()
220 .map_err(|_| TLSError::InvalidCertificate(CertificateError::BadEncoding))?;
221222// Note that we don't even check timeliness or key usage: Tor uses the presented
223 // relay certificate just as a container for the relay's public link
224 // key. Actual timeliness checks will happen later, on the certificates
225 // that authenticate this one, when we process the relay's CERTS cell in
226 // `tor_proto::channel::handshake`.
227 //
228 // (This is what makes it safe for us _not_ to call
229 // EndEntityCert::verify_for_usage.)
230231Ok(danger::ServerCertVerified::assertion())
232 }
233234fn verify_tls12_signature(
235&self,
236 message: &[u8],
237 cert: &CertificateDer,
238 dss: &rustls::DigitallySignedStruct,
239 ) -> Result<danger::HandshakeSignatureValid, TLSError> {
240self.0.verify_tls12_signature(message, cert, dss)
241 }
242243fn verify_tls13_signature(
244&self,
245 message: &[u8],
246 cert: &CertificateDer,
247 dss: &rustls::DigitallySignedStruct,
248 ) -> Result<danger::HandshakeSignatureValid, TLSError> {
249self.0.verify_tls13_signature(message, cert, dss)
250 }
251252fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
253self.0.supported_verify_schemes()
254 }
255256fn root_hint_subjects(&self) -> Option<&[rustls::DistinguishedName]> {
257// We don't actually want to send any DNs for our root certs,
258 // since they aren't real.
259None
260}
261}
262263#[cfg(test)]
264mod test {
265// @@ begin test lint list maintained by maint/add_warning @@
266#![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//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
278use super::*;
279280/// A certificate returned by a C Tor relay implementation.
281 ///
282 /// We want to have a test for this, since some older versions of `webpki`
283 /// rejected C Tor's certificates as unparsable because they did not contain
284 /// any extensions. Back then, we had to use `x509_signature`,
285 /// which now appears unmaintained.
286const TOR_CERTIFICATE: &[u8] = include_bytes!("./tor-generated.der");
287288/// An expired certificate generated using C tor.
289 /// We use this to make sure that we can build a verifier using an expired root cert;
290 /// if we can't, then our verifier code above will stop working when its baked-in
291 /// (unused) letsencrypt certificate expires in 2035.
292const EXPIRED_TOR_CERTIFICATE: &[u8] = include_bytes!("./tor-generated-expired.der");
293294#[test]
295fn basic_tor_cert() {
296 ensure_provider_installed();
297let der = CertificateDer::from_slice(TOR_CERTIFICATE);
298let _cert = EndEntityCert::try_from(&der).unwrap();
299 }
300301#[test]
302fn verifier_with_expired_root_cert() {
303 ensure_provider_installed();
304let _verifier = Verifier::from_cert_der(EXPIRED_TOR_CERTIFICATE);
305 }
306}