LCOV - code coverage report
Current view: top level - feature/hs - hs_circuit.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 235 453 51.9 %
Date: 2021-11-24 03:28:48 Functions: 19 31 61.3 %

          Line data    Source code
       1             : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : /**
       5             :  * \file hs_circuit.c
       6             :  **/
       7             : 
       8             : #define HS_CIRCUIT_PRIVATE
       9             : 
      10             : #include "core/or/or.h"
      11             : #include "app/config/config.h"
      12             : #include "core/crypto/hs_ntor.h"
      13             : #include "core/or/circuitbuild.h"
      14             : #include "core/or/circuitlist.h"
      15             : #include "core/or/circuituse.h"
      16             : #include "core/or/policies.h"
      17             : #include "core/or/relay.h"
      18             : #include "core/or/crypt_path.h"
      19             : #include "core/or/extendinfo.h"
      20             : #include "feature/client/circpathbias.h"
      21             : #include "feature/hs/hs_cell.h"
      22             : #include "feature/hs/hs_circuit.h"
      23             : #include "feature/hs/hs_ob.h"
      24             : #include "feature/hs/hs_circuitmap.h"
      25             : #include "feature/hs/hs_client.h"
      26             : #include "feature/hs/hs_ident.h"
      27             : #include "feature/hs/hs_metrics.h"
      28             : #include "feature/hs/hs_service.h"
      29             : #include "feature/nodelist/describe.h"
      30             : #include "feature/nodelist/nodelist.h"
      31             : #include "feature/stats/rephist.h"
      32             : #include "lib/crypt_ops/crypto_dh.h"
      33             : #include "lib/crypt_ops/crypto_rand.h"
      34             : #include "lib/crypt_ops/crypto_util.h"
      35             : 
      36             : /* Trunnel. */
      37             : #include "trunnel/ed25519_cert.h"
      38             : #include "trunnel/hs/cell_common.h"
      39             : #include "trunnel/hs/cell_establish_intro.h"
      40             : 
      41             : #include "core/or/cpath_build_state_st.h"
      42             : #include "core/or/crypt_path_st.h"
      43             : #include "feature/nodelist/node_st.h"
      44             : #include "core/or/origin_circuit_st.h"
      45             : 
      46             : /** A circuit is about to become an e2e rendezvous circuit. Check
      47             :  * <b>circ_purpose</b> and ensure that it's properly set. Return true iff
      48             :  * circuit purpose is properly set, otherwise return false. */
      49             : static int
      50           5 : circuit_purpose_is_correct_for_rend(unsigned int circ_purpose,
      51             :                                     int is_service_side)
      52             : {
      53           5 :   if (is_service_side) {
      54           3 :     if (circ_purpose != CIRCUIT_PURPOSE_S_CONNECT_REND) {
      55           0 :       log_warn(LD_BUG,
      56             :             "HS e2e circuit setup with wrong purpose (%d)", circ_purpose);
      57           0 :       return 0;
      58             :     }
      59             :   }
      60             : 
      61           5 :   if (!is_service_side) {
      62           2 :     if (circ_purpose != CIRCUIT_PURPOSE_C_REND_READY &&
      63             :         circ_purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) {
      64           0 :       log_warn(LD_BUG,
      65             :             "Client e2e circuit setup with wrong purpose (%d)", circ_purpose);
      66           0 :       return 0;
      67             :     }
      68             :   }
      69             : 
      70             :   return 1;
      71             : }
      72             : 
      73             : /** Create and return a crypt path for the final hop of a v3 prop224 rendezvous
      74             :  * circuit. Initialize the crypt path crypto using the output material from the
      75             :  * ntor key exchange at <b>ntor_key_seed</b>.
      76             :  *
      77             :  * If <b>is_service_side</b> is set, we are the hidden service and the final
      78             :  * hop of the rendezvous circuit is the client on the other side. */
      79             : static crypt_path_t *
      80           5 : create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len,
      81             :                   int is_service_side)
      82             : {
      83           5 :   uint8_t keys[HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN];
      84           5 :   crypt_path_t *cpath = NULL;
      85             : 
      86             :   /* Do the key expansion */
      87           5 :   if (hs_ntor_circuit_key_expansion(ntor_key_seed, seed_len,
      88             :                                     keys, sizeof(keys)) < 0) {
      89           0 :     goto err;
      90             :   }
      91             : 
      92             :   /* Setup the cpath */
      93           5 :   cpath = tor_malloc_zero(sizeof(crypt_path_t));
      94           5 :   cpath->magic = CRYPT_PATH_MAGIC;
      95             : 
      96           5 :   if (cpath_init_circuit_crypto(cpath, (char*)keys, sizeof(keys),
      97             :                                 is_service_side, 1) < 0) {
      98           0 :     tor_free(cpath);
      99           0 :     goto err;
     100             :   }
     101             : 
     102           5 :  err:
     103           5 :   memwipe(keys, 0, sizeof(keys));
     104           5 :   return cpath;
     105             : }
     106             : 
     107             : /** Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark
     108             :  * <b>circ</b> ready for use to transfer HS relay cells. */
     109             : static void
     110           5 : finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
     111             :                       int is_service_side)
     112             : {
     113           5 :   tor_assert(circ);
     114           5 :   tor_assert(hop);
     115             : 
     116             :   /* Notify the circuit state machine that we are splicing this circuit */
     117          10 :   int new_circ_purpose = is_service_side ?
     118           5 :     CIRCUIT_PURPOSE_S_REND_JOINED : CIRCUIT_PURPOSE_C_REND_JOINED;
     119           5 :   circuit_change_purpose(TO_CIRCUIT(circ), new_circ_purpose);
     120             : 
     121             :   /* All is well. Extend the circuit. */
     122           5 :   hop->state = CPATH_STATE_OPEN;
     123             :   /* Set the windows to default. */
     124           5 :   hop->package_window = circuit_initial_package_window();
     125           5 :   hop->deliver_window = CIRCWINDOW_START;
     126             : 
     127             :   /* Now that this circuit has finished connecting to its destination,
     128             :    * make sure circuit_get_open_circ_or_launch is willing to return it
     129             :    * so we can actually use it. */
     130           5 :   circ->hs_circ_has_timed_out = 0;
     131             : 
     132             :   /* Append the hop to the cpath of this circuit */
     133           5 :   cpath_extend_linked_list(&circ->cpath, hop);
     134             : 
     135             :   /* Finally, mark circuit as ready to be used for client streams */
     136           5 :   if (!is_service_side) {
     137           2 :     circuit_try_attaching_streams(circ);
     138             :   }
     139           5 : }
     140             : 
     141             : /** For a given circuit and a service introduction point object, register the
     142             :  * intro circuit to the circuitmap. */
     143             : static void
     144           0 : register_intro_circ(const hs_service_intro_point_t *ip,
     145             :                     origin_circuit_t *circ)
     146             : {
     147           0 :   tor_assert(ip);
     148           0 :   tor_assert(circ);
     149             : 
     150           0 :   hs_circuitmap_register_intro_circ_v3_service_side(circ,
     151           0 :                                                     &ip->auth_key_kp.pubkey);
     152           0 : }
     153             : 
     154             : /** Return the number of opened introduction circuit for the given circuit that
     155             :  * is matching its identity key. */
     156             : static unsigned int
     157           1 : count_opened_desc_intro_point_circuits(const hs_service_t *service,
     158             :                                        const hs_service_descriptor_t *desc)
     159             : {
     160           1 :   unsigned int count = 0;
     161             : 
     162           1 :   tor_assert(service);
     163           1 :   tor_assert(desc);
     164             : 
     165           2 :   DIGEST256MAP_FOREACH(desc->intro_points.map, key,
     166             :                        const hs_service_intro_point_t *, ip) {
     167           1 :     const circuit_t *circ;
     168           1 :     const origin_circuit_t *ocirc = hs_circ_service_get_intro_circ(ip);
     169           1 :     if (ocirc == NULL) {
     170           1 :       continue;
     171             :     }
     172           0 :     circ = TO_CIRCUIT(ocirc);
     173           0 :     tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
     174             :                circ->purpose == CIRCUIT_PURPOSE_S_INTRO);
     175             :     /* Having a circuit not for the requested service is really bad. */
     176           0 :     tor_assert(ed25519_pubkey_eq(&service->keys.identity_pk,
     177             :                                  &ocirc->hs_ident->identity_pk));
     178             :     /* Only count opened circuit and skip circuit that will be closed. */
     179           0 :     if (!circ->marked_for_close && circ->state == CIRCUIT_STATE_OPEN) {
     180           0 :       count++;
     181             :     }
     182           1 :   } DIGEST256MAP_FOREACH_END;
     183           1 :   return count;
     184             : }
     185             : 
     186             : /** From a given service, rendezvous cookie and handshake info, create a
     187             :  * rendezvous point circuit identifier. This can't fail. */
     188             : STATIC hs_ident_circuit_t *
     189           1 : create_rp_circuit_identifier(const hs_service_t *service,
     190             :                              const uint8_t *rendezvous_cookie,
     191             :                              const curve25519_public_key_t *server_pk,
     192             :                              const hs_ntor_rend_cell_keys_t *keys)
     193             : {
     194           1 :   hs_ident_circuit_t *ident;
     195           1 :   uint8_t handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN];
     196             : 
     197           1 :   tor_assert(service);
     198           1 :   tor_assert(rendezvous_cookie);
     199           1 :   tor_assert(server_pk);
     200           1 :   tor_assert(keys);
     201             : 
     202           1 :   ident = hs_ident_circuit_new(&service->keys.identity_pk);
     203             :   /* Copy the RENDEZVOUS_COOKIE which is the unique identifier. */
     204           1 :   memcpy(ident->rendezvous_cookie, rendezvous_cookie,
     205             :          sizeof(ident->rendezvous_cookie));
     206             :   /* Build the HANDSHAKE_INFO which looks like this:
     207             :    *    SERVER_PK        [32 bytes]
     208             :    *    AUTH_INPUT_MAC   [32 bytes]
     209             :    */
     210           1 :   memcpy(handshake_info, server_pk->public_key, CURVE25519_PUBKEY_LEN);
     211           1 :   memcpy(handshake_info + CURVE25519_PUBKEY_LEN, keys->rend_cell_auth_mac,
     212             :          DIGEST256_LEN);
     213           1 :   tor_assert(sizeof(ident->rendezvous_handshake_info) ==
     214             :              sizeof(handshake_info));
     215           1 :   memcpy(ident->rendezvous_handshake_info, handshake_info,
     216             :          sizeof(ident->rendezvous_handshake_info));
     217             :   /* Finally copy the NTOR_KEY_SEED for e2e encryption on the circuit. */
     218           1 :   tor_assert(sizeof(ident->rendezvous_ntor_key_seed) ==
     219             :              sizeof(keys->ntor_key_seed));
     220           1 :   memcpy(ident->rendezvous_ntor_key_seed, keys->ntor_key_seed,
     221             :          sizeof(ident->rendezvous_ntor_key_seed));
     222           1 :   return ident;
     223             : }
     224             : 
     225             : /** From a given service and service intro point, create an introduction point
     226             :  * circuit identifier. This can't fail. */
     227             : static hs_ident_circuit_t *
     228           0 : create_intro_circuit_identifier(const hs_service_t *service,
     229             :                                 const hs_service_intro_point_t *ip)
     230             : {
     231           0 :   hs_ident_circuit_t *ident;
     232             : 
     233           0 :   tor_assert(service);
     234           0 :   tor_assert(ip);
     235             : 
     236           0 :   ident = hs_ident_circuit_new(&service->keys.identity_pk);
     237           0 :   ed25519_pubkey_copy(&ident->intro_auth_pk, &ip->auth_key_kp.pubkey);
     238             : 
     239           0 :   return ident;
     240             : }
     241             : 
     242             : /** For a given introduction point and an introduction circuit, send the
     243             :  * ESTABLISH_INTRO cell. The service object is used for logging. This can fail
     244             :  * and if so, the circuit is closed and the intro point object is flagged
     245             :  * that the circuit is not established anymore which is important for the
     246             :  * retry mechanism. */
     247             : static void
     248           1 : send_establish_intro(const hs_service_t *service,
     249             :                      hs_service_intro_point_t *ip, origin_circuit_t *circ)
     250             : {
     251           1 :   ssize_t cell_len;
     252           1 :   uint8_t payload[RELAY_PAYLOAD_SIZE];
     253             : 
     254           1 :   tor_assert(service);
     255           1 :   tor_assert(ip);
     256           1 :   tor_assert(circ);
     257             : 
     258             :   /* Encode establish intro cell. */
     259           1 :   cell_len = hs_cell_build_establish_intro(circ->cpath->prev->rend_circ_nonce,
     260             :                                            &service->config, ip, payload);
     261           1 :   if (cell_len < 0) {
     262           0 :     log_warn(LD_REND, "Unable to encode ESTABLISH_INTRO cell for service %s "
     263             :                       "on circuit %u. Closing circuit.",
     264             :              safe_str_client(service->onion_address),
     265             :              TO_CIRCUIT(circ)->n_circ_id);
     266           0 :     goto err;
     267             :   }
     268             : 
     269             :   /* Send the cell on the circuit. */
     270           1 :   if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
     271             :                                    RELAY_COMMAND_ESTABLISH_INTRO,
     272             :                                    (char *) payload, cell_len,
     273             :                                    circ->cpath->prev) < 0) {
     274           0 :     log_info(LD_REND, "Unable to send ESTABLISH_INTRO cell for service %s "
     275             :                       "on circuit %u.",
     276             :              safe_str_client(service->onion_address),
     277             :              TO_CIRCUIT(circ)->n_circ_id);
     278             :     /* On error, the circuit has been closed. */
     279           0 :     goto done;
     280             :   }
     281             : 
     282             :   /* Record the attempt to use this circuit. */
     283           1 :   pathbias_count_use_attempt(circ);
     284           1 :   goto done;
     285             : 
     286           0 :  err:
     287           0 :   circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
     288           1 :  done:
     289           1 :   memwipe(payload, 0, sizeof(payload));
     290           1 : }
     291             : 
     292             : /** Return a string constant describing the anonymity of service. */
     293             : static const char *
     294           0 : get_service_anonymity_string(const hs_service_t *service)
     295             : {
     296           0 :   if (service->config.is_single_onion) {
     297             :     return "single onion";
     298             :   } else {
     299           0 :     return "hidden";
     300             :   }
     301             : }
     302             : 
     303             : /** For a given service, the ntor onion key and a rendezvous cookie, launch a
     304             :  * circuit to the rendezvous point specified by the link specifiers. On
     305             :  * success, a circuit identifier is attached to the circuit with the needed
     306             :  * data. This function will try to open a circuit for a maximum value of
     307             :  * MAX_REND_FAILURES then it will give up. */
     308           0 : MOCK_IMPL(STATIC void,
     309             : launch_rendezvous_point_circuit,(const hs_service_t *service,
     310             :                                  const hs_service_intro_point_t *ip,
     311             :                                  const hs_cell_introduce2_data_t *data))
     312             : {
     313           0 :   int circ_needs_uptime;
     314           0 :   time_t now = time(NULL);
     315           0 :   extend_info_t *info = NULL;
     316           0 :   origin_circuit_t *circ;
     317             : 
     318           0 :   tor_assert(service);
     319           0 :   tor_assert(ip);
     320           0 :   tor_assert(data);
     321             : 
     322           0 :   circ_needs_uptime = hs_service_requires_uptime_circ(service->config.ports);
     323             : 
     324             :   /* Get the extend info data structure for the chosen rendezvous point
     325             :    * specified by the given link specifiers. */
     326           0 :   info = hs_get_extend_info_from_lspecs(data->link_specifiers,
     327           0 :                                         &data->onion_pk,
     328           0 :                                         service->config.is_single_onion);
     329           0 :   if (info == NULL) {
     330             :     /* We are done here, we can't extend to the rendezvous point. */
     331           0 :     log_fn(LOG_PROTOCOL_WARN, LD_REND,
     332             :            "Not enough info to open a circuit to a rendezvous point for "
     333             :            "%s service %s.",
     334             :            get_service_anonymity_string(service),
     335             :            safe_str_client(service->onion_address));
     336           0 :     goto end;
     337             :   }
     338             : 
     339           0 :   for (int i = 0; i < MAX_REND_FAILURES; i++) {
     340           0 :     int circ_flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL;
     341           0 :     if (circ_needs_uptime) {
     342           0 :       circ_flags |= CIRCLAUNCH_NEED_UPTIME;
     343             :     }
     344             :     /* Firewall and policies are checked when getting the extend info.
     345             :      *
     346             :      * We only use a one-hop path on the first attempt. If the first attempt
     347             :      * fails, we use a 3-hop path for reachability / reliability.
     348             :      * See the comment in retry_service_rendezvous_point() for details. */
     349           0 :     if (service->config.is_single_onion && i == 0) {
     350           0 :       circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
     351             :     }
     352             : 
     353           0 :     circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, info,
     354             :                                          circ_flags);
     355           0 :     if (circ != NULL) {
     356             :       /* Stop retrying, we have a circuit! */
     357             :       break;
     358             :     }
     359             :   }
     360           0 :   if (circ == NULL) {
     361           0 :     log_warn(LD_REND, "Giving up on launching a rendezvous circuit to %s "
     362             :                       "for %s service %s",
     363             :              safe_str_client(extend_info_describe(info)),
     364             :              get_service_anonymity_string(service),
     365             :              safe_str_client(service->onion_address));
     366           0 :     goto end;
     367             :   }
     368             :   /* Update metrics with this new rendezvous circuit launched. */
     369           0 :   hs_metrics_new_rdv(&service->keys.identity_pk);
     370             : 
     371           0 :   log_info(LD_REND, "Rendezvous circuit launched to %s with cookie %s "
     372             :                     "for %s service %s",
     373             :            safe_str_client(extend_info_describe(info)),
     374             :            safe_str_client(hex_str((const char *) data->rendezvous_cookie,
     375             :                                    REND_COOKIE_LEN)),
     376             :            get_service_anonymity_string(service),
     377             :            safe_str_client(service->onion_address));
     378           0 :   tor_assert(circ->build_state);
     379             :   /* Rendezvous circuit have a specific timeout for the time spent on trying
     380             :    * to connect to the rendezvous point. */
     381           0 :   circ->build_state->expiry_time = now + MAX_REND_TIMEOUT;
     382             : 
     383             :   /* Create circuit identifier and key material. */
     384             :   {
     385           0 :     hs_ntor_rend_cell_keys_t keys;
     386           0 :     curve25519_keypair_t ephemeral_kp;
     387             :     /* No need for extra strong, this is only for this circuit life time. This
     388             :      * key will be used for the RENDEZVOUS1 cell that will be sent on the
     389             :      * circuit once opened. */
     390           0 :     curve25519_keypair_generate(&ephemeral_kp, 0);
     391           0 :     if (hs_ntor_service_get_rendezvous1_keys(&ip->auth_key_kp.pubkey,
     392           0 :                                              &ip->enc_key_kp,
     393           0 :                                              &ephemeral_kp, &data->client_pk,
     394             :                                              &keys) < 0) {
     395             :       /* This should not really happened but just in case, don't make tor
     396             :        * freak out, close the circuit and move on. */
     397           0 :       log_info(LD_REND, "Unable to get RENDEZVOUS1 key material for "
     398             :                         "service %s",
     399             :                safe_str_client(service->onion_address));
     400           0 :       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
     401           0 :       goto end;
     402             :     }
     403           0 :     circ->hs_ident = create_rp_circuit_identifier(service,
     404             :                                                   data->rendezvous_cookie,
     405             :                                                   &ephemeral_kp.pubkey, &keys);
     406           0 :     memwipe(&ephemeral_kp, 0, sizeof(ephemeral_kp));
     407           0 :     memwipe(&keys, 0, sizeof(keys));
     408           0 :     tor_assert(circ->hs_ident);
     409             :   }
     410             : 
     411           0 :  end:
     412           0 :   extend_info_free(info);
     413           0 : }
     414             : 
     415             : /** Return true iff the given service rendezvous circuit circ is allowed for a
     416             :  * relaunch to the rendezvous point. */
     417             : static int
     418           0 : can_relaunch_service_rendezvous_point(const origin_circuit_t *circ)
     419             : {
     420           0 :   tor_assert(circ);
     421             :   /* This is initialized when allocating an origin circuit. */
     422           0 :   tor_assert(circ->build_state);
     423           0 :   tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
     424             : 
     425             :   /* XXX: Retrying under certain condition. This is related to #22455. */
     426             : 
     427             :   /* Avoid to relaunch twice a circuit to the same rendezvous point at the
     428             :    * same time. */
     429           0 :   if (circ->hs_service_side_rend_circ_has_been_relaunched) {
     430           0 :     log_info(LD_REND, "Rendezvous circuit to %s has already been retried. "
     431             :                       "Skipping retry.",
     432             :              safe_str_client(
     433             :                   extend_info_describe(circ->build_state->chosen_exit)));
     434           0 :     goto disallow;
     435             :   }
     436             : 
     437             :   /* We check failure_count >= hs_get_service_max_rend_failures()-1 below, and
     438             :    * the -1 is because we increment the failure count for our current failure
     439             :    * *after* this clause. */
     440           0 :   int max_rend_failures = hs_get_service_max_rend_failures() - 1;
     441             : 
     442             :   /* A failure count that has reached maximum allowed or circuit that expired,
     443             :    * we skip relaunching. */
     444           0 :   if (circ->build_state->failure_count > max_rend_failures ||
     445           0 :       circ->build_state->expiry_time <= time(NULL)) {
     446           0 :     log_info(LD_REND, "Attempt to build a rendezvous circuit to %s has "
     447             :                       "failed with %d attempts and expiry time %ld. "
     448             :                       "Giving up building.",
     449             :              safe_str_client(
     450             :                   extend_info_describe(circ->build_state->chosen_exit)),
     451             :              circ->build_state->failure_count,
     452             :              (long int) circ->build_state->expiry_time);
     453           0 :     goto disallow;
     454             :   }
     455             : 
     456             :   /* Allowed to relaunch. */
     457             :   return 1;
     458             :  disallow:
     459             :   return 0;
     460             : }
     461             : 
     462             : /** Retry the rendezvous point of circ by launching a new circuit to it. */
     463             : static void
     464           0 : retry_service_rendezvous_point(const origin_circuit_t *circ)
     465             : {
     466           0 :   int flags = 0;
     467           0 :   origin_circuit_t *new_circ;
     468           0 :   cpath_build_state_t *bstate;
     469             : 
     470           0 :   tor_assert(circ);
     471             :   /* This is initialized when allocating an origin circuit. */
     472           0 :   tor_assert(circ->build_state);
     473           0 :   tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
     474             : 
     475             :   /* Ease our life. */
     476           0 :   bstate = circ->build_state;
     477             : 
     478           0 :   log_info(LD_REND, "Retrying rendezvous point circuit to %s",
     479             :            safe_str_client(extend_info_describe(bstate->chosen_exit)));
     480             : 
     481             :   /* Get the current build state flags for the next circuit. */
     482           0 :   flags |= (bstate->need_uptime) ? CIRCLAUNCH_NEED_UPTIME : 0;
     483           0 :   flags |= (bstate->need_capacity) ? CIRCLAUNCH_NEED_CAPACITY : 0;
     484           0 :   flags |= (bstate->is_internal) ? CIRCLAUNCH_IS_INTERNAL : 0;
     485             : 
     486             :   /* We do NOT add the onehop tunnel flag even though it might be a single
     487             :    * onion service. The reason is that if we failed once to connect to the RP
     488             :    * with a direct connection, we consider that chances are that we will fail
     489             :    * again so try a 3-hop circuit and hope for the best. Because the service
     490             :    * has no anonymity (single onion), this change of behavior won't affect
     491             :    * security directly. */
     492             : 
     493           0 :   new_circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND,
     494             :                                            bstate->chosen_exit, flags);
     495           0 :   if (new_circ == NULL) {
     496           0 :     log_warn(LD_REND, "Failed to launch rendezvous circuit to %s",
     497             :              safe_str_client(extend_info_describe(bstate->chosen_exit)));
     498           0 :     goto done;
     499             :   }
     500             : 
     501             :   /* Transfer build state information to the new circuit state in part to
     502             :    * catch any other failures. */
     503           0 :   new_circ->build_state->failure_count = bstate->failure_count+1;
     504           0 :   new_circ->build_state->expiry_time = bstate->expiry_time;
     505           0 :   new_circ->hs_ident = hs_ident_circuit_dup(circ->hs_ident);
     506             : 
     507           0 :  done:
     508           0 :   return;
     509             : }
     510             : 
     511             : /** Using the given descriptor intro point ip, the node of the
     512             :  * rendezvous point rp_node and the service's subcredential, populate the
     513             :  * already allocated intro1_data object with the needed key material and link
     514             :  * specifiers.
     515             :  *
     516             :  * Return 0 on success or a negative value if we couldn't properly filled the
     517             :  * introduce1 data from the RP node. In other word, it means the RP node is
     518             :  * unusable to use in the introduction. */
     519             : static int
     520           4 : setup_introduce1_data(const hs_desc_intro_point_t *ip,
     521             :                       const node_t *rp_node,
     522             :                       const hs_subcredential_t *subcredential,
     523             :                       hs_cell_introduce1_data_t *intro1_data)
     524             : {
     525           4 :   int ret = -1;
     526           4 :   smartlist_t *rp_lspecs;
     527             : 
     528           4 :   tor_assert(ip);
     529           4 :   tor_assert(rp_node);
     530           4 :   tor_assert(subcredential);
     531           4 :   tor_assert(intro1_data);
     532             : 
     533             :   /* Build the link specifiers from the node at the end of the rendezvous
     534             :    * circuit that we opened for this introduction. */
     535           4 :   rp_lspecs = node_get_link_specifier_smartlist(rp_node, 0);
     536           4 :   if (smartlist_len(rp_lspecs) == 0) {
     537             :     /* We can't rendezvous without link specifiers. */
     538           0 :     smartlist_free(rp_lspecs);
     539           0 :     goto end;
     540             :   }
     541             : 
     542             :   /* Populate the introduce1 data object. */
     543           4 :   memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
     544           4 :   intro1_data->auth_pk = &ip->auth_key_cert->signed_key;
     545           4 :   intro1_data->enc_pk = &ip->enc_key;
     546           4 :   intro1_data->subcredential = subcredential;
     547           4 :   intro1_data->link_specifiers = rp_lspecs;
     548           4 :   intro1_data->onion_pk = node_get_curve25519_onion_key(rp_node);
     549           4 :   if (intro1_data->onion_pk == NULL) {
     550             :     /* We can't rendezvous without the curve25519 onion key. */
     551           0 :     goto end;
     552             :   }
     553             :   /* Success, we have valid introduce data. */
     554             :   ret = 0;
     555             : 
     556           4 :  end:
     557           4 :   return ret;
     558             : }
     559             : 
     560             : /** Helper: cleanup function for client circuit. This is for every HS version.
     561             :  * It is called from hs_circ_cleanup_on_close() entry point. */
     562             : static void
     563           5 : cleanup_on_close_client_circ(circuit_t *circ)
     564             : {
     565           5 :   tor_assert(circ);
     566             : 
     567           5 :   if (circuit_is_hs_v3(circ)) {
     568           5 :     hs_client_circuit_cleanup_on_close(circ);
     569             :   }
     570             :   /* It is possible the circuit has an HS purpose but no identifier (hs_ident).
     571             :    * Thus possible that this passes through. */
     572           5 : }
     573             : 
     574             : /** Helper: cleanup function for client circuit. This is for every HS version.
     575             :  * It is called from hs_circ_cleanup_on_free() entry point. */
     576             : static void
     577          11 : cleanup_on_free_client_circ(circuit_t *circ)
     578             : {
     579          11 :   tor_assert(circ);
     580             : 
     581          11 :   if (circuit_is_hs_v3(circ)) {
     582           9 :     hs_client_circuit_cleanup_on_free(circ);
     583             :   }
     584             :   /* It is possible the circuit has an HS purpose but no identifier (hs_ident).
     585             :    * Thus possible that this passes through. */
     586          11 : }
     587             : 
     588             : /* ========== */
     589             : /* Public API */
     590             : /* ========== */
     591             : 
     592             : /** Return an introduction point circuit matching the given intro point object.
     593             :  * NULL is returned is no such circuit can be found. */
     594             : origin_circuit_t *
     595           9 : hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
     596             : {
     597           9 :   tor_assert(ip);
     598             : 
     599           9 :   return hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
     600             : }
     601             : 
     602             : /** Return an introduction point established circuit matching the given intro
     603             :  * point object. The circuit purpose has to be CIRCUIT_PURPOSE_S_INTRO. NULL
     604             :  * is returned is no such circuit can be found. */
     605             : origin_circuit_t *
     606           0 : hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
     607             : {
     608           0 :   origin_circuit_t *circ;
     609             : 
     610           0 :   tor_assert(ip);
     611             : 
     612           0 :   circ = hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
     613             : 
     614             :   /* Only return circuit if it is established. */
     615           0 :   return (circ && TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO) ?
     616           0 :           circ : NULL;
     617             : }
     618             : 
     619             : /** Called when we fail building a rendezvous circuit at some point other than
     620             :  * the last hop: launches a new circuit to the same rendezvous point.
     621             :  *
     622             :  * We currently relaunch connections to rendezvous points if:
     623             :  * - A rendezvous circuit timed out before connecting to RP.
     624             :  * - The rendezvous circuit failed to connect to the RP.
     625             :  *
     626             :  * We avoid relaunching a connection to this rendezvous point if:
     627             :  * - We have already tried MAX_REND_FAILURES times to connect to this RP,
     628             :  * - We've been trying to connect to this RP for more than MAX_REND_TIMEOUT
     629             :  *   seconds, or
     630             :  * - We've already retried this specific rendezvous circuit.
     631             :  */
     632             : void
     633           0 : hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ)
     634             : {
     635           0 :   tor_assert(circ);
     636           0 :   tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
     637             : 
     638             :   /* Check if we are allowed to relaunch to the rendezvous point of circ. */
     639           0 :   if (!can_relaunch_service_rendezvous_point(circ)) {
     640           0 :     goto done;
     641             :   }
     642             : 
     643             :   /* Flag the circuit that we are relaunching, to avoid to relaunch twice a
     644             :    * circuit to the same rendezvous point at the same time. */
     645           0 :   circ->hs_service_side_rend_circ_has_been_relaunched = 1;
     646             : 
     647             :   /* Legacy services don't have a hidden service ident. */
     648           0 :   if (circ->hs_ident) {
     649           0 :     retry_service_rendezvous_point(circ);
     650             :   }
     651             : 
     652           0 :  done:
     653           0 :   return;
     654             : }
     655             : 
     656             : /** For a given service and a service intro point, launch a circuit to the
     657             :  * extend info ei. If the service is a single onion, and direct_conn is true,
     658             :  * a one-hop circuit will be requested.
     659             :  *
     660             :  * Return 0 if the circuit was successfully launched and tagged
     661             :  * with the correct identifier. On error, a negative value is returned. */
     662             : int
     663           0 : hs_circ_launch_intro_point(hs_service_t *service,
     664             :                            const hs_service_intro_point_t *ip,
     665             :                            extend_info_t *ei,
     666             :                            bool direct_conn)
     667             : {
     668             :   /* Standard flags for introduction circuit. */
     669           0 :   int ret = -1, circ_flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
     670           0 :   origin_circuit_t *circ;
     671             : 
     672           0 :   tor_assert(service);
     673           0 :   tor_assert(ip);
     674           0 :   tor_assert(ei);
     675             : 
     676             :   /* Update circuit flags in case of a single onion service that requires a
     677             :    * direct connection. */
     678           0 :   tor_assert_nonfatal(ip->circuit_retries > 0);
     679             :   /* Only single onion services can make direct conns */
     680           0 :   if (BUG(!service->config.is_single_onion && direct_conn)) {
     681           0 :     goto end;
     682             :   }
     683             :   /* We only use a one-hop path on the first attempt. If the first attempt
     684             :    * fails, we use a 3-hop path for reachability / reliability. */
     685           0 :   if (direct_conn && ip->circuit_retries == 1) {
     686           0 :     circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
     687             :   }
     688             : 
     689           0 :   log_info(LD_REND, "Launching a circuit to intro point %s for service %s.",
     690             :            safe_str_client(extend_info_describe(ei)),
     691             :            safe_str_client(service->onion_address));
     692             : 
     693             :   /* Note down the launch for the retry period. Even if the circuit fails to
     694             :    * be launched, we still want to respect the retry period to avoid stress on
     695             :    * the circuit subsystem. */
     696           0 :   service->state.num_intro_circ_launched++;
     697           0 :   circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO,
     698             :                                        ei, circ_flags);
     699           0 :   if (circ == NULL) {
     700           0 :     goto end;
     701             :   }
     702             : 
     703             :   /* Setup the circuit identifier and attach it to it. */
     704           0 :   circ->hs_ident = create_intro_circuit_identifier(service, ip);
     705           0 :   tor_assert(circ->hs_ident);
     706             :   /* Register circuit in the global circuitmap. */
     707           0 :   register_intro_circ(ip, circ);
     708             : 
     709             :   /* Success. */
     710           0 :   ret = 0;
     711           0 :  end:
     712           0 :   return ret;
     713             : }
     714             : 
     715             : /** Called when a service introduction point circuit is done building. Given
     716             :  * the service and intro point object, this function will send the
     717             :  * ESTABLISH_INTRO cell on the circuit. Return 0 on success. Return 1 if the
     718             :  * circuit has been repurposed to General because we already have too many
     719             :  * opened. */
     720             : int
     721           1 : hs_circ_service_intro_has_opened(hs_service_t *service,
     722             :                                  hs_service_intro_point_t *ip,
     723             :                                  const hs_service_descriptor_t *desc,
     724             :                                  origin_circuit_t *circ)
     725             : {
     726           1 :   int ret = 0;
     727           1 :   unsigned int num_intro_circ, num_needed_circ;
     728             : 
     729           1 :   tor_assert(service);
     730           1 :   tor_assert(ip);
     731           1 :   tor_assert(desc);
     732           1 :   tor_assert(circ);
     733             : 
     734             :   /* Count opened circuits that have sent ESTABLISH_INTRO cells or are already
     735             :    * established introduction circuits */
     736           1 :   num_intro_circ = count_opened_desc_intro_point_circuits(service, desc);
     737           1 :   num_needed_circ = service->config.num_intro_points;
     738           1 :   if (num_intro_circ > num_needed_circ) {
     739             :     /* There are too many opened valid intro circuit for what the service
     740             :      * needs so repurpose this one. */
     741             : 
     742             :     /* XXX: Legacy code checks options->ExcludeNodes and if not NULL it just
     743             :      * closes the circuit. I have NO idea why it does that so it hasn't been
     744             :      * added here. I can only assume in case our ExcludeNodes list changes but
     745             :      * in that case, all circuit are flagged unusable (config.c). --dgoulet */
     746             : 
     747           0 :     log_info(LD_CIRC | LD_REND, "Introduction circuit just opened but we "
     748             :                                 "have enough for service %s. Repurposing "
     749             :                                 "it to general and leaving internal.",
     750             :              safe_str_client(service->onion_address));
     751           0 :     tor_assert(circ->build_state->is_internal);
     752             :     /* Remove it from the circuitmap. */
     753           0 :     hs_circuitmap_remove_circuit(TO_CIRCUIT(circ));
     754             :     /* Cleaning up the hidden service identifier and repurpose. */
     755           0 :     hs_ident_circuit_free(circ->hs_ident);
     756           0 :     circ->hs_ident = NULL;
     757           0 :     if (circuit_should_use_vanguards(TO_CIRCUIT(circ)->purpose))
     758           0 :       circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_HS_VANGUARDS);
     759             :     else
     760           0 :       circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_GENERAL);
     761             : 
     762             :     /* Inform that this circuit just opened for this new purpose. */
     763           0 :     circuit_has_opened(circ);
     764             :     /* This return value indicate to the caller that the IP object should be
     765             :      * removed from the service because it's corresponding circuit has just
     766             :      * been repurposed. */
     767           0 :     ret = 1;
     768           0 :     goto done;
     769             :   }
     770             : 
     771           1 :   log_info(LD_REND, "Introduction circuit %u established for service %s.",
     772             :            TO_CIRCUIT(circ)->n_circ_id,
     773             :            safe_str_client(service->onion_address));
     774           1 :   circuit_log_path(LOG_INFO, LD_REND, circ);
     775             : 
     776             :   /* Time to send an ESTABLISH_INTRO cell on this circuit. On error, this call
     777             :    * makes sure the circuit gets closed. */
     778           1 :   send_establish_intro(service, ip, circ);
     779             : 
     780           1 :  done:
     781           1 :   return ret;
     782             : }
     783             : 
     784             : /** Called when a service rendezvous point circuit is done building. Given the
     785             :  * service and the circuit, this function will send a RENDEZVOUS1 cell on the
     786             :  * circuit using the information in the circuit identifier. If the cell can't
     787             :  * be sent, the circuit is closed. */
     788             : void
     789           2 : hs_circ_service_rp_has_opened(const hs_service_t *service,
     790             :                               origin_circuit_t *circ)
     791             : {
     792           2 :   size_t payload_len;
     793           2 :   uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
     794             : 
     795           2 :   tor_assert(service);
     796           2 :   tor_assert(circ);
     797           2 :   tor_assert(circ->hs_ident);
     798             : 
     799             :   /* Some useful logging. */
     800           2 :   log_info(LD_REND, "Rendezvous circuit %u has opened with cookie %s "
     801             :                     "for service %s",
     802             :            TO_CIRCUIT(circ)->n_circ_id,
     803             :            hex_str((const char *) circ->hs_ident->rendezvous_cookie,
     804             :                    REND_COOKIE_LEN),
     805             :            safe_str_client(service->onion_address));
     806           2 :   circuit_log_path(LOG_INFO, LD_REND, circ);
     807             : 
     808             :   /* This can't fail. */
     809           4 :   payload_len = hs_cell_build_rendezvous1(
     810           2 :                         circ->hs_ident->rendezvous_cookie,
     811             :                         sizeof(circ->hs_ident->rendezvous_cookie),
     812           2 :                         circ->hs_ident->rendezvous_handshake_info,
     813             :                         sizeof(circ->hs_ident->rendezvous_handshake_info),
     814             :                         payload);
     815             : 
     816             :   /* Pad the payload with random bytes so it matches the size of a legacy cell
     817             :    * which is normally always bigger. Also, the size of a legacy cell is
     818             :    * always smaller than the RELAY_PAYLOAD_SIZE so this is safe. */
     819           2 :   if (payload_len < HS_LEGACY_RENDEZVOUS_CELL_SIZE) {
     820           2 :     crypto_rand((char *) payload + payload_len,
     821             :                 HS_LEGACY_RENDEZVOUS_CELL_SIZE - payload_len);
     822           2 :     payload_len = HS_LEGACY_RENDEZVOUS_CELL_SIZE;
     823             :   }
     824             : 
     825           2 :   if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
     826             :                                    RELAY_COMMAND_RENDEZVOUS1,
     827             :                                    (const char *) payload, payload_len,
     828             :                                    circ->cpath->prev) < 0) {
     829             :     /* On error, circuit is closed. */
     830           0 :     log_warn(LD_REND, "Unable to send RENDEZVOUS1 cell on circuit %u "
     831             :                       "for service %s",
     832             :              TO_CIRCUIT(circ)->n_circ_id,
     833             :              safe_str_client(service->onion_address));
     834           0 :     goto done;
     835             :   }
     836             : 
     837             :   /* Setup end-to-end rendezvous circuit between the client and us. */
     838           2 :   if (hs_circuit_setup_e2e_rend_circ(circ,
     839           2 :                        circ->hs_ident->rendezvous_ntor_key_seed,
     840             :                        sizeof(circ->hs_ident->rendezvous_ntor_key_seed),
     841             :                        1) < 0) {
     842           0 :     log_warn(LD_GENERAL, "Failed to setup circ");
     843           0 :     goto done;
     844             :   }
     845             : 
     846           2 :  done:
     847           2 :   memwipe(payload, 0, sizeof(payload));
     848           2 : }
     849             : 
     850             : /** Circ has been expecting an INTRO_ESTABLISHED cell that just arrived. Handle
     851             :  * the INTRO_ESTABLISHED cell payload of length payload_len arriving on the
     852             :  * given introduction circuit circ. The service is only used for logging
     853             :  * purposes. Return 0 on success else a negative value. */
     854             : int
     855           1 : hs_circ_handle_intro_established(const hs_service_t *service,
     856             :                                  const hs_service_intro_point_t *ip,
     857             :                                  origin_circuit_t *circ,
     858             :                                  const uint8_t *payload, size_t payload_len)
     859             : {
     860           1 :   int ret = -1;
     861             : 
     862           1 :   tor_assert(service);
     863           1 :   tor_assert(ip);
     864           1 :   tor_assert(circ);
     865           1 :   tor_assert(payload);
     866             : 
     867           1 :   if (BUG(TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)) {
     868           0 :     goto done;
     869             :   }
     870             : 
     871             :   /* Try to parse the payload into a cell making sure we do actually have a
     872             :    * valid cell. */
     873           1 :   if (hs_cell_parse_intro_established(payload, payload_len) < 0) {
     874           0 :     log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on "
     875             :                       "circuit %u for service %s",
     876             :              TO_CIRCUIT(circ)->n_circ_id,
     877             :              safe_str_client(service->onion_address));
     878           0 :     goto done;
     879             :   }
     880             : 
     881             :   /* Switch the purpose to a fully working intro point. */
     882           1 :   circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_S_INTRO);
     883             :   /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully used the
     884             :    * circuit so update our pathbias subsystem. */
     885           1 :   pathbias_mark_use_success(circ);
     886             :   /* Success. */
     887           1 :   ret = 0;
     888             : 
     889           1 :  done:
     890           1 :   return ret;
     891             : }
     892             : 
     893             : /**
     894             :  *  Go into <b>data</b> and add the right subcredential to be able to handle
     895             :  *  this incoming cell.
     896             :  *
     897             :  *  <b>desc_subcred</b> is the subcredential of the descriptor that corresponds
     898             :  *  to the intro point that received this intro request. This subcredential
     899             :  *  should be used if we are not an onionbalance instance.
     900             :  *
     901             :  *  Return 0 if everything went well, or -1 in case of internal error.
     902             :  */
     903             : static int
     904           8 : get_subcredential_for_handling_intro2_cell(const hs_service_t *service,
     905             :                                         hs_cell_introduce2_data_t *data,
     906             :                                         const hs_subcredential_t *desc_subcred)
     907             : {
     908             :   /* Handle the simple case first: We are not an onionbalance instance and we
     909             :    * should just use the regular descriptor subcredential */
     910           8 :   if (!hs_ob_service_is_instance(service)) {
     911           2 :     data->n_subcredentials = 1;
     912           2 :     data->subcredentials = desc_subcred;
     913           2 :     return 0;
     914             :   }
     915             : 
     916             :   /* This should not happen since we should have made onionbalance
     917             :    * subcredentials when we created our descriptors. */
     918           6 :   if (BUG(!service->state.ob_subcreds)) {
     919           0 :     return -1;
     920             :   }
     921             : 
     922             :   /* We are an onionbalance instance: */
     923           6 :   data->n_subcredentials = service->state.n_ob_subcreds;
     924           6 :   data->subcredentials = service->state.ob_subcreds;
     925             : 
     926           6 :   return 0;
     927             : }
     928             : 
     929             : /** We just received an INTRODUCE2 cell on the established introduction circuit
     930             :  * circ.  Handle the INTRODUCE2 payload of size payload_len for the given
     931             :  * circuit and service. This cell is associated with the intro point object ip
     932             :  * and the subcredential. Return 0 on success else a negative value. */
     933             : int
     934           8 : hs_circ_handle_introduce2(const hs_service_t *service,
     935             :                           const origin_circuit_t *circ,
     936             :                           hs_service_intro_point_t *ip,
     937             :                           const hs_subcredential_t *subcredential,
     938             :                           const uint8_t *payload, size_t payload_len)
     939             : {
     940           8 :   int ret = -1;
     941           8 :   time_t elapsed;
     942           8 :   hs_cell_introduce2_data_t data;
     943             : 
     944           8 :   tor_assert(service);
     945           8 :   tor_assert(circ);
     946           8 :   tor_assert(ip);
     947           8 :   tor_assert(subcredential);
     948           8 :   tor_assert(payload);
     949             : 
     950             :   /* Populate the data structure with everything we need for the cell to be
     951             :    * parsed, decrypted and key material computed correctly. */
     952           8 :   data.auth_pk = &ip->auth_key_kp.pubkey;
     953           8 :   data.enc_kp = &ip->enc_key_kp;
     954           8 :   data.payload = payload;
     955           8 :   data.payload_len = payload_len;
     956           8 :   data.link_specifiers = smartlist_new();
     957           8 :   data.replay_cache = ip->replay_cache;
     958             : 
     959           8 :   if (get_subcredential_for_handling_intro2_cell(service,
     960             :                                                  &data, subcredential)) {
     961           0 :     goto done;
     962             :   }
     963             : 
     964           8 :   if (hs_cell_parse_introduce2(&data, circ, service) < 0) {
     965           3 :     goto done;
     966             :   }
     967             : 
     968             :   /* Check whether we've seen this REND_COOKIE before to detect repeats. */
     969           5 :   if (replaycache_add_test_and_elapsed(
     970           5 :            service->state.replay_cache_rend_cookie,
     971             :            data.rendezvous_cookie, sizeof(data.rendezvous_cookie),
     972             :            &elapsed)) {
     973             :     /* A Tor client will send a new INTRODUCE1 cell with the same REND_COOKIE
     974             :      * as its previous one if its intro circ times out while in state
     975             :      * CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT. If we received the first
     976             :      * INTRODUCE1 cell (the intro-point relay converts it into an INTRODUCE2
     977             :      * cell), we are already trying to connect to that rend point (and may
     978             :      * have already succeeded); drop this cell. */
     979           1 :     log_info(LD_REND, "We received an INTRODUCE2 cell with same REND_COOKIE "
     980             :                       "field %ld seconds ago. Dropping cell.",
     981             :              (long int) elapsed);
     982           1 :     goto done;
     983             :   }
     984             : 
     985             :   /* At this point, we just confirmed that the full INTRODUCE2 cell is valid
     986             :    * so increment our counter that we've seen one on this intro point. */
     987           4 :   ip->introduce2_count++;
     988             : 
     989             :   /* Launch rendezvous circuit with the onion key and rend cookie. */
     990           4 :   launch_rendezvous_point_circuit(service, ip, &data);
     991             :   /* Success. */
     992           4 :   ret = 0;
     993             : 
     994           8 :  done:
     995           8 :   link_specifier_smartlist_free(data.link_specifiers);
     996           8 :   memwipe(&data, 0, sizeof(data));
     997           8 :   return ret;
     998             : }
     999             : 
    1000             : /** Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
    1001             :  * exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to
    1002             :  * serve as a rendezvous end-to-end circuit between the client and the
    1003             :  * service. If <b>is_service_side</b> is set, then we are the hidden service
    1004             :  * and the other side is the client.
    1005             :  *
    1006             :  * Return 0 if the operation went well; in case of error return -1. */
    1007             : int
    1008           5 : hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
    1009             :                                const uint8_t *ntor_key_seed, size_t seed_len,
    1010             :                                int is_service_side)
    1011             : {
    1012           5 :   if (BUG(!circuit_purpose_is_correct_for_rend(TO_CIRCUIT(circ)->purpose,
    1013             :                                         is_service_side))) {
    1014           0 :     return -1;
    1015             :   }
    1016             : 
    1017           5 :   crypt_path_t *hop = create_rend_cpath(ntor_key_seed, seed_len,
    1018             :                                         is_service_side);
    1019           5 :   if (!hop) {
    1020           0 :     log_warn(LD_REND, "Couldn't get v3 %s cpath!",
    1021             :              is_service_side ? "service-side" : "client-side");
    1022           0 :     return -1;
    1023             :   }
    1024             : 
    1025           5 :   finalize_rend_circuit(circ, hop, is_service_side);
    1026             : 
    1027           5 :   return 0;
    1028             : }
    1029             : 
    1030             : /** Given the introduction circuit intro_circ, the rendezvous circuit
    1031             :  * rend_circ, a descriptor intro point object ip and the service's
    1032             :  * subcredential, send an INTRODUCE1 cell on intro_circ.
    1033             :  *
    1034             :  * This will also setup the circuit identifier on rend_circ containing the key
    1035             :  * material for the handshake and e2e encryption. Return 0 on success else
    1036             :  * negative value. Because relay_send_command_from_edge() closes the circuit
    1037             :  * on error, it is possible that intro_circ is closed on error. */
    1038             : int
    1039           4 : hs_circ_send_introduce1(origin_circuit_t *intro_circ,
    1040             :                         origin_circuit_t *rend_circ,
    1041             :                         const hs_desc_intro_point_t *ip,
    1042             :                         const hs_subcredential_t *subcredential)
    1043             : {
    1044           4 :   int ret = -1;
    1045           4 :   ssize_t payload_len;
    1046           4 :   uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
    1047           4 :   hs_cell_introduce1_data_t intro1_data;
    1048             : 
    1049           4 :   tor_assert(intro_circ);
    1050           4 :   tor_assert(rend_circ);
    1051           4 :   tor_assert(ip);
    1052           4 :   tor_assert(subcredential);
    1053             : 
    1054             :   /* It is undefined behavior in hs_cell_introduce1_data_clear() if intro1_data
    1055             :    * has been declared on the stack but not initialized. Here, we set it to 0.
    1056             :    */
    1057           4 :   memset(&intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
    1058             : 
    1059             :   /* This takes various objects in order to populate the introduce1 data
    1060             :    * object which is used to build the content of the cell. */
    1061           4 :   const node_t *exit_node = build_state_get_exit_node(rend_circ->build_state);
    1062           4 :   if (exit_node == NULL) {
    1063           0 :     log_info(LD_REND, "Unable to get rendezvous point for circuit %u. "
    1064             :              "Failing.", TO_CIRCUIT(intro_circ)->n_circ_id);
    1065           0 :     goto done;
    1066             :   }
    1067             : 
    1068             :   /* We should never select an invalid rendezvous point in theory but if we
    1069             :    * do, this function will fail to populate the introduce data. */
    1070           4 :   if (setup_introduce1_data(ip, exit_node, subcredential, &intro1_data) < 0) {
    1071           0 :     log_info(LD_REND, "Unable to setup INTRODUCE1 data. The chosen rendezvous "
    1072             :                       "point is unusable. Closing circuit.");
    1073           0 :     goto close;
    1074             :   }
    1075             : 
    1076             :   /* Final step before we encode a cell, we setup the circuit identifier which
    1077             :    * will generate both the rendezvous cookie and client keypair for this
    1078             :    * connection. Those are put in the ident. */
    1079           4 :   intro1_data.rendezvous_cookie = rend_circ->hs_ident->rendezvous_cookie;
    1080           4 :   intro1_data.client_kp = &rend_circ->hs_ident->rendezvous_client_kp;
    1081             : 
    1082           4 :   memcpy(intro_circ->hs_ident->rendezvous_cookie,
    1083             :          rend_circ->hs_ident->rendezvous_cookie,
    1084             :          sizeof(intro_circ->hs_ident->rendezvous_cookie));
    1085             : 
    1086             :   /* From the introduce1 data object, this will encode the INTRODUCE1 cell
    1087             :    * into payload which is then ready to be sent as is. */
    1088           4 :   payload_len = hs_cell_build_introduce1(&intro1_data, payload);
    1089           4 :   if (BUG(payload_len < 0)) {
    1090           0 :     goto close;
    1091             :   }
    1092             : 
    1093           4 :   if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(intro_circ),
    1094             :                                    RELAY_COMMAND_INTRODUCE1,
    1095             :                                    (const char *) payload, payload_len,
    1096             :                                    intro_circ->cpath->prev) < 0) {
    1097             :     /* On error, circuit is closed. */
    1098           0 :     log_warn(LD_REND, "Unable to send INTRODUCE1 cell on circuit %u.",
    1099             :              TO_CIRCUIT(intro_circ)->n_circ_id);
    1100           0 :     goto done;
    1101             :   }
    1102             : 
    1103             :   /* Success. */
    1104           4 :   ret = 0;
    1105           4 :   goto done;
    1106             : 
    1107           0 :  close:
    1108           0 :   circuit_mark_for_close(TO_CIRCUIT(rend_circ), END_CIRC_REASON_INTERNAL);
    1109           4 :  done:
    1110           4 :   hs_cell_introduce1_data_clear(&intro1_data);
    1111           4 :   memwipe(payload, 0, sizeof(payload));
    1112           4 :   return ret;
    1113             : }
    1114             : 
    1115             : /** Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On
    1116             :  * success, 0 is returned else -1 and the circuit is marked for close. */
    1117             : int
    1118           0 : hs_circ_send_establish_rendezvous(origin_circuit_t *circ)
    1119             : {
    1120           0 :   ssize_t cell_len = 0;
    1121           0 :   uint8_t cell[RELAY_PAYLOAD_SIZE] = {0};
    1122             : 
    1123           0 :   tor_assert(circ);
    1124           0 :   tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
    1125             : 
    1126           0 :   log_info(LD_REND, "Send an ESTABLISH_RENDEZVOUS cell on circuit %u",
    1127             :            TO_CIRCUIT(circ)->n_circ_id);
    1128             : 
    1129             :   /* Set timestamp_dirty, because circuit_expire_building expects it,
    1130             :    * and the rend cookie also means we've used the circ. */
    1131           0 :   TO_CIRCUIT(circ)->timestamp_dirty = time(NULL);
    1132             : 
    1133             :   /* We've attempted to use this circuit. Probe it if we fail */
    1134           0 :   pathbias_count_use_attempt(circ);
    1135             : 
    1136             :   /* Generate the RENDEZVOUS_COOKIE and place it in the identifier so we can
    1137             :    * complete the handshake when receiving the acknowledgement. */
    1138           0 :   crypto_rand((char *) circ->hs_ident->rendezvous_cookie, HS_REND_COOKIE_LEN);
    1139             :   /* Generate the client keypair. No need to be extra strong, not long term */
    1140           0 :   curve25519_keypair_generate(&circ->hs_ident->rendezvous_client_kp, 0);
    1141             : 
    1142           0 :   cell_len =
    1143           0 :     hs_cell_build_establish_rendezvous(circ->hs_ident->rendezvous_cookie,
    1144             :                                        cell);
    1145           0 :   if (BUG(cell_len < 0)) {
    1146           0 :     goto err;
    1147             :   }
    1148             : 
    1149           0 :   if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
    1150             :                                    RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
    1151             :                                    (const char *) cell, cell_len,
    1152             :                                    circ->cpath->prev) < 0) {
    1153             :     /* Circuit has been marked for close */
    1154           0 :     log_warn(LD_REND, "Unable to send ESTABLISH_RENDEZVOUS cell on "
    1155             :                       "circuit %u", TO_CIRCUIT(circ)->n_circ_id);
    1156           0 :     memwipe(cell, 0, cell_len);
    1157           0 :     goto err;
    1158             :   }
    1159             : 
    1160           0 :   memwipe(cell, 0, cell_len);
    1161           0 :   return 0;
    1162             :  err:
    1163             :   return -1;
    1164             : }
    1165             : 
    1166             : /** Circuit cleanup strategy:
    1167             :  *
    1168             :  *  What follows is a series of functions that notifies the HS subsystem of 3
    1169             :  *  different circuit cleanup phase: close, free and repurpose.
    1170             :  *
    1171             :  *  Tor can call any of those in any orders so they have to be safe between
    1172             :  *  each other. In other words, the free should never depend on close to be
    1173             :  *  called before.
    1174             :  *
    1175             :  *  The "on_close()" is called from circuit_mark_for_close() which is
    1176             :  *  considered the tor fast path and thus as little work as possible should
    1177             :  *  done in that function. Currently, we only remove the circuit from the HS
    1178             :  *  circuit map and move on.
    1179             :  *
    1180             :  *  The "on_free()" is called from circuit circuit_free_() and it is very
    1181             :  *  important that at the end of the function, no state or objects related to
    1182             :  *  this circuit remains alive.
    1183             :  *
    1184             :  *  The "on_repurpose()" is called from circuit_change_purpose() for which we
    1185             :  *  simply remove it from the HS circuit map. We do not have other cleanup
    1186             :  *  requirements after that.
    1187             :  *
    1188             :  *  NOTE: The onion service code, specifically the service code, cleans up
    1189             :  *  lingering objects or state if any of its circuit disappear which is why
    1190             :  *  our cleanup strategy doesn't involve any service specific actions. As long
    1191             :  *  as the circuit is removed from the HS circuit map, it won't be used.
    1192             :  */
    1193             : 
    1194             : /** We are about to close this <b>circ</b>. Clean it up from any related HS
    1195             :  * data structures. This function can be called multiple times safely for the
    1196             :  * same circuit. */
    1197             : void
    1198          25 : hs_circ_cleanup_on_close(circuit_t *circ)
    1199             : {
    1200          25 :   tor_assert(circ);
    1201             : 
    1202          25 :   if (circuit_purpose_is_hs_client(circ->purpose)) {
    1203           5 :     cleanup_on_close_client_circ(circ);
    1204             :   }
    1205             : 
    1206          25 :   if (circuit_purpose_is_hs_service(circ->purpose)) {
    1207           2 :     if (circuit_is_hs_v3(circ)) {
    1208           1 :       hs_service_circuit_cleanup_on_close(circ);
    1209             :     }
    1210             :   }
    1211             : 
    1212             :   /* On close, we simply remove it from the circuit map. It can not be used
    1213             :    * anymore. We keep this code path fast and lean. */
    1214             : 
    1215          25 :   if (circ->hs_token) {
    1216           2 :     hs_circuitmap_remove_circuit(circ);
    1217             :   }
    1218          25 : }
    1219             : 
    1220             : /** We are about to free this <b>circ</b>. Clean it up from any related HS
    1221             :  * data structures. This function can be called multiple times safely for the
    1222             :  * same circuit. */
    1223             : void
    1224         151 : hs_circ_cleanup_on_free(circuit_t *circ)
    1225             : {
    1226         151 :   tor_assert(circ);
    1227             : 
    1228             :   /* NOTE: Bulk of the work of cleaning up a circuit is done here. */
    1229             : 
    1230         151 :   if (circuit_purpose_is_hs_client(circ->purpose)) {
    1231          11 :     cleanup_on_free_client_circ(circ);
    1232             :   }
    1233             : 
    1234             :   /* We have no assurance that the given HS circuit has been closed before and
    1235             :    * thus removed from the HS map. This actually happens in unit tests. */
    1236         151 :   if (circ->hs_token) {
    1237          13 :     hs_circuitmap_remove_circuit(circ);
    1238             :   }
    1239         151 : }
    1240             : 
    1241             : /** We are about to repurpose this <b>circ</b>. Clean it up from any related
    1242             :  * HS data structures. This function can be called multiple times safely for
    1243             :  * the same circuit. */
    1244             : void
    1245           0 : hs_circ_cleanup_on_repurpose(circuit_t *circ)
    1246             : {
    1247           0 :   tor_assert(circ);
    1248             : 
    1249             :   /* On repurpose, we simply remove it from the circuit map but we do not do
    1250             :    * the on_free actions since we don't treat a repurpose as something we need
    1251             :    * to report in the client cache failure. */
    1252             : 
    1253           0 :   if (circ->hs_token) {
    1254           0 :     hs_circuitmap_remove_circuit(circ);
    1255             :   }
    1256           0 : }
    1257             : 
    1258             : /** Return true iff the given established client rendezvous circuit was sent
    1259             :  * into the INTRODUCE1 cell. This is called so we can take a decision on
    1260             :  * expiring or not the circuit.
    1261             :  *
    1262             :  * The caller MUST make sure the circuit is an established client rendezvous
    1263             :  * circuit (purpose: CIRCUIT_PURPOSE_C_REND_READY).
    1264             :  *
    1265             :  * This function supports all onion service versions. */
    1266             : bool
    1267           0 : hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ)
    1268             : {
    1269           0 :   tor_assert(circ);
    1270             :   /* This can only be called for a rendezvous circuit that is an established
    1271             :    * confirmed rendezsvous circuit but without an introduction ACK. */
    1272           0 :   tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY);
    1273             : 
    1274             :   /* When the INTRODUCE1 cell is sent, the introduction encryption public
    1275             :    * key is copied in the rendezvous circuit hs identifier. If it is a valid
    1276             :    * key, we know that this circuit is waiting the ACK on the introduction
    1277             :    * circuit. We want to _not_ spare the circuit if the key was never set. */
    1278             : 
    1279           0 :   if (circ->hs_ident) {
    1280             :     /* v3. */
    1281           0 :     if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) {
    1282           0 :       return true;
    1283             :     }
    1284             :   } else {
    1285             :     /* A circuit with an HS purpose without an hs_ident in theory can not
    1286             :      * happen. In case, scream loudly and return false to the caller that the
    1287             :      * rendezvous was not sent in the INTRO1 cell. */
    1288           0 :     tor_assert_nonfatal_unreached();
    1289             :   }
    1290             : 
    1291             :   /* The rendezvous has not been specified in the INTRODUCE1 cell. */
    1292             :   return false;
    1293             : }

Generated by: LCOV version 1.14