Ejemplo n.º 1
0
Archivo: bench.c Proyecto: 1234max/tor
static void
bench_ed25519_impl(void)
{
  uint64_t start, end;
  const int iters = 1<<12;
  int i;
  const uint8_t msg[] = "but leaving, could not tell what they had heard";
  ed25519_signature_t sig;
  ed25519_keypair_t kp;
  curve25519_keypair_t curve_kp;
  ed25519_public_key_t pubkey_tmp;

  ed25519_secret_key_generate(&kp.seckey, 0);
  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
  }
  end = perftime();
  printf("Generate public key: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_sign(&sig, msg, sizeof(msg), &kp);
  }
  end = perftime();
  printf("Sign a short message: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_checksig(&sig, msg, sizeof(msg), &kp.pubkey);
  }
  end = perftime();
  printf("Verify signature: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  curve25519_keypair_generate(&curve_kp, 0);
  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_public_key_from_curve25519_public_key(&pubkey_tmp,
                                                  &curve_kp.pubkey, 1);
  }
  end = perftime();
  printf("Convert public point from curve25519: %.2f usec\n",
         MICROCOUNT(start, end, iters));

  curve25519_keypair_generate(&curve_kp, 0);
  start = perftime();
  for (i = 0; i < iters; ++i) {
    ed25519_public_blind(&pubkey_tmp, &kp.pubkey, msg);
  }
  end = perftime();
  printf("Blind a public key: %.2f usec\n",
         MICROCOUNT(start, end, iters));
}
Ejemplo n.º 2
0
static void
test_routerkeys_cross_certify_ntor(void *args)
{
  (void) args;

  tor_cert_t *cert = NULL;
  curve25519_keypair_t onion_keys;
  ed25519_public_key_t master_key;
  ed25519_public_key_t onion_check_key;
  time_t now = time(NULL);
  int sign;

  tt_int_op(0, OP_EQ, ed25519_public_from_base64(&master_key,
                               "IamwritingthesetestsOnARainyAfternoonin2014"));
  tt_int_op(0, OP_EQ, curve25519_keypair_generate(&onion_keys, 0));
  cert = make_ntor_onion_key_crosscert(&onion_keys,
                                       &master_key,
                                       now, 10000,
                                       &sign);
  tt_assert(cert);
  tt_assert(sign == 0 || sign == 1);
  tt_int_op(cert->cert_type, OP_EQ, CERT_TYPE_ONION_ID);
  tt_int_op(1, OP_EQ, ed25519_pubkey_eq(&cert->signed_key, &master_key));
  tt_int_op(0, OP_EQ, ed25519_public_key_from_curve25519_public_key(
                               &onion_check_key, &onion_keys.pubkey, sign));
  tt_int_op(0, OP_EQ, tor_cert_checksig(cert, &onion_check_key, now));

 done:
  tor_cert_free(cert);
}
Ejemplo n.º 3
0
Archivo: onion.c Proyecto: adoll/tor
/** Fill in a server_onion_keys_t object at <b>keys</b> with all of the keys
 * and other info we might need to do onion handshakes.  (We make a copy of
 * our keys for each cpuworker to avoid race conditions with the main thread,
 * and to avoid locking) */
void
setup_server_onion_keys(server_onion_keys_t *keys)
{
  memset(keys, 0, sizeof(server_onion_keys_t));
  memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);
  dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
  keys->curve25519_key_map = construct_ntor_key_map();
  keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t));
  curve25519_keypair_generate(keys->junk_keypair, 0);
}
Ejemplo n.º 4
0
/* Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On
 * success, 0 is returned else -1 and the circuit is marked for close. */
