1
//! Declarations for traits that we need our runtimes to implement.
2
use async_trait::async_trait;
3
use futures::stream;
4
use futures::task::Spawn;
5
use futures::{AsyncRead, AsyncWrite, Future};
6
use std::io::Result as IoResult;
7
use std::net::SocketAddr;
8
use std::time::{Duration, Instant, SystemTime};
9

            
10
/// A runtime that we can use to run Tor as a client.
11
///
12
/// This trait comprises several other traits that we require all of our
13
/// runtimes to provide:
14
///
15
/// * [`futures::task::Spawn`] to launch new background tasks.
16
/// * [`SleepProvider`] to pause a task for a given amount of time.
17
/// * [`TcpProvider`] to launch and accept TCP connections.
18
/// * [`TlsProvider`] to launch TLS connections.
19
/// * [`BlockOn`] to block on a future and run it to completion
20
///   (This may become optional in the future, if/when we add WASM
21
///   support).
22
///
23
/// We require that every `Runtime` has an efficient [`Clone`] implementation
24
/// that gives a new opaque reference to the same underlying runtime.
25
///
26
/// Additionally, every `Runtime` is [`Send`] and [`Sync`], though these
27
/// requirements may be somewhat relaxed in the future.
28
///
29
/// At some future point,
30
/// Arti may require that the runtime `impl<S> TlsProvider<S>` (for suitable`S`),
31
/// rather than just for their own `TcpStream`s.
32
/// I.e., Arti may start to require that the runtime's TLS provider can wrap any streams,
33
/// not only the runtime's own TCP streams.
34
/// This might be expressed as an additional supertrait bound on `Runtime`,
35
/// eg when Rust supports GATs,
36
/// or as an additional bound on the Arti APIs that currently use `Runtime`.
37
/// For API future compatibility, if you `impl Runtime for MyRuntime`,
38
/// you should also ensure that you
39
/// ```ignore
40
/// impl<S> TlsProvider<S> for MyRuntime
41
/// where S: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static
42
/// ```
43
//
44
/// Perhaps we will need this if we make our own TLS connections *through* Tor,
45
/// rather than just channels to guards.
46
pub trait Runtime:
47
    Sync
48
    + Send
49
    + Spawn
50
    + BlockOn
51
    + Clone
52
    + SleepProvider
53
    + TcpProvider
54
    + TlsProvider<Self::TcpStream>
55
    + 'static
56
{
57
}
58

            
59
impl<T> Runtime for T where
60
    T: Sync
61
        + Send
62
        + Spawn
63
        + BlockOn
64
        + Clone
65
        + SleepProvider
66
        + TcpProvider
67
        + TlsProvider<Self::TcpStream>
68
        + 'static
