示例#1
0
static void
test_introduce1_suitable_circuit(void *arg)
{
  int ret;
  or_circuit_t *circ = NULL;

  (void) arg;

  /* Valid suitable circuit. */
  {
    circ = or_circuit_new(0, NULL);
    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    ret = circuit_is_suitable_for_introduce1(circ);
    circuit_free_(TO_CIRCUIT(circ));
    tt_int_op(ret, OP_EQ, 1);
  }

  /* Test if the circuit purpose safeguard works correctly. */
  {
    circ = or_circuit_new(0, NULL);
    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
    ret = circuit_is_suitable_for_introduce1(circ);
    circuit_free_(TO_CIRCUIT(circ));
    tt_int_op(ret, OP_EQ, 0);
  }

  /* Test the non-edge circuit safeguard works correctly. */
  {
    circ = or_circuit_new(0, NULL);
    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    /* Bogus pointer, the check is against NULL on n_chan. */
    circ->base_.n_chan = (channel_t *) circ;
    ret = circuit_is_suitable_for_introduce1(circ);
    circuit_free_(TO_CIRCUIT(circ));
    tt_int_op(ret, OP_EQ, 0);
  }

  /* Mangle the circuit a bit more so see if our only one INTRODUCE1 cell
   * limit works correctly. */
  {
    circ = or_circuit_new(0, NULL);
    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    circ->already_received_introduce1 = 1;
    ret = circuit_is_suitable_for_introduce1(circ);
    circuit_free_(TO_CIRCUIT(circ));
    tt_int_op(ret, OP_EQ, 0);
  }

 done:
  ;
}
示例#2
0
/* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should
 * fail. */
static void
test_establish_intro_wrong_sig(void *arg)
{
  int retval;
  char circ_nonce[DIGEST_LEN] = {0};
  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  ssize_t cell_len = 0;
  or_circuit_t *intro_circ = or_circuit_new(0,NULL);

  (void) arg;

  /* Get the auth key of the intro point */
  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. */
  cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
  tt_i64_op(cell_len, OP_GT, 0);

  /* Mutate the last byte (signature)! :) */
  cell_body[cell_len - 1]++;

  /* Receive the cell. Should fail. */
  setup_full_capture_of_logs(LOG_INFO);
  retval = hs_intro_received_establish_intro(intro_circ, cell_body,
                                             (size_t)cell_len);
  expect_log_msg_containing("Failed to verify ESTABLISH_INTRO cell.");
  teardown_capture_of_logs();
  tt_int_op(retval, OP_EQ, -1);

 done:
  circuit_free_(TO_CIRCUIT(intro_circ));
}
示例#3
0
/* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro
 * point. Should fail. */
