tor_proto/tunnel/circuit/
handshake.rs1use tor_cell::relaycell::RelayCellFormat;
15use tor_error::internal;
16
17use crate::crypto::binding::CircuitBinding;
18#[cfg(feature = "counter-galois-onion")]
19use crate::crypto::cell::CgoRelayCrypto;
20#[cfg(feature = "hs-common")]
21use crate::crypto::cell::Tor1Hsv3RelayCrypto;
22use crate::crypto::cell::{
23 ClientLayer, CryptInit, InboundClientLayer, InboundRelayLayer, OutboundClientLayer,
24 OutboundRelayLayer, RelayLayer, Tor1RelayCrypto,
25};
26
27use crate::Result;
28
29#[cfg(feature = "hs-common")]
30#[cfg_attr(docsrs, doc(cfg(feature = "hs-common")))]
31pub use crate::crypto::handshake::hs_ntor;
32pub use crate::crypto::handshake::KeyGenerator;
33
34#[derive(Copy, Clone, Debug)]
40#[non_exhaustive]
41#[cfg(feature = "hs-common")]
42pub enum RelayProtocol {
43 HsV3,
45}
46
47#[derive(Copy, Clone, Debug)]
50pub(crate) enum RelayCryptLayerProtocol {
51 Tor1(RelayCellFormat),
57 #[cfg(feature = "hs-common")]
64 HsV3(RelayCellFormat),
65 #[cfg(feature = "counter-galois-onion")]
67 Cgo,
68}
69
70#[cfg(feature = "hs-common")]
71impl From<RelayProtocol> for RelayCryptLayerProtocol {
72 fn from(value: RelayProtocol) -> Self {
73 match value {
74 RelayProtocol::HsV3 => RelayCryptLayerProtocol::HsV3(RelayCellFormat::V0),
76 }
77 }
78}
79
80#[derive(Copy, Clone, Debug, Eq, PartialEq)]
82#[non_exhaustive]
83pub enum HandshakeRole {
84 Initiator,
86 Responder,
88}
89
90pub(crate) struct BoxedClientLayer {
93 pub(crate) fwd: Box<dyn OutboundClientLayer + Send>,
95 pub(crate) back: Box<dyn InboundClientLayer + Send>,
97 pub(crate) binding: Option<CircuitBinding>,
99}
100
101impl RelayCryptLayerProtocol {
102 pub(crate) fn construct_client_layers(
108 self,
109 role: HandshakeRole,
110 keygen: impl KeyGenerator,
111 ) -> Result<BoxedClientLayer> {
112 use RelayCellFormat::*;
113 use RelayCryptLayerProtocol::*;
114
115 match self {
116 Tor1(V0) => construct::<Tor1RelayCrypto, _, _, _, _>(keygen, role),
117 Tor1(_) => Err(internal!("protocol not implemented").into()),
118 #[cfg(feature = "hs-common")]
119 HsV3(V0) => construct::<Tor1Hsv3RelayCrypto, _, _, _, _>(keygen, role),
120 #[cfg(feature = "hs-common")]
121 HsV3(_) => Err(internal!("protocol not implemented").into()),
122 #[cfg(feature = "counter-galois-onion")]
123 Cgo => construct::<CgoRelayCrypto, _, _, _, _>(keygen, role),
124 }
125 }
126
127 pub(crate) fn relay_cell_format(&self) -> RelayCellFormat {
129 match self {
130 RelayCryptLayerProtocol::Tor1(v) => *v,
131 #[cfg(feature = "hs-common")]
132 RelayCryptLayerProtocol::HsV3(v) => *v,
133 #[cfg(feature = "counter-galois-onion")]
134 RelayCryptLayerProtocol::Cgo => RelayCellFormat::V1,
135 }
136 }
137}
138
139struct ResponderOutboundLayer<L: InboundRelayLayer>(L);
144impl<L: InboundRelayLayer> OutboundClientLayer for ResponderOutboundLayer<L> {
145 fn originate_for(
146 &mut self,
147 cmd: tor_cell::chancell::ChanCmd,
148 cell: &mut crate::crypto::cell::RelayCellBody,
149 ) -> tor_cell::relaycell::msg::SendmeTag {
150 self.0.originate(cmd, cell)
151 }
152
153 fn encrypt_outbound(
154 &mut self,
155 cmd: tor_cell::chancell::ChanCmd,
156 cell: &mut crate::crypto::cell::RelayCellBody,
157 ) {
158 self.0.encrypt_inbound(cmd, cell);
159 }
160}
161struct ResponderInboundLayer<L: OutboundRelayLayer>(L);
166impl<L: OutboundRelayLayer> InboundClientLayer for ResponderInboundLayer<L> {
167 fn decrypt_inbound(
168 &mut self,
169 cmd: tor_cell::chancell::ChanCmd,
170 cell: &mut crate::crypto::cell::RelayCellBody,
171 ) -> Option<tor_cell::relaycell::msg::SendmeTag> {
172 self.0.decrypt_outbound(cmd, cell)
173 }
174}
175
176fn construct<L, FC, BC, FR, BR>(
179 keygen: impl KeyGenerator,
180 role: HandshakeRole,
181) -> Result<BoxedClientLayer>
182where
183 L: CryptInit + ClientLayer<FC, BC> + RelayLayer<FR, BR>,
184 FC: OutboundClientLayer + Send + 'static,
185 BC: InboundClientLayer + Send + 'static,
186 FR: OutboundRelayLayer + Send + 'static,
187 BR: InboundRelayLayer + Send + 'static,
188{
189 let layer = L::construct(keygen)?;
190 match role {
191 HandshakeRole::Initiator => {
192 let (fwd, back, binding) = layer.split_client_layer();
193 Ok(BoxedClientLayer {
194 fwd: Box::new(fwd),
195 back: Box::new(back),
196 binding: Some(binding),
197 })
198 }
199 HandshakeRole::Responder => {
200 let (fwd, back, binding) = layer.split_relay_layer();
201 Ok(BoxedClientLayer {
202 fwd: Box::new(ResponderOutboundLayer(back)),
206 back: Box::new(ResponderInboundLayer(fwd)),
207 binding: Some(binding),
208 })
209 }
210 }
211}