1
//! Relay channel code.
2
//!
3
//! This contains relay specific channel code. In other words, everything that a relay needs to
4
//! establish a channel according to the Tor protocol.
5

            
6
pub(crate) mod create_handler;
7
pub(crate) mod handshake;
8
pub(crate) mod initiator;
9
pub(crate) mod responder;
10

            
11
pub use responder::MaybeVerifiableRelayResponderChannel;
12

            
13
use digest::Digest;
14
use futures::{AsyncRead, AsyncWrite};
15
use rand::RngExt;
16
use safelog::Sensitive;
17
use std::net::{IpAddr, SocketAddr};
18
use std::sync::Arc;
19
use std::time::UNIX_EPOCH;
20

            
21
use tor_cell::chancell::msg;
22
use tor_cert::EncodedEd25519Cert;
23
use tor_cert::rsa::EncodedRsaCrosscert;
24
use tor_cert::x509::TlsKeyAndCert;
25
use tor_error::internal;
26
use tor_linkspec::{HasRelayIds, OwnedChanTarget, RelayIdRef, RelayIdType};
27
use tor_llcrypto as ll;
28
use tor_llcrypto::pk::{
29
    ed25519::{Ed25519Identity, Ed25519SigningKey},
30
    rsa,
31
    rsa::RsaIdentity,
32
};
33
use tor_relay_crypto::pk::RelayLinkSigningKeypair;
34
use tor_rtcompat::{CertifiedConn, CoarseTimeProvider, SleepProvider, StreamOps};
35

            
36
use crate::channel::handshake::VerifiedChannel;
37
use crate::channel::{ClogDigest, SlogDigest};
38
use crate::peer::PeerAddr;
39
use crate::relay::CreateRequestHandler;
40
use crate::relay::channel::handshake::{AUTHTYPE_ED25519_SHA256_RFC5705, RelayResponderHandshake};
41
use crate::{Error, Result, channel::RelayInitiatorHandshake, memquota::ChannelAccount};
42

            
43
// TODO(relay): We should probably get those values from protover crate or some other
44
// crate that have all "network parameters" we support?
45
/// A list of link authentication that we support (LinkAuth).
46
pub(crate) static LINK_AUTH: &[u16] = &[AUTHTYPE_ED25519_SHA256_RFC5705];
47

            
48
/// Object containing the keys and certificates for channel authentication.
49
///
50
/// We use this intermediary object in order to not have tor-proto crate have access to the KeyMgr
51
/// meaning access to all keys. This restricts the view to what is needed.
52
pub struct RelayChannelAuthMaterial {
53
    /// The SHA256(DER(KP_relayid_rsa)) digest for the AUTHENTICATE cell CID.
54
    pub(crate) rsa_id_der_digest: [u8; 32],
55
    /// Our RSA identity `KP_relayid_rsa` (SHA1). Needed for HasRelayIds which is required to
56
    /// compare this with a [`tor_linkspec::ChanTarget`].
57
    pub(crate) rsa_id: RsaIdentity,
58
    /// Our Ed identity key (KP_relayid_ed). For the [`msg::Authenticate`] cell CID_ED field.
59
    pub(crate) ed_id: Ed25519Identity,
60
    /// Our link signing keypair. Used to sign the [`msg::Authenticate`] cell.
61
    pub(crate) link_sign_kp: RelayLinkSigningKeypair,
62
    /// The Ed25519 identity signing cert (CertType 4) for the [`msg::Certs`] cell.
63
    pub(crate) cert_id_sign_ed: EncodedEd25519Cert,
64
    /// The Ed25519 signing TLS cert (CertType 5) for the [`msg::Certs`] cell.
65
    pub(crate) cert_sign_tls_ed: EncodedEd25519Cert,
66
    /// The Ed25519 signing link auth cert (CertType 6) for the [`msg::Certs`] cell.
67
    pub(crate) cert_sign_link_auth_ed: EncodedEd25519Cert,
68
    /// Legacy: the RSA identity X509 cert (CertType 2) for the [`msg::Certs`] cell.
69
    ///
70
    /// We only have the bytes here as create_legacy_rsa_id_cert() takes a key and gives us back
71
    /// the encoded cert.
72
    pub(crate) cert_id_x509_rsa: Vec<u8>,
73
    /// Legacy: the RSA identity cert (CertType 7) for the [`msg::Certs`] cell.
74
    pub(crate) cert_id_rsa: EncodedRsaCrosscert,
75
    /// Tls key and cert. This is for the TLS acceptor object needed to be a responder (TLS server
76
    /// side).
77
    pub(crate) tls_key_and_cert: TlsKeyAndCert,
78
}
79

            
80
impl RelayChannelAuthMaterial {
81
    /// Constructor.
82
    #[allow(clippy::too_many_arguments)] // Yes, plethora of keys...
83
104
    pub fn new(
84
104
        rsa_id_pk: &rsa::PublicKey,
85
104
        ed_id: Ed25519Identity,
86
104
        link_sign_kp: RelayLinkSigningKeypair,
87
104
        cert_id_sign_ed: EncodedEd25519Cert,
88
104
        cert_sign_tls_ed: EncodedEd25519Cert,
89
104
        cert_sign_link_auth_ed: EncodedEd25519Cert,
90
104
        cert_id_x509_rsa: Vec<u8>,
91
104
        cert_id_rsa: EncodedRsaCrosscert,
92
104
        tls_key_and_cert: TlsKeyAndCert,
93
104
    ) -> Self {
94
104
        Self {
95
104
            rsa_id_der_digest: ll::d::Sha256::digest(rsa_id_pk.to_der()).into(),
96
104
            rsa_id: rsa_id_pk.to_rsa_identity(),
97
104
            ed_id,
98
104
            link_sign_kp,
99
104
            cert_id_sign_ed,
100
104
            cert_sign_tls_ed,
101
104
            cert_sign_link_auth_ed,
102
104
            cert_id_x509_rsa,
103
104
            cert_id_rsa,
104
104
            tls_key_and_cert,
105
104
        }
106
104
    }
107

            
108
    /// Return the TLS key and certificate to use for the underlying TLS provider.
109
    ///
110
    /// This is used by the TLS acceptor that acts as the TLS server provider.
111
    pub fn tls_key_and_cert(&self) -> &TlsKeyAndCert {
112
        &self.tls_key_and_cert
113
    }
114

            
115
    /// Return our Ed identity key (KP_relayid_ed) as bytes.
116
    pub(crate) fn ed_id_bytes(&self) -> [u8; 32] {
117
        self.ed_id.into()
118
    }
119
}
120

            
121
impl HasRelayIds for RelayChannelAuthMaterial {
122
    fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
123
        match key_type {
124
            RelayIdType::Ed25519 => Some(RelayIdRef::from(&self.ed_id)),
125
            RelayIdType::Rsa => Some(RelayIdRef::from(&self.rsa_id)),
126
            _ => None, // Non-exhaustive...
127
        }
128
    }