static void
test_establish_intro_wrong_purpose(void *arg)
{
  int retval;
  ssize_t cell_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(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. */
  cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
  tt_i64_op(cell_len, OP_GT, 0);

  /* Receive the cell. Should fail. */
  setup_full_capture_of_logs(LOG_INFO);
  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  expect_log_msg_containing("Rejecting ESTABLISH_INTRO on non-OR circuit.");
  teardown_capture_of_logs();
  tt_int_op(retval, OP_EQ, -1);

 done:
  circuit_free_(TO_CIRCUIT(intro_circ));
}
示例#4
0
文件: test.c 项目: ageis/tor
/** Run unit tests for the onion queues. */
static void
test_onion_queues(void *arg)
{
  uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
  uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0};

  or_circuit_t *circ1 = or_circuit_new(0, NULL);
  or_circuit_t *circ2 = or_circuit_new(0, NULL);

  create_cell_t *onionskin = NULL, *create2_ptr;
  create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t));
  create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
  (void)arg;
  create2_ptr = create2; /* remember, but do not free */

  create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
                   TAP_ONIONSKIN_CHALLENGE_LEN, buf1);
  create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
                   NTOR_ONIONSKIN_LEN, buf2);

  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
  tt_int_op(0,OP_EQ, onion_pending_add(circ1, create1));
  create1 = NULL;
  tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));

  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
  tt_int_op(0,OP_EQ, onion_pending_add(circ2, create2));
  create2 = NULL;
  tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));

  tt_ptr_op(circ2,OP_EQ, onion_next_task(&onionskin));
  tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
  tt_ptr_op(onionskin, OP_EQ, create2_ptr);

  clear_pending_onions();
  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));

 done:
  circuit_free_(TO_CIRCUIT(circ1));
  circuit_free_(TO_CIRCUIT(circ2));
  tor_free(create1);
  tor_free(create2);
  tor_free(onionskin);
}
示例#5
0
static void
test_halfstream_wrap(void *arg)
{
  origin_circuit_t *circ =
      helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
  edge_connection_t *edgeconn;
  entry_connection_t *entryconn;

  circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
  circ->cpath->deliver_window = CIRCWINDOW_START;

  entryconn = fake_entry_conn(circ, 23);
  edgeconn = ENTRY_TO_EDGE_CONN(entryconn);

  (void)arg;

  /* Suppress the WARN message we generate in this test */
  setup_full_capture_of_logs(LOG_WARN);
  MOCK(connection_mark_for_close_internal_, mock_mark_for_close);

  /* Verify that get_unique_stream_id_by_circ() can wrap uint16_t */
  circ->next_stream_id = 65530;
  halfstream_insert(circ, edgeconn, NULL, 7, 0);
  tt_int_op(circ->next_stream_id, OP_EQ, 2);
  tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 7);

  /* Insert full-1 */
  halfstream_insert(circ, edgeconn, NULL,
                    65534-smartlist_len(circ->half_streams), 0);
  tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65534);

  /* Verify that we can get_unique_stream_id_by_circ() successfully */
  edgeconn->stream_id = get_unique_stream_id_by_circ(circ);
  tt_int_op(edgeconn->stream_id, OP_NE, 0); /* 0 is failure */

  /* Insert an opened stream on the circ with that id */
  ENTRY_TO_CONN(entryconn)->marked_for_close = 0;
  ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0;
  edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
  circ->p_streams = edgeconn;

  /* Verify that get_unique_stream_id_by_circ() fails */
  tt_int_op(get_unique_stream_id_by_circ(circ), OP_EQ, 0); /* 0 is failure */

  /* eof the one opened stream. Verify it is now in half-closed */
  tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65534);
  connection_edge_reached_eof(edgeconn);
  tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65535);

  /* Verify get_unique_stream_id_by_circ() fails due to full half-closed */
  circ->p_streams = NULL;
  tt_int_op(get_unique_stream_id_by_circ(circ), OP_EQ, 0); /* 0 is failure */

 done:
  circuit_free_(TO_CIRCUIT(circ));
  connection_free_minimal(ENTRY_TO_CONN(entryconn));
  UNMOCK(connection_mark_for_close_internal_);
}
示例#6
0
static void
test_circuit_n_cells(void *arg)
{
  packed_cell_t *pc1=NULL, *pc2=NULL, *pc3=NULL, *pc4=NULL, *pc5=NULL;
  origin_circuit_t *origin_c=NULL;
  or_circuit_t *or_c=NULL;

  (void)arg;

  pc1 = packed_cell_new();
  pc2 = packed_cell_new();
  pc3 = packed_cell_new();
  pc4 = packed_cell_new();
  pc5 = packed_cell_new();
  tt_assert(pc1 && pc2 && pc3 && pc4 && pc5);

  or_c = or_circuit_new(0, NULL);
  origin_c = origin_circuit_new();
  origin_c->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;

  tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), OP_EQ, 0);
  cell_queue_append(&or_c->p_chan_cells, pc1);
  tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), OP_EQ, 1);
  cell_queue_append(&or_c->base_.n_chan_cells, pc2);
  cell_queue_append(&or_c->base_.n_chan_cells, pc3);
  tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), OP_EQ, 3);

  tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), OP_EQ, 0);
  cell_queue_append(&origin_c->base_.n_chan_cells, pc4);
  cell_queue_append(&origin_c->base_.n_chan_cells, pc5);
  tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), OP_EQ, 2);

 done:
  circuit_free_(TO_CIRCUIT(or_c));
  circuit_free_(TO_CIRCUIT(origin_c));
}
示例#7
0
/* Send a legit ESTABLISH_INTRO cell but with a wrong sig length. Should
 * fail. */
