Skip to main content

tor_proto/relay/channel/
handshake.rs

1//! Implementations for the relay channel handshake
2
3use futures::SinkExt;
4use futures::io::{AsyncRead, AsyncWrite};
5use rand::Rng;
6use safelog::Sensitive;
7use std::net::{IpAddr, SocketAddr};
8use std::{sync::Arc, time::SystemTime};
9use tracing::trace;
10
11use tor_cell::chancell::msg;
12use tor_cell::restrict::restricted_msg;
13use tor_error::internal;
14use tor_linkspec::{ChannelMethod, HasChanMethod, OwnedChanTarget};
15use tor_rtcompat::{CertifiedConn, CoarseTimeProvider, SleepProvider, StreamOps};
16
17use crate::Result;
18use crate::channel::handshake::{
19    AuthLogAction, ChannelBaseHandshake, ChannelInitiatorHandshake, UnverifiedChannel,
20    UnverifiedInitiatorChannel, read_msg, unauthenticated_clock_skew,
21};
22use crate::channel::{ChannelFrame, ChannelType, ClogDigest, SlogDigest, UniqId, new_frame};
23use crate::memquota::ChannelAccount;
24use crate::peer::PeerAddr;
25use crate::relay::CreateRequestHandler;
26use crate::relay::channel::initiator::UnverifiedInitiatorRelayChannel;
27use crate::relay::channel::responder::{
28    MaybeVerifiableRelayResponderChannel, NonVerifiableResponderRelayChannel,
29    UnverifiedResponderRelayChannel,
30};
31use crate::relay::channel::{RelayChannelAuthMaterial, build_certs_cell, build_netinfo_cell};
32
33/// The "Ed25519-SHA256-RFC5705" link authentication which is value "00 03".
34pub(super) static AUTHTYPE_ED25519_SHA256_RFC5705: u16 = 3;
35
36/// A relay channel handshake as the initiator.
37pub struct RelayInitiatorHandshake<
38    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
39    S: CoarseTimeProvider + SleepProvider,
40> {
41    /// Runtime handle (insofar as we need it)
42    sleep_prov: S,
43    /// Memory quota account
44    memquota: ChannelAccount,
45    /// Underlying TLS stream in a channel frame.
46    ///
47    /// (We don't enforce that this is actually TLS, but if it isn't, the
48    /// connection won't be secure.)
49    framed_tls: ChannelFrame<T>,
50    /// Logging identifier for this stream.  (Used for logging only.)
51    unique_id: UniqId,
52    /// Our identity keys needed for authentication.
53    auth_material: Arc<RelayChannelAuthMaterial>,
54    /// The peer we are attempting to connect to.
55    target_method: ChannelMethod,
56    /// Our advertised addresses. Needed for the NETINFO.
57    my_addrs: Vec<IpAddr>,
58    /// Provided to each new channel so that they can handle CREATE* requests.
59    create_request_handler: Arc<CreateRequestHandler>,
60}
61
62/// Implement the base channel handshake trait.
63impl<T, S> ChannelBaseHandshake<T> for RelayInitiatorHandshake<T, S>
64where
65    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
66    S: CoarseTimeProvider + SleepProvider,
67{
68    fn framed_tls(&mut self) -> &mut ChannelFrame<T> {
69        &mut self.framed_tls
70    }
71    fn unique_id(&self) -> &UniqId {
72        &self.unique_id
73    }
74}
75
76/// Implement the initiator channel handshake trait.
77impl<T, S> ChannelInitiatorHandshake<T> for RelayInitiatorHandshake<T, S>
78where
79    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
80    S: CoarseTimeProvider + SleepProvider,
81{
82}
83
84impl<
85    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
86    S: CoarseTimeProvider + SleepProvider,
87> RelayInitiatorHandshake<T, S>
88{
89    /// Constructor.
90    pub(crate) fn new(
91        tls: T,
92        sleep_prov: S,
93        auth_material: Arc<RelayChannelAuthMaterial>,
94        my_addrs: Vec<SocketAddr>,
95        peer_target: &OwnedChanTarget,
96        memquota: ChannelAccount,
97        create_request_handler: Arc<CreateRequestHandler>,
98    ) -> Self {
99        Self {
100            framed_tls: new_frame(tls, ChannelType::RelayInitiator),
101            unique_id: UniqId::new(),
102            sleep_prov,
103            auth_material,
104            memquota,
105            my_addrs: my_addrs.into_iter().map(|a| a.ip()).collect(),
106            target_method: peer_target.chan_method(),
107            create_request_handler,
108        }
109    }
110
111    /// Connect to another relay as the relay Initiator.
112    ///
113    /// Takes a function that reports the current time.  In theory, this can just be
114    /// `SystemTime::get()`.
115    pub async fn connect<F>(mut self, now_fn: F) -> Result<UnverifiedInitiatorRelayChannel<T, S>>
116    where
117        F: FnOnce() -> SystemTime,
118    {
119        // Send the VERSIONS.
120        let (versions_flushed_at, versions_flushed_wallclock) =
121            self.send_versions_cell(now_fn).await?;
122
123        // Receive the VERSIONS.
124        let link_protocol = self.recv_versions_cell().await?;
125
126        // VERSIONS cell have been exchanged, set the link protocol into our channel frame.
127        self.set_link_protocol(link_protocol)?;
128
129        // Read until we have all the remaining cells from the responder.
130        let (auth_challenge_cell, certs_cell, (netinfo_cell, netinfo_rcvd_at), slog_digest) =
131            self.recv_cells_from_responder(AuthLogAction::Take).await?;
132
133        // TODO: It would be nice to come up with a better design for getting the SLOG.
134        let slog_digest = slog_digest.ok_or(internal!("Asked for SLOG, but `None` returned?"))?;
135
136        trace!(stream_id = %self.unique_id,
137            "received handshake, ready to verify.",
138        );
139
140        // Calculate our clock skew from the timings we just got/calculated.
141        let clock_skew = unauthenticated_clock_skew(
142            &netinfo_cell,
143            netinfo_rcvd_at,
144            versions_flushed_at,
145            versions_flushed_wallclock,
146        );
147
148        Ok(UnverifiedInitiatorRelayChannel {
149            inner: UnverifiedInitiatorChannel {
150                inner: UnverifiedChannel {
151                    link_protocol,
152                    framed_tls: self.framed_tls,
153                    clock_skew,
154                    memquota: self.memquota,
155                    target_method: Some(self.target_method),
156                    unique_id: self.unique_id,
157                    sleep_prov: self.sleep_prov.clone(),
158                },
159                certs_cell,
160            },
161            auth_challenge_cell,
162            slog_digest,
163            netinfo_cell,
164            auth_material: self.auth_material,
165            my_addrs: self.my_addrs,
166            create_request_handler: self.create_request_handler,
167        })
168    }
169}
170
171/// A relay channel handshake as the responder.
172pub struct RelayResponderHandshake<
173    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
174    S: CoarseTimeProvider + SleepProvider,
175> {
176    /// Runtime handle (insofar as we need it)
177    sleep_prov: S,
178    /// Memory quota account
179    memquota: ChannelAccount,
180    /// Underlying TLS stream in a channel frame.
181    ///
182    /// (We don't enforce that this is actually TLS, but if it isn't, the
183    /// connection won't be secure.)
184    framed_tls: ChannelFrame<T>,
185    /// The peer IP address as in the address the initiator is connecting from. This can be a
186    /// client so keep it sensitive.
187    peer_addr: Sensitive<PeerAddr>,
188    /// Our advertised addresses. Needed for the NETINFO.
189    my_addrs: Vec<IpAddr>,
190    /// Logging identifier for this stream.  (Used for logging only.)
191    unique_id: UniqId,
192    /// Our identity keys needed for authentication.
193    auth_material: Arc<RelayChannelAuthMaterial>,
194    /// Provided to each new channel so that they can handle CREATE* requests.
195    create_request_handler: Arc<CreateRequestHandler>,
196}
197
198/// Implement the base channel handshake trait.
199impl<T, S> ChannelBaseHandshake<T> for RelayResponderHandshake<T, S>
200where
201    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
202    S: CoarseTimeProvider + SleepProvider,
203{
204    fn framed_tls(&mut self) -> &mut ChannelFrame<T> {
205        &mut self.framed_tls
206    }
207    fn unique_id(&self) -> &UniqId {
208        &self.unique_id
209    }
210}
211
212impl<
213    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
214    S: CoarseTimeProvider + SleepProvider,
215> RelayResponderHandshake<T, S>
216{
217    /// Constructor.
218    pub(crate) fn new(
219        peer_addr: Sensitive<PeerAddr>,
220        my_addrs: Vec<SocketAddr>,
221        tls: T,
222        sleep_prov: S,
223        auth_material: Arc<RelayChannelAuthMaterial>,
224        memquota: ChannelAccount,
225        create_request_handler: Arc<CreateRequestHandler>,
226    ) -> Self {
227        Self {
228            peer_addr,
229            my_addrs: my_addrs.into_iter().map(|a| a.ip()).collect(),
230            framed_tls: new_frame(
231                tls,
232                ChannelType::RelayResponder {
233                    authenticated: false,
234                },
235            ),
236            unique_id: UniqId::new(),
237            sleep_prov,
238            auth_material,
239            memquota,
240            create_request_handler,
241        }
242    }
243
244    /// Begin the handshake process.
245    ///
246    /// Takes a function that reports the current time.  In theory, this can just be
247    /// `SystemTime::get()`.
248    pub async fn handshake<F>(
249        mut self,
250        now_fn: F,
251    ) -> Result<MaybeVerifiableRelayResponderChannel<T, S>>
252    where
253        F: FnOnce() -> SystemTime,
254    {
255        // Receive initiator VERSIONS.
256        let link_protocol = self.recv_versions_cell().await?;
257
258        // Send the VERSIONS message.
259        let (versions_flushed_at, versions_flushed_wallclock) =
260            self.send_versions_cell(now_fn).await?;
261
262        // VERSIONS cell have been exchanged, set the link protocol into our channel frame.
263        self.set_link_protocol(link_protocol)?;
264
265        // Send CERTS, AUTH_CHALLENGE and NETINFO
266        let slog_digest = self.send_cells_to_initiator().await?;
267
268        // Receive NETINFO and possibly [CERTS, AUTHENTICATE]. The connection could be from a
269        // client/bridge and thus no authentication meaning no CERTS/AUTHENTICATE cells.
270        let (certs_and_auth_and_clog, (netinfo_cell, netinfo_rcvd_at)) =
271            self.recv_cells_from_initiator().await?;
272
273        // Try to unpack these into something we can use later.
274        let (certs_cell, auth_and_clog) = match certs_and_auth_and_clog {
275            Some((certs, auth, clog)) => (Some(certs), Some((auth, clog))),
276            None => (None, None),
277        };
278
279        // Calculate our clock skew from the timings we just got/calculated.
280        let clock_skew = unauthenticated_clock_skew(
281            &netinfo_cell,
282            netinfo_rcvd_at,
283            versions_flushed_at,
284            versions_flushed_wallclock,
285        );
286
287        let inner = UnverifiedChannel {
288            link_protocol,
289            framed_tls: self.framed_tls,
290            clock_skew,
291            memquota: self.memquota,
292            target_method: None,
293            unique_id: self.unique_id,
294            sleep_prov: self.sleep_prov,
295        };
296
297        // With an AUTHENTICATE cell, we can verify (relay). Else (client/bridge), we can't.
298        Ok(match auth_and_clog {
299            Some((auth_cell, clog_digest)) => {
300                MaybeVerifiableRelayResponderChannel::Verifiable(UnverifiedResponderRelayChannel {
301                    inner,
302                    auth_cell,
303                    netinfo_cell,
304                    // TODO(relay): Should probably put that in the match {} and not assume.
305                    certs_cell: certs_cell.expect("AUTHENTICATE cell without CERTS cell"),
306                    auth_material: self.auth_material,
307                    my_addrs: self.my_addrs,
308                    peer_addr: self.peer_addr.into_inner(), // Relay address.
309                    clog_digest,
310                    slog_digest,
311                    create_request_handler: self.create_request_handler,
312                })
313            }
314            None => MaybeVerifiableRelayResponderChannel::NonVerifiable(
315                NonVerifiableResponderRelayChannel {
316                    inner,
317                    netinfo_cell,
318                    my_addrs: self.my_addrs,
319                    peer_addr: self.peer_addr,
320                    create_request_handler: self.create_request_handler,
321                    our_ed25519_id: self.auth_material.ed_id,
322                    our_rsa_id: self.auth_material.rsa_id,
323                },
324            ),
325        })
326    }
327
328    /// Receive all the cells expected from the initiator of the connection. Keep in mind that it
329    /// can be either a relay or client or bridge.
330    async fn recv_cells_from_initiator(
331        &mut self,
332    ) -> Result<(
333        Option<(msg::Certs, msg::Authenticate, ClogDigest)>,
334        (msg::Netinfo, coarsetime::Instant),
335    )> {
336        // IMPORTANT: Protocol wise, we MUST only allow one single cell of each type for a valid
337        // handshake. Any duplicates lead to a failure.
338        // They must arrive in a specific order in order for the CLOG calculation to be valid.
339
340        // Note that the `ChannelFrame` already restricts the messages due to its handshake cell
341        // handler.
342
343        // This is kind of ugly, but I don't see a nicer way to write the authentication branch
344        // without a bunch of boilerplate for a state machine.
345        let (certs_and_auth_and_clog, netinfo, netinfo_rcvd_at) = 'outer: {
346            // CERTS or NETINFO cell.
347            let certs = loop {
348                restricted_msg! {
349                    enum CertsNetinfoMsg : ChanMsg {
350                        // VPADDING cells (but not PADDING) can be sent during handshaking.
351                        Vpadding,
352                        Netinfo,
353                        Certs,
354                   }
355                }
356
357                break match read_msg(*self.unique_id(), self.framed_tls()).await? {
358                    CertsNetinfoMsg::Vpadding(_) => continue,
359                    // If a NETINFO cell, the initiator did not authenticate and we can stop early.
360                    CertsNetinfoMsg::Netinfo(msg) => {
361                        break 'outer (None, msg, coarsetime::Instant::now());
362                    }
363                    // If a CERTS cell, the initiator is authenticating.
364                    CertsNetinfoMsg::Certs(msg) => msg,
365                };
366            };
367
368            // We're the responder, which means that the recv log is the CLOG.
369            let clog_digest =
370                ClogDigest::new(self.framed_tls().codec_mut().take_recv_log_digest()?);
371
372            // AUTHENTICATE cell.
373            let auth = loop {
374                restricted_msg! {
375                    enum AuthenticateMsg : ChanMsg {
376                        // VPADDING cells (but not PADDING) can be sent during handshaking.
377                        Vpadding,
378                        Authenticate,
379                   }
380                }
381
382                break match read_msg(*self.unique_id(), self.framed_tls()).await? {
383                    AuthenticateMsg::Vpadding(_) => continue,
384                    AuthenticateMsg::Authenticate(msg) => msg,
385                };
386            };
387
388            // NETINFO cell (if we didn't receive it earlier).
389            let (netinfo, netinfo_rcvd_at) = loop {
390                restricted_msg! {
391                    enum NetinfoMsg : ChanMsg {
392                        // VPADDING cells (but not PADDING) can be sent during handshaking.
393                        Vpadding,
394                        Netinfo,
395                   }
396                }
397
398                break match read_msg(*self.unique_id(), self.framed_tls()).await? {
399                    NetinfoMsg::Vpadding(_) => continue,
400                    NetinfoMsg::Netinfo(msg) => (msg, coarsetime::Instant::now()),
401                };
402            };
403
404            (Some((certs, auth, clog_digest)), netinfo, netinfo_rcvd_at)
405        };
406
407        Ok((certs_and_auth_and_clog, (netinfo, netinfo_rcvd_at)))
408    }
409
410    /// Send all expected cells to the initiator of the channel as the responder.
411    ///
412    /// Return the SLOG (send log) digest to be later used when verifying the initiator's
413    /// AUTHENTICATE cell.
414    async fn send_cells_to_initiator(&mut self) -> Result<SlogDigest> {
415        // Send the CERTS message.
416        let certs = build_certs_cell(&self.auth_material, /* is_responder */ true);
417        trace!(channel_id = %self.unique_id, "Sending CERTS as responder cell.");
418        self.framed_tls.send(certs.into()).await?;
419
420        // Send the AUTH_CHALLENGE.
421        let challenge: [u8; 32] = rand::rng().random();
422        let auth_challenge = msg::AuthChallenge::new(challenge, [AUTHTYPE_ED25519_SHA256_RFC5705]);
423        trace!(channel_id = %self.unique_id, "Sending AUTH_CHALLENGE as responder cell.");
424        self.framed_tls.send(auth_challenge.into()).await?;
425
426        // We're the responder, which means that the send log is the SLOG.
427        let slog_digest = SlogDigest::new(self.framed_tls.codec_mut().take_send_log_digest()?);
428
429        // Send the NETINFO message.
430        let peer_ip = self.peer_addr.netinfo_addr();
431        let netinfo = build_netinfo_cell(peer_ip, self.my_addrs.clone(), &self.sleep_prov)?;
432        trace!(channel_id = %self.unique_id, "Sending NETINFO as responder cell.");
433        self.framed_tls.send(netinfo.into()).await?;
434
435        Ok(slog_digest)
436    }
437}