129
}
130

            
131
/// Structure for building and launching a relay Tor channel.
132
#[derive(Default)]
133
#[non_exhaustive]
134
pub struct RelayChannelBuilder;
135

            
136
impl RelayChannelBuilder {
137
    /// Constructor.
138
    pub fn new() -> Self {
139
        Self::default()
140
    }
141

            
142
    /// Launch a new handshake over a TLS stream.
143
    ///
144
    /// After calling this function, you'll need to call `connect()` on the result to start the
145
    /// handshake.  If that succeeds, you'll have authentication info from the relay: call
146
    /// `check()` on the result to check that.  Finally, to finish the handshake, call `finish()`
147
    /// on the result of _that_.
148
    #[allow(clippy::too_many_arguments)] // TODO consider if we want a builder
149
    pub fn launch<T, S>(
150
        self,
151
        tls: T,
152
        sleep_prov: S,
153
        auth_material: Arc<RelayChannelAuthMaterial>,
154
        my_addrs: Vec<SocketAddr>,
155
        peer_target: &OwnedChanTarget,
156
        memquota: ChannelAccount,
157
        create_request_handler: Arc<CreateRequestHandler>,
158
    ) -> RelayInitiatorHandshake<T, S>
159
    where
160
        T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
161
        S: CoarseTimeProvider + SleepProvider,
162
    {
163
        RelayInitiatorHandshake::new(
164
            tls,
165
            sleep_prov,
166
            auth_material,
167
            my_addrs,
168
            peer_target,
169
            memquota,
170
            create_request_handler,
171
        )
172
    }
173

            
174
    /// Accept a new handshake over a TLS stream.
175
    #[expect(clippy::too_many_arguments)]
176
    pub fn accept<T, S>(
177
        self,
178
        peer_addr: Sensitive<PeerAddr>,
179
        my_addrs: Vec<SocketAddr>,
180
        tls: T,
181
        sleep_prov: S,
182
        auth_material: Arc<RelayChannelAuthMaterial>,
183
        memquota: ChannelAccount,
184
        create_request_handler: Arc<CreateRequestHandler>,
185
    ) -> RelayResponderHandshake<T, S>
186
    where
187
        T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
188
        S: CoarseTimeProvider + SleepProvider,
189
    {
190
        RelayResponderHandshake::new(
191
            peer_addr,
192
            my_addrs,
193
            tls,
194
            sleep_prov,
195
            auth_material,
196
            memquota,
197
            create_request_handler,
198
        )
199
    }
200
}
201

            
202
/// Channel authentication data. This is only relevant for a Relay to Relay channel which are
203
/// authenticated using this buffet of bytes.
204
pub(crate) struct ChannelAuthenticationData {
205
    /// Authentication method to use.
206
    pub(crate) link_auth: u16,
207
    /// SHA256 digest of the initiator KP_relayid_rsa.
208
    pub(crate) cid: [u8; 32],
209
    /// SHA256 digest of the responder KP_relayid_rsa.
210
    pub(crate) sid: [u8; 32],
211
    /// The initiator KP_relayid_ed.
212
    pub(crate) cid_ed: [u8; 32],
213
    /// The responder KP_relayid_ed.
214
    pub(crate) sid_ed: [u8; 32],
215
    /// Initiator log SHA256 digest.
216
    pub(crate) clog: ClogDigest,
217
    /// Responder log SHA256 digest.
218
    pub(crate) slog: SlogDigest,
219
    /// SHA256 of responder's TLS certificate.
220
    pub(crate) scert: [u8; 32],
221
}
222

            
223
impl ChannelAuthenticationData {
224
    /// Helper: return the authentication type string from the given link auth version.
225
    const fn auth_type_bytes(link_auth: u16) -> Result<&'static [u8]> {
226
        match link_auth {
227
            3 => Ok(b"AUTH0003"),
228
            _ => Err(Error::BadCellAuth),
229
        }
230
    }
