aboutsummaryrefslogtreecommitdiff
path: root/crates/tor-proto/src/relay/channel/initiator.rs
blob: 499c2192c0b4cbda273fe4c6375786de5ae6982d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! Relay initiator channel.
//!
//! Code only related to a relay channel opened as an initiator. The handshake code is responsible
//! for creating an [`UnverifiedInitiatorRelayChannel`] when connecting to another relay in order
//! to build a tor channel.
//!
//! The [`UnverifiedInitiatorRelayChannel::verify`] function needs to be called to verify the
//! underlying channel and build a [`VerifiedInitiatorRelayChannel`] channel which needs to be
//! finished with [`VerifiedInitiatorRelayChannel::finish`] to get a Channel/Reactor.
//!
//! Note that channel cells are sent in the handshake upon connection. And then in the finish()
//! process. The verify can be CPU intensive and thus in its own function.

use digest::Digest;
use futures::{AsyncRead, AsyncWrite, SinkExt};
use safelog::MaybeSensitive;
use std::{net::IpAddr, ops::Deref, sync::Arc};
use tracing::trace;

use tor_cell::chancell::msg;
use tor_linkspec::OwnedChanTarget;
use tor_rtcompat::{CertifiedConn, CoarseTimeProvider, Runtime, SleepProvider, StreamOps};

use crate::{
    ClockSkew, RelayChannelAuthMaterial, Result,
    channel::{
        Channel, ChannelMode, ClogDigest, Reactor, SlogDigest,
        circmap::CircIdRange,
        handshake::{UnverifiedInitiatorChannel, VerifiedChannel},
    },
    peer::{PeerAddr, PeerInfo},
    relay::CreateRequestHandler,
    relay::channel::ChannelAuthenticationData,
};

/// An unverified relay initiator channel.
///
/// This is built by the [`crate::relay::channel::handshake::RelayInitiatorHandshake`] upon a
/// connect. It has everything needed to verify in order to get a verified channel.
pub struct UnverifiedInitiatorRelayChannel<
    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
    S: CoarseTimeProvider + SleepProvider,
> {
    /// The common unverified channel that both client and relays use.
    pub(crate) inner: UnverifiedInitiatorChannel<T, S>,
    /// AUTH_CHALLENGE cell received from the responder.
    pub(crate) auth_challenge_cell: msg::AuthChallenge,
    /// The SLOG digest.
    pub(crate) slog_digest: SlogDigest,
    /// The netinfo cell received from the responder.
    pub(crate) netinfo_cell: msg::Netinfo,
    /// Our channel key material needed for authentication.
    pub(crate) auth_material: Arc<RelayChannelAuthMaterial>,
    /// Our advertised IP addresses for the final NETINFO
    pub(crate) my_addrs: Vec<IpAddr>,
    /// Provided to each new channel so that they can handle CREATE* requests.
    pub(crate) create_request_handler: Arc<CreateRequestHandler>,
}

impl<T, S> UnverifiedInitiatorRelayChannel<T, S>
where
    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
    S: CoarseTimeProvider + SleepProvider,
{
    /// Validate the certificates and keys in the relay's handshake. As an initiator, we always
    /// authenticate no matter what.
    ///
    /// 'peer_target' is the peer that we want to make sure we're connecting to.
    ///
    /// 'peer_tls_cert' is the x.509 certificate that the peer presented during its TLS handshake
    /// (ServerHello).
    ///
    /// 'now' is the time at which to check that certificates are valid.  `None` means to use the
    /// current time. It can be used for testing to override the current view of the time.
    ///
    /// This is a separate function because it's likely to be somewhat CPU-intensive.
    pub fn verify(
        self,
        peer_target: &OwnedChanTarget,
        peer_tls_cert: &[u8],
        now: Option<std::time::SystemTime>,
    ) -> Result<VerifiedInitiatorRelayChannel<T, S>> {
        // Get these object out as we consume "self" in the inner check().
        let auth_challenge_cell = self.auth_challenge_cell;
        let identities = self.auth_material;
        let my_addrs = self.my_addrs;
        let netinfo_cell = self.netinfo_cell;

        let peer_tls_cert_digest = tor_llcrypto::d::Sha256::digest(peer_tls_cert).into();

        // Verify our inner channel and then proceed to handle the authentication challenge if any.
        let verified = self.inner.verify(peer_target, peer_tls_cert_digest, now)?;

        Ok(VerifiedInitiatorRelayChannel {
            inner: verified,
            auth_material: identities,
            netinfo_cell,
            auth_challenge_cell,
            peer_tls_cert_digest,
            slog_digest: self.slog_digest,
            my_addrs,
            create_request_handler: self.create_request_handler,
        })
    }

    /// Return the clock skew of this channel.
    pub fn clock_skew(&self) -> ClockSkew {
        self.inner.inner.clock_skew
    }

    /// Return the link protocol version of this channel.
    #[cfg(test)]
    pub(crate) fn link_protocol(&self) -> u16 {
        self.inner.inner.link_protocol
    }
}

