Skip to main content

tor_proto/relay/
channel.rs

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
6pub(crate) mod create_handler;
7pub(crate) mod handshake;
8pub(crate) mod initiator;
9pub(crate) mod responder;
10
11pub use responder::MaybeVerifiableRelayResponderChannel;
12
13use digest::Digest;
14use futures::{AsyncRead, AsyncWrite};
15use rand::Rng;
16use safelog::Sensitive;
17use std::net::{IpAddr, SocketAddr};
18use std::sync::Arc;
19use std::time::UNIX_EPOCH;
20
21use tor_cell::chancell::msg;
22use tor_cert::EncodedEd25519Cert;
23use tor_cert::rsa::EncodedRsaCrosscert;
24use tor_cert::x509::TlsKeyAndCert;
25use tor_error::internal;
26use tor_linkspec::{HasRelayIds, OwnedChanTarget, RelayIdRef, RelayIdType};
27use tor_llcrypto as ll;
28use tor_llcrypto::pk::{
29    ed25519::{Ed25519Identity, Ed25519SigningKey},
30    rsa,
31    rsa::RsaIdentity,
32};
33use tor_relay_crypto::pk::RelayLinkSigningKeypair;
34use tor_rtcompat::{CertifiedConn, CoarseTimeProvider, SleepProvider, StreamOps};
35
36use crate::channel::handshake::VerifiedChannel;
37use crate::channel::{ClogDigest, SlogDigest};
38use crate::peer::PeerAddr;
39use crate::relay::CreateRequestHandler;
40use crate::relay::channel::handshake::{AUTHTYPE_ED25519_SHA256_RFC5705, RelayResponderHandshake};
41use 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).
46pub(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.
52pub 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
80impl RelayChannelAuthMaterial {
81    /// Constructor.
82    #[allow(clippy::too_many_arguments)] // Yes, plethora of keys...
83    pub fn new(
84        rsa_id_pk: &rsa::PublicKey,
85        ed_id: Ed25519Identity,
86        link_sign_kp: RelayLinkSigningKeypair,
87        cert_id_sign_ed: EncodedEd25519Cert,
88        cert_sign_tls_ed: EncodedEd25519Cert,
89        cert_sign_link_auth_ed: EncodedEd25519Cert,
90        cert_id_x509_rsa: Vec<u8>,
91        cert_id_rsa: EncodedRsaCrosscert,
92        tls_key_and_cert: TlsKeyAndCert,
93    ) -> Self {
94        Self {
95            rsa_id_der_digest: ll::d::Sha256::digest(rsa_id_pk.to_der()).into(),
96            rsa_id: rsa_id_pk.to_rsa_identity(),
97            ed_id,
98            link_sign_kp,
99            cert_id_sign_ed,
100            cert_sign_tls_ed,
101            cert_sign_link_auth_ed,
102            cert_id_x509_rsa,
103            cert_id_rsa,
104            tls_key_and_cert,
105        }
106    }
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
121impl 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]
134pub struct RelayChannelBuilder;
135
136impl 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.
204pub(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
223impl 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.
397pub(crate) fn build_certs_cell(
398    auth_material: &Arc<RelayChannelAuthMaterial>,
399    is_responder: bool,
400) -> msg::Certs {
401    let mut certs = msg::Certs::new_empty();
402    // Push into the cell the CertType 2 RSA (RSA_ID_X509)
403    certs.push_cert_body(
404        tor_cert::CertType::RSA_ID_X509,
405        auth_material.cert_id_x509_rsa.clone(),
406    );
407
408    // Push into the cell the CertType 7 RSA (RSA_ID_V_IDENTITY)
409    certs.push_cert(&auth_material.cert_id_rsa);
410
411    // Push into the cell the CertType 4 Ed25519 (IDENTITY_V_SIGNING)
412    certs.push_cert(&auth_material.cert_id_sign_ed);
413    // Push into the cell the CertType 5/6 Ed25519
414    if is_responder {
415        // Responder has CertType 5 (SIGNING_V_TLS)
416        certs.push_cert(&auth_material.cert_sign_tls_ed);
417    } else {
418        // Initiator has CertType 6 (SIGINING_V_LINK_AUTH)
419        certs.push_cert(&auth_material.cert_sign_link_auth_ed);
420    }
421    certs
422}
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.
427pub(crate) fn build_netinfo_cell<S>(
428    peer_ip: Option<IpAddr>,
429    my_addrs: Vec<IpAddr>,
430    sleep_prov: &S,
431) -> Result<msg::Netinfo>
432where
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)]
448pub(crate) mod test {
449    #![allow(clippy::unwrap_used)]
450    use futures::channel::mpsc::{Receiver, Sender};
451    use futures::task::{Context, Poll};
452    use futures::{AsyncRead, AsyncWrite};
453    use std::borrow::Cow;
454    use std::io::Result as IoResult;
455    use std::pin::Pin;
456    use std::sync::{Arc, Mutex, OnceLock};
457    use std::time::{Duration, SystemTime};
458
459    use tor_basic_utils::test_rng::testing_rng;
460    use tor_cell::chancell::AnyChanCell;
461    use tor_cert::x509::TlsKeyAndCert;
462    use tor_key_forge::{Keygen, ToEncodableCert};
463    use tor_linkspec::OwnedChanTarget;
464    use tor_relay_crypto::pk::{
465        RelayIdentityKeypair, RelayIdentityRsaKeypair, RelayLinkSigningKeypair, RelaySigningKeypair,
466    };
467    use tor_relay_crypto::{gen_link_cert, gen_signing_cert, gen_tls_cert};
468    use tor_rtcompat::{CertifiedConn, Runtime, SpawnExt, StreamOps};
469    use web_time_compat::SystemTimeExt;
470
471    use crate::channel::Channel;
472    use crate::channel::handler::test::MsgBuf;
473    use crate::channel::test::{CodecResult, new_reactor};
474    use crate::circuit::UniqId;
475    use crate::relay::channel::RelayChannelAuthMaterial;
476    use crate::relay::channel_provider::{ChannelProvider, OutboundChanSender};
477
478    /// Wrapper around [`MsgBuf`] that implements [`CertifiedConn`] which is needed by the relay
479    /// handshake.
480    pub(crate) struct RelayMsgBuf(pub(crate) MsgBuf);
481
482    impl AsyncRead for RelayMsgBuf {
483        fn poll_read(
484            mut self: Pin<&mut Self>,
485            cx: &mut Context<'_>,
486            buf: &mut [u8],
487        ) -> Poll<IoResult<usize>> {
488            Pin::new(&mut self.0).poll_read(cx, buf)
489        }
490    }
491
492    impl AsyncWrite for RelayMsgBuf {
493        fn poll_write(
494            mut self: Pin<&mut Self>,
495            cx: &mut Context<'_>,
496            buf: &[u8],
497        ) -> Poll<IoResult<usize>> {
498            Pin::new(&mut self.0).poll_write(cx, buf)
499        }
500        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>> {
501            Pin::new(&mut self.0).poll_flush(cx)
502        }
503        fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>> {
504            Pin::new(&mut self.0).poll_close(cx)
505        }
506    }
507
508    impl StreamOps for RelayMsgBuf {}
509
510    impl CertifiedConn for RelayMsgBuf {
511        fn export_keying_material(
512            &self,
513            len: usize,
514            _label: &[u8],
515            _context: Option<&[u8]>,
516        ) -> IoResult<Vec<u8>> {
517            Ok(vec![42_u8; len])
518        }
519        fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
520            const ISSUER: &str = "issuer.peer_tls.test.nowar.net";
521            const SUBJECT: &str = "subject.peer_tls.test.nowar.net";
522            Ok(Some(fake_tls_cert(ISSUER, SUBJECT)))
523        }
524        fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
525            const ISSUER: &str = "issuer.own_tls.test.nowar.net";
526            const SUBJECT: &str = "subject.own_tls.test.nowar.net";
527            Ok(Some(fake_tls_cert(ISSUER, SUBJECT)))
528        }
529    }
530
531    fn fake_tls_cert<'a>(issuer: &'a str, subject: &'a str) -> Cow<'a, [u8]> {
532        let mut rng = testing_rng();
533        let tls_cert = TlsKeyAndCert::create(&mut rng, SystemTime::get(), issuer, subject).unwrap();
534        Cow::Owned(tls_cert.certificates_der()[0].to_vec())
535    }
536
537    pub(crate) struct DummyChanProvider<R> {
538        /// A handle to the runtime.
539        runtime: R,
540        /// The outbound channel, shared with the test controller.
541        outbound: Arc<Mutex<Option<DummyChan>>>,
542    }
543
544    impl<R: Runtime> DummyChanProvider<R> {
545        pub(crate) fn new(runtime: R, outbound: Arc<Mutex<Option<DummyChan>>>) -> Self {
546            Self { runtime, outbound }
547        }
548
549        /// Sometimes, no need for the channel.
550        pub(crate) fn new_without_chan(runtime: R) -> Self {
551            Self {
552                runtime,
553                outbound: Arc::new(Mutex::new(None)),
554            }
555        }
556    }
557
558    impl<R: Runtime> ChannelProvider for DummyChanProvider<R> {
559        type BuildSpec = OwnedChanTarget;
560
561        fn get_or_launch(
562            self: Arc<Self>,
563            _reactor_id: UniqId,
564            _target: Self::BuildSpec,
565            tx: OutboundChanSender,
566        ) -> crate::Result<()> {
567            let dummy_chan = working_dummy_channel(&self.runtime);
568            let chan = Arc::clone(&dummy_chan.channel);
569            {
570                let mut lock = self.outbound.lock().unwrap();
571                assert!(lock.is_none());
572                *lock = Some(dummy_chan);
573            }
574
575            tx.send(Ok(chan));
576
577            Ok(())
578        }
579    }
580
581    /// Dummy channel, returned by [`working_fake_channel`].
582    pub(crate) struct DummyChan {
583        /// Tor channel output
584        pub(crate) rx: Receiver<AnyChanCell>,
585        /// Tor channel input
586        pub(crate) tx: Sender<CodecResult>,
587        /// A handle to the Channel object, to prevent the channel reactor
588        /// from shutting down prematurely.
589        pub(crate) channel: Arc<Channel>,
590    }
591
592    pub(crate) fn working_dummy_channel<R: Runtime>(rt: &R) -> DummyChan {
593        let (channel, chan_reactor, rx, tx) = new_reactor(rt.clone());
594        rt.spawn(async {
595            let _ignore = chan_reactor.run().await;
596        })
597        .unwrap();
598
599        DummyChan { tx, rx, channel }
600    }
601
602    /// Returns a fake [`RelayChannelAuthMaterial`]. The keys are generated once and reused across
603    /// tests to avoid repeated expensive key generation using a strong RNG.
604    pub(crate) fn fake_auth_material() -> Arc<RelayChannelAuthMaterial> {
605        const KEY_DURATION_2DAYS: Duration = Duration::from_secs(2 * 24 * 60 * 60);
606        const KEY_DURATION_30DAYS: Duration = Duration::from_secs(30 * 24 * 60 * 60);
607
608        static AUTH: OnceLock<Arc<RelayChannelAuthMaterial>> = OnceLock::new();
609        AUTH.get_or_init(|| {
610            let now = SystemTime::get();
611            // Need this RNG because KeygenRng trait is required.
612            let mut rng = tor_llcrypto::rng::CautiousRng;
613
614            let issuer_hostname = "issuer.test.nowar.net";
615            let subject_hostname = "subject.test.nowar.net";
616
617            // RSA keypair.
618            let kp_relayid_rsa = RelayIdentityRsaKeypair::generate(&mut rng).unwrap();
619
620            // Ed25519 keypairs
621            let kp_relayid_ed = RelayIdentityKeypair::generate(&mut rng).unwrap();
622            let kp_relaysign_ed = RelaySigningKeypair::generate(&mut rng).unwrap();
623            let kp_link_ed = RelayLinkSigningKeypair::generate(&mut rng).unwrap();
624
625            // TLS key and certificate.
626            let tls_key_and_cert =
627                TlsKeyAndCert::create(&mut rng, now, issuer_hostname, subject_hostname).unwrap();
628
629            // Certificate for the CERTS cell.
630            let cert_id_sign_ed =
631                gen_signing_cert(&kp_relayid_ed, &kp_relaysign_ed, now + KEY_DURATION_30DAYS)
632                    .unwrap();
633            let cert_sign_link_auth_ed =
634                gen_link_cert(&kp_relaysign_ed, &kp_link_ed, now + KEY_DURATION_2DAYS).unwrap();
635            let cert_sign_tls_ed = gen_tls_cert(
636                &kp_relaysign_ed,
637                *tls_key_and_cert.link_cert_sha256(),
638                now + KEY_DURATION_2DAYS,
639            )
640            .unwrap();
641
642            // Cross-certifying cert RSA->Ed
643            let cert_id_rsa = tor_cert::rsa::EncodedRsaCrosscert::encode_and_sign(
644                kp_relayid_rsa.keypair(),
645                &kp_relayid_ed.to_ed25519_id(),
646                now + KEY_DURATION_2DAYS,
647            )
648            .unwrap();
649
650            // Legacy X509 RSA cert.
651            let cert_id_x509_rsa = tor_cert::x509::create_legacy_rsa_id_cert(
652                &mut rng,
653                now,
654                issuer_hostname,
655                kp_relayid_rsa.keypair(),
656            )
657            .unwrap();
658
659            Arc::new(RelayChannelAuthMaterial::new(
660                &kp_relayid_rsa.public().into(),
661                kp_relayid_ed.to_ed25519_id(),
662                kp_link_ed,
663                cert_id_sign_ed.to_encodable_cert(),
664                cert_sign_tls_ed,
665                cert_sign_link_auth_ed.to_encodable_cert(),
666                cert_id_x509_rsa,
667                cert_id_rsa,
668                tls_key_and_cert,
669            ))
670        })
671        .clone()
672    }
673}