231

            
232
    /// Helper: return the keying material label from the given link auth version.
233
    const fn keying_material_label_bytes(link_auth: u16) -> Result<&'static [u8]> {
234
        match link_auth {
235
            3 => Ok(b"EXPORTER FOR TOR TLS CLIENT BINDING AUTH0003"),
236
            _ => Err(Error::BadCellAuth),
237
        }
238
    }
239

            
240
    /// Return a vector of bytes of an [`msg::Authenticate`] cell but without the random bytes and
241
    /// the signature.
242
    ///
243
    /// This is needed so a responder can compare what is expected from what it got. A responder
244
    /// can only verify the signature and so we can't compare the full [`msg::Authenticate`]
245
    /// message we received with what we expect.
246
    pub(crate) fn as_body_no_rand<C: CertifiedConn>(&self, tls: &C) -> Result<Vec<u8>> {
247
        // The body without the rand and sig is exactly 264 bytes so optimize a bit memory.
248
        let mut body = Vec::with_capacity(msg::Authenticate::BODY_LEN);
249

            
250
        // Obviously, ordering matteres. See tor-spec section Ed25519-SHA256-RFC5705
251
        body.extend_from_slice(Self::auth_type_bytes(self.link_auth)?);
252
        body.extend_from_slice(&self.cid);
253
        body.extend_from_slice(&self.sid);
254
        body.extend_from_slice(&self.cid_ed);
255
        body.extend_from_slice(&self.sid_ed);
256
        body.extend_from_slice(self.slog.as_ref());
257
        body.extend_from_slice(self.clog.as_ref());
258
        body.extend_from_slice(&self.scert);
259

            
260
        // TLSSECRETS is built from the CID.
261
        let tls_secrets = tls.export_keying_material(
262
            32,
263
            Self::keying_material_label_bytes(self.link_auth)?,
264
            Some(&self.cid[..]),
265
        )?;
266
        body.extend_from_slice(tls_secrets.as_slice());
267

            
268
        // Make sure our Authenticate cell is filled.
269
        debug_assert_eq!(body.len(), msg::Authenticate::BODY_LEN);
270
        debug_assert_eq!(body.capacity(), msg::Authenticate::BODY_LEN);
271

            
272
        Ok(body)
273
    }
