1use std::clone::Clone;
3use std::convert::TryInto;
4use std::net::TcpStream;
5
6use bson::doc;
8use bson::spec::BinarySubtype;
9use bson::{Binary, Bson};
10use honk_rpc::honk_rpc::{ApiSet, ErrorCode, RequestCookie, Session};
11use rand::rngs::OsRng;
12use rand::{rand_core, TryRngCore};
13use tor_interface::tor_crypto::*;
14
15use crate::ascii_string::*;
17use crate::gosling::*;
18
19#[derive(thiserror::Error, Debug)]
24pub enum Error {
25 #[error("HonkRPC method failed: {0}")]
26 HonkRPCFailure(#[from] honk_rpc::honk_rpc::Error),
27
28 #[error("server is in invalid state: {0}")]
29 InvalidState(String),
30
31 #[error("incorrect usage: {0}")]
32 IncorrectUsage(String),
33
34 #[error("client sent invalid request")]
35 BadClient,
36
37 #[error("OsRng::try_fill_bytes() failed: {0}")]
38 OsRngTryFillBytesFailure(#[from] rand_core::OsError),
39}
40
41pub(crate) enum EndpointServerEvent {
42 ChannelRequestReceived {
43 client_service_id: V3OnionServiceId,
44 requested_channel: AsciiString,
45 },
46 HandshakeCompleted {
48 client_service_id: V3OnionServiceId,
49 channel_name: AsciiString,
50 stream: TcpStream,
51 },
52 HandshakeRejected {
54 client_allowed: bool,
55 client_requested_channel_valid: bool,
56 client_proof_signature_valid: bool,
57 },
58}
59
60#[derive(Debug, PartialEq)]
61enum EndpointServerState {
62 WaitingForBeginHandshake,
64 ValidatingChannelRequest,
65 ChannelRequestValidated,
66 WaitingForSendResponse,
67 HandledSendResponse,
68 HandshakeComplete,
69 HandshakeFailed,
71}
72
73pub(crate) struct EndpointServer {
74 rpc: Option<Session<TcpStream>>,
76 pub server_identity: V3OnionServiceId,
77 allowed_client_identity: V3OnionServiceId,
78
79 state: EndpointServerState,
81 begin_handshake_request_cookie: Option<RequestCookie>,
82 client_identity: Option<V3OnionServiceId>,
83 requested_channel: Option<AsciiString>,
84 server_cookie: Option<ServerCookie>,
85 handshake_succeeded: Option<bool>,
86
87 client_allowed: bool,
91 client_requested_channel_valid: bool,
93 client_proof_signature_valid: bool,
95}
96
97impl EndpointServer {
98 fn get_state(&self) -> String {
99 format!("{{ state: {:?}, begin_handshake_request_cookie: {:?}, client_identity: {:?}, requested_channel: {:?}, server_cookie: {:?}, handshake_succeeded:{:?} }}", self.state, self.begin_handshake_request_cookie, self.client_identity, self.requested_channel, self.server_cookie, self.handshake_succeeded)
100 }
101
102 pub fn new(
103 rpc: Session<TcpStream>,
104 client_identity: V3OnionServiceId,
105 server_identity: V3OnionServiceId,
106 ) -> Self {
107 EndpointServer {
108 rpc: Some(rpc),
109 server_identity,
110 allowed_client_identity: client_identity,
111 state: EndpointServerState::WaitingForBeginHandshake,
112 begin_handshake_request_cookie: None,
113 requested_channel: None,
114 client_identity: None,
115 server_cookie: None,
116 handshake_succeeded: None,
117 client_allowed: false,
118 client_requested_channel_valid: true,
120 client_proof_signature_valid: false,
121 }
122 }
123
124 pub fn update(&mut self) -> Result<Option<EndpointServerEvent>, Error> {
125 if let Some(mut rpc) = std::mem::take(&mut self.rpc) {
126 match rpc.update(Some(&mut [self])) {
127 Ok(()) => {
128 self.rpc = Some(rpc);
129 }
130 Err(err) => {
131 self.rpc = Some(rpc);
132 return Err(err.into());
133 }
134 }
135 }
136
137 match(&self.state,
138 self.begin_handshake_request_cookie,
139 self.client_identity.as_ref(),
140 self.requested_channel.as_ref(),
141 self.server_cookie.as_ref(),
142 self.handshake_succeeded) {
143 (&EndpointServerState::WaitingForBeginHandshake,
144 None, None, None, None, None) => {},
150 (&EndpointServerState::WaitingForBeginHandshake,
151 Some(_begin_handshake_request_cookie),
152 Some(client_identity),
153 Some(requested_channel),
154 None, None) => {
157 self.state = EndpointServerState::ValidatingChannelRequest;
158 return Ok(
159 Some(
160 EndpointServerEvent::ChannelRequestReceived
161 {
162 client_service_id: client_identity.clone(),
163 requested_channel: requested_channel.clone()
164 }));
165 },
166 (&EndpointServerState::ValidatingChannelRequest,
167 Some(_begin_handshake_request_cookie),
168 Some(_client_identity),
169 Some(_requested_channel),
170 None, None) => {},
173 (&EndpointServerState::ChannelRequestValidated,
174 Some(_begin_handshake_request_cookie),
175 Some(_client_identity),
176 Some(_requested_channel),
177 Some(_server_cookie),
178 None) => {},
180 (&EndpointServerState::WaitingForSendResponse,
181 Some(_begin_handshake_request_cookie),
182 Some(_client_identity),
183 Some(_requested_channel),
184 Some(_server_cookie),
185 None) => {},
187 (&EndpointServerState::HandledSendResponse,
188 Some(_begin_handshake_request_cookie),
189 Some(client_identity),
190 Some(requested_channel),
191 Some(_server_cookie),
192 Some(handshake_succeeded))
193 => {
194 self.state = EndpointServerState::HandshakeComplete;
195 if handshake_succeeded {
196 let stream = std::mem::take(&mut self.rpc).unwrap().into_stream();
197 return Ok(Some(EndpointServerEvent::HandshakeCompleted{
198 client_service_id: client_identity.clone(),
199 channel_name: requested_channel.clone(),
200 stream}));
201 } else {
202 return Ok(Some(EndpointServerEvent::HandshakeRejected{
203 client_allowed: self.client_allowed,
204 client_requested_channel_valid: self.client_requested_channel_valid,
205 client_proof_signature_valid: self.client_proof_signature_valid}));
206 }
207 },
208 _ => {
209 if self.state == EndpointServerState::HandshakeFailed {
210 return Err(Error::BadClient);
211 } else {
212 return Err(Error::InvalidState(self.get_state()));
213 }
214 }
215 }
216
217 Ok(None)
218 }
219
220 pub fn handle_channel_request_received(
221 &mut self,
222 client_requested_channel_valid: bool,
223 ) -> Result<(), Error> {
224 match(&self.state,
225 self.begin_handshake_request_cookie,
226 self.client_identity.as_ref(),
227 self.requested_channel.as_ref(),
228 self.server_cookie.as_ref(),
229 self.handshake_succeeded) {
230 (&EndpointServerState::ValidatingChannelRequest,
231 Some(_begin_handshake_request_cookie),
232 Some(client_identity),
233 Some(_requested_channel),
234 None, None) => {
237 let mut server_cookie: ServerCookie = Default::default();
238 OsRng.try_fill_bytes(&mut server_cookie)?;
239 self.server_cookie = Some(server_cookie);
240 self.client_allowed = *client_identity == self.allowed_client_identity;
241 self.client_requested_channel_valid = client_requested_channel_valid;
242 self.state = EndpointServerState::ChannelRequestValidated;
243 Ok(())
244 },
245 _ => Err(Error::IncorrectUsage("handle_channel_request_received() may only be called after ChannelRequestReceived has been returned from update(), and it may only be called once".to_string()))
246 }
247 }
248}
249
250impl ApiSet for EndpointServer {
251 fn namespace(&self) -> &str {
252 "gosling_endpoint"
253 }
254
255 fn exec_function(
256 &mut self,
257 name: &str,
258 version: i32,
259 mut args: bson::document::Document,
260 request_cookie: Option<RequestCookie>,
261 ) -> Option<Result<Option<bson::Bson>, ErrorCode>> {
262 let request_cookie = match request_cookie {
263 Some(request_cookie) => request_cookie,
264 None => {
265 return Some(Err(ErrorCode::Runtime(
266 RpcError::RequestCookieRequired as i32,
267 )))
268 }
269 };
270
271 match
272 (name, version,
273 &self.state,
274 self.client_identity.as_ref(),
275 self.requested_channel.as_ref(),
276 self.server_cookie.as_ref()) {
277 ("begin_handshake", 0,
279 &EndpointServerState::WaitingForBeginHandshake,
280 None, None, None) => {
284 let valid_version = match args.remove("version") {
285 Some(Bson::String(value)) => value == GOSLING_PROTOCOL_VERSION,
286 _ => false,
287 };
288 if !valid_version {
289 self.state = EndpointServerState::HandshakeFailed;
290 return Some(Err(ErrorCode::Runtime(RpcError::BadVersion as i32)));
291 }
292
293 if let (
294 Some(Bson::String(client_identity)),
295 Some(Bson::String(channel_name))
296 ) = (
297 args.remove("client_identity"),
298 args.remove("channel")
299 ) {
300 self.client_identity = match V3OnionServiceId::from_string(&client_identity) {
302 Ok(client_identity) => Some(client_identity),
303 Err(_) => {
304 self.state = EndpointServerState::HandshakeFailed;
305 return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
306 }
307 };
308
309 let channel_name = match AsciiString::new(channel_name) {
310 Ok(channel_name) => channel_name,
311 Err(_) => {
312 self.state = EndpointServerState::HandshakeFailed;
313 return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
314 }
315 };
316
317 self.begin_handshake_request_cookie = Some(request_cookie);
319
320 self.requested_channel = Some(channel_name);
322
323 None
324 } else {
325 self.state = EndpointServerState::HandshakeFailed;
326 Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)))
327 }
328 },
329 ("send_response", 0,
330 &EndpointServerState::WaitingForSendResponse,
331 Some(client_identity),
332 Some(requested_channel),
333 Some(server_cookie))
334 => {
335 if let (Some(Bson::Binary(Binary{subtype: BinarySubtype::Generic, bytes: client_cookie})),
336 Some(Bson::Binary(Binary{subtype: BinarySubtype::Generic, bytes: client_identity_proof_signature}))) =
337 (args.remove("client_cookie"),
338 args.remove("client_identity_proof_signature")) {
339 let client_cookie : ClientCookie = match client_cookie.try_into() {
341 Ok(client_cookie) => client_cookie,
342 Err(_) => {
343 self.state = EndpointServerState::HandshakeFailed;
344 return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
345 }
346 };
347
348 let client_identity_proof_signature : [u8; ED25519_SIGNATURE_SIZE] = match client_identity_proof_signature.try_into() {
350 Ok(client_identity_proof_signature) => client_identity_proof_signature,
351 Err(_) => {
352 self.state = EndpointServerState::HandshakeFailed;
353 return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
354 }
355 };
356 let client_identity_proof_signature = match Ed25519Signature::from_raw(&client_identity_proof_signature) {
357 Ok(client_identity_proof_signature) => client_identity_proof_signature,
358 Err(_) => {
359 self.state = EndpointServerState::HandshakeFailed;
360 return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
361 }
362 };
363
364 let client_identity_key = match Ed25519PublicKey::from_service_id(client_identity) {
366 Ok(client_identity_key) => client_identity_key,
367 Err(_) => {
368 self.state = EndpointServerState::HandshakeFailed;
369 return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
370 }
371 };
372
373 let client_proof = build_client_proof(
375 DomainSeparator::GoslingEndpoint,
376 requested_channel,
377 client_identity,
378 &self.server_identity,
379 &client_cookie,
380 server_cookie,
381 );
382 self.client_proof_signature_valid =
383 client_identity_proof_signature.verify(&client_proof, &client_identity_key);
384
385 if self.client_allowed
386 && self.client_requested_channel_valid
387 && self.client_proof_signature_valid
388 {
389 self.handshake_succeeded = Some(true);
390 self.state = EndpointServerState::HandledSendResponse;
391 Some(Ok(Some(Bson::Document(doc! {}))))
393 } else {
394 self.handshake_succeeded = Some(false);
395 self.state = EndpointServerState::HandledSendResponse;
396 Some(Err(ErrorCode::Runtime(RpcError::Failure as i32)))
397 }
398 } else {
399 self.state = EndpointServerState::HandshakeFailed;
400 Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)))
401 }
402 },
403 _ => {
404 self.state = EndpointServerState::HandshakeFailed;
405 Some(Err(ErrorCode::Runtime(RpcError::Failure as i32)))
406 }
407 }
408 }
409
410 fn next_result(&mut self) -> Option<(RequestCookie, Result<Option<bson::Bson>, ErrorCode>)> {
411 match (
412 &self.state,
413 self.begin_handshake_request_cookie,
414 self.server_cookie.as_ref(),
415 ) {
416 (
417 &EndpointServerState::ChannelRequestValidated,
418 Some(begin_handshake_request_cookie),
419 Some(server_cookie),
420 ) => {
421 self.state = EndpointServerState::WaitingForSendResponse;
422 Some((
423 begin_handshake_request_cookie,
424 Ok(Some(Bson::Document(doc! {
425 "server_cookie" : Bson::Binary(Binary{subtype: BinarySubtype::Generic, bytes: server_cookie.to_vec()}),
426 }))),
427 ))
428 }
429 _ => None,
430 }
431 }
432}