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

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

            
5
use async_rustls::webpki::{DNSNameRef, Error as WebpkiError};
6
use async_trait::async_trait;
7
use futures::{AsyncRead, AsyncWrite};
8
use rustls::{Session, TLSError};
9
use rustls_crate as rustls;
10
use std::{
11
    io::{self, Error as IoError, Result as IoResult},
12
    sync::Arc,
13
};
14

            
15
/// A [`TlsProvider`] that uses `rustls`.
16
///
17
/// It supports wrapping any reasonable stream type that implements `AsyncRead` + `AsyncWrite`.
18
#[non_exhaustive]
19
pub struct RustlsProvider {
20
    /// Inner `ClientConfig` logic used to create connectors.
21
    config: Arc<async_rustls::rustls::ClientConfig>,
22
}
23

            
24
impl<S> CertifiedConn for async_rustls::client::TlsStream<S> {
25
2
    fn peer_certificate(&self) -> IoResult<Option<Vec<u8>>> {
26
2
        let (_, session) = self.get_ref();
27
2
        Ok(session
28
2
            .get_peer_certificates()
29
2
            .and_then(|certs| certs.get(0).map(|c| Vec::from(c.as_ref()))))
30
2
    }
31
}
32

            
33
/// An implementation of [`TlsConnector`] built with `rustls`.
34
pub struct RustlsConnector<S> {
35
    /// The inner connector object.
36
    connector: async_rustls::TlsConnector,
37
    /// Phantom data to ensure proper variance.
38
    _phantom: std::marker::PhantomData<fn(S) -> S>,
39
}
40

            
41
#[async_trait]
42
impl<S> TlsConnector<S> for RustlsConnector<S>
43
where
44
    S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
45
{
46
    type Conn = async_rustls::client::TlsStream<S>;
47

            
48
2
    async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
49
2
        let name = get_dns_name(sni_hostname)?;
50
4
        self.connector.connect(name, stream).await
51
4
    }
52
}
53

            
54
impl<S> TlsProvider<S> for RustlsProvider
55
where
56
    S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