274

            
275
    /// Consume ourself and return an AUTHENTICATE cell from the data we hold.
276
    pub(crate) fn into_authenticate<C: CertifiedConn>(
277
        self,
278
        tls: &C,
279
        link_ed: &RelayLinkSigningKeypair,
280
    ) -> Result<msg::Authenticate> {
281
        // Get us everything except the random bytes and signature.
282
        let mut body = self.as_body_no_rand(tls)?;
283

            
284
        // Add the random bytes.
285
        let random: [u8; 24] = rand::rng().random();
286
        body.extend_from_slice(&random);
287

            
288
        // Create signature with our KP_link_ed and append it to body. We hard expect the
289
        // KP_link_ed because this would be a code flow error.
290
        let sig = link_ed.sign(&body);
291
        body.extend_from_slice(&sig.to_bytes());
292

            
293
        // Lets go with the AUTHENTICATE cell.
294
        Ok(msg::Authenticate::new(self.link_auth, body))
295
    }
296

            
297
    /// Build a [`ChannelAuthenticationData`] for an initiator channel handshake.
298
    ///
299
    /// `auth_challenge_cell` is the [`msg::AuthChallenge`] we recevied during the handshake.
300
    ///
301
    /// `identities` are our [`RelayChannelAuthMaterial`]
302
    ///
303
    /// `verified` is a [`VerifiedChannel`] which we need to consume the CLOG/SLOG
304
    ///
305
    /// `peer_cert_digest` is the TLS certificate presented by the peer.
306
    pub(crate) fn build_initiator<T, S>(
307
        auth_challenge_cell: &msg::AuthChallenge,
308
        auth_material: &Arc<RelayChannelAuthMaterial>,
309
        clog: ClogDigest,
310
        slog: SlogDigest,
311
        verified: &mut VerifiedChannel<T, S>,
312
        peer_cert_digest: [u8; 32],
313
    ) -> Result<ChannelAuthenticationData>
314
    where
315
        T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
316
        S: CoarseTimeProvider + SleepProvider,
317
    {
318
        // Keep what we know from the AUTH_CHALLENGE and we max() on it.
319
        let link_auth = *LINK_AUTH
320
            .iter()
321
            .filter(|m| auth_challenge_cell.methods().contains(m))
322
            .max()
323
            .ok_or(Error::BadCellAuth)?;
324
        // The ordering matter as this is an initiator.
325
        let cid = auth_material.rsa_id_der_digest;
326
        let sid = verified.peer_rsa_id_digest;
327
        let cid_ed = auth_material.ed_id_bytes();
328
        let sid_ed = (*verified
329
            .relay_ids()
330
            .ed_identity()
331
            .expect("Verified channel without Ed25519 identity"))
332
        .into();
333

            
334
        Ok(Self {
335
            link_auth,
336
            cid,
337
            sid,
338
            cid_ed,
339
            sid_ed,
340
            clog,
341
            slog,
342
            scert: peer_cert_digest,
343
        })
344
    }
345

            
346
    /// Build a [`ChannelAuthenticationData`] for a responder channel handshake.
347
    ///
348
    /// `initiator_auth_type` is the authentication type from the [`msg::Authenticate`] received
349
    /// from the initiator.
350
    ///
351
    /// `auth_material` are our [`RelayChannelAuthMaterial`]
352
    ///
353
    /// `verified` is a [`VerifiedChannel`] which we need to consume the CLOG/SLOG
354
    ///
355
    /// `our_cert_digest` is our TLS certificate that we presented as a channel responder.
356
    ///
357
    /// IMPORTANT: The CLOG and SLOG from the framed_tls codec is consumed here so calling twice
358
    /// build_auth_data() will result in different AUTHENTICATE cells.