/// A verified relay initiator channel.
///
/// Holding this object means the channel TLS layer has been verified against the received CERTS
/// cell and we now believe that we are talking to the right relay end point.
///
/// The finish() function needs to be called in order to finalize this channel into a generic
/// Channel/Reactor.
pub struct VerifiedInitiatorRelayChannel<
    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
    S: CoarseTimeProvider + SleepProvider,
> {
    /// The common unverified channel that both client and relays use.
    inner: VerifiedChannel<T, S>,
    /// Relay channel authentication material.
    auth_material: Arc<RelayChannelAuthMaterial>,
    /// The netinfo cell that we got from the relay.
    netinfo_cell: msg::Netinfo,
    /// The AUTH_CHALLENGE cell that we got from the relay.
    auth_challenge_cell: msg::AuthChallenge,
    /// The peer TLS certificate digest.
    peer_tls_cert_digest: [u8; 32],
    /// The SLOG digest.
    slog_digest: SlogDigest,
    /// Our advertised IP addresses.
    my_addrs: Vec<IpAddr>,
    /// Provided to each new channel so that they can handle CREATE* requests.
    create_request_handler: Arc<CreateRequestHandler>,
}

impl<T, S> VerifiedInitiatorRelayChannel<T, S>
where
    T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
    S: CoarseTimeProvider + SleepProvider,
{
    /// Send our [`msg::Certs`], [`msg::Authenticate`] and [`msg::Netinfo`] to the relay to finish
    /// the handshake, which will create an open channel and reactor.
    ///
    /// The resulting channel is considered, by Tor protocol standard, an authenticated relay
    /// channel on which circuits can be opened.
    pub async fn finish(mut self, peer_addr: PeerAddr) -> Result<(Arc<Channel>, Reactor<S>)>
    where
        S: Runtime,
    {
        // Send the CERTS cell.
        let certs = super::build_certs_cell(&self.auth_material, /* is_responder */ false);
        trace!(channel_id = %self.inner.unique_id, "Sending CERTS as initiator cell.");
        self.inner.framed_tls.send(certs.into()).await?;

        // We're the initiator, which means that the send log is the CLOG.
        //
        // We can finalize the CLOG now that we're about to send the AUTHENTICATE cell.
        //
        // > The CLOG field is computed as the SHA-256 digest of all bytes sent within
        // > the TLS channel up to but not including the AUTHENTICATE cell.
        let clog_digest =
            ClogDigest::new(self.inner.framed_tls.codec_mut().take_send_log_digest()?);

        // Build the AUTHENTICATE cell.
        //
        // By building the ChannelAuthenticationData, we are certain that the authentication
        // type requested by the responder is supported by us.
        let auth_cell = ChannelAuthenticationData::build_initiator(
            &self.auth_challenge_cell,
            &self.auth_material,
            clog_digest,
            self.slog_digest,
            &mut self.inner,
            self.peer_tls_cert_digest,
        )?
        .into_authenticate(
            self.inner.framed_tls.deref(),
            &self.auth_material.link_sign_kp,
        )?;

        // Send the AUTHENTICATE cell.
        trace!(channel_id = %self.inner.unique_id, "Sending AUTHENTICATE as initiator cell.");
        self.inner.framed_tls.send(auth_cell.into()).await?;

        // Send our NETINFO cell. This will indicate the end of the handshake.
        let netinfo = super::build_netinfo_cell(
            peer_addr.netinfo_addr(),
            self.my_addrs.clone(),
            &self.inner.sleep_prov,
        )?;
        trace!(channel_id = %self.inner.unique_id, "Sending NETINFO as initiator cell.");
        self.inner.framed_tls.send(netinfo.into()).await?;

        // Relay only initiate to another relay so NOT sensitive.
        let peer_info =
            MaybeSensitive::not_sensitive(PeerInfo::new(peer_addr, self.inner.relay_ids().clone()));

        let channel_mode = ChannelMode::Relay {
            circ_id_range: CircIdRange::High,
            our_ed25519_id: self.auth_material.ed_id,
            our_rsa_id: self.auth_material.rsa_id,
            create_request_handler: self.create_request_handler,
        };

        // Get a Channel and a Reactor.
        self.inner
            .finish(&self.netinfo_cell, &self.my_addrs, peer_info, channel_mode)
            .await
    }
}