static void
test_establish_intro_wrong_sig_len(void *arg)
{
  int retval;
  char circ_nonce[DIGEST_LEN] = {0};
  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  ssize_t cell_len = 0;
  size_t bad_sig_len = ED25519_SIG_LEN - 1;
  trn_cell_establish_intro_t *cell = NULL;
  or_circuit_t *intro_circ = or_circuit_new(0,NULL);

  (void) arg;

  /* Get the auth key of the intro point */
  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. */
  cell_len = new_establish_intro_cell(circ_nonce, &cell);
  tt_i64_op(cell_len, OP_GT, 0);
  tt_assert(cell);

  /* Mangle the signature length. */
  trn_cell_establish_intro_set_sig_len(cell, bad_sig_len);
  trn_cell_establish_intro_setlen_sig(cell, bad_sig_len);
  /* Encode 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. */
  setup_full_capture_of_logs(LOG_INFO);
  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  expect_log_msg_containing("ESTABLISH_INTRO sig len is invalid");
  teardown_capture_of_logs();
  tt_int_op(retval, OP_EQ, -1);

 done:
  trn_cell_establish_intro_free(cell);
  circuit_free_(TO_CIRCUIT(intro_circ));
}
示例#8
0
/* Send an empty ESTABLISH_INTRO cell. Should fail. */
static void
test_establish_intro_wrong_keytype(void *arg)
{
  int retval;
  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
  char circ_nonce[DIGEST_LEN] = {0};

  (void) arg;

  /* Get the auth key of the intro point */
  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);
  expect_log_msg_containing("Empty ESTABLISH_INTRO cell.");
  teardown_capture_of_logs();
  tt_int_op(retval, OP_EQ, -1);

 done:
  circuit_free_(TO_CIRCUIT(intro_circ));
}
示例#9
0
/* Test outbound cell. The callstack is:
 *  channel_flush_some_cells()
 *   -> channel_flush_from_first_active_circuit()
 *     -> channel_write_packed_cell()
 *       -> write_packed_cell()
 *         -> chan->write_packed_cell() fct ptr.
 *
 * This test goes from a cell in a circuit up to the channel write handler
 * that should put them on the connection outbuf. */
