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}