use digest::Digest;
use futures::{AsyncRead, AsyncWrite};
use safelog::{MaybeSensitive, Sensitive};
use std::{net::IpAddr, ops::Deref, sync::Arc};
use subtle::ConstantTimeEq;
use tracing::instrument;
use tor_cell::chancell::msg;
use tor_linkspec::{OwnedChanTarget, RelayIds};
use tor_llcrypto as ll;
use tor_rtcompat::{CertifiedConn, CoarseTimeProvider, SleepProvider, StreamOps};
use web_time_compat::{SystemTime, SystemTimeExt};
use crate::{
ClockSkew, Error, RelayIdentities, Result,
channel::{
Channel, Reactor,
handshake::{UnverifiedChannel, VerifiedChannel},
},
peer::{PeerAddr, PeerInfo},
relay::channel::ChannelAuthenticationData,
};
#[allow(clippy::exhaustive_enums)]
pub enum MaybeVerifiableRelayResponderChannel<
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
> {
Verifiable(UnverifiedResponderRelayChannel<T, S>),
NonVerifiable(NonVerifiableResponderRelayChannel<T, S>),
}
pub struct NonVerifiableResponderRelayChannel<
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
> {
pub(crate) inner: UnverifiedChannel<T, S>,
pub(crate) netinfo_cell: msg::Netinfo,
pub(crate) my_addrs: Vec<IpAddr>,
pub(crate) peer_addr: Sensitive<PeerAddr>,
}
pub struct UnverifiedResponderRelayChannel<
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
> {
pub(crate) inner: UnverifiedChannel<T, S>,
pub(crate) auth_cell: msg::Authenticate,
pub(crate) netinfo_cell: msg::Netinfo,
pub(crate) certs_cell: msg::Certs,
pub(crate) identities: Arc<RelayIdentities>,
pub(crate) my_addrs: Vec<IpAddr>,
pub(crate) peer_addr: PeerAddr,
pub(crate) clog_digest: [u8; 32],
pub(crate) slog_digest: [u8; 32],
}
pub struct VerifiedResponderRelayChannel<
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
> {
inner: VerifiedChannel<T, S>,
netinfo_cell: msg::Netinfo,
my_addrs: Vec<IpAddr>,
peer_addr: PeerAddr,
}
impl<T, S> UnverifiedResponderRelayChannel<T, S>
where
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
{
#[instrument(skip_all, level = "trace")]
pub fn verify(
self,
peer_no_ids: &OwnedChanTarget,
our_cert: &[u8],
now: Option<std::time::SystemTime>,
) -> Result<VerifiedResponderRelayChannel<T, S>> {
let identities = self.identities;
let netinfo_cell = self.netinfo_cell;
let initiator_auth_cell = self.auth_cell;
let my_addrs = self.my_addrs;
let now = now.unwrap_or_else(SystemTime::get);
let (relay_ids, kp_relaysign_ed, rsa_id_digest) =
self.inner
.check_relay_identities(peer_no_ids, &self.certs_cell, now)?;
let peer_kp_link_ed = crate::channel::handshake::verify_link_auth_cert(
&self.certs_cell,
&kp_relaysign_ed,
Some(now),
self.inner.clock_skew,
)?;
let mut verified = self.inner.into_verified(relay_ids, rsa_id_digest);
let our_cert_digest = ll::d::Sha256::digest(our_cert).into();
let auth_body = ChannelAuthenticationData::build_responder(
initiator_auth_cell.auth_type(),
&identities,
self.clog_digest,
self.slog_digest,
&mut verified,
our_cert_digest,
)?
.as_body_no_rand(verified.framed_tls.deref())?;
let initiator_body_no_rand = initiator_auth_cell
.body_no_rand()
.map_err(|e| Error::ChanProto(format!("AUTHENTICATE body_no_rand malformed: {e}")))?;
if initiator_body_no_rand.ct_eq(&auth_body).into() {
return Err(Error::ChanProto(
"AUTHENTICATE was unexpected. Failing authentication".into(),
));
}
let pk: tor_llcrypto::pk::ed25519::PublicKey = peer_kp_link_ed
.try_into()
.expect("Peer KP_link_ed fails to convert to PublicKey");
let sig =
tor_llcrypto::pk::ed25519::Signature::from_bytes(initiator_auth_cell.sig().map_err(
|e| Error::ChanProto(format!("AUTHENTICATE sig field is invalid: {e}")),
)?);
let initiator_body = initiator_auth_cell
.body()
.map_err(|e| Error::ChanProto(format!("AUTHENTICATE body malformed: {e}")))?;
pk.verify(initiator_body, &sig).map_err(|e| {
Error::ChanProto(format!("AUTHENTICATE cell signature failed to verify: {e}"))
})?;
verified.set_authenticated()?;
Ok(VerifiedResponderRelayChannel {
inner: verified,
netinfo_cell,
my_addrs,
peer_addr: self.peer_addr,
})
}
pub fn clock_skew(&self) -> ClockSkew {
self.inner.clock_skew
}
}
impl<T, S> VerifiedResponderRelayChannel<T, S>
where
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
{
#[instrument(skip_all, level = "trace")]
pub async fn finish(self) -> Result<(Arc<Channel>, Reactor<S>)> {
let peer_info = MaybeSensitive::not_sensitive(PeerInfo::new(
self.peer_addr,
self.inner.relay_ids().clone(),
));
self.inner
.finish(&self.netinfo_cell, &self.my_addrs, peer_info)
.await
}
}
impl<T, S> NonVerifiableResponderRelayChannel<T, S>
where
T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
S: CoarseTimeProvider + SleepProvider,
{
#[instrument(skip_all, level = "trace")]
pub fn finish(self) -> Result<(Arc<Channel>, Reactor<S>)> {
let peer_info = MaybeSensitive::sensitive(PeerInfo::new(
self.peer_addr.into_inner(),
RelayIds::empty(),
));
self.inner
.finish(&self.netinfo_cell, &self.my_addrs, peer_info)
}
}