gosling/
endpoint_server.rs

1// standard
2use std::clone::Clone;
3use std::convert::TryInto;
4use std::net::TcpStream;
5
6// extern crates
7use 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
15// internal crates
16use crate::ascii_string::*;
17use crate::gosling::*;
18
19//
20// Endpoint Server
21//
22
23#[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    // endpoint server has acepted incoming channel request from identity client
47    HandshakeCompleted {
48        client_service_id: V3OnionServiceId,
49        channel_name: AsciiString,
50        stream: TcpStream,
51    },
52    // endpoint server has reject an incoming channel request
53    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    // valid/expected states
63    WaitingForBeginHandshake,
64    ValidatingChannelRequest,
65    ChannelRequestValidated,
66    WaitingForSendResponse,
67    HandledSendResponse,
68    HandshakeComplete,
69    // failure state
70    HandshakeFailed,
71}
72
73pub(crate) struct EndpointServer {
74    // Session Data
75    rpc: Option<Session<TcpStream>>,
76    pub server_identity: V3OnionServiceId,
77    allowed_client_identity: V3OnionServiceId,
78
79    // State Machine Data
80    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    // Verification flags
88
89    // Client not on the block-list
90    client_allowed: bool,
91    // The requested endpoint is valid
92    client_requested_channel_valid: bool,
93    // The client proof is valid and signed with client's public key
94    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            // TODO: hookup this to event and callback
119            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, // begin_handshake_request_cookie
145             None, // client_identity
146             None, // requested_channel
147             None, // server_cookie
148             None) // handshake_succeeded
149            => {},
150            (&EndpointServerState::WaitingForBeginHandshake,
151             Some(_begin_handshake_request_cookie),
152             Some(client_identity),
153             Some(requested_channel),
154             None, // server_cookie
155             None) // handshake_succeeded
156            => {
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, // server_cookie
171             None) // handshake_succeeded
172            => {},
173            (&EndpointServerState::ChannelRequestValidated,
174             Some(_begin_handshake_request_cookie),
175             Some(_client_identity),
176             Some(_requested_channel),
177             Some(_server_cookie),
178             None) // handshake_succeeded
179            => {},
180            (&EndpointServerState::WaitingForSendResponse,
181             Some(_begin_handshake_request_cookie),
182             Some(_client_identity),
183             Some(_requested_channel),
184             Some(_server_cookie),
185             None) // handshake_succeeded
186            => {},
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, // server_cookie
235             None) // handshake_succeeded
236            => {
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            // handle begin_handshake call
278            ("begin_handshake", 0,
279            &EndpointServerState::WaitingForBeginHandshake,
280            None, // client_identity
281            None, // requested_channel
282            None) // server_cookie
283            => {
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                    // client_identiity
301                    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                    // save cookie
318                    self.begin_handshake_request_cookie = Some(request_cookie);
319
320                    // save channel name
321                    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                    // client_cookie
340                    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                    // client_identity_proof_signature
349                    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                    // convert client_identity to client's public ed25519 key
365                    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                    // construct + verify client proof
374                    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                        // success, return empty doc
392                        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}