359
    pub(crate) fn build_responder(
360
        initiator_auth_type: u16,
361
        auth_material: &Arc<RelayChannelAuthMaterial>,
362
        clog: ClogDigest,
363
        slog: SlogDigest,
364
        peer_rsa_id_digest: [u8; 32],
365
        peer_relayid_ed: Ed25519Identity,
366
        our_cert_digest: [u8; 32],
367
    ) -> Result<ChannelAuthenticationData> {
368
        // Max on what we know.
369
        let link_auth = if LINK_AUTH.contains(&initiator_auth_type) {
370
            initiator_auth_type
371
        } else {
372
            return Err(Error::UnsupportedAuth(initiator_auth_type));
373
        };
374
        // The ordering matter as this is a respodner. It is inversed from the initiator.
375
        let cid = auth_material.rsa_id_der_digest;
376
        let sid = peer_rsa_id_digest;
377
        let cid_ed = auth_material.ed_id_bytes();
378
        let sid_ed = peer_relayid_ed.into();
379

            
380
        Ok(Self {
381
            link_auth,
382
            // Notice, everything is inversed here as the responder.
383
            cid: sid,
384
            sid: cid,
385
            cid_ed: sid_ed,
386
            sid_ed: cid_ed,
387
            clog,
388
            slog,
389
            scert: our_cert_digest,
390
        })
391
    }
392
}
393

            
394
/// Helper: Build a [`msg::Certs`] cell for the given relay identities and channel type.
395
///
396
/// Both relay initiator and responder handshake use this.
397
4
pub(crate) fn build_certs_cell(
398
4
    auth_material: &Arc<RelayChannelAuthMaterial>,
399
4
    is_responder: bool,
400
4
) -> msg::Certs {
401
4
    let mut certs = msg::Certs::new_empty();
402
    // Push into the cell the CertType 2 RSA (RSA_ID_X509)
403
4
    certs.push_cert_body(
404
        tor_cert::CertType::RSA_ID_X509,
405
4
        auth_material.cert_id_x509_rsa.clone(),
406
    );
407

            
408
    // Push into the cell the CertType 7 RSA (RSA_ID_V_IDENTITY)
409
4
    certs.push_cert(&auth_material.cert_id_rsa);
410

            
411
    // Push into the cell the CertType 4 Ed25519 (IDENTITY_V_SIGNING)
412
4
    certs.push_cert(&auth_material.cert_id_sign_ed);
413
    // Push into the cell the CertType 5/6 Ed25519
414
4
    if is_responder {
415
        // Responder has CertType 5 (SIGNING_V_TLS)
416
        certs.push_cert(&auth_material.cert_sign_tls_ed);
417
4
    } else {
418
4
        // Initiator has CertType 6 (SIGINING_V_LINK_AUTH)
419
4
        certs.push_cert(&auth_material.cert_sign_link_auth_ed);
420
4
    }
421
4
    certs
422
4
}
423

            
424
/// Build a [`msg::Netinfo`] cell from the given peer IPs and our advertised addresses.
425
///
426
/// Both relay initiator and responder handshake use this.
427
pub(crate) fn build_netinfo_cell<S>(
428
    peer_ip: Option<IpAddr>,
429
    my_addrs: Vec<IpAddr>,
430
    sleep_prov: &S,
431
) -> Result<msg::Netinfo>
432
where
433
    S: CoarseTimeProvider + SleepProvider,
