/** We simulate a failure to create an ESTABLISH_INTRO cell */ static void test_gen_establish_intro_cell_bad(void *arg) { (void) arg; ssize_t cell_len = 0; trn_cell_establish_intro_t *cell = NULL; char circ_nonce[DIGEST_LEN] = {0}; hs_service_intro_point_t *ip = NULL; MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed); 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 = trn_cell_establish_intro_new(); tt_assert(cell); ip = service_intro_point_new(NULL); 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_i64_op(cell_len, OP_EQ, -1); done: trn_cell_establish_intro_free(cell); UNMOCK(ed25519_sign_prefixed); }
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; /* Ensure that *cell_out is NULL such that we can use to check if we need to * free `cell` in case of an error. */ *cell_out = 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); tt_assert(ip); cell_len = hs_cell_build_establish_intro(circ_nonce, ip, buf); tt_i64_op(cell_len, OP_GT, 0); cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf)); tt_i64_op(cell_len, OP_GT, 0); tt_assert(cell); *cell_out = cell; done: if (*cell_out == NULL) trn_cell_establish_intro_free(cell); service_intro_point_free(ip); return cell_len; }
/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we * parse it from the receiver side. */ static void test_gen_establish_intro_cell(void *arg) { (void) arg; ssize_t ret; char circ_nonce[DIGEST_LEN] = {0}; uint8_t buf[RELAY_PAYLOAD_SIZE]; trn_cell_establish_intro_t *cell_in = NULL; crypto_rand(circ_nonce, sizeof(circ_nonce)); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we attempt to parse it. */ { /* We only need the auth key pair here. */ hs_service_intro_point_t *ip = service_intro_point_new(NULL); /* 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); } /* Check the contents of the cell */ { /* First byte is the auth key type: make sure its correct */ tt_int_op(buf[0], OP_EQ, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519); /* Next two bytes is auth key len */ tt_int_op(ntohs(get_uint16(buf+1)), OP_EQ, ED25519_PUBKEY_LEN); /* Skip to the number of extensions: no extensions */ tt_int_op(buf[35], OP_EQ, 0); /* Skip to the sig len. Make sure it's the size of an ed25519 sig */ tt_int_op(ntohs(get_uint16(buf+35+1+32)), OP_EQ, ED25519_SIG_LEN); } /* Parse it as the receiver */ { 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_in); }
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); tt_assert(ip); cell_len = hs_cell_build_establish_intro(circ_nonce, ip, cell_out); tt_i64_op(cell_len, OP_GT, 0); done: service_intro_point_free(ip); return cell_len; }
/* For a given introduction point and an introduction circuit, send the * ESTABLISH_INTRO cell. The service object is used for logging. This can fail * and if so, the circuit is closed and the intro point object is flagged * that the circuit is not established anymore which is important for the * retry mechanism. */ static void send_establish_intro(const hs_service_t *service, hs_service_intro_point_t *ip, origin_circuit_t *circ) { ssize_t cell_len; uint8_t payload[RELAY_PAYLOAD_SIZE]; tor_assert(service); tor_assert(ip); tor_assert(circ); /* Encode establish intro cell. */ cell_len = hs_cell_build_establish_intro(circ->cpath->prev->rend_circ_nonce, ip, payload); if (cell_len < 0) { log_warn(LD_REND, "Unable to encode ESTABLISH_INTRO cell for service %s " "on circuit %u. Closing circuit.", safe_str_client(service->onion_address), TO_CIRCUIT(circ)->n_circ_id); goto err; } /* Send the cell on the circuit. */ if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), RELAY_COMMAND_ESTABLISH_INTRO, (char *) payload, cell_len, circ->cpath->prev) < 0) { log_info(LD_REND, "Unable to send ESTABLISH_INTRO cell for service %s " "on circuit %u.", safe_str_client(service->onion_address), TO_CIRCUIT(circ)->n_circ_id); /* On error, the circuit has been closed. */ goto done; } /* Record the attempt to use this circuit. */ pathbias_count_use_attempt(circ); goto done; err: circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); done: memwipe(payload, 0, sizeof(payload)); }