tor_proto/client/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
29pub use crate::crypto::handshake::KeyGenerator;
30#[cfg(feature = "hs-common")]
31pub use crate::crypto::handshake::hs_ntor;
32
33#[derive(Copy, Clone, Debug)]
39#[non_exhaustive]
40#[cfg(feature = "hs-common")]
41pub enum RelayProtocol {
42 HsV3,
44}
45
46#[derive(Copy, Clone, Debug)]
49pub(crate) enum RelayCryptLayerProtocol {
50 Tor1(RelayCellFormat),
56 #[cfg(feature = "hs-common")]
63 HsV3(RelayCellFormat),
64 #[cfg(feature = "counter-galois-onion")]
66 Cgo,
67}
68
69#[cfg(feature = "hs-common")]
70impl From<RelayProtocol> for RelayCryptLayerProtocol {
71 fn from(value: RelayProtocol) -> Self {
72 match value {
73 RelayProtocol::HsV3 => RelayCryptLayerProtocol::HsV3(RelayCellFormat::V0),
75 }
76 }
77}
78
79#[derive(Copy, Clone, Debug, Eq, PartialEq)]
81#[non_exhaustive]
82pub enum HandshakeRole {
83 Initiator,
85 Responder,
87}
88
89pub(crate) struct BoxedClientLayer {
92 pub(crate) fwd: Box<dyn OutboundClientLayer + Send>,
94 pub(crate) back: Box<dyn InboundClientLayer + Send>,
96 pub(crate) binding: Option<CircuitBinding>,
98}
99
100impl RelayCryptLayerProtocol {
101 pub(crate) fn construct_client_layers(
107 self,
108 role: HandshakeRole,
109 keygen: impl KeyGenerator,
110 ) -> Result<BoxedClientLayer> {
111 use RelayCellFormat::*;
112 use RelayCryptLayerProtocol::*;
113
114 match self {
115 Tor1(V0) => construct::<Tor1RelayCrypto, _, _, _, _>(keygen, role),
116 Tor1(_) => Err(internal!("protocol not implemented").into()),
117 #[cfg(feature = "hs-common")]
118 HsV3(V0) => construct::<Tor1Hsv3RelayCrypto, _, _, _, _>(keygen, role),
119 #[cfg(feature = "hs-common")]
120 HsV3(_) => Err(internal!("protocol not implemented").into()),
121 #[cfg(feature = "counter-galois-onion")]
122 Cgo => construct::<CgoRelayCrypto, _, _, _, _>(keygen, role),
123 }
124 }
125
126 pub(crate) fn relay_cell_format(&self) -> RelayCellFormat {
128 match self {
129 RelayCryptLayerProtocol::Tor1(v) => *v,
130 #[cfg(feature = "hs-common")]
131 RelayCryptLayerProtocol::HsV3(v) => *v,
132 #[cfg(feature = "counter-galois-onion")]
133 RelayCryptLayerProtocol::Cgo => RelayCellFormat::V1,
134 }
135 }
136}
137
138struct ResponderOutboundLayer<L: InboundRelayLayer>(L);
143impl<L: InboundRelayLayer> OutboundClientLayer for ResponderOutboundLayer<L> {
144 fn originate_for(
145 &mut self,
146 cmd: tor_cell::chancell::ChanCmd,
147 cell: &mut crate::crypto::cell::RelayCellBody,
148 ) -> tor_cell::relaycell::msg::SendmeTag {
149 self.0.originate(cmd, cell)
150 }
151
152 fn encrypt_outbound(
153 &mut self,
154 cmd: tor_cell::chancell::ChanCmd,
155 cell: &mut crate::crypto::cell::RelayCellBody,
156 ) {
157 self.0.encrypt_inbound(cmd, cell);
158 }
159}
160struct ResponderInboundLayer<L: OutboundRelayLayer>(L);
165impl<L: OutboundRelayLayer> InboundClientLayer for ResponderInboundLayer<L> {
166 fn decrypt_inbound(
167 &mut self,
168 cmd: tor_cell::chancell::ChanCmd,
169 cell: &mut crate::crypto::cell::RelayCellBody,
170 ) -> Option<tor_cell::relaycell::msg::SendmeTag> {
171 self.0.decrypt_outbound(cmd, cell)
172 }
173}
174
175fn construct<L, FC, BC, FR, BR>(
178 keygen: impl KeyGenerator,
179 role: HandshakeRole,
180) -> Result<BoxedClientLayer>
181where
182 L: CryptInit + ClientLayer<FC, BC> + RelayLayer<FR, BR>,
183 FC: OutboundClientLayer + Send + 'static,
184 BC: InboundClientLayer + Send + 'static,
185 FR: OutboundRelayLayer + Send + 'static,
186 BR: InboundRelayLayer + Send + 'static,
187{
188 let layer = L::construct(keygen)?;
189 match role {
190 HandshakeRole::Initiator => {
191 let (fwd, back, binding) = layer.split_client_layer();
192 Ok(BoxedClientLayer {
193 fwd: Box::new(fwd),
194 back: Box::new(back),
195 binding: Some(binding),
196 })
197 }
198 HandshakeRole::Responder => {
199 let (fwd, back, binding) = layer.split_relay_layer();
200 Ok(BoxedClientLayer {
201 fwd: Box::new(ResponderOutboundLayer(back)),
205 back: Box::new(ResponderInboundLayer(fwd)),
206 binding: Some(binding),
207 })
208 }
209 }
210}