1
//! Implementation for using Rustls with a runtime.
2

            
3
use crate::traits::{CertifiedConn, TlsConnector, TlsProvider};
4
use crate::StreamOps;
5

            
6
use async_trait::async_trait;
7
use futures::{AsyncRead, AsyncWrite};
8
use futures_rustls::rustls::client::WebPkiServerVerifier;
9
use futures_rustls::rustls::{self, RootCertStore};
10
use rustls::client::danger;
11
use rustls::{CertificateError, Error as TLSError};
12
use rustls_pki_types::{CertificateDer, ServerName};
13
use webpki::EndEntityCert; // this is actually rustls_webpki.
14

            
15
use std::{
16
    io::{self, Error as IoError, Result as IoResult},
17
    sync::Arc,
18
};
19

            
20
/// 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]
33
pub struct RustlsProvider {
34
    /// Inner `ClientConfig` logic used to create connectors.
35
    config: Arc<futures_rustls::rustls::ClientConfig>,
36
}
37

            
38
impl<S> CertifiedConn for futures_rustls::client::TlsStream<S> {
39
4
    fn peer_certificate(&self) -> IoResult<Option<Vec<u8>>> {
40
4
        let (_, session) = self.get_ref();
41
4
        Ok(session
42
4
            .peer_certificates()
43
6
            .and_then(|certs| certs.first().map(|c| Vec::from(c.as_ref()))))
44
4
    }
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

            
59
impl<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

            
69
/// An implementation of [`TlsConnector`] built with `rustls`.
70
pub struct RustlsConnector<S> {
71
    /// The inner connector object.
72
    connector: futures_rustls::TlsConnector,
73
    /// Phantom data to ensure proper variance.
74
    _phantom: std::marker::PhantomData<fn(S) -> S>,
75
}
76

            
77
#[async_trait]
78
impl<S> TlsConnector<S> for RustlsConnector<S>
79
where
80
    S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
81
{
82
    type Conn = futures_rustls::client::TlsStream<S>;
83

            
84
4
    async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
85
4
        let name: ServerName<'_> = sni_hostname
86
4
            .try_into()
87
4
            .map_err(|e| IoError::new(io::ErrorKind::InvalidInput, e))?;
88
4
        self.connector.connect(name.to_owned(), stream).await
89
8
    }
90
}
91

            
92
impl<S> TlsProvider<S> for RustlsProvider
93
where
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
6
    fn tls_connector(&self) -> Self::Connector {
101
6
        let connector = futures_rustls::TlsConnector::from(Arc::clone(&self.config));
102
6
        RustlsConnector {
103
6
            connector,
104
6
            _phantom: std::marker::PhantomData,
105
6
        }
106
6
    }
107

            
108
    fn supports_keying_material_export(&self) -> bool {
109
        true
110
    }
111
}
112

            
113
/// 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.)
116
7258
fn ensure_provider_installed() {
117
7258
    if 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.
121
429
        tracing::warn!(
122
            "Creating a RustlsRuntime, but no CryptoProvider is installed. The application \
123
                        should call CryptoProvider::install_default()"
124
        );
125
429
        let _idempotent_ignore = futures_rustls::rustls::crypto::CryptoProvider::install_default(
126
429
            futures_rustls::rustls::crypto::ring::default_provider(),
127
429
        );
128
6829
    }
129
7258
}
130

            
131
impl RustlsProvider {
132
    /// Construct a new [`RustlsProvider`.]
133
7254
    pub(crate) fn new() -> Self {
134
7254
        ensure_provider_installed();
135
7254

            
136
7254
        // Be afraid: we are overriding the default certificate verification and
137
7254
        // TLS signature checking code! See notes on `Verifier` below for
138
7254
        // details.
139
7254
        //
140
7254
        // Note that the `set_certificate_verifier` function is somewhat
141
7254
        // misnamed: it overrides not only how certificates are verified, but
142
7254
        // also how certificates are used to check the signatures in a TLS
143
7254
        // handshake.
144
7254
        let config = futures_rustls::rustls::client::ClientConfig::builder()
145
7254
            .dangerous()
146
7254
            .with_custom_certificate_verifier(std::sync::Arc::new(Verifier::from_cert_der(
147
7254
                LETSENCRYPT_ROOT,
148
7254
            )))
149
7254
            .with_no_client_auth();
150
7254

            
151
7254
        RustlsProvider {
152
7254
            config: Arc::new(config),
153
7254
        }
154
7254
    }
155
}
156

            
157
impl Default for RustlsProvider {
158
7254
    fn default() -> Self {
159
7254
        Self::new()
160
7254
    }
161
}
162

            
163
/// 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)]
171
struct Verifier(Arc<WebPkiServerVerifier>);
172

            
173
/// 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.
179
const LETSENCRYPT_ROOT: &[u8] = include_bytes!("letsencrypt-isrg-root-x2.der");
180

            
181
impl 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.
187
7256
    fn from_cert_der(cert: &[u8]) -> Self {
188
7256
        let mut root_certs = RootCertStore::empty();
189
7256
        let der = CertificateDer::from_slice(cert);
190
7256
        root_certs
191
7256
            .add(der)
192
7256
            .expect("Unable to add dummy root-certificate for rustls.");
193
7256
        let bld = WebPkiServerVerifier::builder(Arc::new(root_certs));
194
7256
        Self(bld.build().expect("Could not build default verifier!"))
195
7256
    }
196
}
197

            
198
impl danger::ServerCertVerifier for Verifier {
199
4
    fn verify_server_cert(
200
4
        &self,
201
4
        end_entity: &CertificateDer,
202
4
        _roots: &[CertificateDer],
203
4
        _server_name: &ServerName,
204
4
        _ocsp_response: &[u8],
205
4
        _now: rustls_pki_types::UnixTime,
206
4
    ) -> 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.
218
4
        let _cert: EndEntityCert<'_> = end_entity
219
4
            .try_into()
220
4
            .map_err(|_| TLSError::InvalidCertificate(CertificateError::BadEncoding))?;
221

            
222
        // 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.)
230

            
231
4
        Ok(danger::ServerCertVerified::assertion())
232
4
    }
233

            
234
4
    fn verify_tls12_signature(
235
4
        &self,
236
4
        message: &[u8],
237
4
        cert: &CertificateDer,
238
4
        dss: &rustls::DigitallySignedStruct,
239
4
    ) -> Result<danger::HandshakeSignatureValid, TLSError> {
240
4
        self.0.verify_tls12_signature(message, cert, dss)
241
4
    }
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
4
    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
253
4
        self.0.supported_verify_schemes()
254
4
    }
255

            
256
4
    fn root_hint_subjects(&self) -> Option<&[rustls::DistinguishedName]> {
257
4
        // We don't actually want to send any DNs for our root certs,
258
4
        // since they aren't real.
259
4
        None
260
4
    }
261
}
262

            
263
#[cfg(test)]
264
mod 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 @@ -->
278
    use super::*;
279

            
280
    /// 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.
286
    const TOR_CERTIFICATE: &[u8] = include_bytes!("./tor-generated.der");
287

            
288
    /// 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.
292
    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
}