57
{
58
    type Connector = RustlsConnector<S>;
59

            
60
    type TlsStream = async_rustls::client::TlsStream<S>;
61

            
62
10
    fn tls_connector(&self) -> Self::Connector {
63
10
        let connector = async_rustls::TlsConnector::from(Arc::clone(&self.config));
64
10
        RustlsConnector {
65
10
            connector,
66
10
            _phantom: std::marker::PhantomData,
67
10
        }
68
10
    }
69
}
70

            
71
impl RustlsProvider {
72
    /// Construct a new [`RustlsProvider`.]
73
1682
    pub(crate) fn new() -> Self {
74
1682
        let mut config = async_rustls::rustls::ClientConfig::new();
75
1682

            
76
1682
        // Be afraid: we are overriding the default certificate verification and
77
1682
        // TLS signature checking code! See notes on `Verifier` below for
78
1682
        // details.
79
1682
        //
80
1682
        // Note that the `set_certificate_verifier` function is somewhat
81
1682
        // misnamed: it overrides not only how certificates are verified, but
82
1682
        // also how certificates are used to check the signatures in a TLS
83
1682
        // handshake.
84
1682
        config
85
1682
            .dangerous()
86
1682
            .set_certificate_verifier(std::sync::Arc::new(Verifier {}));
87
1682

            
88
1682
        RustlsProvider {
89
1682
            config: Arc::new(config),
90
1682
        }
91
1682
    }
92
}
93

            
94
impl Default for RustlsProvider {
95
1682
    fn default() -> Self {
96
1682
        Self::new()
97
1682
    }
98
}
99

            
100
/// A [`rustls::ServerCertVerifier`] based on the [`x509_signature`] crate.
101
///
102
/// This verifier is necessary since Tor relays doesn't participate in the web
103
/// browser PKI, and as such their certificates won't check out as valid ones.
104
///
105
/// What's more, the `webpki` crate rejects most of Tor's certificates as
106
/// unparsable because they do not contain any extensions: That means we need to
107
/// replace the TLS-handshake signature checking functions too, since otherwise
108
/// `rustls` would  think all the certificates were invalid.
109
///
110
/// Fortunately, the p2p people have provided `x509_signature` for this
111
/// purpose.
112
#[derive(Clone, Debug)]
113
struct Verifier {}
114

            
115
impl rustls::ServerCertVerifier for Verifier {
116
2
    fn verify_server_cert(
117
2
        &self,
118
2
        _roots: &rustls::RootCertStore,
119
2
        presented_certs: &[rustls::Certificate],
120
2
        _dns_name: async_rustls::webpki::DNSNameRef,
121
2
        _ocsp_response: &[u8],
122
2
    ) -> Result<rustls::ServerCertVerified, TLSError> {
123
        // We don't check anything about the certificate at this point other
124
        // than making sure it is well-formed.
125
        //
126
        // When we make a channel, we'll check that it's authenticated by the
127
        // other party's real identity key, inside the Tor handshake.
128
        //
129
        // In theory, we shouldn't have to do even this much: rustls should not
130
        // allow a handshake  without a certificate, and the certificate's
131
        // well-formedness should get checked below in one of the
132
        // verify_*_signature functions.  But this check is cheap, so let's
133
        // leave it in.
134
2
        let cert0 = presented_certs
135
2
            .get(0)
136
2
            .ok_or(TLSError::NoCertificatesPresented)?;
137
2
        let _cert = get_cert(cert0)?;
138

            
139
        // Note that we don't even check timeliness: Tor uses the presented
140
        // relay certificate just as a container for the relay's public link
141
        // key.  Actual timeliness checks will happen later, on the certificates
142
        // that authenticate this one, when we process the relay's CERTS cell in
143
        // `tor_proto::channel::handshake`.
144

            
145
2
        Ok(rustls::ServerCertVerified::assertion())
146
2
    }
147

            
148
2
    fn verify_tls12_signature(
149
2
        &self,
150
2
        message: &[u8],
151
2
        cert: &rustls::Certificate,
152
2
        dss: &rustls::internal::msgs::handshake::DigitallySignedStruct,
153
2
    ) -> Result<rustls::HandshakeSignatureValid, rustls::TLSError> {
154
2
        let cert = get_cert(cert)?;
155
2
        let scheme = convert_scheme(dss.scheme)?;
156
2
        let signature = dss.sig.0.as_ref();
157
2

            
158
2
        // NOTE:
159
2
        //
160
2
        // We call `check_signature` here rather than `check_tls12_signature`.
161
2
        // That means that we're allowing the other side to use signature
162
2
        // algorithms that aren't actually supported by TLS 1.2.
163
2
        //
164
2
        // It turns out, apparently, unless my experiments are wrong,  that
165
2
        // OpenSSL will happily use PSS with TLS 1.2.  At least, it seems to do
166
2
        // so when invoked via native_tls in the test code for this crate.
167
2
        cert.check_signature(scheme, message, signature)
168
2
            .map(|_| rustls::HandshakeSignatureValid::assertion())
169
2
            .map_err(|_| TLSError::WebPKIError(WebpkiError::InvalidSignatureForPublicKey))
170
2
    }
171

            
172
    fn verify_tls13_signature(
173
        &self,
174
        message: &[u8],
175
        cert: &rustls::Certificate,
176
        dss: &rustls::internal::msgs::handshake::DigitallySignedStruct,
177
    ) -> Result<rustls::HandshakeSignatureValid, rustls::TLSError> {
178
        let cert = get_cert(cert)?;
179
        let scheme = convert_scheme(dss.scheme)?;
180
        let signature = dss.sig.0.as_ref();
181

            
182
        cert.check_tls13_signature(scheme, message, signature)
183
            .map(|_| rustls::HandshakeSignatureValid::assertion())
184
            .map_err(|_| TLSError::WebPKIError(WebpkiError::InvalidSignatureForPublicKey))
185
    }
186
}
187

            
188
/// Convert a string into a `DnsNameRef`, if possible.
189
2
fn get_dns_name(s: &str) -> IoResult<DNSNameRef> {
190
2
    DNSNameRef::try_from_ascii_str(s).map_err(|e| IoError::new(io::ErrorKind::InvalidInput, e))
191
2
}
192

            
193
/// Parse a `rustls::Certificate` as an `x509_signature::X509Certificate`, if possible.
194
4
fn get_cert(c: &rustls::Certificate) -> Result<x509_signature::X509Certificate, TLSError> {
195
4
    x509_signature::parse_certificate(c.as_ref())
196
4
        .map_err(|_| TLSError::WebPKIError(async_rustls::webpki::Error::BadDER))
197
4
}
198

            
199
/// Convert from the signature scheme type used in `rustls` to the one used in
200
/// `x509_signature`.
201
///
202
/// (We can't just use the x509_signature crate's "rustls" feature to have it
203
/// use the same enum from `rustls`, because it seems to be on a different
204
/// version from the rustls we want.)
205
14
fn convert_scheme(
206
14
    scheme: rustls::internal::msgs::enums::SignatureScheme,
207
14
) -> Result<x509_signature::SignatureScheme, TLSError> {
208
14
    use rustls::internal::msgs::enums::SignatureScheme as R;
209
14
    use x509_signature::SignatureScheme as X;
210
14

            
211
14
    // Yes, we do allow PKCS1 here.  That's fine in practice when PKCS1 is only
212
14
    // used (as in TLS 1.2) for signatures; the attacks against correctly
213
14
    // implemented PKCS1 make sense only when it's used for encryption.
214
14
    Ok(match scheme {
215
1
        R::RSA_PKCS1_SHA256 => X::RSA_PKCS1_SHA256,
216
1
        R::ECDSA_NISTP256_SHA256 => X::ECDSA_NISTP256_SHA256,
217
1
        R::RSA_PKCS1_SHA384 => X::RSA_PKCS1_SHA384,
218
1
        R::ECDSA_NISTP384_SHA384 => X::ECDSA_NISTP384_SHA384,
219
1
        R::RSA_PKCS1_SHA512 => X::RSA_PKCS1_SHA512,
220
3
        R::RSA_PSS_SHA256 => X::RSA_PSS_SHA256,
221
1
        R::RSA_PSS_SHA384 => X::RSA_PSS_SHA384,
222
1
        R::RSA_PSS_SHA512 => X::RSA_PSS_SHA512,
223
1
        R::ED25519 => X::ED25519,
224
1
        R::ED448 => X::ED448,
225
        R::RSA_PKCS1_SHA1 | R::ECDSA_SHA1_Legacy | R::ECDSA_NISTP521_SHA512 => {
226
            // The `x509-signature` crate doesn't support these, nor should it really.
227
1
            return Err(TLSError::PeerIncompatibleError(format!(
228
1
                "Unsupported signature scheme {:?}",
229
1
                scheme
230
1
            )));
231
        }
232
        R::Unknown(_) => {
233
1
            return Err(TLSError::PeerIncompatibleError(format!(
234
1
                "Unrecognized signature scheme {:?}",
235
1
                scheme
236
1
            )))
237
        }
238
    })
239
14
}
240

            
241
#[cfg(test)]
242
mod test {
243
    use super::*;
244

            
245
    #[test]
246
    fn test_cvt_scheme() {
247
        use rustls::internal::msgs::enums::SignatureScheme as R;
248
        use x509_signature::SignatureScheme as X;
249

            
250
        macro_rules! check_cvt {
251
            { $id:ident } =>
252
            { assert_eq!(convert_scheme(R::$id).unwrap(), X::$id); }
253
        }
254

            
255
        check_cvt!(RSA_PKCS1_SHA256);
256
        check_cvt!(RSA_PKCS1_SHA384);
257
        check_cvt!(RSA_PKCS1_SHA512);
258
        check_cvt!(ECDSA_NISTP256_SHA256);
259
        check_cvt!(ECDSA_NISTP384_SHA384);
260
        check_cvt!(RSA_PSS_SHA256);
261
        check_cvt!(RSA_PSS_SHA384);
262
        check_cvt!(RSA_PSS_SHA512);
263
        check_cvt!(ED25519);
264
        check_cvt!(ED448);
265

            
266
        assert!(convert_scheme(R::RSA_PKCS1_SHA1).is_err());
267
        assert!(convert_scheme(R::Unknown(0x1337)).is_err());
268
    }
269
}