434
{
435
    // Unix timestamp but over 32bit. This will be sad in 2038 but proposal 338 addresses this
436
    // issue with a change to 64bit.
437
    let timestamp = sleep_prov
438
        .wallclock()
439
        .duration_since(UNIX_EPOCH)
440
        .map_err(|e| internal!("Wallclock may have gone backwards: {e}"))?
441
        .as_secs()
442
        .try_into()
443
        .map_err(|e| internal!("Wallclock secs fail to convert to 32bit: {e}"))?;
444
    Ok(msg::Netinfo::from_relay(timestamp, peer_ip, my_addrs))
445
}
446

            
447
#[cfg(test)]
448
pub(crate) mod test {
449
    #![allow(clippy::unwrap_used)]
450
    use futures::task::{Context, Poll};
451
    use futures::{AsyncRead, AsyncWrite};
452
    use std::borrow::Cow;
453
    use std::io::Result as IoResult;
454
    use std::pin::Pin;
455
    use std::sync::{Arc, Mutex, OnceLock};
456
    use std::time::{Duration, SystemTime};
457

            
458
    use tor_basic_utils::test_rng::testing_rng;
459
    use tor_cert::x509::TlsKeyAndCert;
460
    use tor_key_forge::{Keygen, ToEncodableCert};
461
    use tor_linkspec::OwnedChanTarget;
462
    use tor_relay_crypto::pk::{
463
        RelayIdentityKeypair, RelayIdentityRsaKeypair, RelayLinkSigningKeypair, RelaySigningKeypair,
464
    };
465
    use tor_relay_crypto::{gen_link_cert, gen_signing_cert, gen_tls_cert};
466
    use tor_rtcompat::{CertifiedConn, Runtime, StreamOps};
467
    use web_time_compat::SystemTimeExt;
468

            
469
    use crate::channel::ChannelMode;
470
    use crate::channel::handler::test::MsgBuf;
471
    use crate::channel::test_utils::DummyChan;
472
    use crate::circuit::UniqId;
473
    use crate::relay::channel::RelayChannelAuthMaterial;
474
    use crate::relay::channel_provider::{ChannelProvider, OutboundChanSender};
475

            
476
    /// Wrapper around [`MsgBuf`] that implements [`CertifiedConn`] which is needed by the relay
477
    /// handshake.
478
    pub(crate) struct RelayMsgBuf(pub(crate) MsgBuf);
479

            
480
    impl AsyncRead for RelayMsgBuf {
481
        fn poll_read(
482
            mut self: Pin<&mut Self>,
483
            cx: &mut Context<'_>,
484
            buf: &mut [u8],
485
        ) -> Poll<IoResult<usize>> {
486
            Pin::new(&mut self.0).poll_read(cx, buf)
487
        }
488
    }
489

            
490
    impl AsyncWrite for RelayMsgBuf {
491
        fn poll_write(
492
            mut self: Pin<&mut Self>,
493
            cx: &mut Context<'_>,
494
            buf: &[u8],
495
        ) -> Poll<IoResult<usize>> {
496
            Pin::new(&mut self.0).poll_write(cx, buf)
497
        }
498
        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>> {
499
            Pin::new(&mut self.0).poll_flush(cx)
500
        }
501
        fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>> {
502
            Pin::new(&mut self.0).poll_close(cx)
503
        }
504
    }
505

            
506
    impl StreamOps for RelayMsgBuf {}
507

            
508
    impl CertifiedConn for RelayMsgBuf {
509
        fn export_keying_material(
510
            &self,
511
            len: usize,
512
            _label: &[u8],
513
            _context: Option<&[u8]>,
514
        ) -> IoResult<Vec<u8>> {
515
            Ok(vec![42_u8; len])
516
        }
517
        fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
518
            const ISSUER: &str = "issuer.peer_tls.test.nowar.net";
519
            const SUBJECT: &str = "subject.peer_tls.test.nowar.net";
520
            Ok(Some(fake_tls_cert(ISSUER, SUBJECT)))
521
        }
522
        fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
523
            const ISSUER: &str = "issuer.own_tls.test.nowar.net";
524
            const SUBJECT: &str = "subject.own_tls.test.nowar.net";
525
            Ok(Some(fake_tls_cert(ISSUER, SUBJECT)))
526
        }
527
    }
528

            
529
    fn fake_tls_cert<'a>(issuer: &'a str, subject: &'a str) -> Cow<'a, [u8]> {
530
        let mut rng = testing_rng();
531
        let tls_cert = TlsKeyAndCert::create(&mut rng, SystemTime::get(), issuer, subject).unwrap();
532
        Cow::Owned(tls_cert.certificates_der()[0].to_vec())
533
    }
534

            
535
    pub(crate) struct DummyChanProvider<R> {
536
        /// A handle to the runtime.
537
        runtime: R,
538
        /// The outbound channel, shared with the test controller.
539
        outbound: Arc<Mutex<Option<DummyChan>>>,
540
    }
541

            
542
    impl<R: Runtime> DummyChanProvider<R> {
543
        pub(crate) fn new(runtime: R, outbound: Arc<Mutex<Option<DummyChan>>>) -> Self {
544
            Self { runtime, outbound }
545
        }
546

            
547
        /// Sometimes, no need for the channel.
548
        pub(crate) fn new_without_chan(runtime: R) -> Self {
549
            Self {
550
                runtime,
551
                outbound: Arc::new(Mutex::new(None)),
552
            }
553
        }
554
    }