int
hs_circ_send_establish_rendezvous(origin_circuit_t *circ)
{
  ssize_t cell_len = 0;
  uint8_t cell[RELAY_PAYLOAD_SIZE] = {0};

  tor_assert(circ);
  tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);

  log_info(LD_REND, "Send an ESTABLISH_RENDEZVOUS cell on circuit %u",
           TO_CIRCUIT(circ)->n_circ_id);

  /* Set timestamp_dirty, because circuit_expire_building expects it,
   * and the rend cookie also means we've used the circ. */
  TO_CIRCUIT(circ)->timestamp_dirty = time(NULL);

  /* We've attempted to use this circuit. Probe it if we fail */
  pathbias_count_use_attempt(circ);

  /* Generate the RENDEZVOUS_COOKIE and place it in the identifier so we can
   * complete the handshake when receiving the acknowledgement. */
  crypto_rand((char *) circ->hs_ident->rendezvous_cookie, HS_REND_COOKIE_LEN);
  /* Generate the client keypair. No need to be extra strong, not long term */
  curve25519_keypair_generate(&circ->hs_ident->rendezvous_client_kp, 0);

  cell_len =
    hs_cell_build_establish_rendezvous(circ->hs_ident->rendezvous_cookie,
                                       cell);
  if (BUG(cell_len < 0)) {
    goto err;
  }

  if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
                                   RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
                                   (const char *) cell, cell_len,
                                   circ->cpath->prev) < 0) {
    /* Circuit has been marked for close */
    log_warn(LD_REND, "Unable to send ESTABLISH_RENDEZVOUS cell on "
                      "circuit %u", TO_CIRCUIT(circ)->n_circ_id);
    memwipe(cell, 0, cell_len);
    goto err;
  }

  memwipe(cell, 0, cell_len);
  return 0;
 err:
  return -1;
}
Ejemplo n.º 5
0
/** Fill in a server_onion_keys_t object at <b>keys</b> with all of the keys
 * and other info we might need to do onion handshakes.  (We make a copy of
 * our keys for each cpuworker to avoid race conditions with the main thread,
 * and to avoid locking) */
void
setup_server_onion_keys(server_onion_keys_t *keys)
{
  memset(keys, 0, sizeof(server_onion_keys_t));
  memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);

#ifdef IPC_MODE
  if(get_relay_num() == 3) {
    keys->onion_key = NULL;
    keys->last_onion_key = NULL;
  }
  else
    dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
#endif
#ifndef IPC_MODE
  dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
#endif

#ifdef CURVE25519_ENABLED
  keys->curve25519_key_map = construct_ntor_key_map();
  keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t));
  curve25519_keypair_generate(keys->junk_keypair, 0);
#endif
}
Ejemplo n.º 6
0
/* For a given service, the ntor onion key and a rendezvous cookie, launch a
 * circuit to the rendezvous point specified by the link specifiers. On
 * success, a circuit identifier is attached to the circuit with the needed
 * data. This function will try to open a circuit for a maximum value of
 * MAX_REND_FAILURES then it will give up. */
