gosling/
identity_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::{
11    get_message_overhead, get_response_section_size, ApiSet, ErrorCode, RequestCookie, Session,
12};
13use rand::rngs::OsRng;
14use rand::{rand_core, TryRngCore};
15use tor_interface::tor_crypto::*;
16
17// internal crates
18use crate::ascii_string::*;
19use crate::gosling::*;
20
21//
22// Identity Server
23//
24
25#[derive(thiserror::Error, Debug)]
26pub enum Error {
27    #[error("HonkRPC method failed: {0}")]
28    HonkRPCFailure(#[from] honk_rpc::honk_rpc::Error),
29
30    #[error("server is in invalid state: {0}")]
31    InvalidState(String),
32
33    #[error("incorrect usage: {0}")]
34    IncorrectUsage(String),
35
36    #[error("client sent invalid request")]
37    BadClient,
38
39    #[error("provided endpoint challenge too large; encoded size would be {0} but session's maximum honk-rpc message size is {1}")]
40    EndpointChallengeTooLarge(usize, usize),
41
42    #[error("OsRng::try_fill_bytes() failed: {0}")]
43    OsRngTryFillBytesFailure(#[from] rand_core::OsError),
44}
45
46pub(crate) enum IdentityServerEvent {
47    EndpointRequestReceived {
48        client_service_id: V3OnionServiceId,
49        requested_endpoint: AsciiString,
50    },
51
52    ChallengeResponseReceived {
53        challenge_response: bson::document::Document,
54    },
55
56    HandshakeCompleted {
57        endpoint_private_key: Ed25519PrivateKey,
58        endpoint_name: AsciiString,
59        client_service_id: V3OnionServiceId,
60        client_auth_public_key: X25519PublicKey,
61    },
62
63    HandshakeRejected {
64        // Client not on the block-list
65        client_allowed: bool,
66        // The requested endpoint is valid
67        client_requested_endpoint_valid: bool,
68        // The client proof is valid and signed with client's public key
69        client_proof_signature_valid: bool,
70        // The client authorization signature is valid
71        client_auth_signature_valid: bool,
72        // The challenge response is valid
73        challenge_response_valid: bool,
74    },
75}
76
77#[derive(Debug, PartialEq)]
78enum IdentityServerState {
79    // valid/expected states
80    WaitingForBeginHandshake,
81    GettingChallenge,
82    ChallengeReady,
83    WaitingForSendResponse,
84    GettingChallengeVerification,
85    ChallengeVerificationReady,
86    ChallengeVerificationResponseSent,
87    HandshakeComplete,
88    // failure state
89    HandshakeFailed,
90}
91
92pub(crate) struct IdentityServer {
93    // Session Data
94    rpc: Option<Session<TcpStream>>,
95    server_identity: V3OnionServiceId,
96
97    // State Machine Data
98    state: IdentityServerState,
99    begin_handshake_request_cookie: Option<RequestCookie>,
100    client_identity: Option<V3OnionServiceId>,
101    requested_endpoint: Option<AsciiString>,
102    server_cookie: Option<ServerCookie>,
103    endpoint_challenge: Option<bson::document::Document>,
104    send_response_request_cookie: Option<RequestCookie>,
105    client_auth_key: Option<X25519PublicKey>,
106    challenge_response: Option<bson::document::Document>,
107    endpoint_private_key: Option<Ed25519PrivateKey>,
108
109    // Verification flags
110
111    // Client not on the block-list
112    client_allowed: bool,
113    // The requested endpoint is valid
114    client_requested_endpoint_valid: bool,
115    // The client proof is valid and signed with client's public key
116    client_proof_signature_valid: bool,
117    // The client authorization signature is valid
118    client_auth_signature_valid: bool,
119    // The challenge response is valid
120    challenge_response_valid: bool,
121}
122
123impl IdentityServer {
124    fn get_state(&self) -> String {
125        format!("{{ state: {:?}, begin_handshake_request_cookie: {:?}, client_identity: {:?}, requested_endpoint: {:?}, server_cookie: {:?}, endpoint_challenge: {:?}, send_response_request_cookie: {:?}, client_auth_key: {:?}, challenge_response: {:?}, endpoint_private_key: {:?} }}", self.state, self.begin_handshake_request_cookie, self.client_identity, self.requested_endpoint, self.server_cookie, self.endpoint_challenge, self.send_response_request_cookie, self.client_auth_key, self.challenge_response, self.endpoint_private_key)
126    }
127
128    pub fn new(rpc: Session<TcpStream>, server_identity: V3OnionServiceId) -> Self {
129        IdentityServer {
130            // Session Data
131            rpc: Some(rpc),
132            server_identity,
133
134            // State Machine Data
135            state: IdentityServerState::WaitingForBeginHandshake,
136            begin_handshake_request_cookie: None,
137            client_identity: None,
138            requested_endpoint: None,
139            server_cookie: None,
140            endpoint_challenge: None,
141            send_response_request_cookie: None,
142            client_auth_key: None,
143            challenge_response: None,
144            endpoint_private_key: None,
145
146            // Verification Flags
147            client_allowed: false,
148            client_requested_endpoint_valid: false,
149            client_proof_signature_valid: false,
150            client_auth_signature_valid: false,
151            challenge_response_valid: false,
152        }
153    }
154
155    pub fn update(&mut self) -> Result<Option<IdentityServerEvent>, Error> {
156        // need to remove ownership of the HonkRPC session from Self
157        // before being able to pass self into the session update method
158        if let Some(mut rpc) = std::mem::take(&mut self.rpc) {
159            match rpc.update(Some(&mut [self])) {
160                Ok(()) => {
161                    self.rpc = Some(rpc);
162                }
163                Err(err) => {
164                    self.rpc = Some(rpc);
165                    return Err(err.into());
166                }
167            }
168        }
169
170        match(&self.state,
171              self.begin_handshake_request_cookie,
172              self.client_identity.as_ref(),
173              self.requested_endpoint.as_ref(),
174              self.server_cookie.as_ref(),
175              self.endpoint_challenge.as_ref(),
176              self.send_response_request_cookie,
177              self.client_auth_key.as_ref(),
178              self.challenge_response.as_mut(),
179              self.endpoint_private_key.as_ref()) {
180            (&IdentityServerState::WaitingForBeginHandshake,
181             None, // begin_handshake_request_cookie
182             None, // client_identity
183             None, // requested_endpoint
184             None, // server_cookie
185             None, // endpoint_challenge
186             None, // send_response_request_cookie
187             None, // client_auth_key
188             None, // challenge_response
189             None) // endpoint_private_key
190            => {
191                // no-op, waiting for client to connect and begin handshake
192            },
193            (&IdentityServerState::WaitingForBeginHandshake,
194             Some(_begin_handshake_request_cookie),
195             Some(client_identity),
196             Some(requested_endpoint),
197             None, // server_cookie
198             None, // endpoint_challenge
199             None, // send_response_request_cookie
200             None, // client_auth_key
201             None, // challenge_response
202             None) // endpoint_private_key
203            => {
204                self.state = IdentityServerState::GettingChallenge;
205                return Ok(Some(IdentityServerEvent::EndpointRequestReceived{client_service_id: client_identity.clone(), requested_endpoint: requested_endpoint.clone()}));
206            },
207            (&IdentityServerState::WaitingForSendResponse,
208             Some(_begin_handshake_request_cookie),
209             Some(_client_identity),
210             Some(_requested_endpoint),
211             Some(_server_cookie),
212             Some(_endpoint_challenge),
213             None, // send_response_request_cookie
214             None, // client_auth_key
215             None, // challenge_response
216             None) // endpoint_private_key
217            => {
218                // no-op, waiting for client to send challenge response
219            },
220            (&IdentityServerState::WaitingForSendResponse,
221             Some(_begin_handshake_request_cookie),
222             Some(_client_identity),
223             Some(_requested_endpoint),
224             Some(_server_cookie),
225             Some(_endpoint_challenge),
226             Some(_send_response_request_cookie),
227             Some(_client_auth_key),
228             Some(challenge_response),
229             None) // endpoint_private_key
230            => {
231                self.state = IdentityServerState::GettingChallengeVerification;
232                return Ok(Some(IdentityServerEvent::ChallengeResponseReceived{
233                    challenge_response: std::mem::take(challenge_response),
234                }));
235            },
236            (&IdentityServerState::ChallengeVerificationResponseSent,
237             Some(_begin_handshake_request_cookie),
238             Some(client_identity),
239             Some(requested_endpoint),
240             Some(_server_cookie),
241             Some(_endpoint_challenge),
242             Some(_send_response_request_cookie),
243             Some(client_auth_key),
244             Some(_challenge_response),
245             Some(endpoint_private_key))
246            => {
247                self.state = IdentityServerState::HandshakeComplete;
248                return Ok(Some(IdentityServerEvent::HandshakeCompleted{
249                    endpoint_private_key: endpoint_private_key.clone(),
250                    endpoint_name: requested_endpoint.clone(),
251                    client_service_id: client_identity.clone(),
252                    client_auth_public_key: client_auth_key.clone(),
253                }));
254            },
255            (&IdentityServerState::ChallengeVerificationResponseSent,
256             Some(_begin_handshake_request_cookie),
257             Some(_client_identity),
258             Some(_requested_endpoint),
259             Some(_server_cookie),
260             Some(_endpoint_challenge),
261             Some(_send_response_request_cookie),
262             Some(_client_auth_key),
263             Some(_challenge_response),
264             None) // endpoint_private_key
265            => {
266                self.state = IdentityServerState::HandshakeComplete;
267                return Ok(Some(IdentityServerEvent::HandshakeRejected{
268                    client_allowed: self.client_allowed,
269                    client_requested_endpoint_valid: self.client_requested_endpoint_valid,
270                    client_proof_signature_valid: self.client_proof_signature_valid,
271                    client_auth_signature_valid: self.client_auth_signature_valid,
272                    challenge_response_valid: self.challenge_response_valid,
273                }));
274            },
275             _ => {
276                if self.state == IdentityServerState::HandshakeFailed {
277                    return Err(Error::BadClient);
278                } else {
279                    return Err(Error::InvalidState(self.get_state()));
280                }
281            }
282        }
283
284        Ok(None)
285    }
286
287    pub fn handle_endpoint_request_received(
288        &mut self,
289        client_allowed: bool,
290        endpoint_valid: bool,
291        endpoint_challenge: bson::document::Document,
292    ) -> Result<(), Error> {
293        match (
294            &self.state,
295            self.rpc.as_ref(),
296            self.begin_handshake_request_cookie,
297            self.client_identity.as_ref(),
298            self.requested_endpoint.as_ref(),
299            self.server_cookie.as_ref(),
300            self.endpoint_challenge.as_ref(),
301            self.client_auth_key.as_ref(),
302            self.challenge_response.as_ref(),
303            self.endpoint_private_key.as_ref(),
304        ) {
305            (
306                &IdentityServerState::GettingChallenge,
307                Some(rpc),
308                Some(_begin_handshake_request_cookie),
309                Some(_client_identity),
310                Some(_endpoint_name),
311                None, // server_cookie
312                None, // endpoint_challenge
313                None, // client_auth_key
314                None, // challenge_response
315                None, // endpoint_private_key
316            ) => {
317                let mut server_cookie: ServerCookie = Default::default();
318                OsRng.try_fill_bytes(&mut server_cookie)?;
319
320                // calculate required size of response message and ensure if fits our
321                // specified message size budget
322                let result = doc!{
323                    "server_cookie" : Bson::Binary(Binary{subtype: BinarySubtype::Generic, bytes: server_cookie.to_vec()}),
324                    "endpoint_challenge" : endpoint_challenge.clone(),
325                };
326                let response_section_size = get_response_section_size(Some(Bson::Document(result)))?;
327                let message_size = get_message_overhead()? + response_section_size;
328                let max_message_size = rpc.get_max_message_size();
329                if message_size > max_message_size {
330                    Err(Error::EndpointChallengeTooLarge(message_size, max_message_size))
331                } else {
332                    self.server_cookie = Some(server_cookie);
333                    self.endpoint_challenge = Some(endpoint_challenge);
334                    self.client_allowed = client_allowed;
335                    self.client_requested_endpoint_valid = endpoint_valid;
336                    self.state = IdentityServerState::ChallengeReady;
337                    Ok(())
338                }
339            }
340            _ => {
341                Err(Error::IncorrectUsage("handle_endpoint_request_received() may only be called after EndpointRequestReceived has been returned from update(), and it may only be called once".to_string()))
342            }
343        }
344    }
345
346    pub fn handle_challenge_response_received(
347        &mut self,
348        challenge_response_valid: bool,
349    ) -> Result<(), Error> {
350        match (
351            &self.state,
352            self.begin_handshake_request_cookie,
353            self.client_identity.as_ref(),
354            self.requested_endpoint.as_ref(),
355            self.server_cookie.as_ref(),
356            self.endpoint_challenge.as_ref(),
357            self.client_auth_key.as_ref(),
358            self.challenge_response.as_ref(),
359            self.endpoint_private_key.as_ref(),
360        ) {
361            (
362                &IdentityServerState::GettingChallengeVerification,
363                Some(_begin_handshake_request_cookie),
364                Some(_client_identity),
365                Some(_requested_endpoint),
366                Some(_server_cookie),
367                Some(_endpoint_challenge),
368                Some(_client_auth_key),
369                Some(_challenge_response),
370                None,
371            ) =>
372            // endpoint_private_key
373            {
374                self.challenge_response_valid = challenge_response_valid;
375                self.state = IdentityServerState::ChallengeVerificationReady;
376                Ok(())
377            }
378            _ => {
379                Err(Error::IncorrectUsage("handle_challenge_response_received() may only be called after ChallengeResponseReceived event has been returned from update(), and it may only be called once".to_string()))
380            }
381        }
382    }
383}
384
385impl ApiSet for IdentityServer {
386    fn namespace(&self) -> &str {
387        "gosling_identity"
388    }
389
390    fn exec_function(
391        &mut self,
392        name: &str,
393        version: i32,
394        mut args: bson::document::Document,
395        request_cookie: Option<RequestCookie>,
396    ) -> Option<Result<Option<bson::Bson>, ErrorCode>> {
397        let request_cookie = match request_cookie {
398            Some(request_cookie) => request_cookie,
399            None => {
400                return Some(Err(ErrorCode::Runtime(
401                    RpcError::RequestCookieRequired as i32,
402                )))
403            }
404        };
405
406        match (
407            name,
408            version,
409            &self.state,
410            self.begin_handshake_request_cookie,
411            self.client_identity.as_ref(),
412            self.requested_endpoint.as_ref(),
413            self.server_cookie.as_ref(),
414            self.endpoint_challenge.as_ref(),
415            self.client_auth_key.as_ref(),
416            self.challenge_response.as_ref(),
417            self.endpoint_private_key.as_ref(),
418        ) {
419            // handle begin_handshake call
420            (
421                "begin_handshake",
422                0,
423                &IdentityServerState::WaitingForBeginHandshake,
424                None, // begin_handshake_request_cookie
425                None, // client_identity
426                None, // requested_endpoint
427                None, // server_cookie
428                None, // endpoint_challenge
429                None, // client_auth_key
430                None, // challenge_response
431                None, // endpoint_private_key
432            ) => {
433                let valid_version = match args.remove("version") {
434                    Some(Bson::String(value)) => value == GOSLING_PROTOCOL_VERSION,
435                    _ => false,
436                };
437                if !valid_version {
438                    self.state = IdentityServerState::HandshakeFailed;
439                    return Some(Err(ErrorCode::Runtime(RpcError::BadVersion as i32)));
440                }
441
442                if let (Some(Bson::String(client_identity)), Some(Bson::String(endpoint_name))) =
443                    (args.remove("client_identity"), args.remove("endpoint"))
444                {
445                    // client_identiity
446                    let client_identity = match V3OnionServiceId::from_string(&client_identity) {
447                        Ok(client_identity) => client_identity,
448                        Err(_) => {
449                            self.state = IdentityServerState::HandshakeFailed;
450                            return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
451                        }
452                    };
453
454                    // endpoint name
455                    let endpoint_name = match AsciiString::new(endpoint_name) {
456                        Ok(endpoint_name) => endpoint_name,
457                        Err(_) => {
458                            self.state = IdentityServerState::HandshakeFailed;
459                            return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
460                        }
461                    };
462
463                    // save cookie
464                    self.begin_handshake_request_cookie = Some(request_cookie);
465
466                    // save results
467                    self.client_identity = Some(client_identity);
468                    self.requested_endpoint = Some(endpoint_name);
469                    None
470                } else {
471                    self.state = IdentityServerState::HandshakeFailed;
472                    Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)))
473                }
474            }
475            // handle send_response call
476            (
477                "send_response",
478                0,
479                &IdentityServerState::WaitingForSendResponse,
480                Some(_begin_handshake_request_cookie),
481                Some(client_identity),
482                Some(requested_endpoint),
483                Some(server_cookie),
484                Some(_endpoint_challenge),
485                None, // client_auth_key
486                None, // challenge_response
487                None, // endpoint_private_key
488            ) => {
489                // arg validation
490                if let (
491                    Some(Bson::Binary(Binary {
492                        subtype: BinarySubtype::Generic,
493                        bytes: client_cookie,
494                    })),
495                    Some(Bson::Binary(Binary {
496                        subtype: BinarySubtype::Generic,
497                        bytes: client_identity_proof_signature,
498                    })),
499                    Some(Bson::Binary(Binary {
500                        subtype: BinarySubtype::Generic,
501                        bytes: client_authorization_key,
502                    })),
503                    Some(Bson::Boolean(client_authorization_key_signbit)),
504                    Some(Bson::Binary(Binary {
505                        subtype: BinarySubtype::Generic,
506                        bytes: client_authorization_signature,
507                    })),
508                    Some(Bson::Document(challenge_response)),
509                ) = (
510                    args.remove("client_cookie"),
511                    args.remove("client_identity_proof_signature"),
512                    args.remove("client_authorization_key"),
513                    args.remove("client_authorization_key_signbit"),
514                    args.remove("client_authorization_signature"),
515                    args.remove("challenge_response"),
516                ) {
517                    // client_cookie
518                    let client_cookie: ClientCookie = match client_cookie.try_into() {
519                        Ok(client_cookie) => client_cookie,
520                        Err(_) => {
521                            self.state = IdentityServerState::HandshakeFailed;
522                            return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
523                        }
524                    };
525
526                    // client_identity_proof_signature
527                    let client_identity_proof_signature: [u8; ED25519_SIGNATURE_SIZE] =
528                        match client_identity_proof_signature.try_into() {
529                            Ok(client_identity_proof_signature) => client_identity_proof_signature,
530                            Err(_) => {
531                                self.state = IdentityServerState::HandshakeFailed;
532                                return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
533                            }
534                        };
535                    let client_identity_proof_signature =
536                        match Ed25519Signature::from_raw(&client_identity_proof_signature) {
537                            Ok(client_identity_proof_signature) => client_identity_proof_signature,
538                            Err(_) => {
539                                self.state = IdentityServerState::HandshakeFailed;
540                                return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
541                            }
542                        };
543
544                    // client_authorization_key
545                    let client_authorization_key: [u8; X25519_PUBLIC_KEY_SIZE] =
546                        match client_authorization_key.try_into() {
547                            Ok(client_authorization_key) => client_authorization_key,
548                            Err(_) => {
549                                self.state = IdentityServerState::HandshakeFailed;
550                                return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
551                            }
552                        };
553                    let client_authorization_key =
554                        X25519PublicKey::from_raw(&client_authorization_key);
555
556                    // client_authorization_key_signbit
557                    let client_authorization_key_signbit: SignBit =
558                        client_authorization_key_signbit.into();
559
560                    // client_authorization_signature
561                    let client_authorization_signature: [u8; ED25519_SIGNATURE_SIZE] =
562                        match client_authorization_signature.try_into() {
563                            Ok(client_authorization_signature) => client_authorization_signature,
564                            Err(_) => {
565                                self.state = IdentityServerState::HandshakeFailed;
566                                return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
567                            }
568                        };
569                    let client_authorization_signature =
570                        match Ed25519Signature::from_raw(&client_authorization_signature) {
571                            Ok(client_authorization_signature) => client_authorization_signature,
572                            Err(_) => {
573                                self.state = IdentityServerState::HandshakeFailed;
574                                return Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)));
575                            }
576                        };
577
578                    // save  cookie
579                    self.send_response_request_cookie = Some(request_cookie);
580
581                    // convert client_identity to client's public ed25519 key
582                    if let Ok(client_identity_key) =
583                        Ed25519PublicKey::from_service_id(client_identity)
584                    {
585                        // construct + verify client proof
586                        let client_proof = build_client_proof(
587                            DomainSeparator::GoslingIdentity,
588                            requested_endpoint,
589                            client_identity,
590                            &self.server_identity,
591                            &client_cookie,
592                            server_cookie,
593                        );
594                        self.client_proof_signature_valid = client_identity_proof_signature
595                            .verify(&client_proof, &client_identity_key);
596                    }
597
598                    // evaluate the client authorization signature
599                    self.client_auth_signature_valid = client_authorization_signature
600                        .verify_x25519(
601                            client_identity.as_bytes(),
602                            &client_authorization_key,
603                            client_authorization_key_signbit,
604                        );
605
606                    // save off client auth key for future endpoint generation
607                    self.client_auth_key = Some(client_authorization_key);
608
609                    // safe off challenge response for verification
610                    self.challenge_response = Some(challenge_response);
611
612                    None
613                } else {
614                    self.state = IdentityServerState::HandshakeFailed;
615                    Some(Err(ErrorCode::Runtime(RpcError::InvalidArg as i32)))
616                }
617            }
618            _ => {
619                self.state = IdentityServerState::HandshakeFailed;
620                Some(Err(ErrorCode::Runtime(RpcError::Failure as i32)))
621            }
622        }
623    }
624
625    fn next_result(&mut self) -> Option<(RequestCookie, Result<Option<bson::Bson>, ErrorCode>)> {
626        match (
627            &self.state,
628            self.begin_handshake_request_cookie,
629            self.client_identity.as_ref(),
630            self.requested_endpoint.as_ref(),
631            self.server_cookie.as_ref(),
632            self.endpoint_challenge.as_mut(),
633            self.send_response_request_cookie,
634            self.client_auth_key.as_ref(),
635            self.challenge_response.as_ref(),
636        ) {
637            // return challenge from begin_handshake
638            (
639                &IdentityServerState::ChallengeReady,
640                Some(begin_handshake_request_cookie),
641                Some(_client_identity),
642                Some(_requested_endpoint),
643                Some(server_cookie),
644                Some(endpoint_challenge),
645                None, // send_response_request_cookie
646                None, // client_auth_key
647                None,
648            ) =>
649            // challenge_response
650            {
651                self.state = IdentityServerState::WaitingForSendResponse;
652                Some((
653                    begin_handshake_request_cookie,
654                    Ok(Some(Bson::Document(doc! {
655                        "server_cookie" : Bson::Binary(Binary{subtype: BinarySubtype::Generic, bytes: server_cookie.to_vec()}),
656                        "endpoint_challenge" : std::mem::take(endpoint_challenge),
657                    }))),
658                ))
659            }
660            (&IdentityServerState::ChallengeReady, _, _, _, _, _, _, _, _) => unreachable!(),
661            (
662                &IdentityServerState::ChallengeVerificationReady,
663                Some(_begin_handshake_request_cookie),
664                Some(_client_identity),
665                Some(_requested_endpoint),
666                Some(_server_cookie),
667                Some(_endpoint_challenge),
668                Some(send_response_request_cookie),
669                Some(_client_auth_key),
670                Some(_challenge_response),
671            ) => {
672                let mut success = true;
673                success &= self.client_allowed;
674                success &= self.client_requested_endpoint_valid;
675                success &= self.client_proof_signature_valid;
676                success &= self.client_auth_signature_valid;
677                success &= self.challenge_response_valid;
678
679                self.state = IdentityServerState::ChallengeVerificationResponseSent;
680                if success {
681                    let endpoint_private_key = Ed25519PrivateKey::generate();
682                    let endpoint_service_id =
683                        V3OnionServiceId::from_private_key(&endpoint_private_key);
684                    self.endpoint_private_key = Some(endpoint_private_key);
685                    Some((
686                        send_response_request_cookie,
687                        Ok(Some(Bson::String(endpoint_service_id.to_string()))),
688                    ))
689                } else {
690                    Some((
691                        send_response_request_cookie,
692                        Err(ErrorCode::Runtime(RpcError::Failure as i32)),
693                    ))
694                }
695            }
696            _ => None,
697        }
698    }
699}