Skip to main content

tor_proto/relay/
channel.rs

1//! Relay channel code.
2//!
3//! This contains relay specific channel code. In other words, everyting that a relay needs to
4//! establish a channel according to the Tor protocol.
5
6pub(crate) mod handshake;
7
8use async_trait::async_trait;
9use digest::Digest;
10use futures::{AsyncRead, AsyncWrite, SinkExt};
11use rand::Rng;
12use safelog::Sensitive;
13use std::net::{IpAddr, SocketAddr};
14use std::ops::Deref;
15use std::sync::Arc;
16use std::time::UNIX_EPOCH;
17use tracing::{instrument, trace};
18
19use tor_cell::chancell::msg;
20use tor_cert::{Ed25519Cert, rsa::RsaCrosscert};
21use tor_error::internal;
22use tor_linkspec::{ChannelMethod, OwnedChanTarget};
23use tor_llcrypto as ll;
24use tor_llcrypto::pk::{
25    ed25519::{Ed25519Identity, Ed25519SigningKey},
26    rsa::RsaIdentity,
27};
28use tor_relay_crypto::pk::RelayLinkSigningKeypair;
29use tor_rtcompat::{CertifiedConn, CoarseTimeProvider, SleepProvider, StreamOps};
30
31use crate::ClockSkew;
32use crate::channel::handshake::{UnverifiedChannel, VerifiedChannel};
33use crate::channel::{Channel, ChannelType, FinalizableChannel, Reactor, VerifiableChannel};
34use crate::relay::channel::handshake::{AUTHTYPE_ED25519_SHA256_RFC5705, RelayResponderHandshake};
35use crate::{Error, Result, channel::RelayInitiatorHandshake, memquota::ChannelAccount};
36
37// TODO(relay): We should probably get those values from protover crate or some other
38// crate that have all "network parameters" we support?
39/// A list of link authentication that we support (LinkAuth).
40pub(crate) static LINK_AUTH: &[u16] = &[AUTHTYPE_ED25519_SHA256_RFC5705];
41
42/// The authentication cell received on the channel.
43pub(crate) enum AuthenticationCell {
44    /// The AUTH_CHALLENGE. Only relay responder receives this.
45    AuthChallenge(msg::AuthChallenge),
46    /// The AUTHENTICATE. Only relay initiator receives this.
47    Authenticate(msg::Authenticate),
48}
49
50impl AuthenticationCell {
51    /// Return a reference to the [`msg::AuthChallenge`] or None if we are not.
52    fn auth_challenge(&self) -> Option<&msg::AuthChallenge> {
53        match self {
54            AuthenticationCell::AuthChallenge(c) => Some(c),
55            _ => None,
56        }
57    }
58}
59
60/// Object containing the key and certificate that basically identifies us as a relay. They are
61/// used for channel authentication.
62///
63/// We use this intermediary object in order to not have tor-proto crate have access to the KeyMgr
64/// meaning access to all keys. This restricts the view to what is needed.
65#[expect(unused)] // TODO(relay). remove
66pub struct RelayIdentities {
67    /// As a relay, our RSA identity key: KP_relayid_rsa
68    pub(crate) rsa_id: RsaIdentity,
69    /// As a relay, our Ed identity key: KP_relayid_ed
70    pub(crate) ed_id: Ed25519Identity,
71    /// As a relay, our link signing keypair.
72    pub(crate) link_sign_kp: RelayLinkSigningKeypair,
73    /// The Ed25519 identity signing cert (CertType 4)
74    pub(crate) cert_id_sign_ed: Ed25519Cert,
75    /// The Ed25519 signing TLS cert (CertType 5)
76    pub(crate) cert_sign_tls_ed: Ed25519Cert,
77    /// The Ed25519 signing link auth cert (CertType 6)
78    pub(crate) cert_sign_link_auth_ed: Ed25519Cert,
79    /// Legacy: the RSA identity X509 cert (CertType 2). We only have the bytes here as
80    /// create_legacy_rsa_id_cert() takes a key and gives us back the encoded cert.
81    pub(crate) cert_id_x509_rsa: Vec<u8>,
82    /// Legacy: the RSA identity cert (CertType 7)
83    pub(crate) cert_id_rsa: RsaCrosscert,
84}
85
86impl RelayIdentities {
87    /// Constructor.
88    #[allow(clippy::too_many_arguments)] // Yes, plethora of keys...
89    pub fn new(
90        rsa_id: RsaIdentity,
91        ed_id: Ed25519Identity,
92        link_sign_kp: RelayLinkSigningKeypair,
93        cert_id_sign_ed: Ed25519Cert,
94        cert_sign_tls_ed: Ed25519Cert,
95        cert_sign_link_auth_ed: Ed25519Cert,
96        cert_id_x509_rsa: Vec<u8>,
97        cert_id_rsa: RsaCrosscert,
98    ) -> Self {
99        Self {
100            rsa_id,
101            ed_id,
102            link_sign_kp,
103            cert_id_sign_ed,
104            cert_sign_tls_ed,
105            cert_sign_link_auth_ed,
106            cert_id_x509_rsa,
107            cert_id_rsa,
108        }
109    }
110}
111
112impl RelayIdentities {
113    /// Return our Ed identity key (KP_relayid_ed) as bytes.
114    pub(crate) fn ed_id_bytes(&self) -> [u8; 32] {
115        self.ed_id.into()
116    }
117
118    /// Return the digest of the RSA x509 certificate (CertType 2) as bytes.
119    pub(crate) fn rsa_x509_digest(&self) -> [u8; 32] {
120        ll::d::Sha256::digest(&self.cert_id_x509_rsa).into()
121    }
122}
123
124/// Structure for building and launching a relay Tor channel.
125#[derive(Default)]
126#[non_exhaustive]
127pub struct RelayChannelBuilder;
128
129impl RelayChannelBuilder {
130    /// Constructor.
131    pub fn new() -> Self {
132        Self::default()
133    }
134
135    /// Launch a new handshake over a TLS stream.
136    ///
137    /// After calling this function, you'll need to call `connect()` on the result to start the
138    /// handshake.  If that succeeds, you'll have authentication info from the relay: call
139    /// `check()` on the result to check that.  Finally, to finish the handshake, call `finish()`
140    /// on the result of _that_.
141    pub fn launch<T, S>(
142        self,
143        tls: T,
144        sleep_prov: S,
145        identities: Arc<RelayIdentities>,
146        my_addrs: Vec<IpAddr>,
147        memquota: ChannelAccount,
148    ) -> RelayInitiatorHandshake<T, S>
149    where
150        T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
151        S: CoarseTimeProvider + SleepProvider,
152    {
153        RelayInitiatorHandshake::new(tls, sleep_prov, identities, my_addrs, memquota)
154    }
155
156    /// Accept a new handshake over a TLS stream.
157    pub fn accept<T, S>(
158        self,
159        peer: Sensitive<std::net::SocketAddr>,
160        my_addrs: Vec<IpAddr>,
161        tls: T,
162        sleep_prov: S,
163        identities: Arc<RelayIdentities>,
164        memquota: ChannelAccount,
165    ) -> RelayResponderHandshake<T, S>
166    where
167        T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
168        S: CoarseTimeProvider + SleepProvider,
169    {
170        RelayResponderHandshake::new(peer, my_addrs, tls, sleep_prov, identities, memquota)
171    }
172}
173
174/// Channel authentication data. This is only relevant for a Relay to Relay channel which are
175/// authenticated using this buffet of bytes.
176#[derive(Debug)]
177pub(crate) struct ChannelAuthenticationData {
178    /// Authentication method to use.
179    pub(crate) link_auth: u16,
180    /// SHA256 digest of the initiator KP_relayid_rsa.
181    pub(crate) cid: [u8; 32],
182    /// SHA256 digest of the responder KP_relayid_rsa.
183    pub(crate) sid: [u8; 32],
184    /// The initiator KP_relayid_ed.
185    pub(crate) cid_ed: [u8; 32],
186    /// The responder KP_relayid_ed.
187    pub(crate) sid_ed: [u8; 32],
188    /// Initiator log SHA256 digest.
189    pub(crate) clog: [u8; 32],
190    /// Responder log SHA256 digest.
191    pub(crate) slog: [u8; 32],
192    /// SHA256 of responder's TLS certificate.
193    pub(crate) scert: [u8; 32],
194}
195
196#[expect(unused)] // TODO(relay). remove
197impl ChannelAuthenticationData {
198    /// Helper: return the authentication type string from the given link auth version.
199    const fn auth_type_bytes(link_auth: u16) -> Result<&'static [u8]> {
200        match link_auth {
201            3 => Ok(b"AUTH0003"),
202            _ => Err(Error::BadCellAuth),
203        }
204    }
205
206    /// Helper: return the keying material label from the given link auth version.
207    const fn keying_material_label_bytes(link_auth: u16) -> Result<&'static [u8]> {
208        match link_auth {
209            3 => Ok(b"EXPORTER FOR TOR TLS CLIENT BINDING AUTH0003"),
210            _ => Err(Error::BadCellAuth),
211        }
212    }
213
214    /// Consume ourself and return an AUTHENTICATE cell from the data we hold.
215    pub(crate) fn into_authenticate<C: CertifiedConn>(
216        self,
217        tls: &C,
218        link_ed: &RelayLinkSigningKeypair,
219    ) -> Result<msg::Authenticate> {
220        // The body is exactly 352 bytes so optimize a bit memory.
221        let mut body = Vec::with_capacity(352);
222
223        // Obviously, ordering matteres. See tor-spec section Ed25519-SHA256-RFC5705
224        body.extend_from_slice(Self::auth_type_bytes(self.link_auth)?);
225        body.extend_from_slice(&self.cid);
226        body.extend_from_slice(&self.sid);
227        body.extend_from_slice(&self.cid_ed);
228        body.extend_from_slice(&self.sid_ed);
229        body.extend_from_slice(&self.slog);
230        body.extend_from_slice(&self.clog);
231        body.extend_from_slice(&self.scert);
232
233        // TLSSECRETS is built from the CID.
234        let tls_secrets = tls.export_keying_material(
235            32,
236            Self::keying_material_label_bytes(self.link_auth)?,
237            Some(&self.cid[..]),
238        )?;
239        body.extend_from_slice(tls_secrets.as_slice());
240
241        // Add the random bytes.
242        let mut rng = rand::rng();
243        let random: [u8; 24] = rand::rng().random();
244        body.extend_from_slice(&random);
245
246        // Create signature with our KP_link_ed and append it to body. We hard expect the
247        // KP_link_ed because this would be a code flow error.
248        let sig = link_ed.sign(&body);
249        body.extend_from_slice(&sig.to_bytes());
250
251        // Lets go with the AUTHENTICATE cell.
252        Ok(msg::Authenticate::new(self.link_auth, body))
253    }
254}
255
256/// A relay unverified channel which is a channel where the version has been negotiated and the
257/// handshake has been done but where the certificates and keys have not been validated hence
258/// unverified.
259///
260/// This is used for both initiator and responder channels.
261struct UnverifiedRelayChannel<
262    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
263    S: CoarseTimeProvider + SleepProvider,
264> {
265    /// The common unverified channel that both client and relays use.
266    inner: UnverifiedChannel<T, S>,
267    /// The cell used for authentication received (AUTHENTICATE or AUTH_CHALLENGE). If None, this
268    /// channel won't authenticate.
269    ///
270    /// When a channel does NOT authenticate, it means the initiator decided not to authenticate
271    /// and so as the initiator, we won't have an AUTHENTICATE and as the responder we won't have
272    /// an AUTH_CHALLENGE cell.
273    auth_cell: Option<AuthenticationCell>,
274    /// The netinfo cell that we got from the relay.
275    netinfo_cell: msg::Netinfo,
276    /// Our identity keys needed for authentication.
277    identities: Arc<RelayIdentities>,
278    /// Our advertised IP addresses.
279    my_addrs: Vec<IpAddr>,
280}
281
282impl<
283    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
284    S: CoarseTimeProvider + SleepProvider,
285> UnverifiedRelayChannel<T, S>
286{
287    /// Build the [`ChannelAuthenticationData`] given a [`VerifiedChannel`].
288    ///
289    /// We should never check or build authentication data if the channel is not verified thus the
290    /// requirement to pass the verified channel to this function.
291    ///
292    /// Both initiator and responder handshake build this data in order to authenticate.
293    ///
294    /// IMPORTANT: The CLOG and SLOG from the framed_tls codec is consumed here so calling twice
295    /// build_auth_data() will result in different AUTHENTICATE cells.
296    fn build_auth_data(
297        auth_challenge_cell: Option<&msg::AuthChallenge>,
298        identities: &Arc<RelayIdentities>,
299        verified: &mut VerifiedChannel<T, S>,
300    ) -> Result<ChannelAuthenticationData> {
301        // With an AUTH_CHALLENGE, we are the Initiator. With an AUTHENTICATE, we are the
302        // Responder. See tor-spec for a diagram of messages.
303        let is_responder = auth_challenge_cell.is_none();
304
305        // Without an AUTH_CHALLENGE, we use our known link protocol value. Else, we only keep what
306        // we know from the AUTH_CHALLENGE and we max() on it.
307        let link_auth = *LINK_AUTH
308            .iter()
309            .filter(|m| auth_challenge_cell.is_none_or(|cell| cell.methods().contains(m)))
310            .max()
311            .ok_or(Error::BadCellAuth)?;
312        // The ordering matter based on if initiator or responder.
313        let cid = identities.rsa_x509_digest();
314        let sid = verified
315            .rsa_id_cert_digest
316            .ok_or(Error::from(internal!(
317                "Verified channel without a RSA identity"
318            )))?
319            .1;
320        let cid_ed = identities.ed_id_bytes();
321        let sid_ed = verified
322            .ed25519_id
323            .ok_or(Error::from(internal!(
324                "Verified channel without an ed25519 identity"
325            )))?
326            .into();
327        // Both values are consumed from the underlying codec.
328        let clog = verified.framed_tls.codec_mut().get_clog_digest()?;
329        let slog = verified.framed_tls.codec_mut().get_slog_digest()?;
330
331        let (cid, sid, cid_ed, sid_ed) = if is_responder {
332            // Reverse when responder as in CID becomes SID, and so on.
333            (sid, cid, sid_ed, cid_ed)
334        } else {
335            // Keep it that way if we are initiator.
336            (cid, sid, cid_ed, sid_ed)
337        };
338
339        let (clog, slog) = if is_responder {
340            // Reverse as the SLOG is the responder log digest meaning the clog as a responder.
341            (slog, clog)
342        } else {
343            // Keep ordering.
344            (clog, slog)
345        };
346
347        let scert = if is_responder {
348            // TODO(relay): This is the peer certificate but as a responder, we need our
349            // certificate which requires lot more work and a rustls provider configured as a
350            // server side. See arti#2316.
351            todo!()
352        } else {
353            verified.peer_cert_digest
354        };
355
356        Ok(ChannelAuthenticationData {
357            link_auth,
358            cid,
359            sid,
360            cid_ed,
361            sid_ed,
362            clog,
363            slog,
364            scert,
365        })
366    }
367}
368
369impl<
370    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
371    S: CoarseTimeProvider + SleepProvider,
372> VerifiableChannel<T, S> for UnverifiedRelayChannel<T, S>
373{
374    fn clock_skew(&self) -> ClockSkew {
375        self.inner.clock_skew
376    }
377
378    #[instrument(skip_all, level = "trace")]
379    fn check(
380        self: Box<Self>,
381        peer: &OwnedChanTarget,
382        peer_cert: &[u8],
383        now: Option<std::time::SystemTime>,
384    ) -> Result<Box<dyn FinalizableChannel<T, S>>> {
385        // We can't authenticate unless we have an Authentication cell.
386        //
387        // A clever observer can ask if this can be gamed to get an unverified relay channel
388        // considered as a canonical authenticate channel.
389        //
390        // The answer is no because when the handshake starts, Initiators always expect the other
391        // side to send a CERTS, AUTH_CHALLENGE and NETINFO. Else, an error is raised. Responder
392        // are the one dealing with unauthenticated channels and, for instance, if we receive a
393        // CERTS without an AUTHENTICATE , an error is raised.
394        //
395        // In other words, when a VerifiableChannel reaches this function, it either has what it
396        // needs to authenticate (relay<->relay channel) or not (client/bridge<->relay channel).
397        //
398        // An UnverifiedRelayChannel implements FinalizableChannel which enforces, with the type
399        // system, that an unverified channel will never become authenticated.
400        let Some(auth_cell) = self.auth_cell else {
401            return Ok(self);
402        };
403
404        // Get these object out as we consume "self" in the inner check().
405        let identities = self.identities;
406        let netinfo_cell = self.netinfo_cell;
407        let my_addrs = self.my_addrs;
408        let mut authenticate_cell = None;
409
410        // Verify our inner channel and then proceed to handle the authentication challenge if any.
411        let mut verified = self.inner.check(peer, peer_cert, now)?;
412
413        // By building the ChannelAuthenticationData, we are certain that the authentication
414        // type requested by the responder is supported by us.
415        let auth_data =
416            Self::build_auth_data(auth_cell.auth_challenge(), &identities, &mut verified)?;
417        let our_authenticate =
418            auth_data.into_authenticate(verified.framed_tls.deref(), &identities.link_sign_kp)?;
419
420        // CRITICAL: This if is what authenticates a channel on the responder side. We compare
421        // what we expected to what we received.
422        if let AuthenticationCell::Authenticate(received_authenticate) = auth_cell {
423            if received_authenticate != our_authenticate {
424                return Err(Error::ChanProto(
425                    "AUTHENTICATE was unexpected. Failing authentication".into(),
426                ));
427            }
428            // Keep it so we can send it to the other end.
429            authenticate_cell = Some(our_authenticate);
430        }
431        // This part is very important as we now flag that we are authenticated. The responder
432        // checks the received AUTHENTICATE and the initiator just needs to verify the channel.
433        //
434        // At this point, the underlying cell handler is in the Handshake state. Setting the
435        // channel type here as authenticated means that once the handler transition to the Open
436        // state, it will carry this authenticated flag leading to the message filter of the
437        // channel codec to adapt its restricted message sets (meaning R2R only).
438        //
439        // After this call, it is considered a R2R channel.
440        verified.set_authenticated()?;
441
442        Ok(Box::new(VerifiedRelayChannel {
443            inner: verified,
444            identities,
445            netinfo_cell,
446            authenticate_cell,
447            my_addrs,
448        }))
449    }
450
451    /// Return the link protocol version of this channel.
452    #[cfg(test)]
453    fn link_protocol(&self) -> u16 {
454        self.inner.link_protocol
455    }
456}
457
458#[async_trait]
459impl<
460    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
461    S: CoarseTimeProvider + SleepProvider,
462> FinalizableChannel<T, S> for UnverifiedRelayChannel<T, S>
463{
464    #[instrument(skip_all, level = "trace")]
465    async fn finish(mut self: Box<Self>) -> Result<(Arc<Channel>, Reactor<S>)> {
466        // NOTE: The only way to get here is if the channel is a relay responder.
467        //
468        // Initiators always authenticate and so only relay responder can end up with an unverified
469        // relay channel in the finish() state. Plausible future improvement here would be to have
470        // a more specific unverified responder channel type and so never an initiator handshake
471        // can lead to this function.
472        self.inner.finish()
473    }
474}
475
476impl<T, S> crate::channel::seal::Sealed for UnverifiedRelayChannel<T, S>
477where
478    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
479    S: CoarseTimeProvider + SleepProvider,
480{
481}
482
483/// A verified relay channel on which versions have been negotiated, the handshake has been read,
484/// but the relay has not yet finished the handshake.
485///
486/// This type is separate from UnverifiedRelayChannel, since finishing the handshake requires a
487/// bunch of CPU, and you might want to do it as a separate task or after a yield.
488#[expect(unused)] // TODO(relay). remove
489struct VerifiedRelayChannel<
490    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
491    S: CoarseTimeProvider + SleepProvider,
492> {
493    /// The common unverified channel that both client and relays use.
494    inner: VerifiedChannel<T, S>,
495    /// Relay identities.
496    identities: Arc<RelayIdentities>,
497    /// The netinfo cell that we got from the relay.
498    netinfo_cell: msg::Netinfo,
499    /// The AUTHENTICATE cell we need to send back as a responder.
500    authenticate_cell: Option<msg::Authenticate>,
501    /// Our advertised IP addresses.
502    my_addrs: Vec<IpAddr>,
503}
504
505#[async_trait]
506impl<
507    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
508    S: CoarseTimeProvider + SleepProvider,
509> FinalizableChannel<T, S> for VerifiedRelayChannel<T, S>
510{
511    #[instrument(skip_all, level = "trace")]
512    async fn finish(mut self: Box<Self>) -> Result<(Arc<Channel>, Reactor<S>)> {
513        // TODO(relay): This would be the time to set a "is_canonical" flag to Channel which is
514        // true if the Netinfo address matches the address we are connected to. Canonical
515        // definition is if the address we are connected to is what we expect it to be. This only
516        // makes sense for relay channels.
517
518        // If we have an AUTHENTICATE cell, we need to send it along our CERTS and NETINFO. In
519        // other words, it means we are a Responder.
520        if let Some(auth_cell) = self.authenticate_cell {
521            // We got an AUTH_CHALLENGE, send the CERTS and AUTHENTICATE.
522            let certs = build_certs_cell(&self.identities, ChannelType::RelayInitiator);
523            trace!(channel_id = %self.inner.unique_id, "Sending CERTS as initiator cell.");
524            self.inner.framed_tls.send(certs.into()).await?;
525            trace!(channel_id = %self.inner.unique_id, "Sending AUTHENTICATE as initiator cell.");
526            self.inner.framed_tls.send(auth_cell.into()).await?;
527
528            let peer_ip = self
529                .inner
530                .target_method
531                .as_ref()
532                .and_then(ChannelMethod::socket_addrs)
533                .and_then(|addrs| addrs.first())
534                .map(SocketAddr::ip)
535                .ok_or(Error::from(internal!("Target method address invalid")))?;
536            let netinfo = build_netinfo_cell(peer_ip, self.my_addrs, &self.inner.sleep_prov)?;
537            trace!(channel_id = %self.inner.unique_id, "Sending NETINFO as initiator cell.");
538            self.inner.framed_tls.send(netinfo.into()).await?;
539        }
540
541        self.inner.finish().await
542    }
543}
544
545impl<T, S> crate::channel::seal::Sealed for VerifiedRelayChannel<T, S>
546where
547    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
548    S: CoarseTimeProvider + SleepProvider,
549{
550}
551
552/// Helper: Build a [`msg::Certs`] cell for the given relay identities and channel type.
553///
554/// Both relay initiator and responder handshake use this.
555pub(crate) fn build_certs_cell(
556    identities: &Arc<RelayIdentities>,
557    _chan_type: ChannelType,
558) -> msg::Certs {
559    let mut certs = msg::Certs::new_empty();
560    // Push into the cell the CertType 2 RSA
561    certs.push_cert_body(
562        tor_cert::CertType::RSA_ID_X509,
563        identities.cert_id_x509_rsa.clone(),
564    );
565    /* TODO(relay): Need to push these into the CERTS. The current types in RelayIdentities are
566     * wrong as they are not encodable. The types returned by the KeyMgr has encodable cert types
567     * so we'll use then when addressing this.
568
569    // Push into the cell the CertType 7 RSA
570    certs.push_cert_body(
571        self.identities.cert_id_rsa.cert_type(),
572        &self.identities.cert_id_rsa,
573    );
574
575    // Push into the cell the CertType 4 Ed25519
576    certs.push_cert_body(
577        self.identities.cert_id_sign_ed.cert_type(),
578        &self.identities.cert_id_sign_ed,
579    );
580    // Push into the cell the CertType 5/6 Ed25519
581    if chan_type.is_responder() {
582        // Responder has CertType 5
583        certs.push_cert_body(
584            self.identities.cert_sign_tls_ed.cert_type(),
585            &self.identities.cert_sign_tls_ed,
586        );
587    } else {
588        // Initiator has CertType 6
589        certs.push_cert_body(
590            self.identities.cert_sign_link_auth_ed.cert_type(),
591            &self.identities.cert_sign_link_auth_ed,
592        );
593    }
594    */
595    certs
596}
597
598/// Build a [`msg::Netinfo`] cell from the given peer IPs and our advertised addresses.
599///
600/// Both relay initiator and responder handshake use this.
601pub(crate) fn build_netinfo_cell<S>(
602    peer_ip: IpAddr,
603    my_addrs: Vec<IpAddr>,
604    sleep_prov: &S,
605) -> Result<msg::Netinfo>
606where
607    S: CoarseTimeProvider + SleepProvider,
608{
609    // Unix timestamp but over 32bit. This will be sad in 2038 but proposal 338 addresses this
610    // issue with a change to 64bit.
611    let timestamp = sleep_prov
612        .wallclock()
613        .duration_since(UNIX_EPOCH)
614        .map_err(|e| internal!("Wallclock may have gone backwards: {e}"))?
615        .as_secs()
616        .try_into()
617        .map_err(|e| internal!("Wallclock secs fail to convert to 32bit: {e}"))?;
618    Ok(msg::Netinfo::from_relay(timestamp, Some(peer_ip), my_addrs))
619}