tor_proto/client/circuit/
handshake.rs1use tor_cell::relaycell::RelayCellFormat;
15use tor_error::internal;
16
17use crate::crypto::binding::CircuitBinding;
18use crate::crypto::cell::CgoRelayCrypto;
19#[cfg(feature = "hs-common")]
20use crate::crypto::cell::Tor1Hsv3RelayCrypto;
21use crate::crypto::cell::{
22 ClientLayer, CryptInit, InboundClientLayer, InboundRelayLayer, OutboundClientLayer,
23 OutboundRelayLayer, RelayLayer, Tor1RelayCrypto,
24};
25
26use crate::Result;
27
28pub use crate::crypto::handshake::KeyGenerator;
29#[cfg(feature = "hs-common")]
30pub use crate::crypto::handshake::hs_ntor;
31
32#[derive(Copy, Clone, Debug)]
38#[non_exhaustive]
39#[cfg(feature = "hs-common")]
40pub enum RelayProtocol {
41 HsV3,
43}
44
45#[derive(Copy, Clone, Debug)]
48pub(crate) enum RelayCryptLayerProtocol {
49 Tor1(RelayCellFormat),
55 #[cfg(feature = "hs-common")]
62 HsV3(RelayCellFormat),
63 Cgo,
65}
66
67#[cfg(feature = "hs-common")]
68impl From<RelayProtocol> for RelayCryptLayerProtocol {
69 fn from(value: RelayProtocol) -> Self {
70 match value {
71 RelayProtocol::HsV3 => RelayCryptLayerProtocol::HsV3(RelayCellFormat::V0),
73 }
74 }
75}
76
77#[derive(Copy, Clone, Debug, Eq, PartialEq)]
79#[non_exhaustive]
80pub enum HandshakeRole {
81 Initiator,
83 Responder,
85}
86
87pub(crate) struct BoxedClientLayer {
90 pub(crate) fwd: Box<dyn OutboundClientLayer + Send>,
92 pub(crate) back: Box<dyn InboundClientLayer + Send>,
94 pub(crate) binding: Option<CircuitBinding>,
96}
97
98impl RelayCryptLayerProtocol {
99 pub(crate) fn construct_client_layers(
105 self,
106 role: HandshakeRole,
107 keygen: impl KeyGenerator,
108 ) -> Result<BoxedClientLayer> {
109 use RelayCellFormat::*;
110 use RelayCryptLayerProtocol::*;
111
112 match self {
113 Tor1(V0) => construct::<Tor1RelayCrypto, _, _, _, _>(keygen, role),
114 Tor1(_) => Err(internal!("protocol not implemented").into()),
115 #[cfg(feature = "hs-common")]
116 HsV3(V0) => construct::<Tor1Hsv3RelayCrypto, _, _, _, _>(keygen, role),
117 #[cfg(feature = "hs-common")]
118 HsV3(_) => Err(internal!("protocol not implemented").into()),
119 Cgo => construct::<CgoRelayCrypto, _, _, _, _>(keygen, role),
120 }
121 }
122
123 pub(crate) fn relay_cell_format(&self) -> RelayCellFormat {
125 match self {
126 RelayCryptLayerProtocol::Tor1(v) => *v,
127 #[cfg(feature = "hs-common")]
128 RelayCryptLayerProtocol::HsV3(v) => *v,
129 RelayCryptLayerProtocol::Cgo => RelayCellFormat::V1,
130 }
131 }
132}
133
134struct ResponderOutboundLayer<L: InboundRelayLayer>(L);
139impl<L: InboundRelayLayer> OutboundClientLayer for ResponderOutboundLayer<L> {
140 fn originate_for(
141 &mut self,
142 cmd: tor_cell::chancell::ChanCmd,
143 cell: &mut crate::crypto::cell::RelayCellBody,
144 ) -> tor_cell::relaycell::msg::SendmeTag {
145 self.0.originate(cmd, cell)
146 }
147
148 fn encrypt_outbound(
149 &mut self,
150 cmd: tor_cell::chancell::ChanCmd,
151 cell: &mut crate::crypto::cell::RelayCellBody,
152 ) {
153 self.0.encrypt_inbound(cmd, cell);
154 }
155}
156struct ResponderInboundLayer<L: OutboundRelayLayer>(L);
161impl<L: OutboundRelayLayer> InboundClientLayer for ResponderInboundLayer<L> {
162 fn decrypt_inbound(
163 &mut self,
164 cmd: tor_cell::chancell::ChanCmd,
165 cell: &mut crate::crypto::cell::RelayCellBody,
166 ) -> Option<tor_cell::relaycell::msg::SendmeTag> {
167 self.0.decrypt_outbound(cmd, cell)
168 }
169}
170
171fn construct<L, FC, BC, FR, BR>(
174 keygen: impl KeyGenerator,
175 role: HandshakeRole,
176) -> Result<BoxedClientLayer>
177where
178 L: CryptInit + ClientLayer<FC, BC> + RelayLayer<FR, BR>,
179 FC: OutboundClientLayer + Send + 'static,
180 BC: InboundClientLayer + Send + 'static,
181 FR: OutboundRelayLayer + Send + 'static,
182 BR: InboundRelayLayer + Send + 'static,
183{
184 let layer = L::construct(keygen)?;
185 match role {
186 HandshakeRole::Initiator => {
187 let (fwd, back, binding) = layer.split_client_layer();
188 Ok(BoxedClientLayer {
189 fwd: Box::new(fwd),
190 back: Box::new(back),
191 binding: Some(binding),
192 })
193 }
194 HandshakeRole::Responder => {
195 let (fwd, back, binding) = layer.split_relay_layer();
196 Ok(BoxedClientLayer {
197 fwd: Box::new(ResponderOutboundLayer(back)),
201 back: Box::new(ResponderInboundLayer(fwd)),
202 binding: Some(binding),
203 })
204 }
205 }
206}