Lines
96.77 %
Functions
47.71 %
Branches
100 %
//! Different kinds of messages that can be encoded in channel cells.
use super::{ChanCmd, RawCellBody, CELL_DATA_LEN};
use std::convert::TryInto;
use std::net::{IpAddr, Ipv4Addr};
use tor_basic_utils::skip_fmt;
use tor_bytes::{self, Error, Readable, Reader, Result, Writer};
use caret::caret_int;
use educe::Educe;
/// Trait for the 'bodies' of channel messages.
pub trait Body: Readable {
/// Convert this type into a ChanMsg, wrapped as appropriate.
fn into_message(self) -> ChanMsg;
/// Consume this message and encode its body onto `w`.
///
/// Does not encode anything _but_ the cell body, and does not pad
/// to the cell length.
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W);
}
/// Decoded message from a channel.
/// A ChanMsg is an item received on a channel -- a message from
/// another Tor client or relay that we are connected to directly over
/// a TLS connection.
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum ChanMsg {
/// A Padding message
Padding(Padding),
/// Variable-length padding message
VPadding(VPadding),
/// (Deprecated) TAP-based cell to create a new circuit.
Create(Create),
/// (Mostly deprecated) HMAC-based cell to create a new circuit.
CreateFast(CreateFast),
/// Cell to create a new circuit
Create2(Create2),
/// (Deprecated) Answer to a Create cell
Created(Created),
/// (Mostly Deprecated) Answer to a CreateFast cell
CreatedFast(CreatedFast),
/// Answer to a Create2 cell
Created2(Created2),
/// A message sent along a circuit, likely to a more-distant relay.
Relay(Relay),
/// A message sent along a circuit (limited supply)
RelayEarly(Relay),
/// Tear down a circuit
Destroy(Destroy),
/// Part of channel negotiation: describes our position on the network
Netinfo(Netinfo),
/// Part of channel negotiation: describes what link protocol versions
/// we support
Versions(Versions),
/// Negotiates what kind of channel padding to send
PaddingNegotiate(PaddingNegotiate),
/// Part of channel negotiation: additional certificates not in the
/// TLS handshake
Certs(Certs),
/// Part of channel negotiation: additional random material to be used
/// as part of authentication
AuthChallenge(AuthChallenge),
/// Part of channel negotiation: used to authenticate relays when they
/// initiate the channel.
Authenticate(Authenticate),
/// Not yet used
Authorize(Authorize),
/// Any cell whose command we don't recognize
Unrecognized(Unrecognized),
impl ChanMsg {
/// Return the ChanCmd for this message.
pub fn cmd(&self) -> ChanCmd {
use ChanMsg::*;
match self {
Padding(_) => ChanCmd::PADDING,
VPadding(_) => ChanCmd::VPADDING,
Create(_) => ChanCmd::CREATE,
CreateFast(_) => ChanCmd::CREATE_FAST,
Create2(_) => ChanCmd::CREATE2,
Created(_) => ChanCmd::CREATED,
CreatedFast(_) => ChanCmd::CREATED_FAST,
Created2(_) => ChanCmd::CREATED2,
Relay(_) => ChanCmd::RELAY,
RelayEarly(_) => ChanCmd::RELAY_EARLY,
Destroy(_) => ChanCmd::DESTROY,
Netinfo(_) => ChanCmd::NETINFO,
Versions(_) => ChanCmd::VERSIONS,
PaddingNegotiate(_) => ChanCmd::PADDING_NEGOTIATE,
Certs(_) => ChanCmd::CERTS,
AuthChallenge(_) => ChanCmd::AUTH_CHALLENGE,
Authenticate(_) => ChanCmd::AUTHENTICATE,
Authorize(_) => ChanCmd::AUTHORIZE,
Unrecognized(c) => c.cmd(),
/// Write the body of this message (not including length or command).
pub fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) {
Padding(b) => b.write_body_onto(w),
VPadding(b) => b.write_body_onto(w),
Create(b) => b.write_body_onto(w),
CreateFast(b) => b.write_body_onto(w),
Create2(b) => b.write_body_onto(w),
Created(b) => b.write_body_onto(w),
CreatedFast(b) => b.write_body_onto(w),
Created2(b) => b.write_body_onto(w),
Relay(b) => b.write_body_onto(w),
RelayEarly(b) => b.write_body_onto(w),
Destroy(b) => b.write_body_onto(w),
Netinfo(b) => b.write_body_onto(w),
Versions(b) => b.write_body_onto(w),
PaddingNegotiate(b) => b.write_body_onto(w),
Certs(b) => b.write_body_onto(w),
AuthChallenge(b) => b.write_body_onto(w),
Authenticate(b) => b.write_body_onto(w),
Authorize(b) => b.write_body_onto(w),
Unrecognized(b) => b.write_body_onto(w),
/// Decode this message from a given reader, according to a specified
/// command value. The reader must be truncated to the exact length
/// of the body.
pub fn take(r: &mut Reader<'_>, cmd: ChanCmd) -> Result<Self> {
Ok(match cmd {
ChanCmd::PADDING => Padding(r.extract()?),
ChanCmd::VPADDING => VPadding(r.extract()?),
ChanCmd::CREATE => Create(r.extract()?),
ChanCmd::CREATE_FAST => CreateFast(r.extract()?),
ChanCmd::CREATE2 => Create2(r.extract()?),
ChanCmd::CREATED => Created(r.extract()?),
ChanCmd::CREATED_FAST => CreatedFast(r.extract()?),
ChanCmd::CREATED2 => Created2(r.extract()?),
ChanCmd::RELAY => Relay(r.extract()?),
ChanCmd::RELAY_EARLY => RelayEarly(r.extract()?),
ChanCmd::DESTROY => Destroy(r.extract()?),
ChanCmd::NETINFO => Netinfo(r.extract()?),
ChanCmd::VERSIONS => Versions(r.extract()?),
ChanCmd::PADDING_NEGOTIATE => PaddingNegotiate(r.extract()?),
ChanCmd::CERTS => Certs(r.extract()?),
ChanCmd::AUTH_CHALLENGE => AuthChallenge(r.extract()?),
ChanCmd::AUTHENTICATE => Authenticate(r.extract()?),
ChanCmd::AUTHORIZE => Authorize(r.extract()?),
_ => Unrecognized(unrecognized_with_cmd(cmd, r)?),
})
/// A Padding message is a fixed-length message on a channel that is
/// ignored.
/// Padding message can be used to disguise the true amount of data on a
/// channel, or as a "keep-alive".
/// The correct response to a padding cell is to drop it and do nothing.
#[derive(Clone, Debug, Default)]
pub struct Padding {}
impl Padding {
/// Create a new fixed-length padding cell
pub fn new() -> Self {
Padding {}
impl Body for Padding {
fn into_message(self) -> ChanMsg {
ChanMsg::Padding(self)
fn write_body_onto<W: Writer + ?Sized>(self, _w: &mut W) {}
impl Readable for Padding {
fn take_from(_r: &mut Reader<'_>) -> Result<Self> {
Ok(Padding {})
/// A VPadding message is a variable-length padding message.
pub struct VPadding {
/// How much padding to send in this cell's body.
len: u16,
impl VPadding {
/// Return a new vpadding cell with given length.
pub fn new(len: u16) -> Self {
VPadding { len }
impl Body for VPadding {
ChanMsg::VPadding(self)
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) {
w.write_zeros(self.len as usize);
impl Readable for VPadding {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
if r.remaining() > std::u16::MAX as usize {
return Err(Error::BadMessage("Too many bytes in VPADDING cell"));
Ok(VPadding {
len: r.remaining() as u16,
/// helper -- declare a fixed-width cell where a fixed number of bytes
/// matter and the rest are ignored
macro_rules! fixed_len {
{
$(#[$meta:meta])*
$name:ident , $cmd:ident, $len:ident
} => {
$(#[$meta])*
#[derive(Clone,Debug)]
pub struct $name {
handshake: Vec<u8>
impl $name {
/// Create a new cell from a provided handshake.
pub fn new<B>(handshake: B) -> Self
where B: Into<Vec<u8>>
let handshake = handshake.into();
$name { handshake }
impl Body for $name {
ChanMsg::$name(self)
w.write_all(&self.handshake[..])
impl Readable for $name {
Ok($name {
handshake: r.take($len)?.into(),
/// Number of bytes used for a TAP handshake by the initiator.
pub(crate) const TAP_C_HANDSHAKE_LEN: usize = 128 + 16 + 42;
/// Number of bytes used for a TAP handshake response
pub(crate) const TAP_S_HANDSHAKE_LEN: usize = 128 + 20;
/// Number of bytes used for a CREATE_FAST handshake by the initiator
const FAST_C_HANDSHAKE_LEN: usize = 20;
/// Number of bytes used for a CRATE_FAST handshake response
const FAST_S_HANDSHAKE_LEN: usize = 20 + 20;
fixed_len! {
/// A Create message creates a circuit, using the TAP handshake.
/// TAP is an obsolete handshake based on RSA-1024 and DH-1024.
/// Relays respond to Create message with a Created reply on
/// success, or a Destroy message on failure.
/// In Tor today, Create is only used for the deprecated v2 onion
/// service protocol.
Create, CREATE, TAP_C_HANDSHAKE_LEN
/// A Created message responds to a Created message, using the TAP
/// handshake.
Created, CREATED, TAP_S_HANDSHAKE_LEN
/// A CreateFast message creates a circuit using no public-key crypto.
/// CreateFast is safe only when used on an already-secure TLS
/// connection. It can only be used for the first hop of a circuit.
/// Relays reply to a CreateFast message with CreatedFast on
/// This handshake was originally used for the first hop of every
/// circuit. Nowadays it is used for creating one-hop circuits
/// when we don't know any onion key for the first hop.
CreateFast, CREATE_FAST, FAST_C_HANDSHAKE_LEN
impl CreateFast {
/// Return the content of this handshake
pub fn body(&self) -> &[u8] {
&self.handshake
/// A CreatedFast message responds to a CreateFast message
/// Relays send this message back to indicate that the CrateFast handshake
/// is complete.
CreatedFast, CREATED_FAST, FAST_S_HANDSHAKE_LEN
impl CreatedFast {
/// Consume this message and return the content of this handshake
pub fn into_body(self) -> Vec<u8> {
self.handshake
/// A Create2 message create a circuit on the current channel.
/// To create a circuit, the client sends a Create2 cell containing a
/// handshake of a given type; the relay responds with a Created2 cell
/// containing a reply.
/// Currently, most Create2 cells contain a client-side instance of the
/// "ntor" handshake.
pub struct Create2 {
/// Identifier for what kind of handshake this is.
handshake_type: u16,
/// Body of the handshake.
handshake: Vec<u8>,
impl Body for Create2 {
ChanMsg::Create2(self)
w.write_u16(self.handshake_type);
assert!(self.handshake.len() <= std::u16::MAX as usize);
w.write_u16(self.handshake.len() as u16);
w.write_all(&self.handshake[..]);
impl Readable for Create2 {
let handshake_type = r.take_u16()?;
let hlen = r.take_u16()?;
let handshake = r.take(hlen as usize)?.into();
Ok(Create2 {
handshake_type,
handshake,
impl Create2 {
/// Wrap a typed handshake as a Create2 message
pub fn new<B>(handshake_type: u16, handshake: B) -> Self
where
B: Into<Vec<u8>>,
Create2 {
/// Return the type of this handshake.
pub fn handshake_type(&self) -> u16 {
self.handshake_type
/// Return the body of this handshake.
&self.handshake[..]
/// A Created2 message completes a circuit-creation handshake.
/// When a relay receives a valid Create2 message that it can handle, it
/// establishes the circuit and replies with a Created2.
pub struct Created2 {
/// Body of the handshake reply
impl Created2 {
/// Create a new Created2 to hold a given handshake.
Created2 { handshake }
/// Consume this created2 cell and return its body.
impl Body for Created2 {
ChanMsg::Created2(self)
impl Readable for Created2 {
Ok(Created2 { handshake })
/// A Relay cell - that is, one transmitted over a circuit.
/// Once a circuit has been established, relay cells can be sent over
/// it. Clients can send relay cells to any relay on the circuit. Any
/// relay on the circuit can send relay cells to the client, either
/// directly (if it is the first hop), or indirectly through the
/// intermediate hops.
/// A different protocol is defined over the relay cells; it is implemented
/// in the [crate::relaycell] module.
#[derive(Clone, Educe)]
#[educe(Debug)]
pub struct Relay {
/// The contents of the relay cell as encoded for transfer.
/// TODO(nickm): It's nice that this is boxed, since we don't want to copy
/// cell data all over the place. But unfortunately, a there are some other
/// places where we _don't_ Box things that we should, and more copies than
/// necessary happen. We should refactor our data handling until we're mostly
/// moving around pointers rather than copying data; see ticket #7.
#[educe(Debug(method = "skip_fmt"))]
body: Box<RawCellBody>,
impl Relay {
/// Construct a Relay message from a slice containing its contents.
pub fn new<P>(body: P) -> Self
P: AsRef<[u8]>,
let body = body.as_ref();
let mut r = [0_u8; CELL_DATA_LEN];
// TODO: This will panic if body is too long, but that would be a
// programming error anyway.
r[..body.len()].copy_from_slice(body);
Relay { body: Box::new(r) }
/// Construct a Relay message from its body.
pub fn from_raw(body: RawCellBody) -> Self {
Relay {
body: Box::new(body),
/// Consume this Relay message and return a RelayCellBody for
/// encryption/decryption.
pub fn into_relay_body(self) -> RawCellBody {
*self.body
/// Wrap this Relay message into a RelayMsg as a RELAY_EARLY cell.
pub fn into_early(self) -> ChanMsg {
ChanMsg::RelayEarly(self)
impl Body for Relay {
ChanMsg::Relay(self)
w.write_all(&self.body[..]);
impl Readable for Relay {
let mut body = Box::new([0_u8; CELL_DATA_LEN]);
body.copy_from_slice(r.take(CELL_DATA_LEN)?);
Ok(Relay { body })
/// The Destroy message tears down a circuit.
/// On receiving a Destroy message, a Tor implementation should
/// tear down the associated circuit, and pass the destroy message
/// down the circuit to later/earlier hops on the circuit (if any).
pub struct Destroy {
/// Reason code given for tearing down this circuit
reason: DestroyReason,
impl Destroy {
/// Create a new destroy cell.
pub fn new(reason: DestroyReason) -> Self {
Destroy { reason }
/// Return the provided reason for destroying the circuit.
pub fn reason(&self) -> DestroyReason {
self.reason
impl Body for Destroy {
ChanMsg::Destroy(self)
w.write_u8(self.reason.into());
impl Readable for Destroy {
let reason = r.take_u8()?.into();
Ok(Destroy { reason })
caret_int! {
/// Declared reason for ending a circuit.
pub struct DestroyReason(u8) {
/// No reason given.
/// (This is the only reason that clients send.
NONE = 0,
/// Protocol violation
PROTOCOL = 1,
/// Internal error.
INTERNAL = 2,
/// Client sent a TRUNCATE command.
REQUESTED = 3,
/// Relay is hibernating and not accepting requests
HIBERNATING = 4,
/// Ran out of memory, sockets, or circuit IDs
RESOURCELIMIT = 5,
/// Couldn't connect to relay.
CONNECTFAILED = 6,
/// Connected to a relay, but its OR identity wasn't as requested.
OR_IDENTITY = 7,
/// One of the OR channels carrying this circuit died.
CHANNEL_CLOSED = 8,
/// Circuit expired for being too dirty or old
FINISHED = 9,
/// Circuit construction took too long
TIMEOUT = 10,
/// Circuit was destroyed w/o client truncate (?)
DESTROYED = 11,
/// Request for unknown onion service
NOSUCHSERVICE = 12
impl DestroyReason {
/// Return a human-readable string for this reason.
pub fn human_str(&self) -> &'static str {
match *self {
DestroyReason::NONE => "No reason",
DestroyReason::PROTOCOL => "Protocol violation",
DestroyReason::INTERNAL => "Internal error",
DestroyReason::REQUESTED => "Client sent a TRUNCATE command",
DestroyReason::HIBERNATING => "Relay is hibernating and not accepting requests",
DestroyReason::RESOURCELIMIT => "Relay ran out of resources",
DestroyReason::CONNECTFAILED => "Couldn't connect to relay",
DestroyReason::OR_IDENTITY => "Connected to relay with different OR identity",
DestroyReason::CHANNEL_CLOSED => "The OR channels carrying this circuit died",
DestroyReason::FINISHED => "Circuit expired for being too dirty or old",
DestroyReason::TIMEOUT => "Circuit construction took too long",
DestroyReason::DESTROYED => "Circuit was destroyed without client truncate",
DestroyReason::NOSUCHSERVICE => "No such onion service",
_ => "Unrecognized reason",
/// The netinfo message ends channel negotiation.
/// It tells the other party on the channel our view of the current time,
/// our own list of public addresses, and our view of its address.
/// When we get a netinfo cell, we can start creating circuits on a
/// channel and sending data.
pub struct Netinfo {
/// Time when this cell was sent, or 0 if this cell is sent by
/// a client.
timestamp: u32,
/// Observed address for party that did not send the netinfo cell.
their_addr: Option<IpAddr>,
/// Canonical addresses for the party that did send the netinfo cell.
my_addr: Vec<IpAddr>,
/// helper: encode a single address in the form that netinfo messages expect
fn enc_one_netinfo_addr<W: Writer + ?Sized>(w: &mut W, addr: &IpAddr) {
match addr {
IpAddr::V4(ipv4) => {
w.write_u8(0x04); // type.
w.write_u8(4); // length.
w.write_all(&ipv4.octets()[..]);
IpAddr::V6(ipv6) => {
w.write_u8(0x06); // type.
w.write_u8(16); // length.
w.write_all(&ipv6.octets()[..]);
/// helper: take an address as encoded in a netinfo message
fn take_one_netinfo_addr(r: &mut Reader<'_>) -> Result<Option<IpAddr>> {
let atype = r.take_u8()?;
let alen = r.take_u8()?;
let abody = r.take(alen as usize)?;
match (atype, alen) {
(0x04, 4) => {
let bytes = [abody[0], abody[1], abody[2], abody[3]];
Ok(Some(IpAddr::V4(bytes.into())))
(0x06, 16) => {
// TODO(nickm) is there a better way?
let mut bytes = [0_u8; 16];
bytes.copy_from_slice(abody);
Ok(Some(IpAddr::V6(bytes.into())))
(0x04, _) => Ok(None),
(0x06, _) => Ok(None),
(_, _) => Ok(None),
impl Netinfo {
/// Construct a new Netinfo to be sent by a client.
pub fn for_client(their_addr: Option<IpAddr>) -> Self {
Netinfo {
timestamp: 0, // clients don't report their timestamps.
their_addr,
my_addr: Vec::new(), // clients don't report their addrs.
/// Construct a new Netinfo to be sent by a relay
pub fn for_relay<V>(timestamp: u32, their_addr: Option<IpAddr>, my_addrs: V) -> Self
V: Into<Vec<IpAddr>>,
let my_addr = my_addrs.into();
timestamp,
my_addr,
impl Body for Netinfo {
ChanMsg::Netinfo(self)
w.write_u32(self.timestamp);
let their_addr = self
.their_addr
.unwrap_or_else(|| Ipv4Addr::UNSPECIFIED.into());
enc_one_netinfo_addr(w, &their_addr);
let n_addrs: u8 = self
.my_addr
.len()
.try_into()
.expect("Too many addrs in netinfo cell");
w.write_u8(n_addrs);
for addr in &self.my_addr {
enc_one_netinfo_addr(w, addr);
impl Readable for Netinfo {
let timestamp = r.take_u32()?;
let their_addr = take_one_netinfo_addr(r)?.filter(|a| !a.is_unspecified());
let mut my_addr = Vec::new();
let my_n_addrs = r.take_u8()?;
for _ in 0..my_n_addrs {
if let Some(a) = take_one_netinfo_addr(r)? {
my_addr.push(a);
Ok(Netinfo {
/// A Versions message begins channel negotiation.
/// Every channel must begin by sending a Versions message. This message
/// lists the link protocol versions that this Tor implementation supports.
/// Note that we should never actually send Versions cells using the
/// usual channel cell encoding: Versions cells _always_ use two-byte
/// circuit IDs, whereas all the other cell types use four-byte
/// circuit IDs [assuming a non-obsolete version is negotiated].
pub struct Versions {
/// List of supported link protocol versions
versions: Vec<u16>,
impl Versions {
/// Construct a new Versions message using a provided list of link
/// protocols.
/// Returns an error if the list of versions is too long.
pub fn new<B>(vs: B) -> crate::Result<Self>
B: Into<Vec<u16>>,
let versions = vs.into();
if versions.len() < (std::u16::MAX / 2) as usize {
Ok(Self { versions })
} else {
Err(crate::Error::CantEncode)
/// Encode this VERSIONS cell in the manner expected for a handshake.
/// (That's different from a standard cell encoding, since we
/// have not negotiated versions yet, and so our circuit-ID length
/// is an obsolete 2 bytes).
pub fn encode_for_handshake(self) -> Vec<u8> {
let mut v = Vec::new();
v.write_u16(0); // obsolete circuit ID length.
v.write_u8(ChanCmd::VERSIONS.into());
v.write_u16((self.versions.len() * 2) as u16); // message length.
self.write_body_onto(&mut v);
v
/// Return the best (numerically highest) link protocol that is
/// shared by this versions cell and my_protos.
pub fn best_shared_link_protocol(&self, my_protos: &[u16]) -> Option<u16> {
// NOTE: this implementation is quadratic, but it shouldn't matter
// much so long as my_protos is small.
let p = my_protos
.iter()
.filter(|p| self.versions.contains(p))
.fold(0_u16, |a, b| u16::max(a, *b));
if p == 0 {
None
Some(p)
impl Body for Versions {
ChanMsg::Versions(self)
for v in &self.versions {
w.write_u16(*v);
impl Readable for Versions {
let mut versions = Vec::new();
while r.remaining() > 0 {
versions.push(r.take_u16()?);
Ok(Versions { versions })
/// A PaddingNegotiate message is used to negotiate channel padding.
/// TODO: say more once we implement channel padding.
pub struct PaddingNegotiate {
/// Whether to start or stop padding
command: u8,
/// Suggested lower-bound value for inter-packet timeout in msec.
// TODO(nickm) is that right?
ito_low_ms: u16,
/// Suggested upper-bound value for inter-packet timeout in msec.
ito_high_ms: u16,
impl PaddingNegotiate {
/// Create a new PaddingNegotiate message.
/// If `start` is true, this is a message to enable padding. Otherwise
/// this is a message to disable padding.
pub fn new(start: bool, ito_low_ms: u16, ito_high_ms: u16) -> Self {
let command = if start { 2 } else { 1 };
Self {
command,
ito_low_ms,
ito_high_ms,
impl Body for PaddingNegotiate {
ChanMsg::PaddingNegotiate(self)
w.write_u8(0); // version
w.write_u8(self.command);
w.write_u16(self.ito_low_ms);
w.write_u16(self.ito_high_ms);
impl Readable for PaddingNegotiate {
let v = r.take_u8()?;
if v != 0 {
return Err(Error::BadMessage(
"Unrecognized padding negotiation version",
));
let command = r.take_u8()?;
let ito_low_ms = r.take_u16()?;
let ito_high_ms = r.take_u16()?;
Ok(PaddingNegotiate {
/// A single certificate in a Certs cell.
/// The formats used here are implemented in tor-cert. Ed25519Cert is the
/// most common.
struct TorCert {
/// Type code for this certificate.
certtype: u8,
/// Encoded certificate
cert: Vec<u8>,
/// encode a single TorCert `c` onto a Writer `w`.
fn enc_one_tor_cert<W: Writer + ?Sized>(w: &mut W, c: &TorCert) {
w.write_u8(c.certtype);
let cert_len: u16 = c
.cert
.expect("Impossibly long certificate");
w.write_u16(cert_len);
w.write_all(&c.cert[..]);
/// Try to extract a TorCert from the reader `r`.
fn take_one_tor_cert(r: &mut Reader<'_>) -> Result<TorCert> {
let certtype = r.take_u8()?;
let certlen = r.take_u16()?;
let cert = r.take(certlen as usize)?;
Ok(TorCert {
certtype,
cert: cert.into(),
/// A Certs message is used as part of the channel handshake to send
/// additional certificates.
/// These certificates are not presented as part of the TLS handshake.
/// Originally this was meant to make Tor TLS handshakes look "normal", but
/// nowadays it serves less purpose, especially now that we have TLS 1.3.
/// Every relay sends this message as part of channel negotiation;
/// clients do not send them.
pub struct Certs {
/// The certificates in this cell
certs: Vec<TorCert>,
impl Certs {
/// Return a new empty certs cell.
pub fn new_empty() -> Self {
Certs { certs: Vec::new() }
/// Add a new encoded certificate to this cell.
/// Does not check anything about the well-formedness of the certificate.
pub fn push_cert_body<B>(&mut self, certtype: tor_cert::CertType, cert: B)
let certtype = certtype.into();
let cert = cert.into();
self.certs.push(TorCert { certtype, cert });
/// Return the body of the certificate tagged with 'tp', if any.
pub fn cert_body(&self, tp: tor_cert::CertType) -> Option<&[u8]> {
self.certs
.find(|c| c.certtype == tp.into())
.map(|c| &c.cert[..])
/// Look for a certificate of type 'tp' in this cell; return it if
/// there is one.
pub fn parse_ed_cert(&self, tp: tor_cert::CertType) -> crate::Result<tor_cert::KeyUnknownCert> {
let body = self
.cert_body(tp)
.ok_or_else(|| crate::Error::ChanProto(format!("Missing {} certificate", tp)))?;
let cert = tor_cert::Ed25519Cert::decode(body)?;
if cert.peek_cert_type() != tp {
return Err(crate::Error::ChanProto(format!(
"Found a {} certificate labeled as {}",
cert.peek_cert_type(),
tp
)));
Ok(cert)
impl Body for Certs {
ChanMsg::Certs(self)
let n_certs: u8 = self
.certs
.expect("Too many certs to encode in cell.");
w.write_u8(n_certs);
for c in &self.certs {
enc_one_tor_cert(w, c);
impl Readable for Certs {
let n = r.take_u8()?;
let mut certs = Vec::new();
for _ in 0..n {
certs.push(take_one_tor_cert(r)?);
Ok(Certs { certs })
/// Length of the body for an authentication challenge
const CHALLENGE_LEN: usize = 32;
/// An AuthChallenge message is part of negotiation, sent by
/// responders to initiators.
/// The AuthChallenge cell is used to ensure that some unpredictable material
/// has been sent on the channel, and to tell the initiator what
/// authentication methods will be accepted.
/// Clients can safely ignore this message: they don't need to authenticate.
pub struct AuthChallenge {
/// Random challenge to be used in generating response
challenge: [u8; CHALLENGE_LEN],
/// List of permitted authentication methods
methods: Vec<u16>,
impl AuthChallenge {
/// Construct a new AuthChallenge cell with a given challenge
/// value (chosen randomly) and a set of acceptable authentication methods.
pub fn new<B, M>(challenge: B, methods: M) -> Self
B: Into<[u8; CHALLENGE_LEN]>,
M: Into<Vec<u16>>,
AuthChallenge {
challenge: challenge.into(),
methods: methods.into(),
impl Body for AuthChallenge {
ChanMsg::AuthChallenge(self)
w.write_all(&self.challenge[..]);
assert!(self.methods.len() <= std::u16::MAX as usize);
w.write_u16(self.methods.len() as u16);
for m in &self.methods {
w.write_u16(*m);
impl Readable for AuthChallenge {
//let challenge = r.take(CHALLENGE_LEN)?.into();
let challenge = r.extract()?;
let n_methods = r.take_u16()?;
let mut methods = Vec::new();
for _ in 0..n_methods {
methods.push(r.take_u16()?);
Ok(AuthChallenge { challenge, methods })
/// Part of negotiation: sent by initiators to responders.
/// The Authenticate cell proves the initiator's identity to the
/// responder, even if TLS client authentication was not used.
/// Clients do not use this.
pub struct Authenticate {
/// Authentication method in use
authtype: u16,
/// Encoded authentication object
auth: Vec<u8>,
impl Authenticate {
/// Create a new Authenticate message from a given type and body.
pub fn new<B>(authtype: u16, body: B) -> Self
Authenticate {
authtype,
auth: body.into(),
impl Body for Authenticate {
ChanMsg::Authenticate(self)
w.write_u16(self.authtype);
assert!(self.auth.len() <= std::u16::MAX as usize);
w.write_u16(self.auth.len() as u16);
w.write_all(&self.auth[..]);
impl Readable for Authenticate {
let authtype = r.take_u16()?;
let authlen = r.take_u16()?;
let auth = r.take(authlen as usize)?.into();
Ok(Authenticate { authtype, auth })
/// The Authorize message type is not yet used.
pub struct Authorize {
/// The cell's content, which isn't really specified yet.
content: Vec<u8>,
impl Authorize {
/// Construct a new Authorize cell.
pub fn new<B>(content: B) -> Self
let content = content.into();
Authorize { content }
impl Body for Authorize {
ChanMsg::Authorize(self)
w.write_all(&self.content[..]);
impl Readable for Authorize {
Ok(Authorize {
content: r.take(r.remaining())?.into(),
/// Holds any message whose command we don't recognize.
/// Well-behaved Tor implementations are required to ignore commands
/// like this.
/// TODO: I believe that this is not a risky case of Postel's law,
/// since it is only for channels, but we should be careful here.
pub struct Unrecognized {
/// The channel command that we got with this cell
cmd: ChanCmd,
/// The contents of the cell
/// Take an unrecognized cell's body from a reader `r`, and apply
/// the given command to it.
fn unrecognized_with_cmd(cmd: ChanCmd, r: &mut Reader<'_>) -> Result<Unrecognized> {
let mut u = Unrecognized::take_from(r)?;
u.cmd = cmd;
Ok(u)
impl Unrecognized {
/// Construct a new cell of arbitrary or unrecognized type.
pub fn new<B>(cmd: ChanCmd, content: B) -> Self
Unrecognized { cmd, content }
/// Return the command from this cell.
fn cmd(&self) -> ChanCmd {
self.cmd
impl Body for Unrecognized {
ChanMsg::Unrecognized(self)
impl Readable for Unrecognized {
Ok(Unrecognized {
cmd: 0.into(),
impl<B: Body> From<B> for ChanMsg {
fn from(body: B) -> Self {
body.into_message()
/// Helper: declare a From<> implementation from message types for
/// cells that don't take a circid.
macro_rules! msg_into_cell {
($body:ident) => {
impl From<$body> for super::ChanCell {
fn from(body: $body) -> super::ChanCell {
super::ChanCell {
circid: 0.into(),
msg: body.into_message(),
};
msg_into_cell!(Padding);
msg_into_cell!(VPadding);
msg_into_cell!(Netinfo);
msg_into_cell!(Versions);
msg_into_cell!(PaddingNegotiate);
msg_into_cell!(Certs);
msg_into_cell!(AuthChallenge);
msg_into_cell!(Authenticate);
msg_into_cell!(Authorize);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn destroy_reason() {
let r1 = DestroyReason::CONNECTFAILED;
assert_eq!(r1.human_str(), "Couldn't connect to relay");
let r2 = DestroyReason::from(200); // not a specified number.
assert_eq!(r2.human_str(), "Unrecognized reason");