69
{
70
}
71

            
72
/// Trait for a runtime that can wait until a timer has expired.
73
///
74
/// Every `SleepProvider` also implements
75
/// [`SleepProviderExt`](crate::SleepProviderExt); see that trait
76
/// for other useful functions.
77
pub trait SleepProvider {
78
    /// A future returned by [`SleepProvider::sleep()`]
79
    type SleepFuture: Future<Output = ()> + Send + 'static;
80
    /// Return a future that will be ready after `duration` has
81
    /// elapsed.
82
    #[must_use = "sleep() returns a future, which does nothing unless used"]
83
    fn sleep(&self, duration: Duration) -> Self::SleepFuture;
84

            
85
    /// Return the SleepProvider's view of the current instant.
86
    ///
87
    /// (This is the same as `Instant::now`, if not running in test mode.)
88
855
    fn now(&self) -> Instant {
89
855
        Instant::now()
90
855
    }
91

            
92
    /// Return the SleepProvider's view of the current wall-clock time.
93
    ///
94
    /// (This is the same as `SystemTime::now`, if not running in test mode.)
95
834
    fn wallclock(&self) -> SystemTime {
96
834
        SystemTime::now()
97
834
    }
98

            
99
    /// Signify that a test running under mock time shouldn't advance time yet, with a given
100
    /// unique reason string. This is useful for making sure (mock) time doesn't advance while
101
    /// things that might require some (real-world) time to complete do so, such as spawning a task
102
    /// on another thread.
103
    ///
104
    /// Call `release_advance` with the same reason string in order to unblock.
105
    ///
106
    /// This method is only for testing: it should never have any
107
    /// effect when invoked on non-testing runtimes.
108
    fn block_advance<T: Into<String>>(&self, _reason: T) {}
109

            
110
    /// Signify that the reason to withhold time advancing provided in a call to `block_advance` no
111
    /// longer exists, and it's fine to move time forward if nothing else is blocking advances.
112
    ///
113
    /// This method is only for testing: it should never have any
114
    /// effect when invoked on non-testing runtimes.
115
    fn release_advance<T: Into<String>>(&self, _reason: T) {}
116

            
117
    /// Allow a test running under mock time to advance time by the provided duration, even if the
118
    /// above `block_advance` API has been used.
119
    ///
120
    /// This method is only for testing: it should never have any
121
    /// effect when invoked on non-testing runtimes.
122
    fn allow_one_advance(&self, _dur: Duration) {}
123
}
124

            
125
/// Trait for a runtime that can block on a future.
126
pub trait BlockOn {
127
    /// Run `future` until it is ready, and return its output.
128
    fn block_on<F: Future>(&self, future: F) -> F::Output;
129
}
130

            
131
/// Trait for a runtime that can create and accept TCP connections.
132
///
133
/// (In Arti we use the [`AsyncRead`] and [`AsyncWrite`] traits from
134
/// [`futures::io`] as more standard, even though the ones from Tokio
135
/// can be a bit more efficient.  Let's hope that they converge in the
136
/// future.)
137
// TODO: Use of async_trait is not ideal, since we have to box with every
138
// call.  Still, async_io basically makes that necessary :/
139
#[async_trait]
140
pub trait TcpProvider {
141
    /// The type for the TCP connections returned by [`Self::connect()`].
142
    type TcpStream: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static;
143
    /// The type for the TCP listeners returned by [`Self::listen()`].
144
    type TcpListener: TcpListener<TcpStream = Self::TcpStream> + Send + Sync + Unpin + 'static;
145

            
146
    /// Launch a TCP connection to a given socket address.
147
    ///
148
    /// Note that unlike `std::net:TcpStream::connect`, we do not accept
149
    /// any types other than a single [`SocketAddr`].  We do this because,
150
    /// as a Tor implementation, we most be absolutely sure not to perform
151
    /// unnecessary DNS lookups.
152
    async fn connect(&self, addr: &SocketAddr) -> IoResult<Self::TcpStream>;
153

            
154
    /// Open a TCP listener on a given socket address.
155
    async fn listen(&self, addr: &SocketAddr) -> IoResult<Self::TcpListener>;
156
}
157

            
158
/// Trait for a local socket that accepts incoming TCP streams.
159
///
160
/// These objects are returned by instances of [`TcpProvider`].  To use
161
/// one, either call `accept` to accept a single connection, or
162
/// use `incoming` to wrap this object as a [`stream::Stream`].
163
// TODO: Use of async_trait is not ideal here either.
164
#[async_trait]
165
pub trait TcpListener {
166
    /// The type of TCP connections returned by [`Self::accept()`].
167
    type TcpStream: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static;
168

            
169
    /// The type of [`stream::Stream`] returned by [`Self::incoming()`].
170
    type Incoming: stream::Stream<Item = IoResult<(Self::TcpStream, SocketAddr)>> + Unpin;
171

            
172
    /// Wait for an incoming stream; return it along with its address.
173
    async fn accept(&self) -> IoResult<(Self::TcpStream, SocketAddr)>;
174

            
175
    /// Wrap this listener into a new [`stream::Stream`] that yields
176
    /// TCP streams and addresses.
177
    fn incoming(self) -> Self::Incoming;
178

            
179
    /// Return the local address that this listener is bound to.
180
    fn local_addr(&self) -> IoResult<SocketAddr>;
181
}
182

            
183
/// An object with a peer certificate: typically a TLS connection.
184
pub trait CertifiedConn {
185
    /// Try to return the (DER-encoded) peer certificate for this
186
    /// connection, if any.
187
    fn peer_certificate(&self) -> IoResult<Option<Vec<u8>>>;
188
}
189

            
190
/// An object that knows how to wrap a TCP connection (where the type of said TCP
191
/// connection is `S`) with TLS.
192
///
193
/// # Usage notes
194
///
195
/// Note that because of Tor's peculiarities, this is not a
196
/// general-purpose TLS type.  Unlike typical users, Tor does not want
197
/// its TLS library to check whether the certificates used in TLS are signed
198
/// within the web PKI hierarchy, or what their hostnames are, or even whether
199
/// they are valid.  It *does*, however, check that the subject public key in the
200
/// certificate is indeed correctly used to authenticate the TLS handshake.
201
///
202
/// If you are implementing something other than Tor, this is **not** the
203
/// functionality you want.
204
///
205
/// How can this behavior be remotely safe, even in Tor?  It only works for Tor
206
/// because the certificate that a Tor relay uses in TLS is not actually being
207
/// used to certify that relay's public key.  Instead, the certificate only used
208
/// as a container for the relay's public key.  The real certification happens
209
/// later, inside the TLS session, when the relay presents a CERTS cell.
210
///
211
/// Such sneakiness was especially necessary before TLS 1.3, which encrypts more
212
/// of the handshake, and before pluggable transports, which make
213
/// "innocuous-looking TLS handshakes" less important than they once were.  Once
214
/// TLS 1.3 is completely ubiquitous, we might be able to specify a simpler link
215
/// handshake than Tor uses now.
216
#[async_trait]
217
pub trait TlsConnector<S> {
218
    /// The type of connection returned by this connector
219
    type Conn: AsyncRead + AsyncWrite + CertifiedConn + Unpin + Send + 'static;
220

            
221
    /// Start a TLS session over the provided TCP stream `stream`.
222
    ///
223
    /// Declare `sni_hostname` as the desired hostname, but don't actually check
224
    /// whether the hostname in the certificate matches it.  The connector may
225
    /// send `sni_hostname` as part of its handshake, if it supports
226
    /// [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) or one of
227
    /// the TLS 1.3 equivalents.
228
    async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn>;
229
}
230

            
231
/// Trait for a runtime that knows how to create TLS connections over
232
/// TCP streams of type `S`.
233
///
234
/// This is separate from [`TlsConnector`] because eventually we may
235
/// eventually want to support multiple `TlsConnector` implementations
236
/// that use a single [`Runtime`].
237
///
238
/// See the [`TlsConnector`] documentation for a discussion of the Tor-specific
239
/// limitations of this trait: If you are implementing something other than Tor,
240
/// this is **not** the functionality you want.
241
pub trait TlsProvider<S> {
242
    /// The Connector object that this provider can return.
243
    type Connector: TlsConnector<S, Conn = Self::TlsStream> + Send + Sync + Unpin;
244

            
245
    /// The type of the stream returned by that connector.
246
    type TlsStream: AsyncRead + AsyncWrite + CertifiedConn + Unpin + Send + 'static;
247

            
248
    /// Return a TLS connector for use with this runtime.
249
    fn tls_connector(&self) -> Self::Connector;
250
}