Commit 559ffd71 authored by David Goulet's avatar David Goulet 🐼 Committed by Nick Mathewson
Browse files

test: Refactor HS tests to use the new ESTABLISH_INTRO cell code

parent 8ffb4942
Loading
Loading
Loading
Loading
+2 −155
Original line number Diff line number Diff line
@@ -297,7 +297,7 @@ service_free_all(void)
}

/* Free a given service intro point object. */
static void
STATIC void
service_intro_point_free(hs_service_intro_point_t *ip)
{
  if (!ip) {
@@ -322,7 +322,7 @@ service_intro_point_free_(void *obj)
/* Return a newly allocated service intro point and fully initialized from the
 * given extend_info_t ei if non NULL. If is_legacy is true, we also generate
 * the legacy key. On error, NULL is returned. */
static hs_service_intro_point_t *
STATIC hs_service_intro_point_t *
service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy)
{
  hs_desc_link_specifier_t *ls;
@@ -2747,159 +2747,6 @@ hs_service_free_all(void)
  service_free_all();
}

/* XXX We don't currently use these functions, apart from generating unittest
   data. When we start implementing the service-side support for prop224 we
   should revisit these functions and use them. */

/** Given an ESTABLISH_INTRO <b>cell</b>, encode it and place its payload in
 *  <b>buf_out</b> which has size <b>buf_out_len</b>. Return the number of
 *  bytes written, or a negative integer if there was an error. */
ssize_t
get_establish_intro_payload(uint8_t *buf_out, size_t buf_out_len,
                            const trn_cell_establish_intro_t *cell)
{
  ssize_t bytes_used = 0;

  if (buf_out_len < RELAY_PAYLOAD_SIZE) {
    return -1;
  }

  bytes_used = trn_cell_establish_intro_encode(buf_out, buf_out_len,
                                              cell);
  return bytes_used;
}

/* Set the cell extensions of <b>cell</b>. */
static void
set_trn_cell_extensions(trn_cell_establish_intro_t *cell)
{
  trn_cell_extension_t *trn_cell_extensions = trn_cell_extension_new();

  /* For now, we don't use extensions at all. */
  trn_cell_extensions->num = 0; /* It's already zeroed, but be explicit. */
  trn_cell_establish_intro_set_extensions(cell, trn_cell_extensions);
}

/** Given the circuit handshake info in <b>circuit_key_material</b>, create and
 *  return an ESTABLISH_INTRO cell. Return NULL if something went wrong.  The
 *  returned cell is allocated on the heap and it's the responsibility of the
 *  caller to free it. */
trn_cell_establish_intro_t *
generate_establish_intro_cell(const uint8_t *circuit_key_material,
                              size_t circuit_key_material_len)
{
  trn_cell_establish_intro_t *cell = NULL;
  ssize_t encoded_len;

  log_warn(LD_GENERAL,
           "Generating ESTABLISH_INTRO cell (key_material_len: %u)",
           (unsigned) circuit_key_material_len);

  /* Generate short-term keypair for use in ESTABLISH_INTRO */
  ed25519_keypair_t key_struct;
  if (ed25519_keypair_generate(&key_struct, 0) < 0) {
    goto err;
  }

  cell = trn_cell_establish_intro_new();

  /* Set AUTH_KEY_TYPE: 2 means ed25519 */
  trn_cell_establish_intro_set_auth_key_type(cell,
                                             HS_INTRO_AUTH_KEY_TYPE_ED25519);

  /* Set AUTH_KEY_LEN field */
  /* Must also set byte-length of AUTH_KEY to match */
  int auth_key_len = ED25519_PUBKEY_LEN;
  trn_cell_establish_intro_set_auth_key_len(cell, auth_key_len);
  trn_cell_establish_intro_setlen_auth_key(cell, auth_key_len);

  /* Set AUTH_KEY field */
  uint8_t *auth_key_ptr = trn_cell_establish_intro_getarray_auth_key(cell);
  memcpy(auth_key_ptr, key_struct.pubkey.pubkey, auth_key_len);

  /* No cell extensions needed */
  set_trn_cell_extensions(cell);

  /* Set signature size.
     We need to do this up here, because _encode() needs it and we need to call
     _encode() to calculate the MAC and signature.
  */
  int sig_len = ED25519_SIG_LEN;
  trn_cell_establish_intro_set_sig_len(cell, sig_len);
  trn_cell_establish_intro_setlen_sig(cell, sig_len);

  /* XXX How to make this process easier and nicer? */

  /* Calculate the cell MAC (aka HANDSHAKE_AUTH). */
  {
    /* To calculate HANDSHAKE_AUTH, we dump the cell in bytes, and then derive
       the MAC from it. */
    uint8_t cell_bytes_tmp[RELAY_PAYLOAD_SIZE] = {0};
    uint8_t mac[TRUNNEL_SHA3_256_LEN];

    encoded_len = trn_cell_establish_intro_encode(cell_bytes_tmp,
                                                 sizeof(cell_bytes_tmp),
                                                 cell);
    if (encoded_len < 0) {
      log_warn(LD_OR, "Unable to pre-encode ESTABLISH_INTRO cell.");
      goto err;
    }

    /* sanity check */
    tor_assert(encoded_len > ED25519_SIG_LEN + 2 + TRUNNEL_SHA3_256_LEN);

    /* Calculate MAC of all fields before HANDSHAKE_AUTH */
    crypto_mac_sha3_256(mac, sizeof(mac),
                        circuit_key_material, circuit_key_material_len,
                        cell_bytes_tmp,
                        encoded_len -
                          (ED25519_SIG_LEN + 2 + TRUNNEL_SHA3_256_LEN));
    /* Write the MAC to the cell */
    uint8_t *handshake_ptr =
      trn_cell_establish_intro_getarray_handshake_mac(cell);
    memcpy(handshake_ptr, mac, sizeof(mac));
  }

  /* Calculate the cell signature */
  {
    /* To calculate the sig we follow the same procedure as above. We first
       dump the cell up to the sig, and then calculate the sig */
    uint8_t cell_bytes_tmp[RELAY_PAYLOAD_SIZE] = {0};
    ed25519_signature_t sig;

    encoded_len = trn_cell_establish_intro_encode(cell_bytes_tmp,
                                                 sizeof(cell_bytes_tmp),
                                                 cell);
    if (encoded_len < 0) {
      log_warn(LD_OR, "Unable to pre-encode ESTABLISH_INTRO cell (2).");
      goto err;
    }

    tor_assert(encoded_len > ED25519_SIG_LEN);

    if (ed25519_sign_prefixed(&sig,
                              cell_bytes_tmp,
                              encoded_len -
                                (ED25519_SIG_LEN + sizeof(cell->sig_len)),
                              ESTABLISH_INTRO_SIG_PREFIX,
                              &key_struct)) {
      log_warn(LD_BUG, "Unable to gen signature for ESTABLISH_INTRO cell.");
      goto err;
    }

    /* And write the signature to the cell */
    uint8_t *sig_ptr = trn_cell_establish_intro_getarray_sig(cell);
    memcpy(sig_ptr, sig.sig, sig_len);
  }

  /* We are done! Return the cell! */
  return cell;

 err:
  trn_cell_establish_intro_free(cell);
  return NULL;
}

#ifdef TOR_UNIT_TESTS

/* Return the global service map size. Only used by unit test. */
+4 −11
Original line number Diff line number Diff line
@@ -269,17 +269,6 @@ int hs_service_receive_introduce2(origin_circuit_t *circ,
                                  const uint8_t *payload,
                                  size_t payload_len);

/* These functions are only used by unit tests and we need to expose them else
 * hs_service.o ends up with no symbols in libor.a which makes clang throw a
 * warning at compile time. See #21825. */

trn_cell_establish_intro_t *
generate_establish_intro_cell(const uint8_t *circuit_key_material,
                              size_t circuit_key_material_len);
ssize_t
get_establish_intro_payload(uint8_t *buf, size_t buf_len,
                            const trn_cell_establish_intro_t *cell);

#ifdef HS_SERVICE_PRIVATE

#ifdef TOR_UNIT_TESTS
@@ -295,6 +284,10 @@ STATIC hs_service_t *find_service(hs_service_ht *map,
                                  const ed25519_public_key_t *pk);
STATIC void remove_service(hs_service_ht *map, hs_service_t *service);
STATIC int register_service(hs_service_ht *map, hs_service_t *service);
STATIC hs_service_intro_point_t *service_intro_point_new(
                                         const extend_info_t *ei,
                                         unsigned int is_legacy);
STATIC void service_intro_point_free(hs_service_intro_point_t *ip);

#endif /* TOR_UNIT_TESTS */

+34 −24
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include "log_test_helpers.h"

#include "crypto_ed25519.h"
#include "hs_cell.h"
#include "hs_intropoint.h"
#include "hs_service.h"

@@ -26,40 +27,44 @@ static void
test_gen_establish_intro_cell(void *arg)
{
  (void) arg;
  ssize_t retval;
  uint8_t circuit_key_material[DIGEST_LEN] = {0};
  ssize_t ret;
  char circ_nonce[DIGEST_LEN] = {0};
  uint8_t buf[RELAY_PAYLOAD_SIZE];
  trn_cell_establish_intro_t *cell_out = NULL;
  trn_cell_establish_intro_t *cell_in = NULL;

  crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  crypto_rand(circ_nonce, sizeof(circ_nonce));

  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
     attempt to parse it. */
  {
    cell_out = generate_establish_intro_cell(circuit_key_material,
                                             sizeof(circuit_key_material));
    tt_assert(cell_out);

    retval = get_establish_intro_payload(buf, sizeof(buf), cell_out);
    tt_int_op(retval, >=, 0);
    cell_out = trn_cell_establish_intro_new();
    /* We only need the auth key pair here. */
    hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0);
    /* Auth key pair is generated in the constructor so we are all set for
     * using this IP object. */
    ret = hs_cell_build_establish_intro(circ_nonce, ip, buf);
    service_intro_point_free(ip);
    tt_u64_op(ret, OP_GT, 0);

    ret = trn_cell_establish_intro_encode(buf, sizeof(buf), cell_out);
    tt_u64_op(ret, OP_GT, 0);
  }

  /* Parse it as the receiver */
  {
    ssize_t parse_result = trn_cell_establish_intro_parse(&cell_in,
                                                         buf, sizeof(buf));
    tt_int_op(parse_result, >=, 0);

    retval = verify_establish_intro_cell(cell_in,
                                         circuit_key_material,
                                         sizeof(circuit_key_material));
    tt_int_op(retval, >=, 0);
    ret = trn_cell_establish_intro_parse(&cell_in, buf, sizeof(buf));
    tt_u64_op(ret, OP_GT, 0);

    ret = verify_establish_intro_cell(cell_in,
                                      (const uint8_t *) circ_nonce,
                                      sizeof(circ_nonce));
    tt_u64_op(ret, OP_EQ, 0);
  }

 done:
  trn_cell_establish_intro_free(cell_out);
  trn_cell_establish_intro_free(cell_in);
  trn_cell_establish_intro_free(cell_out);
}