static void
test_channel_outbound_cell(void *arg)
{
  int old_count;
  channel_t *chan = NULL;
  packed_cell_t *p_cell = NULL, *p_cell2 = NULL;
  origin_circuit_t *circ = NULL;
  cell_queue_t *queue;

  (void) arg;

  /* Set the test time to be mocked, since this test assumes that no
   * time will pass, ewma values will not need to be re-scaled, and so on */
  monotime_enable_test_mocking();
  monotime_set_mock_time_nsec(U64_LITERAL(1000000000) * 12345);

  cmux_ewma_set_options(NULL,NULL);

  /* The channel will be freed so we need to hijack this so the scheduler
   * doesn't get confused. */
  MOCK(scheduler_release_channel, scheduler_release_channel_mock);

  /* Accept cells to lower layer */
  test_chan_accept_cells = 1;

  /* Setup a valid circuit to queue a cell. */
  circ = origin_circuit_new();
  tt_assert(circ);
  /* Circuit needs an origin purpose to be considered origin. */
  TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
  TO_CIRCUIT(circ)->n_circ_id = 42;
  /* This is the outbound test so use the next channel queue. */
  queue = &TO_CIRCUIT(circ)->n_chan_cells;
  /* Setup packed cell to queue on the circuit. */
  p_cell = packed_cell_new();
  tt_assert(p_cell);
  p_cell2 = packed_cell_new();
  tt_assert(p_cell2);
  /* Setup a channel to put the circuit on. */
  chan = new_fake_channel();
  tt_assert(chan);
  chan->state = CHANNEL_STATE_OPENING;
  channel_change_state_open(chan);
  /* Outbound channel. */
  channel_mark_outgoing(chan);
  /* Try to register it so we can clean it through the channel cleanup
   * process. */
  channel_register(chan);
  tt_int_op(chan->registered, OP_EQ, 1);
  /* Set EWMA policy so we can pick it when flushing. */
  circuitmux_set_policy(chan->cmux, &ewma_policy);
  tt_ptr_op(circuitmux_get_policy(chan->cmux), OP_EQ, &ewma_policy);

  /* Register circuit to the channel circid map which will attach the circuit
   * to the channel's cmux as well. */
  circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan);
  tt_int_op(channel_num_circuits(chan), OP_EQ, 1);
  /* Test the cmux state. */
  tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux);
  tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);

  /* Flush the channel without any cell on it. */
  old_count = test_cells_written;
  ssize_t flushed = channel_flush_some_cells(chan, 1);
  tt_i64_op(flushed, OP_EQ, 0);
  tt_int_op(test_cells_written, OP_EQ, old_count);
  tt_int_op(channel_more_to_flush(chan), OP_EQ, 0);
  tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 0);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0);
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 0);
  tt_u64_op(chan->n_cells_xmitted, OP_EQ, 0);
  tt_u64_op(chan->n_bytes_xmitted, OP_EQ, 0);

  /* Queue cell onto the next queue that is the outbound direction. Than
   * update its cmux so the circuit can be picked when flushing cells. */
  cell_queue_append(queue, p_cell);
  p_cell = NULL;
  tt_int_op(queue->n, OP_EQ, 1);
  cell_queue_append(queue, p_cell2);
  p_cell2 = NULL;
  tt_int_op(queue->n, OP_EQ, 2);

  update_circuit_on_cmux(TO_CIRCUIT(circ), CELL_DIRECTION_OUT);
  tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 1);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 2);
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);

  /* From this point on, we have a queued cell on an active circuit attached
   * to the channel's cmux. */

  /* Flush the first cell. This is going to go down the call stack. */
  old_count = test_cells_written;
  flushed = channel_flush_some_cells(chan, 1);
  tt_i64_op(flushed, OP_EQ, 1);
  tt_int_op(test_cells_written, OP_EQ, old_count + 1);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 1);
  tt_int_op(channel_more_to_flush(chan), OP_EQ, 1);
  /* Circuit should remain active because there is a second cell queued. */
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);
  /* Should still be attached. */
  tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);
  tt_u64_op(chan->n_cells_xmitted, OP_EQ, 1);
  tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0));

  /* Flush second cell. This is going to go down the call stack. */
  old_count = test_cells_written;
  flushed = channel_flush_some_cells(chan, 1);
  tt_i64_op(flushed, OP_EQ, 1);
  tt_int_op(test_cells_written, OP_EQ, old_count + 1);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0);
  tt_int_op(channel_more_to_flush(chan), OP_EQ, 0);
  /* No more cells should make the circuit inactive. */
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 0);
  /* Should still be attached. */
  tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);
  tt_u64_op(chan->n_cells_xmitted, OP_EQ, 2);
  tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0) * 2);

 done:
  if (circ) {
    circuit_free_(TO_CIRCUIT(circ));
  }
  tor_free(p_cell);
  channel_free_all();
  UNMOCK(scheduler_release_channel);
  monotime_disable_test_mocking();
}
示例#10
0
static void
test_circbw_relay(void *arg)
{
  cell_t cell;
  relay_header_t rh;
  tor_addr_t addr;
  edge_connection_t *edgeconn;
  entry_connection_t *entryconn1=NULL;
  origin_circuit_t *circ;
  int delivered = 0;
  int overhead = 0;

  (void)arg;

  MOCK(connection_mark_unattached_ap_, mock_connection_mark_unattached_ap_);
  MOCK(connection_start_reading, mock_start_reading);
  MOCK(connection_mark_for_close_internal_, mock_mark_for_close);
  MOCK(relay_send_command_from_edge_, mock_send_command);
  MOCK(circuit_mark_for_close_, mock_mark_circ_for_close);

  circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
  circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
  circ->cpath->deliver_window = CIRCWINDOW_START;

  entryconn1 = fake_entry_conn(circ, 1);
  edgeconn = ENTRY_TO_EDGE_CONN(entryconn1);

  /* Stream id 0: Not counted */
  PACK_CELL(0, RELAY_COMMAND_END, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Stream id 1: Counted */
  PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  /* Properly formatted connect cell: counted */
  PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234");
  tor_addr_parse(&addr, "30.40.50.60");
  rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
                                            &addr, 1024);
  relay_header_pack((uint8_t*)&cell.payload, &rh);                    \
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  /* Properly formatted resolved cell in correct state: counted */
  edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
  entryconn1->socks_request->command = SOCKS_COMMAND_RESOLVE;
  edgeconn->on_circuit = TO_CIRCUIT(circ);
  PACK_CELL(1, RELAY_COMMAND_RESOLVED,
            "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  edgeconn->base_.state = AP_CONN_STATE_OPEN;
  entryconn1->socks_request->has_finished = 1;

  /* Connected cell after open: not counted */
  PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Resolved cell after open: not counted */
  PACK_CELL(1, RELAY_COMMAND_RESOLVED, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Drop cell: not counted */
  PACK_CELL(1, RELAY_COMMAND_DROP, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Data cell on stream 0: not counted */
  PACK_CELL(0, RELAY_COMMAND_DATA, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Data cell on open connection: counted */
  ENTRY_TO_CONN(entryconn1)->marked_for_close = 0;
  PACK_CELL(1, RELAY_COMMAND_DATA, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  /* Empty Data cell on open connection: not counted */
  ENTRY_TO_CONN(entryconn1)->marked_for_close = 0;
  PACK_CELL(1, RELAY_COMMAND_DATA, "");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Sendme on valid stream: counted */
  edgeconn->package_window -= STREAMWINDOW_INCREMENT;
  ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
  PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  /* Sendme on valid stream with full window: not counted */
  ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
  PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
  edgeconn->package_window = STREAMWINDOW_START;
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Sendme on unknown stream: not counted */
  ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
  PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Sendme on circuit with full window: not counted */
  PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Sendme on circuit with non-full window: counted */
  PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234");
  circ->cpath->package_window = 900;
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  /* Invalid extended cell: not counted */
  PACK_CELL(1, RELAY_COMMAND_EXTENDED2, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Invalid extended cell: not counted */
  PACK_CELL(1, RELAY_COMMAND_EXTENDED, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Invalid HS cell: not counted */
  PACK_CELL(1, RELAY_COMMAND_ESTABLISH_INTRO, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* "Valid" HS cell in expected state: counted */
  TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
  PACK_CELL(1, RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  /* End cell on non-closed connection: counted */
  PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
                                     circ->cpath);
  ASSERT_COUNTED_BW();

  /* End cell on connection that already got one: not counted */
  PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
  connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
                                     circ->cpath);
  ASSERT_UNCOUNTED_BW();

  /* Simulate closed stream on entryconn, then test: */
  if (!subtest_circbw_halfclosed(circ, 2))
    goto done;

  circ->base_.purpose = CIRCUIT_PURPOSE_PATH_BIAS_TESTING;
  if (!subtest_circbw_halfclosed(circ, 6))
    goto done;

  /* Path bias: truncated */
  tt_int_op(circ->base_.marked_for_close, OP_EQ, 0);
  PACK_CELL(0, RELAY_COMMAND_TRUNCATED, "Data1234");
  pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
  tt_int_op(circ->base_.marked_for_close, OP_EQ, 1);

 done:
  UNMOCK(connection_start_reading);
  UNMOCK(connection_mark_unattached_ap_);
  UNMOCK(connection_mark_for_close_internal_);
  UNMOCK(relay_send_command_from_edge_);
  UNMOCK(circuit_mark_for_close_);
  circuit_free_(TO_CIRCUIT(circ));
  connection_free_minimal(ENTRY_TO_CONN(entryconn1));
}
示例#11
0
static void
subtest_halfstream_insertremove(int num)
{
  origin_circuit_t *circ =
      helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
  edge_connection_t *edgeconn;
  entry_connection_t *entryconn;
  streamid_t *streams = tor_malloc_zero(num*sizeof(streamid_t));
  int i = 0;

  circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
  circ->cpath->deliver_window = CIRCWINDOW_START;

  entryconn = fake_entry_conn(circ, 23);
  edgeconn = ENTRY_TO_EDGE_CONN(entryconn);

  /* Explicity test all operations on an absent stream list */
  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 0);

  /* Insert a duplicate element; verify that other elements absent;
   * ensure removing it once works */
  edgeconn->stream_id = 23;
  connection_half_edge_add(edgeconn, circ);
  connection_half_edge_add(edgeconn, circ);
  connection_half_edge_add(edgeconn, circ);

  /* Verify that other elements absent */
  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            22), OP_EQ, 0);

  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            24), OP_EQ, 0);

  /* Verify we only remove it once */
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 1);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 0);

  halfstream_insert(circ, edgeconn, streams, num, 1);

  /* Remove half of them */
  for (i = 0; i < num/2; i++) {
    tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
                                                streams[i]),
              OP_EQ, 1);
  }

  /* Verify first half of list is gone */
  for (i = 0; i < num/2; i++) {
    tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams,
                                                  streams[i]),
              OP_EQ, NULL);
  }

  /* Verify second half of list is present */
  for (; i < num; i++) {
    tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams,
                                                  streams[i]),
              OP_NE, NULL);
  }

  /* Remove other half. Verify list is empty. */
  for (i = num/2; i < num; i++) {
    tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
                                                streams[i]),
              OP_EQ, 1);
  }
  tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 0);

  /* Explicity test all operations on an empty stream list */
  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 0);

  /* For valgrind, leave some around then free the circ */
  halfstream_insert(circ, edgeconn, NULL, 10, 0);

 done:
  tor_free(streams);
  circuit_free_(TO_CIRCUIT(circ));
  connection_free_minimal(ENTRY_TO_CONN(entryconn));
}
示例#12
0
void
test_circuitstats_hoplen(void *arg)
{
  /* Plan:
   *   0. Test no other opened circs (relaxed timeout)
   *   1. Check >3 hop circ building w/o timeout
   *   2. Check >3 hop circs w/ timeouts..
   */
  struct timeval circ_start_time;
  origin_circuit_t *threehop = NULL;
  origin_circuit_t *fourhop = NULL;
  (void)arg;
  MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);

  circuit_build_times_init(get_circuit_build_times_mutable());

  // Let's set a close_ms to 2X the initial timeout, so we can
  // test relaxed functionality (which uses the close_ms timeout)
  get_circuit_build_times_mutable()->close_ms *= 2;

  tor_gettimeofday(&circ_start_time);
  circ_start_time.tv_sec -= 119; // make us hit "relaxed" cutoff

  // Test 1: Build a fourhop circuit that should get marked
  // as relaxed and eventually counted by circuit_expire_building
  // (but not before)
  fourhop = subtest_fourhop_circuit(circ_start_time, 0);
  tt_int_op(fourhop->relaxed_timeout, OP_EQ, 0);
  tt_int_op(marked_for_close, OP_EQ, 0);
  circuit_expire_building();
  tt_int_op(marked_for_close, OP_EQ, 0);
  tt_int_op(fourhop->relaxed_timeout, OP_EQ, 1);
  TO_CIRCUIT(fourhop)->timestamp_began.tv_sec -= 119;
  circuit_expire_building();
  tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);
  tt_int_op(marked_for_close, OP_EQ, 1);

  circuit_free_(TO_CIRCUIT(fourhop));
  circuit_build_times_reset(get_circuit_build_times_mutable());

  // Test 2: Add a threehop circuit for non-relaxed timeouts
  threehop = add_opened_threehop();

  /* This circuit should not timeout */
  tor_gettimeofday(&circ_start_time);
  circ_start_time.tv_sec -= 59;
  fourhop = subtest_fourhop_circuit(circ_start_time, 0);
  circuit_expire_building();
  tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);
  tt_int_op(TO_CIRCUIT(fourhop)->purpose, OP_NE,
            CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);

  circuit_free_((circuit_t *)fourhop);
  circuit_build_times_reset(get_circuit_build_times_mutable());

  /* Test 3: This circuit should now time out and get marked as a
   * measurement circuit, but still get counted (and counted only once)
   */
  circ_start_time.tv_sec -= 2;
  fourhop = subtest_fourhop_circuit(circ_start_time, 0);
  tt_int_op(TO_CIRCUIT(fourhop)->purpose, OP_EQ,
            CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);
  tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);
  circuit_expire_building();
  tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);

 done:
  UNMOCK(circuit_mark_for_close_);
  circuit_free_(TO_CIRCUIT(threehop));
  circuit_free_(TO_CIRCUIT(fourhop));
  circuit_build_times_free_timeouts(get_circuit_build_times_mutable());
}
示例#13
0
static void
test_received_introduce1_handling(void *arg)
{
  int ret;
  uint8_t *request = NULL, buf[128];
  trn_cell_introduce1_t *cell = NULL;
  or_circuit_t *circ = NULL;

  (void) arg;

  MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);

  hs_circuitmap_init();

  /* Too small request length. An INTRODUCE1 expect at the very least a
   * DIGEST_LEN size. */
  {
    memset(buf, 0, sizeof(buf));
    circ = helper_create_intro_circuit();
    ret = hs_intro_received_introduce1(circ, buf, DIGEST_LEN - 1);
    tt_int_op(ret, OP_EQ, -1);
    circuit_free_(TO_CIRCUIT(circ));
  }

  /* We have a unit test only for the suitability of a circuit to receive an
   * INTRODUCE1 cell so from now on we'll only test the handling of a cell. */

  /* Bad request. */
  {
    circ = helper_create_intro_circuit();
    uint8_t test[2]; /* Too small request. */
    memset(test, 0, sizeof(test));
    ret = handle_introduce1(circ, test, sizeof(test));
    tor_free(circ->p_chan);
    circuit_free_(TO_CIRCUIT(circ));
    tt_int_op(ret, OP_EQ, -1);
  }

  /* Valid case. */
  {
    cell = helper_create_introduce1_cell();
    ssize_t request_len = trn_cell_introduce1_encoded_len(cell);
    tt_int_op((int)request_len, OP_GT, 0);
    request = tor_malloc_zero(request_len);
    ssize_t encoded_len =
      trn_cell_introduce1_encode(request, request_len, cell);
    tt_int_op((int)encoded_len, OP_GT, 0);

    circ = helper_create_intro_circuit();
    or_circuit_t *service_circ = helper_create_intro_circuit();
    circuit_change_purpose(TO_CIRCUIT(service_circ),
                           CIRCUIT_PURPOSE_INTRO_POINT);
    /* Register the circuit in the map for the auth key of the cell. */
    ed25519_public_key_t auth_key;
    const uint8_t *cell_auth_key =
      trn_cell_introduce1_getconstarray_auth_key(cell);
    memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN);
    hs_circuitmap_register_intro_circ_v3_relay_side(service_circ, &auth_key);
    ret = hs_intro_received_introduce1(circ, request, request_len);
    circuit_free_(TO_CIRCUIT(circ));
    circuit_free_(TO_CIRCUIT(service_circ));
    tt_int_op(ret, OP_EQ, 0);
  }

  /* Valid legacy cell. */
  {
    tor_free(request);
    trn_cell_introduce1_free(cell);
    cell = helper_create_introduce1_cell();
    uint8_t *legacy_key_id = trn_cell_introduce1_getarray_legacy_key_id(cell);
    memset(legacy_key_id, 'a', DIGEST_LEN);
    /* Add an arbitrary amount of data for the payload of a v2 cell. */
    size_t request_len = trn_cell_introduce1_encoded_len(cell) + 256;
    tt_size_op(request_len, OP_GT, 0);
    request = tor_malloc_zero(request_len + 256);
    ssize_t encoded_len =
      trn_cell_introduce1_encode(request, request_len, cell);
    tt_int_op((int)encoded_len, OP_GT, 0);

    circ = helper_create_intro_circuit();
    or_circuit_t *service_circ = helper_create_intro_circuit();
    circuit_change_purpose(TO_CIRCUIT(service_circ),
                           CIRCUIT_PURPOSE_INTRO_POINT);
    /* Register the circuit in the map for the auth key of the cell. */
    uint8_t token[REND_TOKEN_LEN];
    memcpy(token, legacy_key_id, sizeof(token));
    hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token);
    ret = hs_intro_received_introduce1(circ, request, request_len);
    circuit_free_(TO_CIRCUIT(circ));
    circuit_free_(TO_CIRCUIT(service_circ));
    tt_int_op(ret, OP_EQ, 0);
  }

 done:
  trn_cell_introduce1_free(cell);
  tor_free(request);
  hs_circuitmap_free_all();
  UNMOCK(relay_send_command_from_edge_);
}
示例#14
0
/** Successfully register a v2 intro point and a v3 intro point. Ensure that HS
 *  circuitmap is maintained properly. */
