LCOV - code coverage report
Current view: top level - feature/hs - hs_cell.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 398 449 88.6 %
Date: 2021-11-24 03:28:48 Functions: 22 24 91.7 %

          Line data    Source code
       1             : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : /**
       5             :  * \file hs_cell.c
       6             :  * \brief Hidden service API for cell creation and handling.
       7             :  **/
       8             : 
       9             : #include "core/or/or.h"
      10             : #include "app/config/config.h"
      11             : #include "lib/crypt_ops/crypto_util.h"
      12             : #include "feature/hs_common/replaycache.h"
      13             : 
      14             : #include "feature/hs/hs_cell.h"
      15             : #include "feature/hs/hs_ob.h"
      16             : #include "core/crypto/hs_ntor.h"
      17             : 
      18             : #include "core/or/origin_circuit_st.h"
      19             : 
      20             : /* Trunnel. */
      21             : #include "trunnel/ed25519_cert.h"
      22             : #include "trunnel/hs/cell_common.h"
      23             : #include "trunnel/hs/cell_establish_intro.h"
      24             : #include "trunnel/hs/cell_introduce1.h"
      25             : #include "trunnel/hs/cell_rendezvous.h"
      26             : 
      27             : /** Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is
      28             :  * the cell content up to the ENCRYPTED section of length encoded_cell_len.
      29             :  * The encrypted param is the start of the ENCRYPTED section of length
      30             :  * encrypted_len. The mac_key is the key needed for the computation of the MAC
      31             :  * derived from the ntor handshake of length mac_key_len.
      32             :  *
      33             :  * The length mac_out_len must be at least DIGEST256_LEN. */
      34             : static void
      35          30 : compute_introduce_mac(const uint8_t *encoded_cell, size_t encoded_cell_len,
      36             :                       const uint8_t *encrypted, size_t encrypted_len,
      37             :                       const uint8_t *mac_key, size_t mac_key_len,
      38             :                       uint8_t *mac_out, size_t mac_out_len)
      39             : {
      40          30 :   size_t offset = 0;
      41          30 :   size_t mac_msg_len;
      42          30 :   uint8_t mac_msg[RELAY_PAYLOAD_SIZE] = {0};
      43             : 
      44          30 :   tor_assert(encoded_cell);
      45          30 :   tor_assert(encrypted);
      46          30 :   tor_assert(mac_key);
      47          30 :   tor_assert(mac_out);
      48          30 :   tor_assert(mac_out_len >= DIGEST256_LEN);
      49             : 
      50             :   /* Compute the size of the message which is basically the entire cell until
      51             :    * the MAC field of course. */
      52          30 :   mac_msg_len = encoded_cell_len + (encrypted_len - DIGEST256_LEN);
      53          30 :   tor_assert(mac_msg_len <= sizeof(mac_msg));
      54             : 
      55             :   /* First, put the encoded cell in the msg. */
      56          30 :   memcpy(mac_msg, encoded_cell, encoded_cell_len);
      57          30 :   offset += encoded_cell_len;
      58             :   /* Second, put the CLIENT_PK + ENCRYPTED_DATA but omit the MAC field (which
      59             :    * is junk at this point). */
      60          30 :   memcpy(mac_msg + offset, encrypted, (encrypted_len - DIGEST256_LEN));
      61          30 :   offset += (encrypted_len - DIGEST256_LEN);
      62          30 :   tor_assert(offset == mac_msg_len);
      63             : 
      64          30 :   crypto_mac_sha3_256(mac_out, mac_out_len,
      65             :                       mac_key, mac_key_len,
      66             :                       mac_msg, mac_msg_len);
      67          30 :   memwipe(mac_msg, 0, sizeof(mac_msg));
      68          30 : }
      69             : 
      70             : /**
      71             :  * From a set of keys, a list of subcredentials, and the ENCRYPTED section of
      72             :  * an INTRODUCE2 cell, return an array of newly allocated intro cell keys
      73             :  * structures.  Finally, the client public key is copied in client_pk. On
      74             :  * error, return NULL.
      75             :  **/
      76             : static hs_ntor_intro_cell_keys_t *
      77           7 : get_introduce2_key_material(const ed25519_public_key_t *auth_key,
      78             :                             const curve25519_keypair_t *enc_key,
      79             :                             size_t n_subcredentials,
      80             :                             const hs_subcredential_t *subcredentials,
      81             :                             const uint8_t *encrypted_section,
      82             :                             curve25519_public_key_t *client_pk)
      83             : {
      84           7 :   hs_ntor_intro_cell_keys_t *keys;
      85             : 
      86           7 :   tor_assert(auth_key);
      87           7 :   tor_assert(enc_key);
      88           7 :   tor_assert(n_subcredentials > 0);
      89           7 :   tor_assert(subcredentials);
      90           7 :   tor_assert(encrypted_section);
      91           7 :   tor_assert(client_pk);
      92             : 
      93           7 :   keys = tor_calloc(n_subcredentials, sizeof(hs_ntor_intro_cell_keys_t));
      94             : 
      95             :   /* First bytes of the ENCRYPTED section are the client public key. */
      96           7 :   memcpy(client_pk->public_key, encrypted_section, CURVE25519_PUBKEY_LEN);
      97             : 
      98           7 :   if (hs_ntor_service_get_introduce1_keys_multi(auth_key, enc_key, client_pk,
      99             :                                                 n_subcredentials,
     100             :                                                 subcredentials, keys) < 0) {
     101             :     /* Don't rely on the caller to wipe this on error. */
     102           1 :     memwipe(client_pk, 0, sizeof(curve25519_public_key_t));
     103           1 :     tor_free(keys);
     104           1 :     keys = NULL;
     105             :   }
     106           7 :   return keys;
     107             : }
     108             : 
     109             : /** Using the given encryption key, decrypt the encrypted_section of length
     110             :  * encrypted_section_len of an INTRODUCE2 cell and return a newly allocated
     111             :  * buffer containing the decrypted data. On decryption failure, NULL is
     112             :  * returned. */
     113             : static uint8_t *
     114           5 : decrypt_introduce2(const uint8_t *enc_key, const uint8_t *encrypted_section,
     115             :                    size_t encrypted_section_len)
     116             : {
     117           5 :   uint8_t *decrypted = NULL;
     118           5 :   crypto_cipher_t *cipher = NULL;
     119             : 
     120           5 :   tor_assert(enc_key);
     121           5 :   tor_assert(encrypted_section);
     122             : 
     123             :   /* Decrypt ENCRYPTED section. */
     124           5 :   cipher = crypto_cipher_new_with_bits((char *) enc_key,
     125             :                                        CURVE25519_PUBKEY_LEN * 8);
     126           5 :   tor_assert(cipher);
     127             : 
     128             :   /* This is symmetric encryption so can't be bigger than the encrypted
     129             :    * section length. */
     130           5 :   decrypted = tor_malloc_zero(encrypted_section_len);
     131           5 :   if (crypto_cipher_decrypt(cipher, (char *) decrypted,
     132             :                             (const char *) encrypted_section,
     133             :                             encrypted_section_len) < 0) {
     134           0 :     tor_free(decrypted);
     135           0 :     decrypted = NULL;
     136           0 :     goto done;
     137             :   }
     138             : 
     139           5 :  done:
     140           5 :   crypto_cipher_free(cipher);
     141           5 :   return decrypted;
     142             : }
     143             : 
     144             : /** Given a pointer to the decrypted data of the ENCRYPTED section of an
     145             :  * INTRODUCE2 cell of length decrypted_len, parse and validate the cell
     146             :  * content. Return a newly allocated cell structure or NULL on error. The
     147             :  * circuit and service object are only used for logging purposes. */
     148             : static trn_cell_introduce_encrypted_t *
     149           5 : parse_introduce2_encrypted(const uint8_t *decrypted_data,
     150             :                            size_t decrypted_len, const origin_circuit_t *circ,
     151             :                            const hs_service_t *service)
     152             : {
     153           5 :   trn_cell_introduce_encrypted_t *enc_cell = NULL;
     154             : 
     155           5 :   tor_assert(decrypted_data);
     156           5 :   tor_assert(circ);
     157           5 :   tor_assert(service);
     158             : 
     159           5 :   if (trn_cell_introduce_encrypted_parse(&enc_cell, decrypted_data,
     160             :                                          decrypted_len) < 0) {
     161           0 :     log_info(LD_REND, "Unable to parse the decrypted ENCRYPTED section of "
     162             :                       "the INTRODUCE2 cell on circuit %u for service %s",
     163             :              TO_CIRCUIT(circ)->n_circ_id,
     164             :              safe_str_client(service->onion_address));
     165           0 :     goto err;
     166             :   }
     167             : 
     168           5 :   if (trn_cell_introduce_encrypted_get_onion_key_type(enc_cell) !=
     169             :       TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR) {
     170           0 :     log_info(LD_REND, "INTRODUCE2 onion key type is invalid. Got %u but "
     171             :                       "expected %u on circuit %u for service %s",
     172             :              trn_cell_introduce_encrypted_get_onion_key_type(enc_cell),
     173             :              TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR,
     174             :              TO_CIRCUIT(circ)->n_circ_id,
     175             :              safe_str_client(service->onion_address));
     176           0 :     goto err;
     177             :   }
     178             : 
     179           5 :   if (trn_cell_introduce_encrypted_getlen_onion_key(enc_cell) !=
     180             :       CURVE25519_PUBKEY_LEN) {
     181           0 :     log_info(LD_REND, "INTRODUCE2 onion key length is invalid. Got %u but "
     182             :                       "expected %d on circuit %u for service %s",
     183             :              (unsigned)trn_cell_introduce_encrypted_getlen_onion_key(enc_cell),
     184             :              CURVE25519_PUBKEY_LEN, TO_CIRCUIT(circ)->n_circ_id,
     185             :              safe_str_client(service->onion_address));
     186           0 :     goto err;
     187             :   }
     188             :   /* XXX: Validate NSPEC field as well. */
     189             : 
     190           5 :   return enc_cell;
     191           0 :  err:
     192           0 :   trn_cell_introduce_encrypted_free(enc_cell);
     193           0 :   return NULL;
     194             : }
     195             : 
     196             : /** Parse an INTRODUCE2 cell from payload of size payload_len for the given
     197             :  * service and circuit which are used only for logging purposes. The resulting
     198             :  * parsed cell is put in cell_ptr_out.
     199             :  *
     200             :  * Return 0 on success else a negative value and cell_ptr_out is untouched. */
     201             : static int
     202           8 : parse_introduce2_cell(const hs_service_t *service,
     203             :                       const origin_circuit_t *circ, const uint8_t *payload,
     204             :                       size_t payload_len,
     205             :                       trn_cell_introduce1_t **cell_ptr_out)
     206             : {
     207           8 :   trn_cell_introduce1_t *cell = NULL;
     208             : 
     209           8 :   tor_assert(service);
     210           8 :   tor_assert(circ);
     211           8 :   tor_assert(payload);
     212           8 :   tor_assert(cell_ptr_out);
     213             : 
     214             :   /* Parse the cell so we can start cell validation. */
     215           8 :   if (trn_cell_introduce1_parse(&cell, payload, payload_len) < 0) {
     216           0 :     log_info(LD_PROTOCOL, "Unable to parse INTRODUCE2 cell on circuit %u "
     217             :                           "for service %s",
     218             :              TO_CIRCUIT(circ)->n_circ_id,
     219             :              safe_str_client(service->onion_address));
     220           0 :     goto err;
     221             :   }
     222             : 
     223             :   /* Success. */
     224           8 :   *cell_ptr_out = cell;
     225           8 :   return 0;
     226           0 :  err:
     227           0 :   return -1;
     228             : }
     229             : 
     230             : /** Set the onion public key onion_pk in cell, the encrypted section of an
     231             :  * INTRODUCE1 cell. */
     232             : static void
     233           4 : introduce1_set_encrypted_onion_key(trn_cell_introduce_encrypted_t *cell,
     234             :                                    const uint8_t *onion_pk)
     235             : {
     236           4 :   tor_assert(cell);
     237           4 :   tor_assert(onion_pk);
     238             :   /* There is only one possible key type for a non legacy cell. */
     239           4 :   trn_cell_introduce_encrypted_set_onion_key_type(cell,
     240             :                                    TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR);
     241           4 :   trn_cell_introduce_encrypted_set_onion_key_len(cell, CURVE25519_PUBKEY_LEN);
     242           4 :   trn_cell_introduce_encrypted_setlen_onion_key(cell, CURVE25519_PUBKEY_LEN);
     243           4 :   memcpy(trn_cell_introduce_encrypted_getarray_onion_key(cell), onion_pk,
     244             :          trn_cell_introduce_encrypted_getlen_onion_key(cell));
     245           4 : }
     246             : 
     247             : /** Set the link specifiers in lspecs in cell, the encrypted section of an
     248             :  * INTRODUCE1 cell. */
     249             : static void
     250           4 : introduce1_set_encrypted_link_spec(trn_cell_introduce_encrypted_t *cell,
     251             :                                    const smartlist_t *lspecs)
     252             : {
     253           4 :   tor_assert(cell);
     254           4 :   tor_assert(lspecs);
     255           4 :   tor_assert(smartlist_len(lspecs) > 0);
     256           4 :   tor_assert(smartlist_len(lspecs) <= UINT8_MAX);
     257             : 
     258           4 :   uint8_t lspecs_num = (uint8_t) smartlist_len(lspecs);
     259           4 :   trn_cell_introduce_encrypted_set_nspec(cell, lspecs_num);
     260             :   /* We aren't duplicating the link specifiers object here which means that
     261             :    * the ownership goes to the trn_cell_introduce_encrypted_t cell and those
     262             :    * object will be freed when the cell is. */
     263           8 :   SMARTLIST_FOREACH(lspecs, link_specifier_t *, ls,
     264             :                     trn_cell_introduce_encrypted_add_nspecs(cell, ls));
     265           4 : }
     266             : 
     267             : /** Set padding in the enc_cell only if needed that is the total length of both
     268             :  * sections are below the minimum required for an INTRODUCE1 cell. */
     269             : static void
     270           4 : introduce1_set_encrypted_padding(const trn_cell_introduce1_t *cell,
     271             :                                  trn_cell_introduce_encrypted_t *enc_cell)
     272             : {
     273           4 :   tor_assert(cell);
     274           4 :   tor_assert(enc_cell);
     275             :   /* This is the length we expect to have once encoded of the whole cell. */
     276           4 :   ssize_t full_len = trn_cell_introduce1_encoded_len(cell) +
     277           4 :                      trn_cell_introduce_encrypted_encoded_len(enc_cell);
     278           4 :   tor_assert(full_len > 0);
     279           4 :   if (full_len < HS_CELL_INTRODUCE1_MIN_SIZE) {
     280           4 :     size_t padding = HS_CELL_INTRODUCE1_MIN_SIZE - full_len;
     281           4 :     trn_cell_introduce_encrypted_setlen_pad(enc_cell, padding);
     282           4 :     memset(trn_cell_introduce_encrypted_getarray_pad(enc_cell), 0,
     283             :            trn_cell_introduce_encrypted_getlen_pad(enc_cell));
     284             :   }
     285           4 : }
     286             : 
     287             : /** Encrypt the ENCRYPTED payload and encode it in the cell using the enc_cell
     288             :  * and the INTRODUCE1 data.
     289             :  *
     290             :  * This can't fail but it is very important that the caller sets every field
     291             :  * in data so the computation of the INTRODUCE1 keys doesn't fail. */
     292             : static void
     293           4 : introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell,
     294             :                               const trn_cell_introduce_encrypted_t *enc_cell,
     295             :                               const hs_cell_introduce1_data_t *data)
     296             : {
     297           4 :   size_t offset = 0;
     298           4 :   ssize_t encrypted_len;
     299           4 :   ssize_t encoded_cell_len, encoded_enc_cell_len;
     300           4 :   uint8_t encoded_cell[RELAY_PAYLOAD_SIZE] = {0};
     301           4 :   uint8_t encoded_enc_cell[RELAY_PAYLOAD_SIZE] = {0};
     302           4 :   uint8_t *encrypted = NULL;
     303           4 :   uint8_t mac[DIGEST256_LEN];
     304           4 :   crypto_cipher_t *cipher = NULL;
     305           4 :   hs_ntor_intro_cell_keys_t keys;
     306             : 
     307           4 :   tor_assert(cell);
     308           4 :   tor_assert(enc_cell);
     309           4 :   tor_assert(data);
     310             : 
     311             :   /* Encode the cells up to now of what we have to we can perform the MAC
     312             :    * computation on it. */
     313           4 :   encoded_cell_len = trn_cell_introduce1_encode(encoded_cell,
     314             :                                                 sizeof(encoded_cell), cell);
     315             :   /* We have a much more serious issue if this isn't true. */
     316           4 :   tor_assert(encoded_cell_len > 0);
     317             : 
     318           4 :   encoded_enc_cell_len =
     319           4 :     trn_cell_introduce_encrypted_encode(encoded_enc_cell,
     320             :                                         sizeof(encoded_enc_cell), enc_cell);
     321             :   /* We have a much more serious issue if this isn't true. */
     322           4 :   tor_assert(encoded_enc_cell_len > 0);
     323             : 
     324             :   /* Get the key material for the encryption. */
     325           4 :   if (hs_ntor_client_get_introduce1_keys(data->auth_pk, data->enc_pk,
     326           4 :                                          data->client_kp,
     327           4 :                                          data->subcredential, &keys) < 0) {
     328           0 :     tor_assert_unreached();
     329             :   }
     330             : 
     331             :   /* Prepare cipher with the encryption key just computed. */
     332           4 :   cipher = crypto_cipher_new_with_bits((const char *) keys.enc_key,
     333             :                                        sizeof(keys.enc_key) * 8);
     334           4 :   tor_assert(cipher);
     335             : 
     336             :   /* Compute the length of the ENCRYPTED section which is the CLIENT_PK,
     337             :    * ENCRYPTED_DATA and MAC length. */
     338           4 :   encrypted_len = sizeof(data->client_kp->pubkey) + encoded_enc_cell_len +
     339             :                   sizeof(mac);
     340           4 :   tor_assert(encrypted_len < RELAY_PAYLOAD_SIZE);
     341           4 :   encrypted = tor_malloc_zero(encrypted_len);
     342             : 
     343             :   /* Put the CLIENT_PK first. */
     344           4 :   memcpy(encrypted, data->client_kp->pubkey.public_key,
     345             :          sizeof(data->client_kp->pubkey.public_key));
     346           4 :   offset += sizeof(data->client_kp->pubkey.public_key);
     347             :   /* Then encrypt and set the ENCRYPTED_DATA. This can't fail. */
     348           4 :   crypto_cipher_encrypt(cipher, (char *) encrypted + offset,
     349             :                         (const char *) encoded_enc_cell, encoded_enc_cell_len);
     350           4 :   crypto_cipher_free(cipher);
     351           4 :   offset += encoded_enc_cell_len;
     352             :   /* Compute MAC from the above and put it in the buffer. This function will
     353             :    * make the adjustment to the encrypted_len to omit the MAC length. */
     354           4 :   compute_introduce_mac(encoded_cell, encoded_cell_len,
     355             :                         encrypted, encrypted_len,
     356             :                         keys.mac_key, sizeof(keys.mac_key),
     357             :                         mac, sizeof(mac));
     358           4 :   memcpy(encrypted + offset, mac, sizeof(mac));
     359           4 :   offset += sizeof(mac);
     360           4 :   tor_assert(offset == (size_t) encrypted_len);
     361             : 
     362             :   /* Set the ENCRYPTED section in the cell. */
     363           4 :   trn_cell_introduce1_setlen_encrypted(cell, encrypted_len);
     364           4 :   memcpy(trn_cell_introduce1_getarray_encrypted(cell),
     365             :          encrypted, encrypted_len);
     366             : 
     367             :   /* Cleanup. */
     368           4 :   memwipe(&keys, 0, sizeof(keys));
     369           4 :   memwipe(mac, 0, sizeof(mac));
     370           4 :   memwipe(encrypted, 0, sizeof(encrypted_len));
     371           4 :   memwipe(encoded_enc_cell, 0, sizeof(encoded_enc_cell));
     372           4 :   tor_free(encrypted);
     373           4 : }
     374             : 
     375             : /** Using the INTRODUCE1 data, setup the ENCRYPTED section in cell. This means
     376             :  * set it, encrypt it and encode it. */
     377             : static void
     378           4 : introduce1_set_encrypted(trn_cell_introduce1_t *cell,
     379             :                          const hs_cell_introduce1_data_t *data)
     380             : {
     381           4 :   trn_cell_introduce_encrypted_t *enc_cell;
     382           4 :   trn_cell_extension_t *ext;
     383             : 
     384           4 :   tor_assert(cell);
     385           4 :   tor_assert(data);
     386             : 
     387           4 :   enc_cell = trn_cell_introduce_encrypted_new();
     388           4 :   tor_assert(enc_cell);
     389             : 
     390             :   /* Set extension data. None are used. */
     391           4 :   ext = trn_cell_extension_new();
     392           4 :   tor_assert(ext);
     393           4 :   trn_cell_extension_set_num(ext, 0);
     394           4 :   trn_cell_introduce_encrypted_set_extensions(enc_cell, ext);
     395             : 
     396             :   /* Set the rendezvous cookie. */
     397           4 :   memcpy(trn_cell_introduce_encrypted_getarray_rend_cookie(enc_cell),
     398           4 :          data->rendezvous_cookie, REND_COOKIE_LEN);
     399             : 
     400             :   /* Set the onion public key. */
     401           4 :   introduce1_set_encrypted_onion_key(enc_cell, data->onion_pk->public_key);
     402             : 
     403             :   /* Set the link specifiers. */
     404           4 :   introduce1_set_encrypted_link_spec(enc_cell, data->link_specifiers);
     405             : 
     406             :   /* Set padding. */
     407           4 :   introduce1_set_encrypted_padding(cell, enc_cell);
     408             : 
     409             :   /* Encrypt and encode it in the cell. */
     410           4 :   introduce1_encrypt_and_encode(cell, enc_cell, data);
     411             : 
     412             :   /* Cleanup. */
     413           4 :   trn_cell_introduce_encrypted_free(enc_cell);
     414           4 : }
     415             : 
     416             : /** Set the authentication key in the INTRODUCE1 cell from the given data. */
     417             : static void
     418           4 : introduce1_set_auth_key(trn_cell_introduce1_t *cell,
     419             :                         const hs_cell_introduce1_data_t *data)
     420             : {
     421           4 :   tor_assert(cell);
     422           4 :   tor_assert(data);
     423             :   /* There is only one possible type for a non legacy cell. */
     424           4 :   trn_cell_introduce1_set_auth_key_type(cell,
     425             :                                    TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
     426           4 :   trn_cell_introduce1_set_auth_key_len(cell, ED25519_PUBKEY_LEN);
     427           4 :   trn_cell_introduce1_setlen_auth_key(cell, ED25519_PUBKEY_LEN);
     428           4 :   memcpy(trn_cell_introduce1_getarray_auth_key(cell),
     429           4 :          data->auth_pk->pubkey, trn_cell_introduce1_getlen_auth_key(cell));
     430           4 : }
     431             : 
     432             : /** Build and add to the given DoS cell extension the given parameter type and
     433             :  * value. */
     434             : static void
     435          14 : build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext,
     436             :                                 uint8_t param_type, uint64_t param_value)
     437             : {
     438          14 :   trn_cell_extension_dos_param_t *dos_param =
     439          14 :     trn_cell_extension_dos_param_new();
     440             : 
     441             :   /* Extra safety. We should never send an unknown parameter type. */
     442          14 :   tor_assert(param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC ||
     443             :              param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
     444             : 
     445          14 :   trn_cell_extension_dos_param_set_type(dos_param, param_type);
     446          14 :   trn_cell_extension_dos_param_set_value(dos_param, param_value);
     447          14 :   trn_cell_extension_dos_add_params(dos_ext, dos_param);
     448             : 
     449             :   /* Not freeing the trunnel object because it is now owned by dos_ext. */
     450          14 : }
     451             : 
     452             : /** Build the DoS defense cell extension and put it in the given extensions
     453             :  * object. Return 0 on success, -1 on failure.  (Right now, failure is only
     454             :  * possible if there is a bug.) */
     455             : static int
     456           7 : build_establish_intro_dos_extension(const hs_service_config_t *service_config,
     457             :                                     trn_cell_extension_t *extensions)
     458             : {
     459           7 :   ssize_t ret;
     460           7 :   size_t dos_ext_encoded_len;
     461           7 :   uint8_t *field_array;
     462           7 :   trn_cell_extension_field_t *field = NULL;
     463           7 :   trn_cell_extension_dos_t *dos_ext = NULL;
     464             : 
     465           7 :   tor_assert(service_config);
     466           7 :   tor_assert(extensions);
     467             : 
     468             :   /* We are creating a cell extension field of the type DoS. */
     469           7 :   field = trn_cell_extension_field_new();
     470           7 :   trn_cell_extension_field_set_field_type(field,
     471             :                                           TRUNNEL_CELL_EXTENSION_TYPE_DOS);
     472             : 
     473             :   /* Build DoS extension field. We will put in two parameters. */
     474           7 :   dos_ext = trn_cell_extension_dos_new();
     475           7 :   trn_cell_extension_dos_set_n_params(dos_ext, 2);
     476             : 
     477             :   /* Build DoS parameter INTRO2 rate per second. */
     478           7 :   build_establish_intro_dos_param(dos_ext,
     479             :                                   TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC,
     480           7 :                                   service_config->intro_dos_rate_per_sec);
     481             :   /* Build DoS parameter INTRO2 burst per second. */
     482           7 :   build_establish_intro_dos_param(dos_ext,
     483             :                                   TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC,
     484           7 :                                   service_config->intro_dos_burst_per_sec);
     485             : 
     486             :   /* Set the field with the encoded DoS extension. */
     487           7 :   ret = trn_cell_extension_dos_encoded_len(dos_ext);
     488           7 :   if (BUG(ret <= 0)) {
     489           0 :     goto err;
     490             :   }
     491           7 :   dos_ext_encoded_len = ret;
     492             :   /* Set length field and the field array size length. */
     493           7 :   trn_cell_extension_field_set_field_len(field, dos_ext_encoded_len);
     494           7 :   trn_cell_extension_field_setlen_field(field, dos_ext_encoded_len);
     495             :   /* Encode the DoS extension into the cell extension field. */
     496           7 :   field_array = trn_cell_extension_field_getarray_field(field);
     497           7 :   ret = trn_cell_extension_dos_encode(field_array,
     498             :                  trn_cell_extension_field_getlen_field(field), dos_ext);
     499           7 :   if (BUG(ret <= 0)) {
     500           0 :     goto err;
     501             :   }
     502           7 :   tor_assert(ret == (ssize_t) dos_ext_encoded_len);
     503             : 
     504             :   /* Finally, encode field into the cell extension. */
     505           7 :   trn_cell_extension_add_fields(extensions, field);
     506             : 
     507             :   /* We've just add an extension field to the cell extensions so increment the
     508             :    * total number. */
     509          14 :   trn_cell_extension_set_num(extensions,
     510           7 :                              trn_cell_extension_get_num(extensions) + 1);
     511             : 
     512             :   /* Cleanup. DoS extension has been encoded at this point. */
     513           7 :   trn_cell_extension_dos_free(dos_ext);
     514             : 
     515           7 :   return 0;
     516             : 
     517           0 :  err:
     518           0 :   trn_cell_extension_field_free(field);
     519           0 :   trn_cell_extension_dos_free(dos_ext);
     520           0 :   return -1;
     521             : }
     522             : 
     523             : /* ========== */
     524             : /* Public API */
     525             : /* ========== */
     526             : 
     527             : /** Allocate and build all the ESTABLISH_INTRO cell extension. The given
     528             :  * extensions pointer is always set to a valid cell extension object. */
     529             : STATIC trn_cell_extension_t *
     530          18 : build_establish_intro_extensions(const hs_service_config_t *service_config,
     531             :                                  const hs_service_intro_point_t *ip)
     532             : {
     533          18 :   int ret;
     534          18 :   trn_cell_extension_t *extensions;
     535             : 
     536          18 :   tor_assert(service_config);
     537          18 :   tor_assert(ip);
     538             : 
     539          18 :   extensions = trn_cell_extension_new();
     540          18 :   trn_cell_extension_set_num(extensions, 0);
     541             : 
     542             :   /* If the defense has been enabled service side (by the operator with a
     543             :    * torrc option) and the intro point does support it. */
     544          18 :   if (service_config->has_dos_defense_enabled &&
     545             :       ip->support_intro2_dos_defense) {
     546             :     /* This function takes care to increment the number of extensions. */
     547           7 :     ret = build_establish_intro_dos_extension(service_config, extensions);
     548           7 :     if (ret < 0) {
     549             :       /* Return no extensions on error. */
     550             :       goto end;
     551             :     }
     552             :   }
     553             : 
     554          18 :  end:
     555          18 :   return extensions;
     556             : }
     557             : 
     558             : /** Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
     559             :  * object. The encoded cell is put in cell_out that MUST at least be of the
     560             :  * size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
     561             :  * a negative value and cell_out is untouched. */
     562             : ssize_t
     563          15 : hs_cell_build_establish_intro(const char *circ_nonce,
     564             :                               const hs_service_config_t *service_config,
     565             :                               const hs_service_intro_point_t *ip,
     566             :                               uint8_t *cell_out)
     567             : {
     568          15 :   ssize_t cell_len = -1;
     569          15 :   uint16_t sig_len = ED25519_SIG_LEN;
     570          15 :   trn_cell_establish_intro_t *cell = NULL;
     571          15 :   trn_cell_extension_t *extensions;
     572             : 
     573          15 :   tor_assert(circ_nonce);
     574          15 :   tor_assert(service_config);
     575          15 :   tor_assert(ip);
     576             : 
     577             :   /* Build the extensions, if any. */
     578          15 :   extensions = build_establish_intro_extensions(service_config, ip);
     579             : 
     580             :   /* Set extension data. None used here. */
     581          15 :   cell = trn_cell_establish_intro_new();
     582          15 :   trn_cell_establish_intro_set_extensions(cell, extensions);
     583             :   /* Set signature size. Array is then allocated in the cell. We need to do
     584             :    * this early so we can use trunnel API to get the signature length. */
     585          15 :   trn_cell_establish_intro_set_sig_len(cell, sig_len);
     586          15 :   trn_cell_establish_intro_setlen_sig(cell, sig_len);
     587             : 
     588             :   /* Set AUTH_KEY_TYPE: 2 means ed25519 */
     589          15 :   trn_cell_establish_intro_set_auth_key_type(cell,
     590             :                                     TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
     591             : 
     592             :   /* Set AUTH_KEY and AUTH_KEY_LEN field. Must also set byte-length of
     593             :    * AUTH_KEY to match */
     594             :   {
     595          15 :     uint16_t auth_key_len = ED25519_PUBKEY_LEN;
     596          15 :     trn_cell_establish_intro_set_auth_key_len(cell, auth_key_len);
     597          15 :     trn_cell_establish_intro_setlen_auth_key(cell, auth_key_len);
     598             :     /* We do this call _after_ setting the length because it's reallocated at
     599             :      * that point only. */
     600          15 :     uint8_t *auth_key_ptr = trn_cell_establish_intro_getarray_auth_key(cell);
     601          15 :     memcpy(auth_key_ptr, ip->auth_key_kp.pubkey.pubkey, auth_key_len);
     602             :   }
     603             : 
     604             :   /* Calculate HANDSHAKE_AUTH field (MAC). */
     605             :   {
     606          15 :     ssize_t tmp_cell_enc_len = 0;
     607          30 :     ssize_t tmp_cell_mac_offset =
     608          15 :       sig_len + sizeof(cell->sig_len) +
     609          15 :       trn_cell_establish_intro_getlen_handshake_mac(cell);
     610          15 :     uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0};
     611          15 :     uint8_t mac[TRUNNEL_SHA3_256_LEN], *handshake_ptr;
     612             : 
     613             :     /* We first encode the current fields we have in the cell so we can
     614             :      * compute the MAC using the raw bytes. */
     615          15 :     tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
     616             :                                                        sizeof(tmp_cell_enc),
     617             :                                                        cell);
     618          15 :     if (BUG(tmp_cell_enc_len < 0)) {
     619           0 :       goto done;
     620             :     }
     621             :     /* Sanity check. */
     622          15 :     tor_assert(tmp_cell_enc_len > tmp_cell_mac_offset);
     623             : 
     624             :     /* Circuit nonce is always DIGEST_LEN according to tor-spec.txt. */
     625          15 :     crypto_mac_sha3_256(mac, sizeof(mac),
     626             :                         (uint8_t *) circ_nonce, DIGEST_LEN,
     627          15 :                         tmp_cell_enc, tmp_cell_enc_len - tmp_cell_mac_offset);
     628          15 :     handshake_ptr = trn_cell_establish_intro_getarray_handshake_mac(cell);
     629          15 :     memcpy(handshake_ptr, mac, sizeof(mac));
     630             : 
     631          15 :     memwipe(mac, 0, sizeof(mac));
     632          15 :     memwipe(tmp_cell_enc, 0, sizeof(tmp_cell_enc));
     633             :   }
     634             : 
     635             :   /* Calculate the cell signature SIG. */
     636             :   {
     637          15 :     ssize_t tmp_cell_enc_len = 0;
     638          15 :     ssize_t tmp_cell_sig_offset = (sig_len + sizeof(cell->sig_len));
     639          15 :     uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}, *sig_ptr;
     640          15 :     ed25519_signature_t sig;
     641             : 
     642             :     /* We first encode the current fields we have in the cell so we can
     643             :      * compute the signature from the raw bytes of the cell. */
     644          15 :     tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
     645             :                                                        sizeof(tmp_cell_enc),
     646             :                                                        cell);
     647          15 :     if (BUG(tmp_cell_enc_len < 0)) {
     648           1 :       goto done;
     649             :     }
     650             : 
     651          15 :     if (ed25519_sign_prefixed(&sig, tmp_cell_enc,
     652          15 :                               tmp_cell_enc_len - tmp_cell_sig_offset,
     653             :                               ESTABLISH_INTRO_SIG_PREFIX, &ip->auth_key_kp)) {
     654           1 :       log_warn(LD_BUG, "Unable to make signature for ESTABLISH_INTRO cell.");
     655           1 :       goto done;
     656             :     }
     657             :     /* Copy the signature into the cell. */
     658          14 :     sig_ptr = trn_cell_establish_intro_getarray_sig(cell);
     659          14 :     memcpy(sig_ptr, sig.sig, sig_len);
     660             : 
     661          14 :     memwipe(tmp_cell_enc, 0, sizeof(tmp_cell_enc));
     662             :   }
     663             : 
     664             :   /* Encode the cell. Can't be bigger than a standard cell. */
     665          14 :   cell_len = trn_cell_establish_intro_encode(cell_out, RELAY_PAYLOAD_SIZE,
     666             :                                              cell);
     667             : 
     668          15 :  done:
     669          15 :   trn_cell_establish_intro_free(cell);
     670          15 :   return cell_len;
     671             : }
     672             : 
     673             : /** Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we
     674             :  * are successful at parsing it, return the length of the parsed cell else a
     675             :  * negative value on error. */
     676             : ssize_t
     677           1 : hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
     678             : {
     679           1 :   ssize_t ret;
     680           1 :   trn_cell_intro_established_t *cell = NULL;
     681             : 
     682           1 :   tor_assert(payload);
     683             : 
     684             :   /* Try to parse the payload into a cell making sure we do actually have a
     685             :    * valid cell. */
     686           1 :   ret = trn_cell_intro_established_parse(&cell, payload, payload_len);
     687           1 :   if (ret >= 0) {
     688             :     /* On success, we do not keep the cell, we just notify the caller that it
     689             :      * was successfully parsed. */
     690           1 :     trn_cell_intro_established_free(cell);
     691             :   }
     692           1 :   return ret;
     693             : }
     694             : 
     695             : /** For the encrypted INTRO2 cell in <b>encrypted_section</b>, use the crypto
     696             :  * material in <b>data</b> to compute the right ntor keys. Also validate the
     697             :  * INTRO2 MAC to ensure that the keys are the right ones.
     698             :  *
     699             :  * Return NULL on failure to either produce the key material or on MAC
     700             :  * validation. Else return a newly allocated intro keys object. */
     701             : static hs_ntor_intro_cell_keys_t *
     702           7 : get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data,
     703             :                                    const uint8_t *encrypted_section,
     704             :                                    size_t encrypted_section_len)
     705             : {
     706           7 :   hs_ntor_intro_cell_keys_t *intro_keys = NULL;
     707           7 :   hs_ntor_intro_cell_keys_t *intro_keys_result = NULL;
     708             : 
     709             :   /* Build the key material out of the key material found in the cell. */
     710          14 :   intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp,
     711             :                                            data->n_subcredentials,
     712           7 :                                            data->subcredentials,
     713             :                                            encrypted_section,
     714             :                                            &data->client_pk);
     715           7 :   if (intro_keys == NULL) {
     716           1 :     log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to "
     717             :              "compute key material");
     718           1 :     return NULL;
     719             :   }
     720             : 
     721             :   /* Make sure we are not about to underflow. */
     722           6 :   if (BUG(encrypted_section_len < DIGEST256_LEN)) {
     723           0 :     return NULL;
     724             :   }
     725             : 
     726             :   /* Validate MAC from the cell and our computed key material. The MAC field
     727             :    * in the cell is at the end of the encrypted section. */
     728           6 :   intro_keys_result = tor_malloc_zero(sizeof(*intro_keys_result));
     729          32 :   for (unsigned i = 0; i < data->n_subcredentials; ++i) {
     730          26 :     uint8_t mac[DIGEST256_LEN];
     731             : 
     732             :     /* The MAC field is at the very end of the ENCRYPTED section. */
     733          26 :     size_t mac_offset = encrypted_section_len - sizeof(mac);
     734             :     /* Compute the MAC. Use the entire encoded payload with a length up to the
     735             :      * ENCRYPTED section. */
     736          26 :     compute_introduce_mac(data->payload,
     737          26 :                           data->payload_len - encrypted_section_len,
     738             :                           encrypted_section, encrypted_section_len,
     739          26 :                           intro_keys[i].mac_key,
     740             :                           sizeof(intro_keys[i].mac_key),
     741             :                           mac, sizeof(mac));
     742             :     /* Time-invariant conditional copy: if the MAC is what we expected, then
     743             :      * set intro_keys_result to intro_keys[i]. Otherwise, don't: but don't
     744             :      * leak which one it was! */
     745          26 :     bool equal = tor_memeq(mac, encrypted_section + mac_offset, sizeof(mac));
     746          26 :     memcpy_if_true_timei(equal, intro_keys_result, &intro_keys[i],
     747             :                          sizeof(*intro_keys_result));
     748             :   }
     749             : 
     750             :   /* We no longer need intro_keys. */
     751           6 :   memwipe(intro_keys, 0,
     752             :           sizeof(hs_ntor_intro_cell_keys_t) * data->n_subcredentials);
     753           6 :   tor_free(intro_keys);
     754             : 
     755           6 :   if (safe_mem_is_zero(intro_keys_result, sizeof(*intro_keys_result))) {
     756           1 :     log_info(LD_REND, "Invalid MAC validation for INTRODUCE2 cell");
     757           1 :     tor_free(intro_keys_result); /* sets intro_keys_result to NULL */
     758             :   }
     759             : 
     760             :   return intro_keys_result;
     761             : }
     762             : 
     763             : /** Parse the INTRODUCE2 cell using data which contains everything we need to
     764             :  * do so and contains the destination buffers of information we extract and
     765             :  * compute from the cell. Return 0 on success else a negative value. The
     766             :  * service and circ are only used for logging purposes. */
     767             : ssize_t
     768           8 : hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
     769             :                          const origin_circuit_t *circ,
     770             :                          const hs_service_t *service)
     771             : {
     772           8 :   int ret = -1;
     773           8 :   time_t elapsed;
     774           8 :   uint8_t *decrypted = NULL;
     775           8 :   size_t encrypted_section_len;
     776           8 :   const uint8_t *encrypted_section;
     777           8 :   trn_cell_introduce1_t *cell = NULL;
     778           8 :   trn_cell_introduce_encrypted_t *enc_cell = NULL;
     779           8 :   hs_ntor_intro_cell_keys_t *intro_keys = NULL;
     780             : 
     781           8 :   tor_assert(data);
     782           8 :   tor_assert(circ);
     783           8 :   tor_assert(service);
     784             : 
     785             :   /* Parse the cell into a decoded data structure pointed by cell_ptr. */
     786           8 :   if (parse_introduce2_cell(service, circ, data->payload, data->payload_len,
     787             :                             &cell) < 0) {
     788           0 :     goto done;
     789             :   }
     790             : 
     791           8 :   log_info(LD_REND, "Received a decodable INTRODUCE2 cell on circuit %u "
     792             :                     "for service %s. Decoding encrypted section...",
     793             :            TO_CIRCUIT(circ)->n_circ_id,
     794             :            safe_str_client(service->onion_address));
     795             : 
     796           8 :   encrypted_section = trn_cell_introduce1_getconstarray_encrypted(cell);
     797           8 :   encrypted_section_len = trn_cell_introduce1_getlen_encrypted(cell);
     798             : 
     799             :   /* Encrypted section must at least contain the CLIENT_PK and MAC which is
     800             :    * defined in section 3.3.2 of the specification. */
     801           8 :   if (encrypted_section_len < (CURVE25519_PUBKEY_LEN + DIGEST256_LEN)) {
     802           0 :     log_info(LD_REND, "Invalid INTRODUCE2 encrypted section length "
     803             :                       "for service %s. Dropping cell.",
     804             :              safe_str_client(service->onion_address));
     805           0 :     goto done;
     806             :   }
     807             : 
     808             :   /* Check our replay cache for this introduction point. */
     809           8 :   if (replaycache_add_test_and_elapsed(data->replay_cache, encrypted_section,
     810             :                                        encrypted_section_len, &elapsed)) {
     811           1 :     log_warn(LD_REND, "Possible replay detected! An INTRODUCE2 cell with the "
     812             :                       "same ENCRYPTED section was seen %ld seconds ago. "
     813             :                       "Dropping cell.", (long int) elapsed);
     814           1 :     goto done;
     815             :   }
     816             : 
     817             :   /* First bytes of the ENCRYPTED section are the client public key (they are
     818             :    * guaranteed to exist because of the length check above). We are gonna use
     819             :    * the client public key to compute the ntor keys and decrypt the payload:
     820             :    */
     821           7 :   memcpy(&data->client_pk.public_key, encrypted_section,
     822             :          CURVE25519_PUBKEY_LEN);
     823             : 
     824             :   /* Get the right INTRODUCE2 ntor keys and verify the cell MAC */
     825           7 :   intro_keys = get_introduce2_keys_and_verify_mac(data, encrypted_section,
     826             :                                                   encrypted_section_len);
     827           7 :   if (!intro_keys) {
     828           2 :     log_warn(LD_REND, "Could not get valid INTRO2 keys on circuit %u "
     829             :              "for service %s", TO_CIRCUIT(circ)->n_circ_id,
     830             :              safe_str_client(service->onion_address));
     831           2 :     goto done;
     832             :   }
     833             : 
     834             :   {
     835             :     /* The ENCRYPTED_DATA section starts just after the CLIENT_PK. */
     836           5 :     const uint8_t *encrypted_data =
     837             :       encrypted_section + sizeof(data->client_pk);
     838             :     /* It's symmetric encryption so it's correct to use the ENCRYPTED length
     839             :      * for decryption. Computes the length of ENCRYPTED_DATA meaning removing
     840             :      * the CLIENT_PK and MAC length. */
     841           5 :     size_t encrypted_data_len =
     842             :       encrypted_section_len - (sizeof(data->client_pk) + DIGEST256_LEN);
     843             : 
     844             :     /* This decrypts the ENCRYPTED_DATA section of the cell. */
     845           5 :     decrypted = decrypt_introduce2(intro_keys->enc_key,
     846             :                                    encrypted_data, encrypted_data_len);
     847           5 :     if (decrypted == NULL) {
     848           0 :       log_info(LD_REND, "Unable to decrypt the ENCRYPTED section of an "
     849             :                         "INTRODUCE2 cell on circuit %u for service %s",
     850             :                TO_CIRCUIT(circ)->n_circ_id,
     851             :                safe_str_client(service->onion_address));
     852           0 :       goto done;
     853             :     }
     854             : 
     855             :     /* Parse this blob into an encrypted cell structure so we can then extract
     856             :      * the data we need out of it. */
     857           5 :     enc_cell = parse_introduce2_encrypted(decrypted, encrypted_data_len,
     858             :                                           circ, service);
     859           5 :     memwipe(decrypted, 0, encrypted_data_len);
     860           5 :     if (enc_cell == NULL) {
     861           0 :       goto done;
     862             :     }
     863             :   }
     864             : 
     865             :   /* XXX: Implement client authorization checks. */
     866             : 
     867             :   /* Extract onion key and rendezvous cookie from the cell used for the
     868             :    * rendezvous point circuit e2e encryption. */
     869           5 :   memcpy(data->onion_pk.public_key,
     870           5 :          trn_cell_introduce_encrypted_getconstarray_onion_key(enc_cell),
     871             :          CURVE25519_PUBKEY_LEN);
     872           5 :   memcpy(data->rendezvous_cookie,
     873           5 :          trn_cell_introduce_encrypted_getconstarray_rend_cookie(enc_cell),
     874             :          sizeof(data->rendezvous_cookie));
     875             : 
     876             :   /* Extract rendezvous link specifiers. */
     877           5 :   for (size_t idx = 0;
     878          10 :        idx < trn_cell_introduce_encrypted_get_nspec(enc_cell); idx++) {
     879           5 :     link_specifier_t *lspec =
     880           5 :       trn_cell_introduce_encrypted_get_nspecs(enc_cell, idx);
     881           5 :     if (BUG(!lspec)) {
     882           0 :       goto done;
     883             :     }
     884           5 :     link_specifier_t *lspec_dup = link_specifier_dup(lspec);
     885           5 :     if (BUG(!lspec_dup)) {
     886           0 :       goto done;
     887             :     }
     888           5 :     smartlist_add(data->link_specifiers, lspec_dup);
     889             :   }
     890             : 
     891             :   /* Success. */
     892           5 :   ret = 0;
     893           5 :   log_info(LD_REND, "Valid INTRODUCE2 cell. Launching rendezvous circuit.");
     894             : 
     895           8 :  done:
     896           8 :   if (intro_keys) {
     897           5 :     memwipe(intro_keys, 0, sizeof(hs_ntor_intro_cell_keys_t));
     898           5 :     tor_free(intro_keys);
     899             :   }
     900           8 :   tor_free(decrypted);
     901           8 :   trn_cell_introduce_encrypted_free(enc_cell);
     902           8 :   trn_cell_introduce1_free(cell);
     903           8 :   return ret;
     904             : }
     905             : 
     906             : /** Build a RENDEZVOUS1 cell with the given rendezvous cookie and handshake
     907             :  * info. The encoded cell is put in cell_out and the length of the data is
     908             :  * returned. This can't fail. */
     909             : ssize_t
     910           2 : hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie,
     911             :                           size_t rendezvous_cookie_len,
     912             :                           const uint8_t *rendezvous_handshake_info,
     913             :                           size_t rendezvous_handshake_info_len,
     914             :                           uint8_t *cell_out)
     915             : {
     916           2 :   ssize_t cell_len;
     917           2 :   trn_cell_rendezvous1_t *cell;
     918             : 
     919           2 :   tor_assert(rendezvous_cookie);
     920           2 :   tor_assert(rendezvous_handshake_info);
     921           2 :   tor_assert(cell_out);
     922             : 
     923           2 :   cell = trn_cell_rendezvous1_new();
     924             :   /* Set the RENDEZVOUS_COOKIE. */
     925           2 :   memcpy(trn_cell_rendezvous1_getarray_rendezvous_cookie(cell),
     926             :          rendezvous_cookie, rendezvous_cookie_len);
     927             :   /* Set the HANDSHAKE_INFO. */
     928           2 :   trn_cell_rendezvous1_setlen_handshake_info(cell,
     929             :                                             rendezvous_handshake_info_len);
     930           2 :   memcpy(trn_cell_rendezvous1_getarray_handshake_info(cell),
     931             :          rendezvous_handshake_info, rendezvous_handshake_info_len);
     932             :   /* Encoding. */
     933           2 :   cell_len = trn_cell_rendezvous1_encode(cell_out, RELAY_PAYLOAD_SIZE, cell);
     934           2 :   tor_assert(cell_len > 0);
     935             : 
     936           2 :   trn_cell_rendezvous1_free(cell);
     937           2 :   return cell_len;
     938             : }
     939             : 
     940             : /** Build an INTRODUCE1 cell from the given data. The encoded cell is put in
     941             :  * cell_out which must be of at least size RELAY_PAYLOAD_SIZE. On success, the
     942             :  * encoded length is returned else a negative value and the content of
     943             :  * cell_out should be ignored. */
     944             : ssize_t
     945           4 : hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data,
     946             :                          uint8_t *cell_out)
     947             : {
     948           4 :   ssize_t cell_len;
     949           4 :   trn_cell_introduce1_t *cell;
     950           4 :   trn_cell_extension_t *ext;
     951             : 
     952           4 :   tor_assert(data);
     953           4 :   tor_assert(cell_out);
     954             : 
     955           4 :   cell = trn_cell_introduce1_new();
     956           4 :   tor_assert(cell);
     957             : 
     958             :   /* Set extension data. None are used. */
     959           4 :   ext = trn_cell_extension_new();
     960           4 :   tor_assert(ext);
     961           4 :   trn_cell_extension_set_num(ext, 0);
     962           4 :   trn_cell_introduce1_set_extensions(cell, ext);
     963             : 
     964             :   /* Set the authentication key. */
     965           4 :   introduce1_set_auth_key(cell, data);
     966             : 
     967             :   /* Set the encrypted section. This will set, encrypt and encode the
     968             :    * ENCRYPTED section in the cell. After this, we'll be ready to encode. */
     969           4 :   introduce1_set_encrypted(cell, data);
     970             : 
     971             :   /* Final encoding. */
     972           4 :   cell_len = trn_cell_introduce1_encode(cell_out, RELAY_PAYLOAD_SIZE, cell);
     973             : 
     974           4 :   trn_cell_introduce1_free(cell);
     975           4 :   return cell_len;
     976             : }
     977             : 
     978             : /** Build an ESTABLISH_RENDEZVOUS cell from the given rendezvous_cookie. The
     979             :  * encoded cell is put in cell_out which must be of at least
     980             :  * RELAY_PAYLOAD_SIZE. On success, the encoded length is returned and the
     981             :  * caller should clear up the content of the cell.
     982             :  *
     983             :  * This function can't fail. */
     984             : ssize_t
     985           0 : hs_cell_build_establish_rendezvous(const uint8_t *rendezvous_cookie,
     986             :                                    uint8_t *cell_out)
     987             : {
     988           0 :   tor_assert(rendezvous_cookie);
     989           0 :   tor_assert(cell_out);
     990             : 
     991           0 :   memcpy(cell_out, rendezvous_cookie, HS_REND_COOKIE_LEN);
     992           0 :   return HS_REND_COOKIE_LEN;
     993             : }
     994             : 
     995             : /** Handle an INTRODUCE_ACK cell encoded in payload of length payload_len.
     996             :  * Return the status code on success else a negative value if the cell as not
     997             :  * decodable. */
     998             : int
     999           0 : hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len)
    1000             : {
    1001           0 :   int ret = -1;
    1002           0 :   trn_cell_introduce_ack_t *cell = NULL;
    1003             : 
    1004           0 :   tor_assert(payload);
    1005             : 
    1006           0 :   if (trn_cell_introduce_ack_parse(&cell, payload, payload_len) < 0) {
    1007           0 :     log_info(LD_REND, "Invalid INTRODUCE_ACK cell. Unable to parse it.");
    1008           0 :     goto end;
    1009             :   }
    1010             : 
    1011           0 :   ret = trn_cell_introduce_ack_get_status(cell);
    1012             : 
    1013           0 :  end:
    1014           0 :   trn_cell_introduce_ack_free(cell);
    1015           0 :   return ret;
    1016             : }
    1017             : 
    1018             : /** Handle a RENDEZVOUS2 cell encoded in payload of length payload_len. On
    1019             :  * success, handshake_info contains the data in the HANDSHAKE_INFO field, and
    1020             :  * 0 is returned. On error, a negative value is returned. */
    1021             : int
    1022           1 : hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len,
    1023             :                           uint8_t *handshake_info, size_t handshake_info_len)
    1024             : {
    1025           1 :   int ret = -1;
    1026           1 :   trn_cell_rendezvous2_t *cell = NULL;
    1027             : 
    1028           1 :   tor_assert(payload);
    1029           1 :   tor_assert(handshake_info);
    1030             : 
    1031           1 :   if (trn_cell_rendezvous2_parse(&cell, payload, payload_len) < 0) {
    1032           0 :     log_info(LD_REND, "Invalid RENDEZVOUS2 cell. Unable to parse it.");
    1033           0 :     goto end;
    1034             :   }
    1035             : 
    1036             :   /* Static size, we should never have an issue with this else we messed up
    1037             :    * our code flow. */
    1038           1 :   tor_assert(trn_cell_rendezvous2_getlen_handshake_info(cell) ==
    1039             :              handshake_info_len);
    1040           2 :   memcpy(handshake_info,
    1041           1 :          trn_cell_rendezvous2_getconstarray_handshake_info(cell),
    1042             :          handshake_info_len);
    1043           1 :   ret = 0;
    1044             : 
    1045           1 :  end:
    1046           1 :   trn_cell_rendezvous2_free(cell);
    1047           1 :   return ret;
    1048             : }
    1049             : 
    1050             : /** Clear the given INTRODUCE1 data structure data. */
    1051             : void
    1052           4 : hs_cell_introduce1_data_clear(hs_cell_introduce1_data_t *data)
    1053             : {
    1054           4 :   if (data == NULL) {
    1055             :     return;
    1056             :   }
    1057             :   /* Object in this list have been moved to the cell object when building it
    1058             :    * so they've been freed earlier. We do that in order to avoid duplicating
    1059             :    * them leading to more memory and CPU time being used for nothing. */
    1060           4 :   smartlist_free(data->link_specifiers);
    1061             :   /* The data object has no ownership of any members. */
    1062           4 :   memwipe(data, 0, sizeof(hs_cell_introduce1_data_t));
    1063             : }

Generated by: LCOV version 1.14