static void
launch_rendezvous_point_circuit(const hs_service_t *service,
                                const hs_service_intro_point_t *ip,
                                const hs_cell_introduce2_data_t *data)
{
  int circ_needs_uptime;
  time_t now = time(NULL);
  extend_info_t *info = NULL;
  origin_circuit_t *circ;

  tor_assert(service);
  tor_assert(ip);
  tor_assert(data);

  circ_needs_uptime = hs_service_requires_uptime_circ(service->config.ports);

  /* Get the extend info data structure for the chosen rendezvous point
   * specified by the given link specifiers. */
  info = hs_get_extend_info_from_lspecs(data->link_specifiers,
                                        &data->onion_pk,
                                        service->config.is_single_onion);
  if (info == NULL) {
    /* We are done here, we can't extend to the rendezvous point.
     * If you're running an IPv6-only v3 single onion service on 0.3.2 or with
     * 0.3.2 clients, and somehow disable the option check, it will fail here.
     */
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Not enough info to open a circuit to a rendezvous point for "
           "%s service %s.",
           get_service_anonymity_string(service),
           safe_str_client(service->onion_address));
    goto end;
  }

  for (int i = 0; i < MAX_REND_FAILURES; i++) {
    int circ_flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL;
    if (circ_needs_uptime) {
      circ_flags |= CIRCLAUNCH_NEED_UPTIME;
    }
    /* Firewall and policies are checked when getting the extend info. */
    if (service->config.is_single_onion) {
      circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
    }

    circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, info,
                                         circ_flags);
    if (circ != NULL) {
      /* Stop retrying, we have a circuit! */
      break;
    }
  }
  if (circ == NULL) {
    log_warn(LD_REND, "Giving up on launching a rendezvous circuit to %s "
                      "for %s service %s",
             safe_str_client(extend_info_describe(info)),
             get_service_anonymity_string(service),
             safe_str_client(service->onion_address));
    goto end;
  }
  log_info(LD_REND, "Rendezvous circuit launched to %s with cookie %s "
                    "for %s service %s",
           safe_str_client(extend_info_describe(info)),
           safe_str_client(hex_str((const char *) data->rendezvous_cookie,
                                   REND_COOKIE_LEN)),
           get_service_anonymity_string(service),
           safe_str_client(service->onion_address));
  tor_assert(circ->build_state);
  /* Rendezvous circuit have a specific timeout for the time spent on trying
   * to connect to the rendezvous point. */
  circ->build_state->expiry_time = now + MAX_REND_TIMEOUT;

  /* Create circuit identifier and key material. */
  {
    hs_ntor_rend_cell_keys_t keys;
    curve25519_keypair_t ephemeral_kp;
    /* No need for extra strong, this is only for this circuit life time. This
     * key will be used for the RENDEZVOUS1 cell that will be sent on the
     * circuit once opened. */
    curve25519_keypair_generate(&ephemeral_kp, 0);
    if (hs_ntor_service_get_rendezvous1_keys(&ip->auth_key_kp.pubkey,
                                             &ip->enc_key_kp,
                                             &ephemeral_kp, &data->client_pk,
                                             &keys) < 0) {
      /* This should not really happened but just in case, don't make tor
       * freak out, close the circuit and move on. */
      log_info(LD_REND, "Unable to get RENDEZVOUS1 key material for "
                        "service %s",
               safe_str_client(service->onion_address));
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      goto end;
    }
    circ->hs_ident = create_rp_circuit_identifier(service,
                                                  data->rendezvous_cookie,
                                                  &ephemeral_kp.pubkey, &keys);
    memwipe(&ephemeral_kp, 0, sizeof(ephemeral_kp));
    memwipe(&keys, 0, sizeof(keys));
    tor_assert(circ->hs_ident);
  }

 end:
  extend_info_free(info);
}
Ejemplo n.º 7
0
static void
test_crypto_ed25519_fuzz_donna(void *arg)
{
  const unsigned iters = 1024;
  uint8_t msg[1024];
  unsigned i;
  (void)arg;

  tt_uint_op(iters, OP_EQ, sizeof(msg));
  crypto_rand((char*) msg, sizeof(msg));

  /* Fuzz Ed25519-donna vs ref10, alternating the implementation used to
   * generate keys/sign per iteration.
   */
  for (i = 0; i < iters; ++i) {
    const int use_donna = i & 1;
    uint8_t blinding[32];
    curve25519_keypair_t ckp;
    ed25519_keypair_t kp, kp_blind, kp_curve25519;
    ed25519_public_key_t pk, pk_blind, pk_curve25519;
    ed25519_signature_t sig, sig_blind;
    int bit = 0;

    crypto_rand((char*) blinding, sizeof(blinding));

    /* Impl. A:
     *  1. Generate a keypair.
     *  2. Blinded the keypair.
     *  3. Sign a message (unblinded).
     *  4. Sign a message (blinded).
     *  5. Generate a curve25519 keypair, and convert it to Ed25519.
     */
    ed25519_set_impl_params(use_donna);
    tt_int_op(0, OP_EQ, ed25519_keypair_generate(&kp, i&1));
    tt_int_op(0, OP_EQ, ed25519_keypair_blind(&kp_blind, &kp, blinding));
    tt_int_op(0, OP_EQ, ed25519_sign(&sig, msg, i, &kp));
    tt_int_op(0, OP_EQ, ed25519_sign(&sig_blind, msg, i, &kp_blind));

    tt_int_op(0, OP_EQ, curve25519_keypair_generate(&ckp, i&1));
    tt_int_op(0, OP_EQ, ed25519_keypair_from_curve25519_keypair(
            &kp_curve25519, &bit, &ckp));

    /* Impl. B:
     *  1. Validate the public key by rederiving it.
     *  2. Validate the blinded public key by rederiving it.
     *  3. Validate the unblinded signature (and test a invalid signature).
     *  4. Validate the blinded signature.
     *  5. Validate the public key (from Curve25519) by rederiving it.
     */
    ed25519_set_impl_params(!use_donna);
    tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pk, &kp.seckey));
    tt_mem_op(pk.pubkey, OP_EQ, kp.pubkey.pubkey, 32);

    tt_int_op(0, OP_EQ, ed25519_public_blind(&pk_blind, &kp.pubkey, blinding));
    tt_mem_op(pk_blind.pubkey, OP_EQ, kp_blind.pubkey.pubkey, 32);

    tt_int_op(0, OP_EQ, ed25519_checksig(&sig, msg, i, &pk));
    sig.sig[0] ^= 15;
    tt_int_op(-1, OP_EQ, ed25519_checksig(&sig, msg, sizeof(msg), &pk));

    tt_int_op(0, OP_EQ, ed25519_checksig(&sig_blind, msg, i, &pk_blind));

    tt_int_op(0, OP_EQ, ed25519_public_key_from_curve25519_public_key(
            &pk_curve25519, &ckp.pubkey, bit));
    tt_mem_op(pk_curve25519.pubkey, OP_EQ, kp_curve25519.pubkey.pubkey, 32);
  }

 done:
  ;
}
Ejemplo n.º 8
0
hs_desc_intro_point_t *
hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
                            const char *addr, int legacy)
{
  int ret;
  ed25519_keypair_t auth_kp;
  hs_desc_intro_point_t *intro_point = NULL;
  hs_desc_intro_point_t *ip = hs_desc_intro_point_new();

  /* For a usable intro point we need at least two link specifiers: One legacy
   * keyid and one ipv4 */
  {
    tor_addr_t a;
    tor_addr_make_unspec(&a);
    link_specifier_t *ls_legacy = link_specifier_new();
    link_specifier_t *ls_ip = link_specifier_new();
    link_specifier_set_ls_type(ls_legacy, LS_LEGACY_ID);
    memset(link_specifier_getarray_un_legacy_id(ls_legacy), 'C',
           link_specifier_getlen_un_legacy_id(ls_legacy));
    int family = tor_addr_parse(&a, addr);
    switch (family) {
    case AF_INET:
          link_specifier_set_ls_type(ls_ip, LS_IPV4);
          link_specifier_set_un_ipv4_addr(ls_ip, tor_addr_to_ipv4h(&a));
          link_specifier_set_un_ipv4_port(ls_ip, 9001);
          break;
        case AF_INET6:
          link_specifier_set_ls_type(ls_ip, LS_IPV6);
          memcpy(link_specifier_getarray_un_ipv6_addr(ls_ip),
                 tor_addr_to_in6_addr8(&a),
                 link_specifier_getlen_un_ipv6_addr(ls_ip));
          link_specifier_set_un_ipv6_port(ls_ip, 9001);
          break;
        default:
          /* Stop the test, not supposed to have an error.
           * Compare with -1 to show the actual family.
           */
          tt_int_op(family, OP_EQ, -1);
    }
    smartlist_add(ip->link_specifiers, ls_legacy);
    smartlist_add(ip->link_specifiers, ls_ip);
  }

  ret = ed25519_keypair_generate(&auth_kp, 0);
  tt_int_op(ret, ==, 0);
  ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
                                      &auth_kp.pubkey, now,
                                      HS_DESC_CERT_LIFETIME,
                                      CERT_FLAG_INCLUDE_SIGNING_KEY);
  tt_assert(ip->auth_key_cert);

  if (legacy) {
    ip->legacy.key = crypto_pk_new();
    tt_assert(ip->legacy.key);
    ret = crypto_pk_generate_key(ip->legacy.key);
    tt_int_op(ret, ==, 0);
    ssize_t cert_len = tor_make_rsa_ed25519_crosscert(
                                    &signing_kp->pubkey, ip->legacy.key,
                                    now + HS_DESC_CERT_LIFETIME,
                                    &ip->legacy.cert.encoded);
    tt_assert(ip->legacy.cert.encoded);
    tt_u64_op(cert_len, OP_GT, 0);
    ip->legacy.cert.len = cert_len;
  }

  /* Encryption key. */
  {
    int signbit;
    curve25519_keypair_t curve25519_kp;
    ed25519_keypair_t ed25519_kp;
    tor_cert_t *cross_cert;

    ret = curve25519_keypair_generate(&curve25519_kp, 0);
    tt_int_op(ret, ==, 0);
    ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
                                            &curve25519_kp);
    cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
                                 &ed25519_kp.pubkey, time(NULL),
                                 HS_DESC_CERT_LIFETIME,
                                 CERT_FLAG_INCLUDE_SIGNING_KEY);
    tt_assert(cross_cert);
    ip->enc_key_cert = cross_cert;
  }

  intro_point = ip;
 done:
  if (intro_point == NULL)
    tor_free(ip);

  return intro_point;
}
Ejemplo n.º 9
0
/* Return a valid hs_descriptor_t object. If no_ip is set, no introduction
 * points are added. */