static void
test_intro_point_registration(void *arg)
{
  int retval;
  hs_circuitmap_ht *the_hs_circuitmap = NULL;

  or_circuit_t *intro_circ = NULL;
  trn_cell_establish_intro_t *establish_intro_cell = NULL;
  ed25519_public_key_t auth_key;

  crypto_pk_t *legacy_auth_key = NULL;
  or_circuit_t *legacy_intro_circ = NULL;

  or_circuit_t *returned_intro_circ = NULL;

  (void) arg;

  MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);

  hs_circuitmap_init();

  /* Check that the circuitmap is currently empty */
  {
    the_hs_circuitmap = get_hs_circuitmap();
    tt_assert(the_hs_circuitmap);
    tt_int_op(0, OP_EQ, HT_SIZE(the_hs_circuitmap));
    /* Do a circuitmap query in any case */
    returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
    tt_ptr_op(returned_intro_circ, OP_EQ, NULL);
  }

  /* Create a v3 intro point */
  {
    intro_circ = or_circuit_new(0, NULL);
    tt_assert(intro_circ);
    establish_intro_cell = helper_establish_intro_v3(intro_circ);

    /* Check that the intro point was registered on the HS circuitmap */
    the_hs_circuitmap = get_hs_circuitmap();
    tt_assert(the_hs_circuitmap);
    tt_int_op(1, OP_EQ, HT_SIZE(the_hs_circuitmap));
    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
                           establish_intro_cell);
    returned_intro_circ =
      hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
    tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ);
  }

  /* Create a v2 intro point */
  {
    char key_digest[DIGEST_LEN];

    legacy_intro_circ = or_circuit_new(1, NULL);
    tt_assert(legacy_intro_circ);
    legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ);
    tt_assert(legacy_auth_key);

    /* Check that the circuitmap now has two elements */
    the_hs_circuitmap = get_hs_circuitmap();
    tt_assert(the_hs_circuitmap);
    tt_int_op(2, OP_EQ, HT_SIZE(the_hs_circuitmap));

    /* Check that the new element is our legacy intro circuit. */
    retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
    tt_int_op(retval, OP_EQ, 0);
    returned_intro_circ =
      hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest);
    tt_ptr_op(legacy_intro_circ, OP_EQ, returned_intro_circ);
  }

  /* XXX Continue test and try to register a second v3 intro point with the
   * same auth key. Make sure that old intro circuit gets closed. */

 done:
  crypto_pk_free(legacy_auth_key);
  circuit_free_(TO_CIRCUIT(intro_circ));
  circuit_free_(TO_CIRCUIT(legacy_intro_circ));
  trn_cell_establish_intro_free(establish_intro_cell);
  test_circuitmap_free_all();

  UNMOCK(hs_intro_send_intro_established_cell);
}
示例#15
0
/* Send a legit ESTABLISH_INTRO cell but with a wrong MAC. Should fail. */
static void
test_establish_intro_wrong_mac(void *arg)
{
  int retval;
  char circ_nonce[DIGEST_LEN] = {0};
  ssize_t cell_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;

  /* Get the auth key of the intro point */
  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. */
  cell_len = new_establish_intro_cell(circ_nonce, &cell);
  tt_i64_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(cell);
  handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++;
  /* We need to resign the payload with that change. */
  {
    ed25519_signature_t sig;
    ed25519_keypair_t key_struct;
    /* New keypair for the signature since we don't have access to the private
     * key material generated earlier when creating the cell. */
    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(cell);
    memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN);
    /* Encode payload so we can sign it. */
    cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
                                               cell);
    tt_i64_op(cell_len, OP_GT, 0);

    retval = ed25519_sign_prefixed(&sig, cell_body,
                                   cell_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(cell);
    memcpy(sig_ptr, sig.sig, cell->sig_len);
    /* Re-encode with the new signature. */
    cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
                                               cell);
    tt_i64_op(cell_len, OP_GT, 0);
  }

  /* Receive the cell. Should fail because our MAC is wrong. */
  setup_full_capture_of_logs(LOG_INFO);
  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  expect_log_msg_containing("ESTABLISH_INTRO handshake_auth not as expected");
  teardown_capture_of_logs();
  tt_int_op(retval, OP_EQ, -1);

 done:
  trn_cell_establish_intro_free(cell);
  circuit_free_(TO_CIRCUIT(intro_circ));
}