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


Signed-off-by: David Goulet's avatarDavid Goulet <dgoulet@torproject.org>
parent 8ffb4942
......@@ -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. */
......
......@@ -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 */
......
......@@ -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);
......
......@@ -17,21 +17,66 @@
#include "log_test_helpers.h"
#include "or.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "ht.h"
#include "relay.h"
#include "rendservice.h"
#include "hs_cell.h"
#include "hs_circuitmap.h"
#include "hs_common.h"
#include "hs_intropoint.h"
#include "hs_service.h"
/* Trunnel. */
#include "hs/cell_establish_intro.h"
#include "hs/cell_introduce1.h"
#include "hs/cell_common.h"
#include "hs_service.h"
#include "hs_common.h"
#include "hs_circuitmap.h"
#include "hs_intropoint.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "rendservice.h"
#include "relay.h"
static size_t
new_establish_intro_cell(const char *circ_nonce,
trn_cell_establish_intro_t **cell_out)
{
ssize_t cell_len = 0;
uint8_t buf[RELAY_PAYLOAD_SIZE] = {0};
trn_cell_establish_intro_t *cell = NULL;
hs_service_intro_point_t *ip = NULL;
/* Auth key pair is generated in the constructor so we are all set for
* using this IP object. */
ip = service_intro_point_new(NULL, 0);
tt_assert(ip);
cell_len = hs_cell_build_establish_intro(circ_nonce, ip, buf);
tt_u64_op(cell_len, OP_GT, 0);
cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf));
tt_int_op(cell_len, OP_GT, 0);
tt_assert(cell);
*cell_out = cell;
done:
service_intro_point_free(ip);
return cell_len;
}
static ssize_t
new_establish_intro_encoded_cell(const char *circ_nonce, uint8_t *cell_out)
{
ssize_t cell_len = 0;
hs_service_intro_point_t *ip = NULL;
/* Auth key pair is generated in the constructor so we are all set for
* using this IP object. */
ip = service_intro_point_new(NULL, 0);
tt_assert(ip);
cell_len = hs_cell_build_establish_intro(circ_nonce, ip, cell_out);
tt_u64_op(cell_len, OP_GT, 0);
done:
service_intro_point_free(ip);
return cell_len;
}
/* Mock function to avoid networking in unittests */
static int
......@@ -122,29 +167,24 @@ static void
test_establish_intro_wrong_purpose(void *arg)
{
int retval;
trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
char circ_nonce[DIGEST_LEN] = {0};
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
(void)arg;
/* Get the auth key of the intro point */
crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
memcpy(intro_circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN);
crypto_rand(circ_nonce, sizeof(circ_nonce));
memcpy(intro_circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
/* Set a bad circuit purpose!! :) */
circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT);
/* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
attempt to parse it. */
establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
sizeof(circuit_key_material));
tt_assert(establish_intro_cell);
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
establish_intro_cell);
tt_int_op(cell_len, >, 0);
cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
tt_u64_op(cell_len, OP_GT, 0);
/* Receive the cell. Should fail. */
setup_full_capture_of_logs(LOG_INFO);
......@@ -154,18 +194,16 @@ test_establish_intro_wrong_purpose(void *arg)
tt_int_op(retval, ==, -1);
done:
trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
/* Prepare a circuit for accepting an ESTABLISH_INTRO cell */
static void
helper_prepare_circ_for_intro(or_circuit_t *circ,
uint8_t *circuit_key_material)
helper_prepare_circ_for_intro(or_circuit_t *circ, const char *circ_nonce)
{
/* Prepare the circuit for the incoming ESTABLISH_INTRO */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
memcpy(circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN);
memcpy(circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
}
/* Send an empty ESTABLISH_INTRO cell. Should fail. */
......@@ -174,17 +212,17 @@ test_establish_intro_wrong_keytype(void *arg)
{
int retval;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
char circ_nonce[DIGEST_LEN] = {0};
(void)arg;
(void) arg;
/* Get the auth key of the intro point */
crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
crypto_rand(circ_nonce, sizeof(circ_nonce));
helper_prepare_circ_for_intro(intro_circ, circ_nonce);
/* Receive the cell. Should fail. */
setup_full_capture_of_logs(LOG_INFO);
retval = hs_intro_received_establish_intro(intro_circ, (uint8_t*)"", 0);
retval = hs_intro_received_establish_intro(intro_circ, (uint8_t *) "", 0);
expect_log_msg_containing("Empty ESTABLISH_INTRO cell.");
teardown_capture_of_logs();
tt_int_op(retval, ==, -1);
......@@ -198,26 +236,21 @@ static void
test_establish_intro_wrong_keytype2(void *arg)
{
int retval;
trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
char circ_nonce[DIGEST_LEN] = {0};
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
(void)arg;
(void) arg;
/* Get the auth key of the intro point */
crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
crypto_rand(circ_nonce, sizeof(circ_nonce));
helper_prepare_circ_for_intro(intro_circ, circ_nonce);
/* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
attempt to parse it. */
establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
sizeof(circuit_key_material));
tt_assert(establish_intro_cell);
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
establish_intro_cell);
tt_int_op(cell_len, >, 0);
* attempt to parse it. */
cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
tt_u64_op(cell_len, OP_GT, 0);
/* Mutate the auth key type! :) */
cell_body[0] = 42;
......@@ -230,7 +263,6 @@ test_establish_intro_wrong_keytype2(void *arg)
tt_int_op(retval, ==, -1);
done:
trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
......@@ -239,26 +271,27 @@ static void
test_establish_intro_wrong_mac(void *arg)
{
int retval;
trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
char circ_nonce[DIGEST_LEN] = {0};
ssize_t cell_len = 0;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
trn_cell_establish_intro_t *cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
(void)arg;
(void) arg;
/* Get the auth key of the intro point */
crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
crypto_rand(circ_nonce, sizeof(circ_nonce));
helper_prepare_circ_for_intro(intro_circ, circ_nonce);
/* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
attempt to parse it. */
establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
sizeof(circuit_key_material));
tt_assert(establish_intro_cell);
* attempt to parse it. */
cell_len = new_establish_intro_cell(circ_nonce, &cell);
tt_u64_op(cell_len, OP_GT, 0);
tt_assert(cell);
/* Mangle one byte of the MAC. */
uint8_t *handshake_ptr =
trn_cell_establish_intro_getarray_handshake_mac(establish_intro_cell);
trn_cell_establish_intro_getarray_handshake_mac(cell);
handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++;
/* We need to resign the payload with that change. */
{
......@@ -269,26 +302,26 @@ test_establish_intro_wrong_mac(void *arg)
retval = ed25519_keypair_generate(&key_struct, 0);
tt_int_op(retval, OP_EQ, 0);
uint8_t *auth_key_ptr =
trn_cell_establish_intro_getarray_auth_key(establish_intro_cell);
trn_cell_establish_intro_getarray_auth_key(cell);
memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN);
/* Encode payload so we can sign it. */
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
establish_intro_cell);
tt_int_op(cell_len, >, 0);
cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
cell);
tt_int_op(cell_len, OP_GT, 0);
retval = ed25519_sign_prefixed(&sig, cell_body,
cell_len -
(ED25519_SIG_LEN +
sizeof(establish_intro_cell->sig_len)),
(ED25519_SIG_LEN + sizeof(cell->sig_len)),
ESTABLISH_INTRO_SIG_PREFIX, &key_struct);
tt_int_op(retval, OP_EQ, 0);
/* And write the signature to the cell */
uint8_t *sig_ptr =
trn_cell_establish_intro_getarray_sig(establish_intro_cell);
memcpy(sig_ptr, sig.sig, establish_intro_cell->sig_len);
trn_cell_establish_intro_getarray_sig(cell);
memcpy(sig_ptr, sig.sig, cell->sig_len);
/* Re-encode with the new signature. */
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
establish_intro_cell);
cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
cell);
tt_int_op(cell_len, OP_GT, 0);
}
/* Receive the cell. Should fail because our MAC is wrong. */
......@@ -299,7 +332,7 @@ test_establish_intro_wrong_mac(void *arg)
tt_int_op(retval, ==, -1);
done:
trn_cell_establish_intro_free(establish_intro_cell);
trn_cell_establish_intro_free(cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
......@@ -309,32 +342,32 @@ static void
test_establish_intro_wrong_auth_key_len(void *arg)
{
int retval;
trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
char circ_nonce[DIGEST_LEN] = {0};
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
size_t bad_auth_key_len = ED25519_PUBKEY_LEN - 1;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
trn_cell_establish_intro_t *cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
(void)arg;
(void) arg;
/* Get the auth key of the intro point */
crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
crypto_rand(circ_nonce, sizeof(circ_nonce));
helper_prepare_circ_for_intro(intro_circ, circ_nonce);
/* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
attempt to parse it. */
establish_intro_cell = generate_establish_intro_cell(circuit_key_material,