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

            
5
#[cfg(feature = "tls-server")]
6
pub(crate) mod rustls_server;
7

            
8
use crate::StreamOps;
9
use crate::tls::TlsAcceptorSettings;
10
use crate::traits::{CertifiedConn, TlsConnector, TlsProvider};
11

            
12
use async_trait::async_trait;
13
use futures::{AsyncRead, AsyncWrite};
14
use futures_rustls::rustls::{self, crypto::CryptoProvider};
15
use rustls::client::danger;
16
use rustls::crypto::{WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature};
17
use rustls::{CertificateError, Error as TLSError};
18
use rustls_pki_types::{CertificateDer, ServerName};
19
use tracing::instrument;
20
use webpki::EndEntityCert; // this is actually rustls_webpki.
21

            
22
use std::borrow::Cow;
23
use std::{
24
    io::{self, Error as IoError, Result as IoResult},
25
    sync::Arc,
26
};
27

            
28
/// A [`TlsProvider`] that uses `rustls`.
29
///
30
/// It supports wrapping any reasonable stream type that implements `AsyncRead` + `AsyncWrite`.
31
///
32
/// # Cryptographic providers
33
///
34
/// The application is responsible for calling [`CryptoProvider::install_default()`]
35
/// before constructing [`TlsProvider`].  If they do not, we will issue a warning,
36
/// and install a default ([ring]) provider.
37
///
38
/// We choose ring because, of the two builtin providers that ship with rustls,
39
/// it has the best license.
40
/// We _could_ instead use [aws-lc-rs] (for its early MLKEM768 support),
41
/// but it is [still under the old OpenSSL license][aws-lc-license], which is GPL-incompatible.
42
/// (Although Arti isn't under the GPL itself, we are trying to stay compatible with it.)
43
///
44
/// See the [rustls documentation][all-providers] for a list of other rustls
45
/// cryptography providcers.
46
///
47
/// [ring]: https://crates.io/crates/ring
48
/// [aws-lc-rs]: https://github.com/aws/aws-lc-rs
49
/// [aws-lc-license]: https://github.com/aws/aws-lc/issues/2203
50
/// [all-providers]: https://docs.rs/rustls/latest/rustls/#cryptography-providers
51
#[cfg_attr(
52
    docsrs,
53
    doc(cfg(all(
54
        feature = "rustls",
55
        any(feature = "tokio", feature = "async-std", feature = "smol")
56
    )))
57
)]
58
#[derive(Clone)]
59
#[non_exhaustive]
60
pub struct RustlsProvider {
61
    /// Inner `ClientConfig` logic used to create connectors.
62
    config: Arc<futures_rustls::rustls::ClientConfig>,
63
}
64

            
65
impl<S> CertifiedConn for futures_rustls::client::TlsStream<S> {
66
12
    fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
67
12
        let (_, session) = self.get_ref();
68
12
        Ok(session
69
12
            .peer_certificates()
70
18
            .and_then(|certs| certs.first().map(|c| Cow::from(c.as_ref()))))
71
12
    }
72

            
73
    fn export_keying_material(
74
        &self,
75
        len: usize,
76
        label: &[u8],
77
        context: Option<&[u8]>,
78
    ) -> IoResult<Vec<u8>> {
79
        let (_, session) = self.get_ref();
80
        session
81
            .export_keying_material(vec![0_u8; len], label, context)
82
            .map_err(|e| IoError::new(io::ErrorKind::InvalidData, e))
83
    }
84

            
85
    fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
86
        // This is a client stream, so (as we build them currently) we know we didn't present a certificate.
87
        Ok(None)
88
    }
89
}
90

            
91
impl<S: StreamOps> StreamOps for futures_rustls::client::TlsStream<S> {
92
    fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
93
        self.get_ref().0.set_tcp_notsent_lowat(notsent_lowat)
94
    }
95

            
96
    fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
97
        self.get_ref().0.new_handle()
98
    }
99
}
100

            
101
/// An implementation of [`TlsConnector`] built with `rustls`.
102
pub struct RustlsConnector<S> {
103
    /// The inner connector object.
104
    connector: futures_rustls::TlsConnector,
105
    /// Phantom data to ensure proper variance.
106
    _phantom: std::marker::PhantomData<fn(S) -> S>,
107
}
108

            
109
#[async_trait]
110
impl<S> TlsConnector<S> for RustlsConnector<S>
111
where
112
    S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
