tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

hs_intropoint.c (29429B)


      1 /* Copyright (c) 2016-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file hs_intropoint.c
      6 * \brief Implement next generation introductions point functionality
      7 **/
      8 
      9 #define HS_INTROPOINT_PRIVATE
     10 
     11 #include "core/or/or.h"
     12 #include "app/config/config.h"
     13 #include "core/or/channel.h"
     14 #include "core/or/circuitlist.h"
     15 #include "core/or/circuituse.h"
     16 #include "core/or/relay.h"
     17 #include "feature/rend/rendmid.h"
     18 #include "feature/relay/relay_metrics.h"
     19 #include "feature/stats/rephist.h"
     20 #include "lib/crypt_ops/crypto_format.h"
     21 #include "lib/time/compat_time.h"
     22 
     23 /* Trunnel */
     24 #include "trunnel/ed25519_cert.h"
     25 #include "trunnel/extension.h"
     26 #include "trunnel/hs/cell_establish_intro.h"
     27 #include "trunnel/hs/cell_introduce1.h"
     28 
     29 #include "feature/hs/hs_circuitmap.h"
     30 #include "feature/hs/hs_common.h"
     31 #include "feature/hs/hs_config.h"
     32 #include "feature/hs/hs_descriptor.h"
     33 #include "feature/hs/hs_dos.h"
     34 #include "feature/hs/hs_intropoint.h"
     35 
     36 #include "core/or/or_circuit_st.h"
     37 
     38 /** Extract the authentication key from an ESTABLISH_INTRO or INTRODUCE1 using
     39 * the given <b>cell_type</b> from <b>cell</b> and place it in
     40 * <b>auth_key_out</b>. */
     41 STATIC void
     42 get_auth_key_from_cell(ed25519_public_key_t *auth_key_out,
     43                       unsigned int cell_type, const void *cell)
     44 {
     45  size_t auth_key_len;
     46  const uint8_t *key_array;
     47 
     48  tor_assert(auth_key_out);
     49  tor_assert(cell);
     50 
     51  switch (cell_type) {
     52  case RELAY_COMMAND_ESTABLISH_INTRO:
     53  {
     54    const trn_cell_establish_intro_t *c_cell = cell;
     55    key_array = trn_cell_establish_intro_getconstarray_auth_key(c_cell);
     56    auth_key_len = trn_cell_establish_intro_getlen_auth_key(c_cell);
     57    break;
     58  }
     59  case RELAY_COMMAND_INTRODUCE1:
     60  {
     61    const trn_cell_introduce1_t *c_cell = cell;
     62    key_array = trn_cell_introduce1_getconstarray_auth_key(cell);
     63    auth_key_len = trn_cell_introduce1_getlen_auth_key(c_cell);
     64    break;
     65  }
     66  default:
     67    /* Getting here is really bad as it means we got a unknown cell type from
     68     * this file where every call has an hardcoded value. */
     69    tor_assert_unreached(); /* LCOV_EXCL_LINE */
     70  }
     71  tor_assert(key_array);
     72  tor_assert(auth_key_len == sizeof(auth_key_out->pubkey));
     73  memcpy(auth_key_out->pubkey, key_array, auth_key_len);
     74 }
     75 
     76 /** We received an ESTABLISH_INTRO <b>cell</b>. Verify its signature and MAC,
     77 *  given <b>circuit_key_material</b>. Return 0 on success else -1 on error. */
     78 STATIC int
     79 verify_establish_intro_cell(const trn_cell_establish_intro_t *cell,
     80                            const uint8_t *circuit_key_material,
     81                            size_t circuit_key_material_len)
     82 {
     83  /* We only reach this function if the first byte of the cell is 0x02 which
     84   * means that auth_key_type is of ed25519 type, hence this check should
     85   * always pass. See hs_intro_received_establish_intro().  */
     86  if (BUG(cell->auth_key_type != TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
     87    return -1;
     88  }
     89 
     90  /* Make sure the auth key length is of the right size for this type. For
     91   * EXTRA safety, we check both the size of the array and the length which
     92   * must be the same. Safety first!*/
     93  if (trn_cell_establish_intro_getlen_auth_key(cell) != ED25519_PUBKEY_LEN ||
     94      trn_cell_establish_intro_get_auth_key_len(cell) != ED25519_PUBKEY_LEN) {
     95    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
     96           "ESTABLISH_INTRO auth key length is invalid");
     97    return -1;
     98  }
     99 
    100  const uint8_t *msg = cell->start_cell;
    101 
    102  /* Verify the sig */
    103  {
    104    ed25519_signature_t sig_struct;
    105    const uint8_t *sig_array =
    106      trn_cell_establish_intro_getconstarray_sig(cell);
    107 
    108    /* Make sure the signature length is of the right size. For EXTRA safety,
    109     * we check both the size of the array and the length which must be the
    110     * same. Safety first!*/
    111    if (trn_cell_establish_intro_getlen_sig(cell) != sizeof(sig_struct.sig) ||
    112        trn_cell_establish_intro_get_sig_len(cell) != sizeof(sig_struct.sig)) {
    113      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    114             "ESTABLISH_INTRO sig len is invalid");
    115      return -1;
    116    }
    117    /* We are now sure that sig_len is of the right size. */
    118    memcpy(sig_struct.sig, sig_array, cell->sig_len);
    119 
    120    ed25519_public_key_t auth_key;
    121    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO, cell);
    122 
    123    const size_t sig_msg_len = cell->end_sig_fields - msg;
    124    int sig_mismatch = ed25519_checksig_prefixed(&sig_struct,
    125                                                 msg, sig_msg_len,
    126                                                 ESTABLISH_INTRO_SIG_PREFIX,
    127                                                 &auth_key);
    128    if (sig_mismatch) {
    129      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    130             "ESTABLISH_INTRO signature not as expected");
    131      return -1;
    132    }
    133  }
    134 
    135  /* Verify the MAC */
    136  {
    137    const size_t auth_msg_len = cell->end_mac_fields - msg;
    138    uint8_t mac[DIGEST256_LEN];
    139    crypto_mac_sha3_256(mac, sizeof(mac),
    140                        circuit_key_material, circuit_key_material_len,
    141                        msg, auth_msg_len);
    142    if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) {
    143      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    144             "ESTABLISH_INTRO handshake_auth not as expected");
    145      return -1;
    146    }
    147  }
    148 
    149  return 0;
    150 }
    151 
    152 /** Send an INTRO_ESTABLISHED cell to <b>circ</b>. */
    153 MOCK_IMPL(int,
    154 hs_intro_send_intro_established_cell,(or_circuit_t *circ))
    155 {
    156  int ret;
    157  uint8_t *encoded_cell = NULL;
    158  ssize_t encoded_len, result_len;
    159  trn_cell_intro_established_t *cell;
    160  trn_extension_t *ext;
    161 
    162  tor_assert(circ);
    163 
    164  /* Build the cell payload. */
    165  cell = trn_cell_intro_established_new();
    166  ext = trn_extension_new();
    167  trn_extension_set_num(ext, 0);
    168  trn_cell_intro_established_set_extensions(cell, ext);
    169  /* Encode the cell to binary format. */
    170  encoded_len = trn_cell_intro_established_encoded_len(cell);
    171  tor_assert(encoded_len > 0);
    172  encoded_cell = tor_malloc_zero(encoded_len);
    173  result_len = trn_cell_intro_established_encode(encoded_cell, encoded_len,
    174                                                cell);
    175  tor_assert(encoded_len == result_len);
    176 
    177  ret = relay_send_command_from_edge(0, TO_CIRCUIT(circ),
    178                                     RELAY_COMMAND_INTRO_ESTABLISHED,
    179                                     (char *) encoded_cell, encoded_len,
    180                                     NULL);
    181  /* On failure, the above function will close the circuit. */
    182  trn_cell_intro_established_free(cell);
    183  tor_free(encoded_cell);
    184  return ret;
    185 }
    186 
    187 /** Validate the cell DoS extension parameters. Return true iff they've been
    188 * bound check and can be used. Else return false. See proposal 305 for
    189 * details and reasons about this validation. */
    190 STATIC bool
    191 cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec,
    192                                        uint64_t intro2_burst_per_sec)
    193 {
    194  bool ret = false;
    195 
    196  /* Check that received value is not below the minimum. Don't check if minimum
    197     is set to 0, since the param is a positive value and gcc will complain. */
    198 #if HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0
    199  if (intro2_rate_per_sec < HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN) {
    200    log_fn(LOG_PROTOCOL_WARN, LD_REND,
    201           "Intro point DoS defenses rate per second is "
    202           "too small. Received value: %" PRIu64, intro2_rate_per_sec);
    203    goto end;
    204  }
    205 #endif /* HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN > 0 */
    206 
    207  /* Check that received value is not above maximum */
    208  if (intro2_rate_per_sec > HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX) {
    209    log_fn(LOG_PROTOCOL_WARN, LD_REND,
    210           "Intro point DoS defenses rate per second is "
    211           "too big. Received value: %" PRIu64, intro2_rate_per_sec);
    212    goto end;
    213  }
    214 
    215  /* Check that received value is not below the minimum */
    216 #if HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0
    217  if (intro2_burst_per_sec < HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN) {
    218    log_fn(LOG_PROTOCOL_WARN, LD_REND,
    219           "Intro point DoS defenses burst per second is "
    220           "too small. Received value: %" PRIu64, intro2_burst_per_sec);
    221    goto end;
    222  }
    223 #endif /* HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN > 0 */
    224 
    225  /* Check that received value is not above maximum */
    226  if (intro2_burst_per_sec > HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX) {
    227    log_fn(LOG_PROTOCOL_WARN, LD_REND,
    228           "Intro point DoS defenses burst per second is "
    229           "too big. Received value: %" PRIu64, intro2_burst_per_sec);
    230    goto end;
    231  }
    232 
    233  /* In a rate limiting scenario, burst can never be smaller than the rate. At
    234   * best it can be equal. */
    235  if (intro2_burst_per_sec < intro2_rate_per_sec) {
    236    log_info(LD_REND, "Intro point DoS defenses burst is smaller than rate. "
    237                      "Rate: %" PRIu64 " vs Burst: %" PRIu64,
    238             intro2_rate_per_sec, intro2_burst_per_sec);
    239    goto end;
    240  }
    241 
    242  /* Passing validation. */
    243  ret = true;
    244 
    245 end:
    246  return ret;
    247 }
    248 
    249 /** Parse the cell DoS extension and apply defenses on the given circuit if
    250 * validation passes. If the cell extension is malformed or contains unusable
    251 * values, the DoS defenses is disabled on the circuit. */
    252 static void
    253 handle_establish_intro_cell_dos_extension(
    254                                const trn_extension_field_t *field,
    255                                or_circuit_t *circ)
    256 {
    257  ssize_t ret;
    258  uint64_t intro2_rate_per_sec = 0, intro2_burst_per_sec = 0;
    259  trn_cell_extension_dos_t *dos = NULL;
    260 
    261  tor_assert(field);
    262  tor_assert(circ);
    263 
    264  ret = trn_cell_extension_dos_parse(&dos,
    265                 trn_extension_field_getconstarray_field(field),
    266                 trn_extension_field_getlen_field(field));
    267  if (ret < 0) {
    268    goto end;
    269  }
    270 
    271  for (size_t i = 0; i < trn_cell_extension_dos_get_n_params(dos); i++) {
    272    const trn_cell_extension_dos_param_t *param =
    273      trn_cell_extension_dos_getconst_params(dos, i);
    274    if (BUG(param == NULL)) {
    275      goto end;
    276    }
    277 
    278    switch (trn_cell_extension_dos_param_get_type(param)) {
    279    case TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC:
    280      intro2_rate_per_sec = trn_cell_extension_dos_param_get_value(param);
    281      break;
    282    case TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC:
    283      intro2_burst_per_sec = trn_cell_extension_dos_param_get_value(param);
    284      break;
    285    default:
    286      goto end;
    287    }
    288  }
    289 
    290  /* At this point, the extension is valid so any values out of it implies
    291   * that it was set explicitly and thus flag the circuit that it should not
    292   * look at the consensus for that reason for the defenses' values. */
    293  circ->introduce2_dos_defense_explicit = 1;
    294 
    295  /* A value of 0 is valid in the sense that we accept it but we still disable
    296   * the defenses so return false. */
    297  if (intro2_rate_per_sec == 0 || intro2_burst_per_sec == 0) {
    298    log_info(LD_REND, "Intro point DoS defenses parameter set to 0. "
    299                      "Disabling INTRO2 DoS defenses on circuit id %u",
    300             circ->p_circ_id);
    301    circ->introduce2_dos_defense_enabled = 0;
    302    goto end;
    303  }
    304 
    305  /* If invalid, we disable the defense on the circuit. */
    306  if (!cell_dos_extension_parameters_are_valid(intro2_rate_per_sec,
    307                                               intro2_burst_per_sec)) {
    308    circ->introduce2_dos_defense_enabled = 0;
    309    log_info(LD_REND, "Disabling INTRO2 DoS defenses on circuit id %u",
    310             circ->p_circ_id);
    311    goto end;
    312  }
    313 
    314  /* We passed validation, enable defenses and apply rate/burst. */
    315  circ->introduce2_dos_defense_enabled = 1;
    316 
    317  /* Initialize the INTRODUCE2 token bucket for the rate limiting. */
    318  token_bucket_ctr_init(&circ->introduce2_bucket,
    319                        (uint32_t) intro2_rate_per_sec,
    320                        (uint32_t) intro2_burst_per_sec,
    321                        (uint32_t) monotime_coarse_absolute_sec());
    322  log_info(LD_REND, "Intro point DoS defenses enabled. Rate is %" PRIu64
    323                    " and Burst is %" PRIu64,
    324           intro2_rate_per_sec, intro2_burst_per_sec);
    325 
    326 end:
    327  trn_cell_extension_dos_free(dos);
    328  return;
    329 }
    330 
    331 /** Parse every cell extension in the given ESTABLISH_INTRO cell. */
    332 static void
    333 handle_establish_intro_cell_extensions(
    334                            const trn_cell_establish_intro_t *parsed_cell,
    335                            or_circuit_t *circ)
    336 {
    337  const trn_extension_t *extensions;
    338 
    339  tor_assert(parsed_cell);
    340  tor_assert(circ);
    341 
    342  extensions = trn_cell_establish_intro_getconst_extensions(parsed_cell);
    343  if (extensions == NULL) {
    344    goto end;
    345  }
    346 
    347  /* Go over all extensions. */
    348  for (size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) {
    349    const trn_extension_field_t *field =
    350      trn_extension_getconst_fields(extensions, idx);
    351    if (BUG(field == NULL)) {
    352      /* The number of extensions should match the number of fields. */
    353      break;
    354    }
    355 
    356    switch (trn_extension_field_get_field_type(field)) {
    357    case TRUNNEL_CELL_EXTENSION_TYPE_DOS:
    358      /* After this, the circuit should be set for DoS defenses. */
    359      handle_establish_intro_cell_dos_extension(field, circ);
    360      break;
    361    default:
    362      /* Unknown extension. Skip over. */
    363      break;
    364    }
    365  }
    366 
    367 end:
    368  return;
    369 }
    370 
    371 /** We received an ESTABLISH_INTRO <b>parsed_cell</b> on <b>circ</b>. It's
    372 *  well-formed and passed our verifications. Perform appropriate actions to
    373 *  establish an intro point. */
    374 static int
    375 handle_verified_establish_intro_cell(or_circuit_t *circ,
    376                               const trn_cell_establish_intro_t *parsed_cell)
    377 {
    378  /* Get the auth key of this intro point */
    379  ed25519_public_key_t auth_key;
    380  get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
    381                         parsed_cell);
    382 
    383  /* Setup INTRODUCE2 defenses on the circuit. Must be done before parsing the
    384   * cell extension that can possibly change the defenses' values. */
    385  hs_dos_setup_default_intro2_defenses(circ);
    386 
    387  /* Handle cell extension if any. */
    388  handle_establish_intro_cell_extensions(parsed_cell, circ);
    389 
    390  /* Then notify the hidden service that the intro point is established by
    391     sending an INTRO_ESTABLISHED cell */
    392  if (hs_intro_send_intro_established_cell(circ)) {
    393    log_warn(LD_PROTOCOL, "Couldn't send INTRO_ESTABLISHED cell.");
    394    return -1;
    395  }
    396 
    397  /* Associate intro point auth key with this circuit. */
    398  hs_circuitmap_register_intro_circ_v3_relay_side(circ, &auth_key);
    399  /* Repurpose this circuit into an intro circuit. */
    400  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
    401 
    402  return 0;
    403 }
    404 
    405 /** We just received an ESTABLISH_INTRO cell in <b>circ</b> with payload in
    406 *  <b>request</b>. Handle it by making <b>circ</b> an intro circuit. Return 0
    407 *  if everything went well, or -1 if there were errors. */
    408 static int
    409 handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
    410                       size_t request_len)
    411 {
    412  int cell_ok, retval = -1;
    413  trn_cell_establish_intro_t *parsed_cell = NULL;
    414 
    415  tor_assert(circ);
    416  tor_assert(request);
    417 
    418  log_info(LD_REND, "Received an ESTABLISH_INTRO request on circuit %" PRIu32,
    419           circ->p_circ_id);
    420 
    421  /* Check that the circuit is in shape to become an intro point */
    422  if (!hs_intro_circuit_is_suitable_for_establish_intro(circ)) {
    423    relay_increment_est_intro_action(EST_INTRO_UNSUITABLE_CIRCUIT);
    424    goto err;
    425  }
    426 
    427  /* Parse the cell */
    428  ssize_t parsing_result = trn_cell_establish_intro_parse(&parsed_cell,
    429                                                         request, request_len);
    430  if (parsing_result < 0) {
    431    relay_increment_est_intro_action(EST_INTRO_MALFORMED);
    432    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    433           "Rejecting %s ESTABLISH_INTRO cell.",
    434           parsing_result == -1 ? "invalid" : "truncated");
    435    goto err;
    436  }
    437 
    438  cell_ok = verify_establish_intro_cell(parsed_cell,
    439                                        (uint8_t *) circ->rend_circ_nonce,
    440                                        sizeof(circ->rend_circ_nonce));
    441  if (cell_ok < 0) {
    442    relay_increment_est_intro_action(EST_INTRO_MALFORMED);
    443    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    444           "Failed to verify ESTABLISH_INTRO cell.");
    445    goto err;
    446  }
    447 
    448  /* This cell is legit. Take the appropriate actions. */
    449  cell_ok = handle_verified_establish_intro_cell(circ, parsed_cell);
    450  if (cell_ok < 0) {
    451    relay_increment_est_intro_action(EST_INTRO_CIRCUIT_DEAD);
    452    goto err;
    453  }
    454 
    455  relay_increment_est_intro_action(EST_INTRO_SUCCESS);
    456  /* We are done! */
    457  retval = 0;
    458  goto done;
    459 
    460 err:
    461  /* When sending the intro establish ack, on error the circuit can be marked
    462   * as closed so avoid a double close. */
    463  if (!TO_CIRCUIT(circ)->marked_for_close) {
    464    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
    465  }
    466 
    467 done:
    468  trn_cell_establish_intro_free(parsed_cell);
    469  return retval;
    470 }
    471 
    472 /** Return True if circuit is suitable for being an intro circuit. */
    473 static int
    474 circuit_is_suitable_intro_point(const or_circuit_t *circ,
    475                                const char *log_cell_type_str)
    476 {
    477  tor_assert(circ);
    478  tor_assert(log_cell_type_str);
    479 
    480  /* Basic circuit state sanity checks. */
    481  if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) {
    482    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    483           "Rejecting %s on non-OR circuit.", log_cell_type_str);
    484    return 0;
    485  }
    486 
    487  if (circ->base_.n_chan) {
    488    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    489           "Rejecting %s on non-edge circuit.", log_cell_type_str);
    490    return 0;
    491  }
    492 
    493  /* Suitable. */
    494  return 1;
    495 }
    496 
    497 /** Return True if circuit is suitable for being service-side intro circuit. */
    498 int
    499 hs_intro_circuit_is_suitable_for_establish_intro(const or_circuit_t *circ)
    500 {
    501  return circuit_is_suitable_intro_point(circ, "ESTABLISH_INTRO");
    502 }
    503 
    504 /** We just received an ESTABLISH_INTRO cell in <b>circ</b>. Pass it to the
    505 * appropriate handler. */
    506 int
    507 hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
    508                            size_t request_len)
    509 {
    510  tor_assert(circ);
    511  tor_assert(request);
    512 
    513  if (request_len == 0) {
    514    relay_increment_est_intro_action(EST_INTRO_MALFORMED);
    515    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Empty ESTABLISH_INTRO cell.");
    516    goto err;
    517  }
    518 
    519  /* Using the first byte of the cell, figure out the version of
    520   * ESTABLISH_INTRO and pass it to the appropriate cell handler */
    521  const uint8_t first_byte = request[0];
    522  switch (first_byte) {
    523    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
    524    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
    525      /* Likely version 2 onion service which is now obsolete. Avoid a
    526       * protocol warning considering they still exists on the network. */
    527    relay_increment_est_intro_action(EST_INTRO_MALFORMED);
    528      goto err;
    529    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519:
    530      return handle_establish_intro(circ, request, request_len);
    531    default:
    532      relay_increment_est_intro_action(EST_INTRO_MALFORMED);
    533      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    534             "Unrecognized AUTH_KEY_TYPE %u.", first_byte);
    535      goto err;
    536  }
    537 
    538 err:
    539  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
    540  return -1;
    541 }
    542 
    543 /** Send an INTRODUCE_ACK cell onto the circuit <b>circ</b> with the status
    544 * value in <b>status</b>. Depending on the status, it can be ACK or a NACK.
    545 * Return 0 on success else a negative value on error which will close the
    546 * circuit. */
    547 static int
    548 send_introduce_ack_cell(or_circuit_t *circ, uint16_t status)
    549 {
    550  int ret = -1;
    551  uint8_t *encoded_cell = NULL;
    552  ssize_t encoded_len, result_len;
    553  trn_cell_introduce_ack_t *cell;
    554  trn_extension_t *ext;
    555 
    556  tor_assert(circ);
    557 
    558  /* Setup the INTRODUCE_ACK cell. We have no extensions so the N_EXTENSIONS
    559   * field is set to 0 by default with a new object. */
    560  cell = trn_cell_introduce_ack_new();
    561  ret = trn_cell_introduce_ack_set_status(cell, status);
    562  /* We have no cell extensions in an INTRODUCE_ACK cell. */
    563  ext = trn_extension_new();
    564  trn_extension_set_num(ext, 0);
    565  trn_cell_introduce_ack_set_extensions(cell, ext);
    566  /* A wrong status is a very bad code flow error as this value is controlled
    567   * by the code in this file and not an external input. This means we use a
    568   * code that is not known by the trunnel ABI. */
    569  tor_assert(ret == 0);
    570  /* Encode the payload. We should never fail to get the encoded length. */
    571  encoded_len = trn_cell_introduce_ack_encoded_len(cell);
    572  tor_assert(encoded_len > 0);
    573  encoded_cell = tor_malloc_zero(encoded_len);
    574  result_len = trn_cell_introduce_ack_encode(encoded_cell, encoded_len, cell);
    575  tor_assert(encoded_len == result_len);
    576 
    577  ret = relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
    578                                     RELAY_COMMAND_INTRODUCE_ACK,
    579                                     (char *) encoded_cell, encoded_len,
    580                                     NULL);
    581  /* On failure, the above function will close the circuit. */
    582  trn_cell_introduce_ack_free(cell);
    583  tor_free(encoded_cell);
    584  return ret;
    585 }
    586 
    587 /** Validate a parsed INTRODUCE1 <b>cell</b>. Return 0 if valid or else a
    588 * negative value for an invalid cell that should be NACKed. */
    589 STATIC int
    590 validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell)
    591 {
    592  size_t legacy_key_id_len;
    593  const uint8_t *legacy_key_id;
    594 
    595  tor_assert(cell);
    596 
    597  /* This code path SHOULD NEVER be reached if the cell is a legacy type so
    598   * safety net here. The legacy ID must be zeroes in this case. */
    599  legacy_key_id_len = trn_cell_introduce1_getlen_legacy_key_id(cell);
    600  legacy_key_id = trn_cell_introduce1_getconstarray_legacy_key_id(cell);
    601  if (BUG(!fast_mem_is_zero((char *) legacy_key_id, legacy_key_id_len))) {
    602    goto invalid;
    603  }
    604 
    605  /* The auth key of an INTRODUCE1 should be of type ed25519 thus leading to a
    606   * known fixed length as well. */
    607  if (trn_cell_introduce1_get_auth_key_type(cell) !=
    608      TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519) {
    609    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    610           "Rejecting invalid INTRODUCE1 cell auth key type. "
    611           "Responding with NACK.");
    612    goto invalid;
    613  }
    614  if (trn_cell_introduce1_get_auth_key_len(cell) != ED25519_PUBKEY_LEN ||
    615      trn_cell_introduce1_getlen_auth_key(cell) != ED25519_PUBKEY_LEN) {
    616    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    617           "Rejecting invalid INTRODUCE1 cell auth key length. "
    618           "Responding with NACK.");
    619    goto invalid;
    620  }
    621  if (trn_cell_introduce1_getlen_encrypted(cell) == 0) {
    622    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    623           "Rejecting invalid INTRODUCE1 cell encrypted length. "
    624           "Responding with NACK.");
    625    goto invalid;
    626  }
    627 
    628  return 0;
    629 invalid:
    630  return -1;
    631 }
    632 
    633 /** We just received a non legacy INTRODUCE1 cell on <b>client_circ</b> with
    634 * the payload in <b>request</b> of size <b>request_len</b>. Return 0 if
    635 * everything went well, or -1 if an error occurred. This function is in charge
    636 * of sending back an INTRODUCE_ACK cell and will close client_circ on error.
    637 */
    638 STATIC int
    639 handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
    640                  size_t request_len)
    641 {
    642  int ret = -1;
    643  or_circuit_t *service_circ;
    644  trn_cell_introduce1_t *parsed_cell;
    645  uint16_t status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
    646 
    647  tor_assert(client_circ);
    648  tor_assert(request);
    649 
    650  /* Parse cell. Note that we can only parse the non encrypted section for
    651   * which we'll use the authentication key to find the service introduction
    652   * circuit and relay the cell on it. */
    653  ssize_t cell_size = trn_cell_introduce1_parse(&parsed_cell, request,
    654                                               request_len);
    655  if (cell_size < 0) {
    656    relay_increment_intro1_action(INTRO1_MALFORMED);
    657    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    658           "Rejecting %s INTRODUCE1 cell. Responding with NACK.",
    659           cell_size == -1 ? "invalid" : "truncated");
    660    /* Inform client that the INTRODUCE1 has a bad format. */
    661    status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
    662    goto send_ack;
    663  }
    664 
    665  /* Once parsed validate the cell format. */
    666  if (validate_introduce1_parsed_cell(parsed_cell) < 0) {
    667    relay_increment_intro1_action(INTRO1_MALFORMED);
    668    /* Inform client that the INTRODUCE1 has bad format. */
    669    status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
    670    goto send_ack;
    671  }
    672 
    673  /* Find introduction circuit through our circuit map. */
    674  {
    675    ed25519_public_key_t auth_key;
    676    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_INTRODUCE1, parsed_cell);
    677    service_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
    678    if (service_circ == NULL) {
    679      relay_increment_intro1_action(INTRO1_UNKNOWN_SERVICE);
    680      char b64_key[ED25519_BASE64_LEN + 1];
    681      ed25519_public_to_base64(b64_key, &auth_key);
    682      log_info(LD_REND, "No intro circuit found for INTRODUCE1 cell "
    683                        "with auth key %s from circuit %" PRIu32 ". "
    684                        "Responding with NACK.",
    685               safe_str(b64_key), client_circ->p_circ_id);
    686      /* Inform the client that we don't know the requested service ID. */
    687      status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
    688      goto send_ack;
    689    }
    690  }
    691 
    692  /* Before sending, lets make sure this cell can be sent on the service
    693   * circuit asking the DoS defenses. */
    694  if (!hs_dos_can_send_intro2(service_circ)) {
    695    relay_increment_intro1_action(INTRO1_RATE_LIMITED);
    696    char *msg;
    697    static ratelim_t rlimit = RATELIM_INIT(5 * 60);
    698    if ((msg = rate_limit_log(&rlimit, approx_time()))) {
    699      log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v3 cell due to DoS "
    700                            "limitations. Sending NACK to client.");
    701      tor_free(msg);
    702    }
    703    status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
    704    goto send_ack;
    705  }
    706 
    707  /* Relay the cell to the service on its intro circuit with an INTRODUCE2
    708   * cell which is the same exact payload. */
    709  if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(service_circ),
    710                                   RELAY_COMMAND_INTRODUCE2,
    711                                   (char *) request, request_len, NULL)) {
    712    relay_increment_intro1_action(INTRO1_CIRCUIT_DEAD);
    713    /* Inform the client that we can't relay the cell. Use the unknown ID
    714     * status code since it means that we do not know the service. */
    715    status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
    716    goto send_ack;
    717  }
    718 
    719  relay_increment_intro1_action(INTRO1_SUCCESS);
    720  /* Success! Send an INTRODUCE_ACK success status onto the client circuit. */
    721  status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
    722  ret = 0;
    723 
    724 send_ack:
    725  /* Send INTRODUCE_ACK or INTRODUCE_NACK to client */
    726  if (send_introduce_ack_cell(client_circ, status) < 0) {
    727    log_warn(LD_PROTOCOL, "Unable to send an INTRODUCE ACK status %d "
    728                          "to client.", status);
    729    /* Circuit has been closed on failure of transmission. */
    730    goto done;
    731  }
    732 done:
    733  trn_cell_introduce1_free(parsed_cell);
    734  return ret;
    735 }
    736 
    737 /** Return true iff the circuit <b>circ</b> is suitable for receiving an
    738 * INTRODUCE1 cell. */
    739 STATIC int
    740 circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
    741 {
    742  tor_assert(circ);
    743 
    744  /* Is this circuit an intro point circuit? */
    745  if (!circuit_is_suitable_intro_point(circ, "INTRODUCE1")) {
    746    return 0;
    747  }
    748 
    749  if (circ->already_received_introduce1) {
    750    relay_increment_intro1_action(INTRO1_CIRCUIT_REUSED);
    751    log_fn(LOG_PROTOCOL_WARN, LD_REND,
    752           "Blocking multiple introductions on the same circuit. "
    753           "Someone might be trying to attack a hidden service through "
    754           "this relay.");
    755    return 0;
    756  }
    757 
    758  /* Disallow single hop client circuit. */
    759  if (circ->p_chan && channel_is_client(circ->p_chan)) {
    760    relay_increment_intro1_action(INTRO1_SINGLE_HOP);
    761    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    762           "Single hop client was rejected while trying to introduce. "
    763           "Closing circuit.");
    764    return 0;
    765  }
    766 
    767  return 1;
    768 }
    769 
    770 /** We just received an INTRODUCE1 cell on <b>circ</b>. Figure out which type
    771 * it is and pass it to the appropriate handler. Return 0 on success else a
    772 * negative value and the circuit is closed. */
    773 int
    774 hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request,
    775                             size_t request_len)
    776 {
    777  tor_assert(circ);
    778  tor_assert(request);
    779 
    780  /* A cell that can't hold a DIGEST_LEN is invalid. */
    781  if (request_len < DIGEST_LEN) {
    782    relay_increment_intro1_action(INTRO1_MALFORMED);
    783    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid INTRODUCE1 cell length.");
    784    goto err;
    785  }
    786 
    787  /* Make sure we have a circuit that can have an INTRODUCE1 cell on it. */
    788  if (!circuit_is_suitable_for_introduce1(circ)) {
    789    /* We do not send a NACK because the circuit is not suitable for any kind
    790     * of response or transmission as it's a violation of the protocol. */
    791    goto err;
    792  }
    793  /* Mark the circuit that we got this cell. None are allowed after this as a
    794   * DoS mitigation since one circuit with one client can hammer a service. */
    795  circ->already_received_introduce1 = 1;
    796 
    797  /* Handle the cell. */
    798  return handle_introduce1(circ, request, request_len);
    799 
    800 err:
    801  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
    802  return -1;
    803 }
    804 
    805 /** Clear memory allocated by the given intropoint object ip (but don't free
    806 * the object itself). */
    807 void
    808 hs_intropoint_clear(hs_intropoint_t *ip)
    809 {
    810  if (ip == NULL) {
    811    return;
    812  }
    813  tor_cert_free(ip->auth_key_cert);
    814  SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, ls,
    815                    link_specifier_free(ls));
    816  smartlist_free(ip->link_specifiers);
    817  memset(ip, 0, sizeof(hs_intropoint_t));
    818 }