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, SleepProvider, StreamOps};
use crate::{
ClockSkew, RelayIdentities, Result,
channel::{
Channel, Reactor,
handshake::{UnverifiedInitiatorChannel, VerifiedChannel},
},
peer::{PeerAddr, PeerInfo},
relay::channel::ChannelAuthenticationData,
};
pub struct UnverifiedInitiatorRelayChannel<
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
> {
pub(crate) inner: UnverifiedInitiatorChannel<T, S>,
pub(crate) auth_challenge_cell: msg::AuthChallenge,
pub(crate) slog_digest: [u8; 32],
pub(crate) netinfo_cell: msg::Netinfo,
pub(crate) identities: Arc<RelayIdentities>,
pub(crate) my_addrs: Vec<IpAddr>,
}
impl<T, S> UnverifiedInitiatorRelayChannel<T, S>
where
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
{
pub fn verify(
self,
peer: &OwnedChanTarget,
peer_cert: &[u8],
now: Option<std::time::SystemTime>,
) -> Result<VerifiedInitiatorRelayChannel<T, S>> {
let auth_challenge_cell = self.auth_challenge_cell;
let identities = self.identities;
let my_addrs = self.my_addrs;
let netinfo_cell = self.netinfo_cell;
let peer_cert_digest = tor_llcrypto::d::Sha256::digest(peer_cert).into();
let mut verified = self.inner.verify(peer, peer_cert_digest, now)?;
verified.set_authenticated()?;
Ok(VerifiedInitiatorRelayChannel {
inner: verified,
identities,
netinfo_cell,
auth_challenge_cell,
peer_cert_digest,
slog_digest: self.slog_digest,
my_addrs,
})
}
pub fn clock_skew(&self) -> ClockSkew {
self.inner.inner.clock_skew
}
}
pub struct VerifiedInitiatorRelayChannel<
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
> {
inner: VerifiedChannel<T, S>,
identities: Arc<RelayIdentities>,
netinfo_cell: msg::Netinfo,
auth_challenge_cell: msg::AuthChallenge,
peer_cert_digest: [u8; 32],
slog_digest: [u8; 32],
my_addrs: Vec<IpAddr>,
}
impl<T, S> VerifiedInitiatorRelayChannel<T, S>
where
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
{
pub async fn finish(mut self, peer_addr: PeerAddr) -> Result<(Arc<Channel>, Reactor<S>)> {
let certs = super::build_certs_cell(&self.identities, false);
trace!(channel_id = %self.inner.unique_id, "Sending CERTS as initiator cell.");
self.inner.framed_tls.send(certs.into()).await?;
let clog_digest = self.inner.framed_tls.codec_mut().take_send_log_digest()?;
let auth_cell = ChannelAuthenticationData::build_initiator(
&self.auth_challenge_cell,
&self.identities,
clog_digest,
self.slog_digest,
&mut self.inner,
self.peer_cert_digest,
)?
.into_authenticate(self.inner.framed_tls.deref(), &self.identities.link_sign_kp)?;
trace!(channel_id = %self.inner.unique_id, "Sending AUTHENTICATE as initiator cell.");
self.inner.framed_tls.send(auth_cell.into()).await?;
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?;
let peer_info =
MaybeSensitive::not_sensitive(PeerInfo::new(peer_addr, self.inner.relay_ids().clone()));
self.inner
.finish(&self.netinfo_cell, &self.my_addrs, peer_info)
.await
}
}