113
{
114
    type Conn = futures_rustls::client::TlsStream<S>;
115

            
116
    #[instrument(skip_all, level = "trace")]
117
    async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
118
        let name: ServerName<'_> = sni_hostname
119
            .try_into()
120
            .map_err(|e| IoError::new(io::ErrorKind::InvalidInput, e))?;
121
        self.connector.connect(name.to_owned(), stream).await
122
    }
123
}
124

            
125
impl<S> TlsProvider<S> for RustlsProvider
126
where
127
    S: AsyncRead + AsyncWrite + StreamOps + Unpin + Send + 'static,
128
{
129
    type Connector = RustlsConnector<S>;
130

            
131
    type TlsStream = futures_rustls::client::TlsStream<S>;
132

            
133
14
    fn tls_connector(&self) -> Self::Connector {
134
14
        let connector = futures_rustls::TlsConnector::from(Arc::clone(&self.config));
135
14
        RustlsConnector {
136
14
            connector,
137
14
            _phantom: std::marker::PhantomData,
138
14
        }
139
14
    }
140

            
141
    cfg_if::cfg_if! {
142
        if #[cfg(feature = "tls-server")] {
143
            type Acceptor = rustls_server::RustlsAcceptor<S>;
144
            type TlsServerStream = rustls_server::RustlsServerStream<S>;
145
6
            fn tls_acceptor(&self, settings: TlsAcceptorSettings) -> IoResult<Self::Acceptor> {
146
6
                rustls_server::RustlsAcceptor::new(&settings)
147
6
            }
148
        } else {
149
            type Acceptor = crate::tls::UnimplementedTls;
150
            type TlsServerStream = crate::tls::UnimplementedTls;
151
            fn tls_acceptor(&self, _settings: TlsAcceptorSettings) -> IoResult<Self::Acceptor> {
152
                Err(crate::tls::TlsServerUnsupported{}.into())
153
            }
154
        }
155
    }
156

            
157
    fn supports_keying_material_export(&self) -> bool {
158
        true
159
    }