/* Mocked ed25519_sign_prefixed() function that always fails :) */
@@ -81,22 +86,27 @@ static void
test_gen_establish_intro_cell_bad(void *arg)
{
  (void) arg;
  ssize_t cell_len = 0;
  trn_cell_establish_intro_t *cell = NULL;
  uint8_t circuit_key_material[DIGEST_LEN] = {0};
  char circ_nonce[DIGEST_LEN] = {0};
  hs_service_intro_point_t *ip = NULL;

  MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed);

  crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  crypto_rand(circ_nonce, sizeof(circ_nonce));

  setup_full_capture_of_logs(LOG_WARN);
  /* Easiest way to make that function fail is to mock the
     ed25519_sign_prefixed() function and make it fail. */
  cell = generate_establish_intro_cell(circuit_key_material,
                                       sizeof(circuit_key_material));
  expect_log_msg_containing("Unable to gen signature for "
  cell = trn_cell_establish_intro_new();
  tt_assert(cell);
  ip = service_intro_point_new(NULL, 0);
  cell_len = hs_cell_build_establish_intro(circ_nonce, ip, NULL);
  service_intro_point_free(ip);
  expect_log_msg_containing("Unable to make signature for "
                            "ESTABLISH_INTRO cell.");
  teardown_capture_of_logs();
  tt_assert(!cell);
  tt_u64_op(cell_len, OP_EQ, -1);

 done:
  trn_cell_establish_intro_free(cell);
+160 −131

File changed.

Preview size limit exceeded, changes collapsed.