static hs_descriptor_t *
hs_helper_build_hs_desc_impl(unsigned int no_ip,
                             const ed25519_keypair_t *signing_kp)
{
  int ret;
  int i;
  time_t now = approx_time();
  ed25519_keypair_t blinded_kp;
  curve25519_keypair_t auth_ephemeral_kp;
  hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));

  desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;

  /* Copy only the public key into the descriptor. */
  memcpy(&desc->plaintext_data.signing_pubkey, &signing_kp->pubkey,
         sizeof(ed25519_public_key_t));

  uint64_t current_time_period = hs_get_time_period_num(0);
  hs_build_blinded_keypair(signing_kp, NULL, 0,
                           current_time_period, &blinded_kp);
  /* Copy only the public key into the descriptor. */
  memcpy(&desc->plaintext_data.blinded_pubkey, &blinded_kp.pubkey,
         sizeof(ed25519_public_key_t));

  desc->plaintext_data.signing_key_cert =
    tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
                    &signing_kp->pubkey, now, 3600,
                    CERT_FLAG_INCLUDE_SIGNING_KEY);
  tt_assert(desc->plaintext_data.signing_key_cert);
  desc->plaintext_data.revision_counter = 42;
  desc->plaintext_data.lifetime_sec = 3 * 60 * 60;

  hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey,
                    desc->subcredential);

  /* Setup superencrypted data section. */
  ret = curve25519_keypair_generate(&auth_ephemeral_kp, 0);
  tt_int_op(ret, ==, 0);
  memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey,
         &auth_ephemeral_kp.pubkey,
         sizeof(curve25519_public_key_t));

  desc->superencrypted_data.clients = smartlist_new();
  for (i = 0; i < HS_DESC_AUTH_CLIENT_MULTIPLE; i++) {
    hs_desc_authorized_client_t *desc_client =
      hs_desc_build_fake_authorized_client();
    smartlist_add(desc->superencrypted_data.clients, desc_client);
  }

  /* Setup encrypted data section. */
  desc->encrypted_data.create2_ntor = 1;
  desc->encrypted_data.intro_auth_types = smartlist_new();
  desc->encrypted_data.single_onion_service = 1;
  smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
  desc->encrypted_data.intro_points = smartlist_new();
  if (!no_ip) {
    /* Add four intro points. */
    smartlist_add(desc->encrypted_data.intro_points,
              hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0));