160
}
161

            
162
/// Try to install a default crypto provider if none has been installed, so that Rustls can operate.
163
///
164
/// (Warns if we have to do this: the application should be responsible for choosing a provider.)
165
11745
fn ensure_provider_installed() {
166
11745
    if CryptoProvider::get_default().is_none() {
167
        // If we haven't installed a CryptoProvider at this point, we warn and install
168
        // the `ring` provider.  That isn't great, but the alternative would be to
169
        // panic.  Right now, that would cause many of our tests to fail.
170
506
        tracing::warn!(
171
            "Creating a RustlsRuntime, but no CryptoProvider is installed. The application \
172
                        should call CryptoProvider::install_default()"
173
        );
174
506
        let _idempotent_ignore = CryptoProvider::install_default(
175
506
            futures_rustls::rustls::crypto::ring::default_provider(),
176
        );
177
11239
    }
178
11745
}
179

            
180
impl RustlsProvider {
181
    /// Construct a new [`RustlsProvider`].
182
11743
    pub(crate) fn new() -> Self {
183
11743
        ensure_provider_installed();
184

            
185
        // Be afraid: we are overriding the default certificate verification and
186
        // TLS signature checking code! See notes on `Verifier` below for
187
        // details.
188
        //
189
        // Note that the `set_certificate_verifier` function is somewhat
190
        // misnamed: it overrides not only how certificates are verified, but
191
        // also how certificates are used to check the signatures in a TLS
192
        // handshake.
193
11743
        let mut config = futures_rustls::rustls::client::ClientConfig::builder()
194
11743
            .dangerous()
195
11743
            .with_custom_certificate_verifier(Arc::new(Verifier(
196
11743
                CryptoProvider::get_default()
197
11743
                    .expect("CryptoProvider not installed")
198
11743
                    .signature_verification_algorithms,
199
11743
            )))
200
11743
            .with_no_client_auth();
201

            
202
        // tor-spec:
203
        // > Implementations SHOULD NOT allow TLS session resumption – it can exacerbate some
204
        // > attacks (e.g. the “Triple Handshake” attack from Feb 2013), and it plays havoc with
205
        // > forward secrecy guarantees.
206
11743
        config.resumption = futures_rustls::rustls::client::Resumption::disabled();
207

            
208
11743
        RustlsProvider {
209
11743
            config: Arc::new(config),
210
11743
        }
211
11743
    }
212
}
213

            
214
impl Default for RustlsProvider {
215
11743
    fn default() -> Self {
216
11743
        Self::new()
217
11743
    }
218
}
219

            
220
/// A custom [`rustls::client::danger::ServerCertVerifier`]
221
///
222
/// This verifier is necessary since Tor relays doesn't participate in the web
223
/// browser PKI, and as such their certificates won't check out as valid ones.
224
///
225
/// We enforce that the certificate itself has correctly authenticated the TLS
226
/// connection, but nothing else.
227
#[derive(Clone, Debug)]
228
struct Verifier(pub(crate) WebPkiSupportedAlgorithms);
229

            
230
impl danger::ServerCertVerifier for Verifier {
231
12
    fn verify_server_cert(
232
12
        &self,
233
12
        end_entity: &CertificateDer,
234
12
        _roots: &[CertificateDer],
235
12
        _server_name: &ServerName,
236
12
        _ocsp_response: &[u8],
237
12
        _now: rustls_pki_types::UnixTime,
238
12
    ) -> Result<danger::ServerCertVerified, TLSError> {
239
        // We don't check anything about the certificate at this point other
240
        // than making sure it is well-formed.
241
        //
242
        // When we make a channel, we'll check that it's authenticated by the
243
        // other party's real identity key, inside the Tor handshake.
244
        //
245
        // In theory, we shouldn't have to do even this much: rustls should not
246
        // allow a handshake  without a certificate, and the certificate's
247
        // well-formedness should get checked below in one of the
248
        // verify_*_signature functions.  But this check is cheap, so let's
249
        // leave it in.
250
12
        let _cert: EndEntityCert<'_> = end_entity
251
12
            .try_into()
252
12
            .map_err(|_| TLSError::InvalidCertificate(CertificateError::BadEncoding))?;
253

            
254
        // Note that we don't even check timeliness or key usage: Tor uses the presented
255
        // relay certificate just as a container for the relay's public link
256
        // key.  Actual timeliness checks will happen later, on the certificates
257
        // that authenticate this one, when we process the relay's CERTS cell in
258
        // `tor_proto::channel::handshake`.
259
        //
260
        // (This is what makes it safe for us _not_ to call
261
        // EndEntityCert::verify_for_usage.)
262

            
263
12
        Ok(danger::ServerCertVerified::assertion())
264
12
    }
265

            
266
6
    fn verify_tls12_signature(
267
6
        &self,
268
6
        message: &[u8],
269
6
        cert: &CertificateDer,
270
6
        dss: &rustls::DigitallySignedStruct,
271
6
    ) -> Result<danger::HandshakeSignatureValid, TLSError> {
272
6
        verify_tls12_signature(message, cert, dss, &self.0)
273
6
    }
274

            
275
6
    fn verify_tls13_signature(
276
6
        &self,
277
6
        message: &[u8],
278
6
        cert: &CertificateDer,
279
6
        dss: &rustls::DigitallySignedStruct,
280
6
    ) -> Result<danger::HandshakeSignatureValid, TLSError> {
281
6
        verify_tls13_signature(message, cert, dss, &self.0)
282
6
    }
283

            
284
12
    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
285
12
        self.0.supported_schemes()
286
12
    }
287

            
288
12
    fn root_hint_subjects(&self) -> Option<&[rustls::DistinguishedName]> {
289
        // We don't actually want to send any DNs for our root certs,
290
        // since they aren't real.
291
12
        None
292
12
    }
293
}
294

            
295
#[cfg(test)]
296
mod test {
297
    // @@ begin test lint list maintained by maint/add_warning @@
298
    #![allow(clippy::bool_assert_comparison)]
299
    #![allow(clippy::clone_on_copy)]
300
    #![allow(clippy::dbg_macro)]
301
    #![allow(clippy::mixed_attributes_style)]
302
    #![allow(clippy::print_stderr)]
303
    #![allow(clippy::print_stdout)]
304
    #![allow(clippy::single_char_pattern)]
305
    #![allow(clippy::unwrap_used)]
306
    #![allow(clippy::unchecked_time_subtraction)]
307
    #![allow(clippy::useless_vec)]
308
    #![allow(clippy::needless_pass_by_value)]
309
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
310
    use super::*;
311

            
312
    /// A certificate returned by a C Tor relay implementation.
313
    ///
314
    /// We want to have a test for this, since some older versions of `webpki`
315
    /// rejected C Tor's certificates as unparsable because they did not contain
316
    /// any extensions.  Back then, we had to use `x509_signature`,
317
    /// which now appears unmaintained.
318
    const TOR_CERTIFICATE: &[u8] = include_bytes!("./tor-generated.der");
319

            
320
    #[test]
321
    fn basic_tor_cert() {
322
        ensure_provider_installed();
323
        let der = CertificateDer::from_slice(TOR_CERTIFICATE);
324
        let _cert = EndEntityCert::try_from(&der).unwrap();
325
    }
326
}