1
//! Handler for CREATE* cells.
2

            
3
use crate::FlowCtrlParameters;
4
use crate::ccparams::{
5
    AlgorithmDiscriminants, CongestionWindowParams, FixedWindowParams, RoundTripEstimatorParams,
6
    VegasParams,
7
};
8
use crate::channel::Channel;
9
use crate::circuit::celltypes::{CreateRequest, CreateResponse};
10
use crate::circuit::circhop::{HandshakeParamsError, HopSettings};
11
use crate::circuit::{
12
    CircuitRxSender, HandshakeSubprotocols, InvalidHandshakeSubprotocolError, UniqId,
13
};
14
use crate::client::circuit::padding::PaddingController;
15
use crate::crypto::binding::CircuitBinding;
16
use crate::crypto::cell::CryptInit as _;
17
use crate::crypto::cell::{
18
    CgoRelayCrypto, InboundRelayLayer, OutboundRelayLayer, RelayLayer, Tor1RelayCrypto,
19
};
20
use crate::crypto::handshake::RelayHandshakeError;
21
use crate::crypto::handshake::ServerHandshake as _;
22
use crate::crypto::handshake::fast::CreateFastServer;
23
use crate::crypto::handshake::ntor::{NtorSecretKey, NtorServer};
24
use crate::crypto::handshake::ntor_v3::{NtorV3SecretKey, NtorV3Server};
25
use crate::memquota::SpecificAccount as _;
26
use crate::memquota::{ChannelAccount, CircuitAccount};
27
use crate::relay::channel_provider::ChannelProvider;
28
use crate::relay::reactor::Reactor;
29
use crate::relay::{IncomingStreamRequestFilter, RelayCirc};
30
use crate::stream::IncomingStream;
31
use futures::channel::mpsc;
32
use futures::{SinkExt, Stream};
33
use smallvec::SmallVec;
34
use std::sync::{Arc, RwLock, Weak};
35
use tor_cell::chancell::ChanMsg as _;
36
use tor_cell::chancell::CircId;
37
use tor_cell::chancell::msg::{
38
    CreateFast, Created2, CreatedFast, Destroy, DestroyReason, HandshakeType,
39
};
40
use tor_cell::relaycell::RelayCmd;
41
use tor_cell::relaycell::extend::{
42
    CcRequest, CcResponse, CircRequestExt, CircResponseExt, SubprotocolRequest,
43
};
44
use tor_error::{ErrorKind, HasKind, debug_report, internal, into_internal, warn_report};
45
use tor_linkspec::OwnedChanTarget;
46
use tor_llcrypto::pk::ed25519::Ed25519Identity;
47
use tor_llcrypto::pk::rsa::RsaIdentity;
48
use tor_memquota::mq_queue::ChannelSpec as _;
49
use tor_memquota::mq_queue::MpscSpec;
50
use tor_relay_crypto::pk::{RelayNtorKeypair, RelayNtorKeys};
51
use tor_rtcompat::SpawnExt as _;
52
use tor_rtcompat::{DynTimeProvider, Runtime};
53
use tracing::{debug, trace};
54

            
55
/// Everything needed to handle CREATE* messages on channels.
56
#[derive(derive_more::Debug)]
57
pub struct CreateRequestHandler {
58
    /// Something that can launch channels. Typically the `ChanMgr`.
59
    chan_provider: Weak<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
60
    /// Circuit-related network parameters.
61
    circ_net_params: RwLock<CircNetParameters>,
62
    /// The circuit extension keys.
63
    #[debug(skip)]
64
    ntor_keys: RwLock<RelayNtorKeys>,
65
    /// An [`IncomingStreamRequestFilter`] factory for checking whether the user wants
66
    /// this request, or wants to reject it immediately.
67
    ///
68
    /// Used for obtaining a current [`IncomingStreamRequestFilter`]
69
    /// for building a circuit reactor.
70
    //
71
    // TODO(relay): it's likely this will end up changing quite a bit once we start
72
    // figuring out exactly how the config/reconfigure() logic and IncomingStreamRequestFilter
73
    // should function for relays.
74
    #[debug(skip)]
75
    incoming_filter_factory: Box<dyn IncomingStreamRequestFilterFactory + Send + Sync>,
76
    /// The allowed incoming stream commands.
77
    ///
78
    /// Used for rejecting BEGIN and RESOLVE if we are not configured to be an exit.
79
    ///
80
    // TODO(relay): we might use this for rejecting BEGIN_DIR too,
81
    // if we decide to allow relays to opt out of being dir mirrors.
82
    // See https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/4107/diffs#note_3426447
83
    allowed_stream_cmds: SmallVec<[RelayCmd; 3]>,
84
    /// A sender for the [`Stream`]s of `IncomingStream` of all circuits.
85
    ///
86
    /// The receiver will receive one [`Stream`] (of tor streams) per circuit.
87
    ///
88
    /// This being a bounded MPSC might seem a bit risky, because in theory,
89
    /// if the receiver is not reading fast enough, sending will block.
90
    /// In practice, however, it should never block (or buffer very much at all,
91
    /// for that matter), because the user (arti-relay) is expected to read from
92
    /// this in a tight loop, and spawn a task for handling each [`Stream`].
93
    ///
94
    /// Note: because this MPSC is not associated with any particular circuit or channel,
95
    /// it does not participate in the memquota system (see [crate::memquota]).
96
    #[debug(skip)]
97
    circuit_stream_tx: mpsc::Sender<Box<dyn Stream<Item = IncomingStream> + Send + Sync + Unpin>>,
98
}
99

            
100
// We make the CREATE-handling methods of `CreateRequestHandler` async
101
// since we expect that in the future we may want to offload the crypto to a worker thread.
102
#[expect(clippy::unused_async)]
103
impl CreateRequestHandler {
104
    /// Build a new [`CreateRequestHandler`], and a [`CircuitIncomingStreamReceiver`]
105
    /// for receiving new streams that are opened on any incoming circuits.
106
30
    pub fn new(
107
30
        chan_provider: Weak<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
108
30
        circ_net_params: CircNetParameters,
109
30
        ntor_keys: RelayNtorKeys,
110
30
        incoming_filter_factory: Box<dyn IncomingStreamRequestFilterFactory + Send + Sync>,
111
30
        allowed_stream_cmds: &[RelayCmd],
112
30
    ) -> (Self, CircuitIncomingStreamReceiver) {
113
        // TODO(relay-tuning): this MPSC can be a bottleneck,
114
        // as all the channels on this relay will want to send one item on it
115
        // each time a new circuit is created.
116
        //
117
        // The value set here is a guesstimate.
118
        const CIRC_STREAM_BUF_SIZE: usize = 1024;
119

            
120
        // This is not associated with any particular circuit
121
        // (it is for *all* circuits), so it doesn't participate in memquota
122
        // (see circuit_stream_tx docs)
123
        #[allow(clippy::disallowed_methods)]
124
30
        let (stream_tx, stream_rx) = mpsc::channel(CIRC_STREAM_BUF_SIZE);
125

            
126
30
        let handler = Self {
127
30
            chan_provider,
128
30
            circ_net_params: RwLock::new(circ_net_params),
129
30
            ntor_keys: RwLock::new(ntor_keys),
130
30
            incoming_filter_factory,
131
30
            allowed_stream_cmds: allowed_stream_cmds.into(),
132
30
            circuit_stream_tx: stream_tx,
133
30
        };
134

            
135
30
        let circuit_stream_rx = CircuitIncomingStreamReceiver {
136
30
            circuit_stream_rx: stream_rx,
137
30
        };
138

            
139
30
        (handler, circuit_stream_rx)
140
30
    }
141

            
142
    /// Update the circuit parameters from a network consensus.
143
    pub fn update_params(&self, circ_net_params: CircNetParameters) {
144
        *self.circ_net_params.write().expect("rwlock poisoned") = circ_net_params;
145
    }
146

            
147
    /// Update the handler with a new set of circuit extension keys.
148
    ///
149
    /// This is called periodically by the relay key rotation task.
150
    pub fn update_ntor_keys(&self, ntor_keys: RelayNtorKeys) {
151
        *self.ntor_keys.write().expect("rwlock poisoned") = ntor_keys;
152
    }
153

            
154
    /// Handle a CREATE* cell.
155
    ///
156
    /// This intentionally does not return a [`crate::Error`] so that we don't accidentally shut
157
    /// down the channel reactor when we really should be returning a DESTROY. Shutting down a
158
    /// channel may cause us to leak information about paths of circuits travelling through this
159
    /// relay. This is especially important here since we're handling data that is controllable from
160
    /// the other end of the circuit.
161
    #[allow(clippy::too_many_arguments)]
162
14
    pub(crate) async fn handle_create<R: Runtime>(
163
14
        &self,
164
14
        runtime: &R,
165
14
        channel: &Arc<Channel>,
166
14
        our_ed25519_id: &Ed25519Identity,
167
14
        our_rsa_id: &RsaIdentity,
168
14
        circ_id: CircId,
169
14
        msg: &CreateRequest,
170
14
        memquota: &ChannelAccount,
171
14
        circ_unique_id: UniqId,
172
14
    ) -> Result<(CreateResponse, RelayCircComponents), Destroy> {
173
14
        let result = self
174
14
            .handle_create_inner(
175
14
                runtime,
176
14
                channel,
177
14
                our_ed25519_id,
178
14
                our_rsa_id,
179
14
                circ_id,
180
14
                msg,
181
14
                memquota,
182
14
                circ_unique_id,
183
14
            )
184
14
            .await;
185

            
186
14
        match result {
187
14
            Ok(x) => Ok(x),
188
            Err(e) => {
189
                // TODO(relay): The log messages throughout could be very noisy, so should have rate limiting.
190
                let cmd = msg.cmd();
191
                debug_report!(&e, %cmd, "Failed to handle circuit create request");
192

            
193
                // `tor-spec/tearing-down-circuits.md`:
194
                //
195
                // > Implementations SHOULD always use the NONE reason to avoid side channels: [...]
196
                Err(Destroy::new(DestroyReason::NONE))
197
            }
198
        }
199
14
    }
200

            
201
    /// See [`Self::handle_create`].
202
    #[allow(clippy::too_many_arguments)]
203
14
    async fn handle_create_inner<R: Runtime>(
204
14
        &self,
205
14
        runtime: &R,
206
14
        channel: &Arc<Channel>,
207
14
        our_ed25519_id: &Ed25519Identity,
208
14
        our_rsa_id: &RsaIdentity,
209
14
        circ_id: CircId,
210
14
        msg: &CreateRequest,
211
14
        memquota: &ChannelAccount,
212
14
        circ_unique_id: UniqId,
213
14
    ) -> Result<(CreateResponse, RelayCircComponents), HandleCreateError> {
214
        // Perform the handshake crypto and build the response.
215
14
        let handshake_components = match msg {
216
2
            CreateRequest::CreateFast(msg) => self.handle_create_fast(msg).await?,
217
12
            CreateRequest::Create2(msg) => match msg.handshake_type() {
218
                HandshakeType::NTOR_V3 => {
219
6
                    self.handle_create2_ntorv3(msg.body(), our_ed25519_id)
220
6
                        .await?
221
                }
222
6
                HandshakeType::NTOR => self.handle_create2_ntor(msg.body(), our_rsa_id).await?,
223
                x @ HandshakeType::TAP | x => {
224
                    return Err(HandleCreateError::Create2HandshakeType(x));
225
                }
226
            },
227
        };
228

            
229
14
        let memquota = CircuitAccount::new(memquota)?;
230

            
231
        // We use a large mpsc queue here since a circuit should never block the channel,
232
        // and we hope that memquota will help us if an attacker intentionally fills this buffer.
233
        // We use `10_000_000` since `usize::MAX` causes `futures::channel::mpsc` to panic.
234
        // TODO(relay): We should switch to an unbounded queue, but the circuit reactor is expecting
235
        // a bounded queue.
236
14
        let time_provider = DynTimeProvider::new(runtime.clone());
237
14
        let account = memquota.as_raw_account();
238
14
        let (sender, receiver) =
239
14
            MpscSpec::new(10_000_000).new_mq(time_provider.clone(), account)?;
240
14
        let (sender, receiver) = crate::circuit::circ_sender::channel(sender, receiver);
241

            
242
        // TODO(relay): Do we really want a client padding machine here?
243
14
        let (padding_ctrl, padding_stream) =
244
14
            crate::client::circuit::padding::new_padding(DynTimeProvider::new(runtime.clone()));
245

            
246
        // Upgrade the channel provider, which in practice is the `ChanMgr` so this should not fail.
247
14
        let Some(chan_provider) = self.chan_provider.upgrade() else {
248
            return Err(internal!("Unable to upgrade weak `ChannelProvider`").into());
249
        };
250

            
251
        // Create an IncomingStreamRequestFilter for this circuit.
252
        // This will get applied to every stream request (BEGIN, BEGIN_DIR, RESOLVE)
253
        // arriving on the circuit.
254
        //
255
        // Note: once built, a circuit reactor's IncomingStreamRequestFilter cannot be changed
256
        // (it's fixed for the entire duration of the circuit).
257
14
        let incoming_filter = self.incoming_filter_factory.current_filter();
258

            
259
        // Build the relay circuit reactor.
260
14
        let (reactor, circ, incoming_streams) = Reactor::new(
261
14
            runtime.clone(),
262
14
            channel,
263
14
            circ_id,
264
14
            circ_unique_id,
265
14
            receiver,
266
14
            handshake_components.crypto_in,
267
14
            handshake_components.crypto_out,
268
14
            &handshake_components.hop_settings,
269
14
            chan_provider,
270
14
            padding_ctrl.clone(),
271
14
            padding_stream,
272
14
            incoming_filter,
273
14
            &self.allowed_stream_cmds,
274
14
            &memquota,
275
        )
276
14
        .map_err(into_internal!("Failed to start circuit reactor"))?;
277

            
278
14
        let mut circuit_stream_tx = self.circuit_stream_tx.clone();
279
        // Start the reactor in a task.
280
14
        let () = runtime.spawn(async move {
281
14
            if let Err(e) = circuit_stream_tx.send(Box::new(incoming_streams)).await {
282
                warn_report!(e, "IncomingStream handler disappeared?!");
283
                // If we get here, it means the relay stream handler task has gone away,
284
                // so there won't be anything handling the incoming streams.
285
                //
286
                // The reactor is dropped, making the RelayCirc returned below
287
                // in the RelayCircComponents unusable
288
                // (RelayCirc::is_closing() will return `true`).
289
                drop(reactor);
290
            } else {
291
                // Only spawn the circuit reactor if the incoming stream handler was
292
                // able to receive our message
293
14
                match reactor.run().await {
294
10
                    Ok(()) => {}
295
                    Err(e) => {
296
                        debug_report!(e, "Relay circuit reactor exited with an error");
297
                    }
298
                }
299
            }
300
10
        })?;
301

            
302
14
        Ok((
303
14
            handshake_components.response,
304
14
            RelayCircComponents {
305
14
                circ,
306
14
                sender,
307
14
                padding_ctrl,
308
14
            },
309
14
        ))
310
14
    }
311

            
312
    /// The handshake code for a CREATE_FAST request.
313
2
    async fn handle_create_fast(
314
2
        &self,
315
2
        msg: &CreateFast,
316
3
    ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
317
        // TODO(relay): We might want to offload this to a CPU worker in the future.
318
2
        let (keygen, handshake_msg) = CreateFastServer::server(
319
2
            &mut rand::rng(),
320
            // The CREATE_FAST handshake doesn't accept or return extensions,
321
            // so this `AuxDataReply` is a no-op.
322
2
            &mut |_: &()| Some(()),
323
            // The CREATE_FAST handshake doesn't use any keys.
324
2
            &[()],
325
2
            msg.handshake(),
326
        )?;
327

            
328
2
        let circ_net_params = self
329
2
            .circ_net_params
330
2
            .read()
331
2
            .expect("rwlock poisoned")
332
2
            .clone();
333

            
334
        // No subprotocols are requested during a CREATE_FAST handshake.
335
2
        let subprotos = HandshakeSubprotocols::default();
336

            
337
2
        let hop_settings = HopSettings::from_handshake_params(
338
2
            circ_net_params,
339
            // CREATE_FAST always uses fixed-window flow control.
340
2
            AlgorithmDiscriminants::FixedWindow,
341
2
            subprotos,
342
        )?;
343

            
344
2
        let crypt = Tor1RelayCrypto::construct(keygen)
345
2
            .map_err(into_internal!("Circuit crypt state construction failed"))?;
346

            
347
2
        let (crypto_out, crypto_in, _binding) = split_relay_layer(crypt);
348

            
349
2
        let response = CreatedFast::new(handshake_msg);
350
2
        let response = CreateResponse::CreatedFast(response);
351

            
352
2
        trace!("Completed CREATE_FAST handshake");
353

            
354
2
        Ok(CompletedHandshakeComponents {
355
2
            response,
356
2
            hop_settings,
357
2
            crypto_out,
358
2
            crypto_in,
359
2
        })
360
2
    }
361

            
362
    /// The handshake code for a CREATE2 ntor (non-v3) request.
363
6
    async fn handle_create2_ntor(
364
6
        &self,
365
6
        msg_body: &[u8],
366
6
        our_rsa_id: &RsaIdentity,
367
9
    ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
368
6
        let ntor_keys = self.ntor_keys(|k| {
369
6
            NtorSecretKey::new(k.secret().clone(), *k.public().inner(), *our_rsa_id)
370
6
        });
371

            
372
        // TODO(relay): We might want to offload this to a CPU worker in the future.
373
6
        let (keygen, handshake_msg) = NtorServer::server(
374
6
            &mut rand::rng(),
375
            // The ntor (non-v3) handshake doesn't accept or return extensions,
376
            // so this `AuxDataReply` is a no-op.
377
6
            &mut |_: &()| Some(()),
378
6
            ntor_keys.as_ref(),
379
6
            msg_body,
380
        )?;
381

            
382
6
        let circ_net_params = self
383
6
            .circ_net_params
384
6
            .read()
385
6
            .expect("rwlock poisoned")
386
6
            .clone();
387

            
388
        // No subprotocols are requested during an ntor (non-v3) handshake.
389
6
        let subprotos = HandshakeSubprotocols::default();
390

            
391
6
        let hop_settings = HopSettings::from_handshake_params(
392
6
            circ_net_params,
393
            // CREATE2 with ntor (non-v3) always uses fixed-window flow control.
394
6
            AlgorithmDiscriminants::FixedWindow,
395
6
            subprotos,
396
        )?;
397

            
398
6
        let crypt = Tor1RelayCrypto::construct(keygen)
399
6
            .map_err(into_internal!("Circuit crypt state construction failed"))?;
400

            
401
6
        let (crypto_out, crypto_in, _binding) = split_relay_layer(crypt);
402

            
403
6
        let response = Created2::new(handshake_msg);
404
6
        let response = CreateResponse::Created2(response);
405

            
406
6
        trace!("Completed ntor handshake");
407

            
408
6
        Ok(CompletedHandshakeComponents {
409
6
            response,
410
6
            hop_settings,
411
6
            crypto_out,
412
6
            crypto_in,
413
6
        })
414
6
    }
415

            
416
    /// The handshake code for a CREATE2 ntor-v3 request.
417
6
    async fn handle_create2_ntorv3(
418
6
        &self,
419
6
        msg_body: &[u8],
420
6
        our_ed25519_id: &Ed25519Identity,
421
9
    ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
422
6
        let ntor_keys = self.ntor_keys(|k| {
423
6
            NtorV3SecretKey::new(k.secret().clone(), *k.public().inner(), *our_ed25519_id)
424
6
        });
425

            
426
6
        let circ_net_params = self
427
6
            .circ_net_params
428
6
            .read()
429
6
            .expect("rwlock poisoned")
430
6
            .clone();
431

            
432
        // These extensions can be negotiated during the handshake.
433
6
        let mut cc_algorithm = AlgorithmDiscriminants::FixedWindow;
434

            
435
        // These subprotocols were requested during the handshake.
436
        // They are not validated.
437
6
        let mut subprotos = SubprotocolRequest::default();
438

            
439
        // Helper which processes extension requests and returns any responses.
440
        // Returns `None` if the handshake should fail.
441
6
        let mut ext_reply_fn = |client_exts: &[CircRequestExt]| {
442
6
            let mut response_exts = Vec::new();
443

            
444
            // https://spec.torproject.org/tor-spec/create-created-cells.html#additional-data
445
            //
446
            // > Unless otherwise specified in the documentation for an extension type:
447
            // > - [...]
448
            // > - Parties MUST ignore any occurrence of an extension with a given type after the first such occurrence.
449
            //
450
            // TODO: Is there something nicer that we can do here?
451
            // We could use accessors like `ExtList::get_cc_request()`
452
            // which iterate over the extension list for each extension,
453
            // but using an enum match like we do below is kind of nice.
454
6
            let mut handled_cc_request = false;
455
6
            let mut handled_subproto_request = false;
456

            
457
6
            for ext in client_exts {
458
                match ext {
459
                    CircRequestExt::CcRequest(CcRequest { .. }) => {
460
                        if handled_cc_request {
461
                            continue;
462
                        }
463
                        handled_cc_request = true;
464

            
465
                        cc_algorithm = AlgorithmDiscriminants::Vegas;
466

            
467
                        let sendme_inc: u8 = circ_net_params.cc.cwnd.sendme_inc();
468
                        let response = CcResponse::new(sendme_inc);
469
                        response_exts.push(CircResponseExt::CcResponse(response));
470
                    }
471
                    // The given `SubprotocolRequest` stores a list of `NumberedSubver`,
472
                    // but a circuit extension request is limited to 255 bytes (127 subprotocols).
473
                    // So while a malicious client could send us a lot of invalid subprotocols,
474
                    // this limit prevents this list from being excessively large.
475
                    CircRequestExt::SubprotocolRequest(subproto_request) => {
476
                        if handled_subproto_request {
477
                            continue;
478
                        }
479
                        handled_subproto_request = true;
480

            
481
                        // We don't check the requested subprotocols here.
482
                        subprotos = subproto_request.clone();
483
                    }
484
                    CircRequestExt::Unrecognized(ext) => {
485
                        // https://spec.torproject.org/tor-spec/create-created-cells.html#additional-data
486
                        //
487
                        // > Parties MUST ignore extensions with `EXT_FIELD_TYPE` bodies they do not recognize.
488
                        debug!(
489
                            ?ext,
490
                            "CREATE2 ntor-v3 handshake requested unrecognized extension",
491
                        );
492
                    }
493
                    ext => {
494
                        // https://spec.torproject.org/tor-spec/create-created-cells.html#additional-data
495
                        //
496
                        // > Parties MUST ignore extensions with `EXT_FIELD_TYPE` bodies they do not recognize.
497
                        //
498
                        // We recognize this but don't know what to do with it.
499
                        // We haven't implemented it, or it doesn't make sense
500
                        // (for example `CircRequestExt::ProofOfWork`).
501
                        // So we'll just behave as if we don't recognize it.
502
                        debug!(
503
                            ?ext,
504
                            "CREATE2 ntor-v3 handshake requested unsupported extension",
505
                        );
506
                    }
507
                }
508
            }
509

            
510
6
            Some(response_exts)
511
6
        };
512

            
513
        // TODO(relay): We might want to offload this to a CPU worker in the future.
514
6
        let (keygen, handshake_msg) = NtorV3Server::server(
515
6
            &mut rand::rng(),
516
6
            &mut ext_reply_fn,
517
6
            ntor_keys.as_ref(),
518
6
            msg_body,
519
        )?;
520

            
521
        // Ensure that the client did not request invalid/unsupported subprotocols.
522
6
        let subprotos = HandshakeSubprotocols::try_from_request(subprotos)?;
523

            
524
6
        let hop_settings =
525
6
            HopSettings::from_handshake_params(circ_net_params, cc_algorithm, subprotos)?;
526

            
527
6
        let (crypto_out, crypto_in, _binding) = if subprotos.relay_crypt_cgo {
528
            let crypt = CgoRelayCrypto::construct(keygen)
529
                .map_err(into_internal!("Circuit crypt state construction failed"))?;
530
            split_relay_layer(crypt)
531
        } else {
532
6
            let crypt = Tor1RelayCrypto::construct(keygen)
533
6
                .map_err(into_internal!("Circuit crypt state construction failed"))?;
534
6
            split_relay_layer(crypt)
535
        };
536

            
537
6
        let response = Created2::new(handshake_msg);
538
6
        let response = CreateResponse::Created2(response);
539

            
540
6
        trace!(?cc_algorithm, ?subprotos, "Completed ntor-v3 handshake");
541

            
542
6
        Ok(CompletedHandshakeComponents {
543
6
            response,
544
6
            hop_settings,
545
6
            crypto_out,
546
6
            crypto_in,
547
6
        })
548
6
    }
549

            
550
    /// Helper to get the ntor keypairs after some transformation `map`.
551
    ///
552
    /// The `map` transformation must be fast since it blocks a read lock.
553
    /// The returned keys are sorted with the most recent key first.
554
    ///
555
    /// It would be nice if this just returned an iterator,
556
    /// but the read lock prevents this.
557
12
    fn ntor_keys<T>(&self, map: impl FnMut(&RelayNtorKeypair) -> T) -> impl AsRef<[T]> {
558
12
        let ntor_keys = self.ntor_keys.read().expect("rwlock poisoned");
559
12
        let ntor_keys = [Some(ntor_keys.latest()), ntor_keys.previous()];
560
12
        ntor_keys
561
12
            .into_iter()
562
12
            .flatten()
563
12
            .map(map)
564
12
            .collect::<SmallVec<[T; 2]>>()
565
12
    }
566
}
567

            
568
/// A receiver of [`Stream`]s (one for each incoming circuit),
569
/// where each `Stream` produces [`IncomingStream`]s for that circuit.
570
///
571
// Note: in theory, it would be nice if we could get rid of this type altogether.
572
// In an ideal world, I would've instead
573
//
574
//   * added a `RelayCirc::take_incoming_streams()` method for obtaining
575
//     the futures::Stream of IncomingStream of that circuit
576
//   * made the CreateRequestHandler send each Arc<RelayCirc> over to arti-relay for handling
577
//   * made arti-relay obtain the futures::Stream<Item = IncomingStream> of each RelayCirc
578
//     by calling `RelayCirc::take_incoming_streams()`
579
//
580
// However, that would involve adding some locking/interior mutability within RelayCirc
581
// (which is always behind an Arc), or extending mq_queue::Receiver to be Clone,
582
// which would be tricky to pull off (see the comment on mq_queue::Receiver about this).
583
pub struct CircuitIncomingStreamReceiver {
584
    /// The receiver for the [`Stream`]s of `IncomingStream` of all circuits.
585
    ///
586
    /// Receives one [`Stream`] (of tor streams) per circuit.
587
    /// Each of these will be handled in a new task.
588
    circuit_stream_rx: mpsc::Receiver<<Self as Stream>::Item>,
589
}
590

            
591
impl Stream for CircuitIncomingStreamReceiver {
592
    // TODO: it would be nice if we could return a type-erased Stream here
593
    // (impl Stream<...>), but impl Trait in associated types is unstable.
594
    // See rust issue #63063 <https://github.com/rust-lang/rust/issues/63063>
595
    type Item = Box<dyn Stream<Item = IncomingStream> + Send + Sync + Unpin>;
596

            
597
    fn poll_next(
598
        mut self: std::pin::Pin<&mut Self>,
599
        cx: &mut std::task::Context<'_>,
600
    ) -> std::task::Poll<Option<Self::Item>> {
601
        use futures::StreamExt as _;
602

            
603
        self.circuit_stream_rx.poll_next_unpin(cx)
604
    }
605
}
606

            
607
/// Helper function to split a `RelayLayer` into forward and backward type-erased trait objects.
608
14
fn split_relay_layer<F, B>(
609
14
    crypt: impl RelayLayer<F, B>,
610
14
) -> (
611
14
    Box<dyn OutboundRelayLayer + Send>,
612
14
    Box<dyn InboundRelayLayer + Send>,
613
14
    CircuitBinding,
614
14
)
615
14
where
616
14
    F: OutboundRelayLayer + Send + 'static,