/* IPv6-only introduction points are not supported yet, see #23588 */
#if 0
    smartlist_add(desc->encrypted_data.intro_points,
              hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0));
#endif
    smartlist_add(desc->encrypted_data.intro_points,
              hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1));
    smartlist_add(desc->encrypted_data.intro_points,
              hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1));
  }

  descp = desc;
 done:
  if (descp == NULL)
    tor_free(desc);

  return descp;
}
Ejemplo n.º 10
0
/* Test the HS ntor handshake. Simulate the sending of an encrypted INTRODUCE1
 * cell, and verify the proper derivation of decryption keys on the other end.
 * Then simulate the sending of an authenticated RENDEZVOUS1 cell and verify
 * the proper verification on the other end. */
static void
test_hs_ntor(void *arg)
{
  int retval;

  uint8_t subcredential[DIGEST256_LEN];

  ed25519_keypair_t service_intro_auth_keypair;
  curve25519_keypair_t service_intro_enc_keypair;
  curve25519_keypair_t service_ephemeral_rend_keypair;

  curve25519_keypair_t client_ephemeral_enc_keypair;

  hs_ntor_intro_cell_keys_t client_hs_ntor_intro_cell_keys;
  hs_ntor_intro_cell_keys_t service_hs_ntor_intro_cell_keys;

  hs_ntor_rend_cell_keys_t service_hs_ntor_rend_cell_keys;
  hs_ntor_rend_cell_keys_t client_hs_ntor_rend_cell_keys;

  (void) arg;

  /* Generate fake data for this unittest */
  {
    /* Generate fake subcredential */
    memset(subcredential, 'Z', DIGEST256_LEN);

    /* service */
    curve25519_keypair_generate(&service_intro_enc_keypair, 0);
    ed25519_keypair_generate(&service_intro_auth_keypair, 0);
    curve25519_keypair_generate(&service_ephemeral_rend_keypair, 0);
    /* client */
    curve25519_keypair_generate(&client_ephemeral_enc_keypair, 0);
  }

  /* Client: Simulate the sending of an encrypted INTRODUCE1 cell */
  retval =
    hs_ntor_client_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
                                       &service_intro_enc_keypair.pubkey,
                                       &client_ephemeral_enc_keypair,
                                       subcredential,
                                       &client_hs_ntor_intro_cell_keys);
  tt_int_op(retval, OP_EQ, 0);

  /* Service: Simulate the decryption of the received INTRODUCE1 */
  retval =
    hs_ntor_service_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
                                        &service_intro_enc_keypair,
                                        &client_ephemeral_enc_keypair.pubkey,
                                        subcredential,
                                        &service_hs_ntor_intro_cell_keys);
  tt_int_op(retval, OP_EQ, 0);

  /* Test that the INTRODUCE1 encryption/mac keys match! */
  tt_mem_op(client_hs_ntor_intro_cell_keys.enc_key, OP_EQ,
            service_hs_ntor_intro_cell_keys.enc_key,
            CIPHER256_KEY_LEN);
  tt_mem_op(client_hs_ntor_intro_cell_keys.mac_key, OP_EQ,
            service_hs_ntor_intro_cell_keys.mac_key,
            DIGEST256_LEN);

  /* Service: Simulate creation of RENDEZVOUS1 key material. */
  retval =
    hs_ntor_service_get_rendezvous1_keys(&service_intro_auth_keypair.pubkey,
                                         &service_intro_enc_keypair,
                                         &service_ephemeral_rend_keypair,
                                         &client_ephemeral_enc_keypair.pubkey,
                                         &service_hs_ntor_rend_cell_keys);
  tt_int_op(retval, OP_EQ, 0);

  /* Client: Simulate the verification of a received RENDEZVOUS1 cell */
  retval =
    hs_ntor_client_get_rendezvous1_keys(&service_intro_auth_keypair.pubkey,
                                        &client_ephemeral_enc_keypair,
                                        &service_intro_enc_keypair.pubkey,
                                        &service_ephemeral_rend_keypair.pubkey,
                                        &client_hs_ntor_rend_cell_keys);
  tt_int_op(retval, OP_EQ, 0);

  /* Test that the RENDEZVOUS1 key material match! */
  tt_mem_op(client_hs_ntor_rend_cell_keys.rend_cell_auth_mac, OP_EQ,
            service_hs_ntor_rend_cell_keys.rend_cell_auth_mac,
            DIGEST256_LEN);
  tt_mem_op(client_hs_ntor_rend_cell_keys.ntor_key_seed, OP_EQ,
            service_hs_ntor_rend_cell_keys.ntor_key_seed,
            DIGEST256_LEN);
 done:
  ;
}