diff --git a/crates/tor-proto/semver.md b/crates/tor-proto/semver.md index 2ca6fcd9f..0447b2448 100644 --- a/crates/tor-proto/semver.md +++ b/crates/tor-proto/semver.md @@ -14,3 +14,6 @@ ADDED: `ClientCirc::start_conversation()` to eventually replace BREAKING: `ClientCirc::allow_stream_requests` is now async BREAKING: `IncomingStream::discard` now takes `mut self` instead of `self` and returns a `Result<(), Bug>` +ADDED: `ClientCirc::binding_key` + + diff --git a/crates/tor-proto/src/circuit.rs b/crates/tor-proto/src/circuit.rs index b673e6f4f..f30964055 100644 --- a/crates/tor-proto/src/circuit.rs +++ b/crates/tor-proto/src/circuit.rs @@ -57,12 +57,14 @@ use crate::circuit::reactor::{ CircuitHandshake, CtrlMsg, Reactor, RECV_WINDOW_INIT, STREAM_READER_BUFFER, }; pub use crate::circuit::unique_id::UniqId; +pub use crate::crypto::binding::CircuitBinding; use crate::crypto::cell::HopNum; use crate::stream::{ AnyCmdChecker, DataCmdChecker, DataStream, ResolveCmdChecker, ResolveStream, StreamParameters, StreamReader, }; use crate::{Error, ResolveError, Result}; +use educe::Educe; use tor_cell::{ chancell::{self, msg::AnyChanMsg, CircId}, relaycell::msg::{AnyRelayMsg, Begin, Resolve, Resolved, ResolvedVal}, @@ -171,7 +173,8 @@ pub struct ClientCirc { } /// Mutable state shared by [`ClientCirc`] and [`Reactor`]. -#[derive(Debug)] +#[derive(Educe)] +#[educe(Debug)] struct MutableState { /// Information about this circuit's path. /// @@ -179,6 +182,16 @@ struct MutableState { /// client code; when we need to add a hop (which is less frequent) we use /// [`Arc::make_mut()`]. path: Arc, + + /// Circuit binding keys [q.v.][`CircuitBinding`] information for each hop + /// in the circuit's path. + /// + /// NOTE: Right now, there is a `CircuitBinding` for every hop. There's a + /// fair chance that this will change in the future, and I don't want other + /// code to assume that a `CircuitBinding` _must_ exist, so I'm making this + /// an `Option`. + #[educe(Debug(ignore))] + binding: Vec>, } /// A ClientCirc that needs to send a create cell and receive a created* cell. @@ -342,6 +355,25 @@ impl ClientCirc { &self.channel } + /// Return the cryptographic material used to prove knowledge of a shared + /// secret with with `hop`. + /// + /// See [`CircuitBinding`] for more information on how this is used. + /// + /// Return None if we have no circuit binding information for the hop, or if + /// the hop does not exist. + pub fn binding_key(&self, hop: HopNum) -> Option { + self.mutable + .lock() + .expect("poisoned lock") + .binding + .get::(hop.into()) + .cloned() + .flatten() + // NOTE: I'm not thrilled to have to copy this information, but we use + // it very rarely, so it's not _that_ bad IMO. + } + /// Start an ad-hoc protocol exchange to the specified hop on this circuit /// /// To use this: diff --git a/crates/tor-proto/src/circuit/reactor.rs b/crates/tor-proto/src/circuit/reactor.rs index 484bd07fa..dc2f506d4 100644 --- a/crates/tor-proto/src/circuit/reactor.rs +++ b/crates/tor-proto/src/circuit/reactor.rs @@ -643,7 +643,8 @@ impl Reactor { let crypto_out = OutboundClientCrypt::new(); let (control_tx, control_rx) = mpsc::unbounded(); let path = Arc::new(path::Path::default()); - let mutable = Arc::new(Mutex::new(MutableState { path })); + let binding = Vec::new(); + let mutable = Arc::new(Mutex::new(MutableState { path, binding })); let (reactor_closed_tx, reactor_closed_rx) = oneshot::channel(); @@ -1080,9 +1081,9 @@ impl Reactor { self.hops.push(hop); self.crypto_in.add_layer(rev); self.crypto_out.add_layer(fwd); - drop(binding); // XXXX let mut mutable = self.mutable.lock().expect("poisoned lock"); Arc::make_mut(&mut mutable.path).push_hop(peer_id); + mutable.binding.push(binding); } /// Handle a RELAY cell on this circuit with stream ID 0. diff --git a/crates/tor-proto/src/crypto/binding.rs b/crates/tor-proto/src/crypto/binding.rs index 8275d5ebe..2ffcb0efa 100644 --- a/crates/tor-proto/src/crypto/binding.rs +++ b/crates/tor-proto/src/crypto/binding.rs @@ -1,7 +1,6 @@ //! Types related to binding messages to specific circuits -#![allow(dead_code, unreachable_pub)] // XXXX remove. - +#[cfg(feature = "hs-service")] use tor_hscrypto::ops::HsMacKey; use zeroize::Zeroizing;