555

            
556
    impl<R: Runtime> ChannelProvider for DummyChanProvider<R> {
557
        type BuildSpec = OwnedChanTarget;
558

            
559
        fn get_or_launch(
560
            self: Arc<Self>,
561
            _reactor_id: UniqId,
562
            _target: Self::BuildSpec,
563
            tx: OutboundChanSender,
564
        ) -> crate::Result<()> {
565
            // Note: this will create channels in Client mode, which isn't strictly right,
566
            // but our relay circuit reactor tests don't currently require Relay-mode
567
            // for the channels they initiate. If this becomes a problem, we should
568
            // update the DummyChanProvider constructor to take all the pieces it
569
            // needs for building a ChannelMode::Relay here
570
            let mode = ChannelMode::Client;
571
            let dummy_chan = DummyChan::run(&self.runtime, mode);
572
            let chan = Arc::clone(&dummy_chan.channel);
573
            {
574
                let mut lock = self.outbound.lock().unwrap();
575
                assert!(lock.is_none());
576
                *lock = Some(dummy_chan);
577
            }
578

            
579
            tx.send(Ok(chan));
580

            
581
            Ok(())
582
        }
583
    }
584

            
585
    /// Returns a fake [`RelayChannelAuthMaterial`]. The keys are generated once and reused across
586
    /// tests to avoid repeated expensive key generation using a strong RNG.
587
    pub(crate) fn fake_auth_material() -> Arc<RelayChannelAuthMaterial> {
588
        const KEY_DURATION_2DAYS: Duration = Duration::from_secs(2 * 24 * 60 * 60);
589
        const KEY_DURATION_30DAYS: Duration = Duration::from_secs(30 * 24 * 60 * 60);
590

            
591
        static AUTH: OnceLock<Arc<RelayChannelAuthMaterial>> = OnceLock::new();
592
        AUTH.get_or_init(|| {
593
            let now = SystemTime::get();
594
            // Need this RNG because KeygenRng trait is required.
595
            let mut rng = tor_llcrypto::rng::CautiousRng;
596

            
597
            let issuer_hostname = "issuer.test.nowar.net";
598
            let subject_hostname = "subject.test.nowar.net";
599

            
600
            // RSA keypair.
601
            let kp_relayid_rsa = RelayIdentityRsaKeypair::generate(&mut rng).unwrap();
602

            
603
            // Ed25519 keypairs
604
            let kp_relayid_ed = RelayIdentityKeypair::generate(&mut rng).unwrap();
605
            let kp_relaysign_ed = RelaySigningKeypair::generate(&mut rng).unwrap();
606
            let kp_link_ed = RelayLinkSigningKeypair::generate(&mut rng).unwrap();
607

            
608
            // TLS key and certificate.
609
            let tls_key_and_cert =
610
                TlsKeyAndCert::create(&mut rng, now, issuer_hostname, subject_hostname).unwrap();
611

            
612
            // Certificate for the CERTS cell.
613
            let cert_id_sign_ed =
614
                gen_signing_cert(&kp_relayid_ed, &kp_relaysign_ed, now + KEY_DURATION_30DAYS)
615
                    .unwrap();
616
            let cert_sign_link_auth_ed =
617
                gen_link_cert(&kp_relaysign_ed, &kp_link_ed, now + KEY_DURATION_2DAYS).unwrap();
618
            let cert_sign_tls_ed = gen_tls_cert(
619
                &kp_relaysign_ed,
620
                *tls_key_and_cert.link_cert_sha256(),
621
                now + KEY_DURATION_2DAYS,
622
            )
623
            .unwrap();
624

            
625
            // Cross-certifying cert RSA->Ed
626
            let cert_id_rsa = tor_cert::rsa::EncodedRsaCrosscert::encode_and_sign(
627
                kp_relayid_rsa.keypair(),
628
                &kp_relayid_ed.to_ed25519_id(),
629
                now + KEY_DURATION_2DAYS,
630
            )
631
            .unwrap();
632

            
633
            // Legacy X509 RSA cert.
634
            let cert_id_x509_rsa = tor_cert::x509::create_legacy_rsa_id_cert(
635
                &mut rng,
636
                now,
637
                issuer_hostname,
638
                kp_relayid_rsa.keypair(),
639
            )
640
            .unwrap();
641

            
642
            Arc::new(RelayChannelAuthMaterial::new(
643
                &kp_relayid_rsa.public().into(),
644
                kp_relayid_ed.to_ed25519_id(),
645
                kp_link_ed,
646
                cert_id_sign_ed.to_encodable_cert(),
647
                cert_sign_tls_ed,
648
                cert_sign_link_auth_ed.to_encodable_cert(),
649
                cert_id_x509_rsa,
650
                cert_id_rsa,
651
                tls_key_and_cert,
652
            ))
653
        })
654
        .clone()
655
    }
656
}