617
14
    B: InboundRelayLayer + Send + 'static,
618
{
619
14
    let (crypto_out, crypto_in, binding) = crypt.split_relay_layer();
620
14
    let (crypto_out, crypto_in) = (Box::new(crypto_out), Box::new(crypto_in));
621

            
622
14
    (crypto_out, crypto_in, binding)
623
14
}
624

            
625
/// An error that occurred while handling a CREATE* request.
626
#[derive(Debug, thiserror::Error)]
627
enum HandleCreateError {
628
    /// Circuit relay handshake failed.
629
    #[error("Circuit relay handshake failed")]
630
    Handshake(#[from] RelayHandshakeError),
631
    /// Circuit relay handshake failed.
632
    #[error("Failed to process the circuit relay handshake parameters")]
633
    HandshakeParameters(#[from] HandshakeParamsError),
634
    /// Requested subprotocols which aren't supported.
635
    #[error("Client requested subprotocol(s) which aren't supported")]
636
    HandshakeSubprotocols(#[from] InvalidHandshakeSubprotocolError),
637
    /// The requested handshake type is unsupported.
638
    #[error("Unsupported handshake type {0}")]
639
    Create2HandshakeType(HandshakeType),
640
    /// A memquota error.
641
    #[error("Memquota error")]
642
    Memquota(#[from] tor_memquota::Error),
643
    /// Error when spawning a task.
644
    #[error("Runtime task spawn error")]
645
    Spawn(#[from] futures::task::SpawnError),
646
    /// An internal error.
647
    ///
648
    /// Note that other variants (such as `Handshake` containing a [`RelayHandshakeError`])
649
    /// may themselves contain internal errors.
650
    #[error("Internal error")]
651
    Internal(#[from] tor_error::Bug),
652
}
653

            
654
impl HasKind for HandleCreateError {
655
    fn kind(&self) -> ErrorKind {
656
        match self {
657
            Self::Handshake(e) => e.kind(),
658
            Self::HandshakeParameters(e) => e.kind(),
659
            Self::HandshakeSubprotocols(e) => e.kind(),
660
            Self::Create2HandshakeType(_) => ErrorKind::NotImplemented,
661
            Self::Memquota(e) => e.kind(),
662
            Self::Spawn(e) => e.kind(),
663
            Self::Internal(_) => ErrorKind::Internal,
664
        }
665
    }
666
}
667

            
668
/// The components of a completed CREATE* handshake.
669
struct CompletedHandshakeComponents {
670
    /// The message to send in response.
671
    response: CreateResponse,
672
    /// The negotiated hop settings.
673
    hop_settings: HopSettings,
674
    /// Outbound onion crypto.
675
    crypto_out: Box<dyn OutboundRelayLayer + Send>,
676
    /// Inbound onion crypto.
677
    crypto_in: Box<dyn InboundRelayLayer + Send>,
678
}
679

            
680
/// A collection of objects built for a new relay circuit.
681
pub(crate) struct RelayCircComponents {
682
    /// The relay circuit handle.
683
    pub(crate) circ: Arc<RelayCirc>,
684
    /// Used to send data from the channel to the circuit reactor.
685
    pub(crate) sender: CircuitRxSender,
686
    /// The circuit's padding controller.
687
    pub(crate) padding_ctrl: PaddingController,
688
}
689

            
690
/// Congestion control network parameters.
691
#[derive(Debug, Clone)]
692
#[allow(clippy::exhaustive_structs)]
693
pub struct CongestionControlNetParams {
694
    /// Fixed-window algorithm parameters.
695
    pub fixed_window: FixedWindowParams,
696

            
697
    /// Vegas algorithm parameters for exit circuits.
698
    // NOTE: In this module we are handling CREATE* cells,
699
    // which only happens for non-hs circuits.
700
    // So we don't need to store the vegas hs parameters here.
701
    pub vegas_exit: VegasParams,
702

            
703
    /// Congestion window parameters.
704
    pub cwnd: CongestionWindowParams,
705

            
706
    /// RTT calculation parameters.
707
    pub rtt: RoundTripEstimatorParams,
708

            
709
    /// Flow control parameters to use for all streams on this circuit.
710
    pub flow_ctrl: FlowCtrlParameters,
711
}
712

            
713
impl CongestionControlNetParams {
714
    #[cfg(test)]
715
    // These have been copied from C-tor.
716
30
    pub(crate) fn defaults_for_tests() -> Self {
717
30
        Self {
718
30
            fixed_window: FixedWindowParams::defaults_for_tests(),
719
30
            vegas_exit: VegasParams::defaults_for_tests(),
720
30
            cwnd: CongestionWindowParams::defaults_for_tests(),
721
30
            rtt: RoundTripEstimatorParams::defaults_for_tests(),
722
30
            flow_ctrl: FlowCtrlParameters::defaults_for_tests(),
723
30
        }
724
30
    }
725
}
726

            
727
/// Network consensus parameters for handling incoming circuits.
728
///
729
/// Unlike `CircParameters`,
730
/// this is unopinionated and contains all relevant consensus parameters,
731
/// which is needed when handling an incoming CREATE* request where the
732
/// circuit origin chooses the type/settings
733
/// (for example congestion control type) of the circuit.
734
#[derive(Debug, Clone)]
735
#[allow(clippy::exhaustive_structs)]
736
pub struct CircNetParameters {
737
    /// Congestion control network parameters.
738
    pub cc: CongestionControlNetParams,
739
}
740

            
741
/// An [`IncomingStreamRequestFilter`] factory for building [`IncomingStreamRequestFilter`]s.
742
///
743
/// Each time a new circuit is opened, the [`CreateRequestHandler`] calls
744
/// [`IncomingStreamRequestFilterFactory::current_filter`] to build
745
/// an [`IncomingStreamRequestFilter`] for the circuit.
746
pub trait IncomingStreamRequestFilterFactory {
747
    /// Return the [`IncomingStreamRequestFilter`] to apply to the incoming stream requests
748
    /// arriving on a circuit.
749
    fn current_filter(&self) -> Box<dyn IncomingStreamRequestFilter>;
750
}
751

            
752
impl<F> IncomingStreamRequestFilterFactory for F
753
where
754
    F: Fn() -> Box<dyn IncomingStreamRequestFilter>,
755
{
756
14
    fn current_filter(&self) -> Box<dyn IncomingStreamRequestFilter> {
757
14
        (self)()
758
14
    }
759
}
760

            
761
#[cfg(test)]
762
mod test {
763
    // @@ begin test lint list maintained by maint/add_warning @@
764
    #![allow(clippy::bool_assert_comparison)]
765
    #![allow(clippy::clone_on_copy)]
766
    #![allow(clippy::dbg_macro)]
767
    #![allow(clippy::mixed_attributes_style)]
768
    #![allow(clippy::print_stderr)]
769
    #![allow(clippy::print_stdout)]
770
    #![allow(clippy::single_char_pattern)]
771
    #![allow(clippy::unwrap_used)]
772
    #![allow(clippy::unchecked_time_subtraction)]
773
    #![allow(clippy::useless_vec)]
774
    #![allow(clippy::needless_pass_by_value)]
775
    #![allow(clippy::string_slice)] // See arti#2571
776
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
777

            
778
    use tor_cell::chancell::msg::{AnyChanMsg, HandshakeType};
779
    use tor_cell::chancell::{ChanCmd, ChanMsg as _};
780
    use tor_rtcompat::test_with_one_runtime;
781

            
782
    use crate::channel::test_utils;
783
    use crate::circuit::CircParameters;
784

            
785
    #[test]
786
    fn create_fast() {
787
        test_with_one_runtime!(|rt| async move {
788
            let mut conn_inspector = test_utils::ConnInspector::new();
789

            
790
            let (client_chan, _relay_chan, _circuit_stream_rx, _target_builder) =
791
                test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
792

            
793
            let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
794

            
795
            let circ_params = CircParameters::default();
796

            
797
            let tunnel = pending_tunnel
798
                .create_firsthop_fast(circ_params)
799
                .await
800
                .unwrap();
801

            
802
            assert_eq!(
803
                conn_inspector.try_client_cell().unwrap().msg().cmd(),
804
                ChanCmd::CREATE_FAST,
805
            );
806
            assert_eq!(
807
                conn_inspector.try_relay_cell().unwrap().msg().cmd(),
808
                ChanCmd::CREATED_FAST,
809
            );
810

            
811
            drop(tunnel);
812

            
813
            assert_eq!(
814
                conn_inspector.client_cell().await.unwrap().msg().cmd(),
815
                ChanCmd::DESTROY,
816
            );
817
            // The relay shouldn't be sending a DESTROY back to the client
818
            assert!(conn_inspector.try_relay_cell().is_none());
819
        });
820
    }
821

            
822
    #[test]
823
    fn tap() {
824
        test_with_one_runtime!(|rt| async move {
825
            let mut conn_inspector = test_utils::ConnInspector::new();
826

            
827
            let (client_chan, _relay_chan, _circuit_stream_rx, mut target_builder) =
828
                test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
829

            
830
            let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
831

            
832
            let circ_params = CircParameters::default();
833

            
834
            // https://spec.torproject.org/tor-spec/subprotocol-versioning.html
835
            // 1 = RELAY_BASE
836
            let protocols = "Relay=1".parse().unwrap();
837
            let target = target_builder.protocols(protocols).build().unwrap();
838

            
839
            // TODO: This should fail since we don't support TAP handshakes.
840
            // But the channel will do an ntor handshake anyway even though it's not supported.
841
            // https://gitlab.torproject.org/tpo/core/arti/-/work_items/2489
842
            let _tunnel = pending_tunnel
843
                .create_firsthop(&target, circ_params)
844
                .await
845
                .unwrap();
846

            
847
            // TODO: As above, this is wrong.
848
            assert_eq!(
849
                conn_inspector.try_client_cell().unwrap().msg().cmd(),
850
                ChanCmd::CREATE2,
851
            );
852
            assert_eq!(
853
                conn_inspector.try_relay_cell().unwrap().msg().cmd(),
854
                ChanCmd::CREATED2,
855
            );
856
        });
857
    }
858

            
859
    #[test]
860
    fn ntor() {
861
        test_with_one_runtime!(|rt| async move {
862
            let mut conn_inspector = test_utils::ConnInspector::new();
863

            
864
            let (client_chan, _relay_chan, _circuit_stream_rx, mut target_builder) =
865
                test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
866

            
867
            // https://spec.torproject.org/tor-spec/subprotocol-versioning.html
868
            // 2 = RELAY_NTOR
869
            // 3 = RELAY_EXTEND_IPv6
870
            for relay_version in [2, 3] {
871
                let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
872

            
873
                let circ_params = CircParameters::default();
874

            
875
                let protocols = format!("Relay=2-{relay_version}").parse().unwrap();
876
                let target = target_builder.protocols(protocols).build().unwrap();
877

            
878
                let tunnel = pending_tunnel
879
                    .create_firsthop(&target, circ_params)
880
                    .await
881
                    .unwrap();
882

            
883
                let client_cell = conn_inspector.try_client_cell().unwrap().msg().clone();
884
                let relay_cell = conn_inspector.try_relay_cell().unwrap().msg().clone();
885

            
886
                // Check that we got CREATE2 and CREATED2.
887
                assert_eq!(client_cell.cmd(), ChanCmd::CREATE2);
888
                assert_eq!(relay_cell.cmd(), ChanCmd::CREATED2);
889

            
890
                // Check that it was an ntor handshake.
891
                let AnyChanMsg::Create2(client_cell) = client_cell else {
892
                    unreachable!("CREATE2 checked above");
893
                };
894
                assert_eq!(client_cell.handshake_type(), HandshakeType::NTOR);
895

            
896
                drop(tunnel);
897

            
898
                assert_eq!(
899
                    conn_inspector.client_cell().await.unwrap().msg().cmd(),
900
                    ChanCmd::DESTROY,
901
                );
902
                // The relay shouldn't be sending a DESTROY back to the client
903
                assert!(conn_inspector.try_relay_cell().is_none());
904
            }
905
        });
906
    }
907

            
908
    #[test]
909
    fn ntor_v3() {
910
        test_with_one_runtime!(|rt| async move {
911
            let mut conn_inspector = test_utils::ConnInspector::new();
912

            
913
            let (client_chan, _relay_chan, _circuit_stream_rx, mut target_builder) =
914
                test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
915

            
916
            // https://spec.torproject.org/tor-spec/subprotocol-versioning.html
917
            // 4 = RELAY_NTORV3
918
            // 5 = RELAY_NEGOTIATE_SUBPROTO
919
            // 6 = RELAY_CRYPT_CGO
920
            for relay_version in [4, 5, 6] {
921
                let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
922

            
923
                let circ_params = CircParameters::default();
924

            
925
                let protocols = format!("Relay=4-{relay_version}").parse().unwrap();
926
                let target = target_builder.protocols(protocols).build().unwrap();
927

            
928
                let tunnel = pending_tunnel
929
                    .create_firsthop(&target, circ_params)
930
                    .await
931
                    .unwrap();
932

            
933
                let client_cell = conn_inspector.try_client_cell().unwrap().msg().clone();
934
                let relay_cell = conn_inspector.try_relay_cell().unwrap().msg().clone();
935

            
936
                // Check that we got CREATE2 and CREATED2.
937
                assert_eq!(client_cell.cmd(), ChanCmd::CREATE2);
938
                assert_eq!(relay_cell.cmd(), ChanCmd::CREATED2);
939

            
940
                // Check that it was an ntor-v3 handshake.
941
                let AnyChanMsg::Create2(client_cell) = client_cell else {
942
                    unreachable!("CREATE2 checked above");
943
                };
944
                assert_eq!(client_cell.handshake_type(), HandshakeType::NTOR_V3);
945

            
946
                // TODO: It would be nice if we had a way to check that CGO was in use when
947
                // `relay_version` is >=6, but I don't see a nice way to do that.
948

            
949
                drop(tunnel);
950

            
951
                assert_eq!(
952
                    conn_inspector.client_cell().await.unwrap().msg().cmd(),
953
                    ChanCmd::DESTROY,
954
                );
955
                // The relay shouldn't be sending a DESTROY back to the client
956
                assert!(conn_inspector.try_relay_cell().is_none());
957
            }
958
        });
959
    }
960
}