diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index af061527d6..4d450f1147 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1636,11 +1636,11 @@ circuit_has_opened(origin_circuit_t *circ)
break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/* at the service, waiting for introductions */
- rend_service_intro_has_opened(circ);
+ hs_service_circuit_has_opened(circ);
break;
case CIRCUIT_PURPOSE_S_CONNECT_REND:
/* at the service, connecting to rend point */
- rend_service_rendezvous_has_opened(circ);
+ hs_service_circuit_has_opened(circ);
break;
case CIRCUIT_PURPOSE_TESTING:
circuit_testing_opened(circ);
diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c
new file mode 100644
index 0000000000..e15f4e3e55
--- /dev/null
+++ b/src/or/hs_cell.c
@@ -0,0 +1,163 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_cell.c
+ * \brief Hidden service API for cell creation and handling.
+ **/
+
+#include "or.h"
+#include "rendservice.h"
+
+#include "hs_cell.h"
+
+/* Trunnel. */
+#include "hs/cell_common.h"
+#include "hs/cell_establish_intro.h"
+
+/* Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
+ * encryption key. The encoded cell is put in cell_out that MUST at least be
+ * of the size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on
+ * success else a negative value and cell_out is untouched. */
+static ssize_t
+build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key,
+ uint8_t *cell_out)
+{
+ ssize_t cell_len;
+ char buf[RELAY_PAYLOAD_SIZE] = {0};
+
+ tor_assert(circ_nonce);
+ tor_assert(enc_key);
+ tor_assert(cell_out);
+
+ cell_len = rend_service_encode_establish_intro_cell(buf, sizeof(buf),
+ enc_key, circ_nonce);
+ tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
+ if (cell_len >= 0) {
+ memcpy(cell_out, buf, cell_len);
+ }
+ return cell_len;
+}
+
+/* ========== */
+/* Public API */
+/* ========== */
+
+/* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
+ * object. The encoded cell is put in cell_out that MUST at least be of the
+ * size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
+ * a negative value and cell_out is untouched. This function also supports
+ * legacy cell creation. */
+ssize_t
+hs_cell_build_establish_intro(const char *circ_nonce,
+ const hs_service_intro_point_t *ip,
+ uint8_t *cell_out)
+{
+ ssize_t cell_len = -1;
+ uint16_t sig_len = ED25519_SIG_LEN;
+ trn_cell_extension_t *ext;
+ trn_cell_establish_intro_t *cell = NULL;
+
+ tor_assert(circ_nonce);
+ tor_assert(ip);
+
+ /* Quickly handle the legacy IP. */
+ if (ip->base.is_only_legacy) {
+ tor_assert(ip->legacy_key);
+ cell_len = build_legacy_establish_intro(circ_nonce, ip->legacy_key,
+ cell_out);
+ tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
+ /* Success or not we are done here. */
+ goto done;
+ }
+
+ /* Set extension data. None used here. */
+ ext = trn_cell_extension_new();
+ trn_cell_extension_set_num(ext, 0);
+ cell = trn_cell_establish_intro_new();
+ trn_cell_establish_intro_set_extensions(cell, ext);
+ /* Set signature size. Array is then allocated in the cell. We need to do
+ * this early so we can use trunnel API to get the signature length. */
+ trn_cell_establish_intro_set_sig_len(cell, sig_len);
+ trn_cell_establish_intro_setlen_sig(cell, sig_len);
+
+ /* 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 and AUTH_KEY_LEN field. Must also set byte-length of
+ * AUTH_KEY to match */
+ {
+ uint16_t 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);
+ /* We do this call _after_ setting the length because it's reallocated at
+ * that point only. */
+ uint8_t *auth_key_ptr = trn_cell_establish_intro_getarray_auth_key(cell);
+ memcpy(auth_key_ptr, ip->auth_key_kp.pubkey.pubkey, auth_key_len);
+ }
+
+ /* Calculate HANDSHAKE_AUTH field (MAC). */
+ {
+ ssize_t tmp_cell_enc_len = 0;
+ ssize_t tmp_cell_mac_offset =
+ sig_len + sizeof(cell->sig_len) +
+ trn_cell_establish_intro_getlen_handshake_mac(cell);
+ uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0};
+ uint8_t mac[TRUNNEL_SHA3_256_LEN], *handshake_ptr;
+
+ /* We first encode the current fields we have in the cell so we can
+ * compute the MAC using the raw bytes. */
+ tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
+ sizeof(tmp_cell_enc),
+ cell);
+ if (BUG(tmp_cell_enc_len < 0)) {
+ goto done;
+ }
+ /* Sanity check. */
+ tor_assert(tmp_cell_enc_len > tmp_cell_mac_offset);
+
+ /* Circuit nonce is always DIGEST_LEN according to tor-spec.txt. */
+ crypto_mac_sha3_256(mac, sizeof(mac),
+ (uint8_t *) circ_nonce, DIGEST_LEN,
+ tmp_cell_enc, tmp_cell_enc_len - tmp_cell_mac_offset);
+ handshake_ptr = trn_cell_establish_intro_getarray_handshake_mac(cell);
+ memcpy(handshake_ptr, mac, sizeof(mac));
+ }
+
+ /* Calculate the cell signature SIG. */
+ {
+ ssize_t tmp_cell_enc_len = 0;
+ ssize_t tmp_cell_sig_offset = (sig_len + sizeof(cell->sig_len));
+ uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}, *sig_ptr;
+ ed25519_signature_t sig;
+
+ /* We first encode the current fields we have in the cell so we can
+ * compute the signature from the raw bytes of the cell. */
+ tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
+ sizeof(tmp_cell_enc),
+ cell);
+ if (BUG(tmp_cell_enc_len < 0)) {
+ goto done;
+ }
+
+ if (ed25519_sign_prefixed(&sig, tmp_cell_enc,
+ tmp_cell_enc_len - tmp_cell_sig_offset,
+ ESTABLISH_INTRO_SIG_PREFIX, &ip->auth_key_kp)) {
+ log_warn(LD_BUG, "Unable to make signature for ESTABLISH_INTRO cell.");
+ goto done;
+ }
+ /* Copy the signature into the cell. */
+ sig_ptr = trn_cell_establish_intro_getarray_sig(cell);
+ memcpy(sig_ptr, sig.sig, sig_len);
+ }
+
+ /* Encode the cell. Can't be bigger than a standard cell. */
+ cell_len = trn_cell_establish_intro_encode(cell_out, RELAY_PAYLOAD_SIZE,
+ cell);
+
+ done:
+ trn_cell_establish_intro_free(cell);
+ return cell_len;
+}
+
diff --git a/src/or/hs_cell.h b/src/or/hs_cell.h
new file mode 100644
index 0000000000..9cc6109ebf
--- /dev/null
+++ b/src/or/hs_cell.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_cell.h
+ * \brief Header file containing cell data for the whole HS subsytem.
+ **/
+
+#ifndef TOR_HS_CELL_H
+#define TOR_HS_CELL_H
+
+#include "hs_service.h"
+
+ssize_t hs_cell_build_establish_intro(const char *circ_nonce,
+ const hs_service_intro_point_t *ip,
+ uint8_t *cell_out);
+
+#endif /* TOR_HS_CELL_H */
+
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index 482ba30f35..01fd864839 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -6,13 +6,16 @@
**/
#include "or.h"
+#include "circpathbias.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
+#include "relay.h"
#include "rephist.h"
#include "router.h"
+#include "hs_cell.h"
#include "hs_circuit.h"
#include "hs_ident.h"
#include "hs_ntor.h"
@@ -195,6 +198,48 @@ register_intro_circ(const hs_service_intro_point_t *ip,
}
}
+/* Return the number of opened introduction circuit for the given circuit that
+ * is matching its identity key. */
+static unsigned int
+count_opened_desc_intro_point_circuits(const hs_service_t *service,
+ const hs_service_descriptor_t *desc)
+{
+ unsigned int count = 0;
+
+ tor_assert(service);
+ tor_assert(desc);
+
+ DIGEST256MAP_FOREACH(desc->intro_points.map, key,
+ const hs_service_intro_point_t *, ip) {
+ circuit_t *circ;
+ origin_circuit_t *ocirc;
+ if (ip->base.is_only_legacy) {
+ uint8_t digest[DIGEST_LEN];
+ if (BUG(crypto_pk_get_digest(ip->legacy_key, (char *) digest) < 0)) {
+ continue;
+ }
+ ocirc = hs_circuitmap_get_intro_circ_v2_service_side(digest);
+ } else {
+ ocirc =
+ hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
+ }
+ if (ocirc == NULL) {
+ continue;
+ }
+ circ = TO_CIRCUIT(ocirc);
+ tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
+ circ->purpose == CIRCUIT_PURPOSE_S_INTRO);
+ /* Having a circuit not for the requested service is really bad. */
+ tor_assert(ed25519_pubkey_eq(&service->keys.identity_pk,
+ ô->hs_ident->identity_pk));
+ /* Only count opened circuit and skip circuit that will be closed. */
+ if (!circ->marked_for_close && circ->state == CIRCUIT_STATE_OPEN) {
+ count++;
+ }
+ } DIGEST256MAP_FOREACH_END;
+ return count;
+}
+
/* From a given service and service intro point, create an introduction point
* circuit identifier. This can't fail. */
static hs_ident_circuit_t *
@@ -213,6 +258,60 @@ create_intro_circuit_identifier(const hs_service_t *service,
return ident;
}
+/* 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));
+}
+
+/* ========== */
+/* Public API */
+/* ========== */
+
/* For a given service and a service intro point, launch a circuit to the
* extend info ei. If the service is a single onion, a one-hop circuit will be
* requested. Return 0 if the circuit was successfully launched and tagged
@@ -266,6 +365,69 @@ hs_circ_launch_intro_point(hs_service_t *service,
return ret;
}
+/* Called when a service introduction point circuit is done building. Given
+ * the service and intro point object, this function will send the
+ * ESTABLISH_INTRO cell on the circuit. Return 0 on success. Return 1 if the
+ * circuit has been repurposed to General because we already have too many
+ * opened. */
+int
+hs_circ_service_intro_has_opened(hs_service_t *service,
+ hs_service_intro_point_t *ip,
+ const hs_service_descriptor_t *desc,
+ origin_circuit_t *circ)
+{
+ int ret = 0;
+ unsigned int num_intro_circ, num_needed_circ;
+
+ tor_assert(service);
+ tor_assert(ip);
+ tor_assert(desc);
+ tor_assert(circ);
+
+ num_intro_circ = count_opened_desc_intro_point_circuits(service, desc);
+ num_needed_circ = service->config.num_intro_points;
+ if (num_intro_circ > num_needed_circ) {
+ /* There are too many opened valid intro circuit for what the service
+ * needs so repurpose this one. */
+
+ /* XXX: Legacy code checks options->ExcludeNodes and if not NULL it just
+ * closes the circuit. I have NO idea why it does that so it hasn't been
+ * added here. I can only assume in case our ExcludeNodes list changes but
+ * in that case, all circuit are flagged unusable (config.c). --dgoulet */
+
+ log_info(LD_CIRC | LD_REND, "Introduction circuit just opened but we "
+ "have enough for service %s. Repurposing "
+ "it to general and leaving internal.",
+ safe_str_client(service->onion_address));
+ tor_assert(circ->build_state->is_internal);
+ /* Remove it from the circuitmap. */
+ hs_circuitmap_remove_circuit(TO_CIRCUIT(circ));
+ /* Cleaning up the hidden service identifier and repurpose. */
+ hs_ident_circuit_free(circ->hs_ident);
+ circ->hs_ident = NULL;
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_GENERAL);
+ /* Inform that this circuit just opened for this new purpose. */
+ circuit_has_opened(circ);
+ /* This return value indicate to the caller that the IP object should be
+ * removed from the service because it's corresponding circuit has just
+ * been repurposed. */
+ ret = 1;
+ goto done;
+ }
+
+ log_info(LD_REND, "Introduction circuit %u established for service %s.",
+ TO_CIRCUIT(circ)->n_circ_id,
+ safe_str_client(service->onion_address));
+ circuit_log_path(LOG_INFO, LD_REND, circ);
+
+ /* Time to send an ESTABLISH_INTRO cell on this circuit. On error, this call
+ * makes sure the circuit gets closed. */
+ send_establish_intro(service, ip, circ);
+
+ done:
+ return ret;
+}
+
/* Circuit circ just finished the rend ntor key exchange. Use the key
* exchange output material at ntor_key_seed and setup circ to
* serve as a rendezvous end-to-end circuit between the client and the
@@ -273,7 +435,7 @@ hs_circ_launch_intro_point(hs_service_t *service,
* and the other side is the client.
*
* Return 0 if the operation went well; in case of error return -1. */
-int
+ int
hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
const uint8_t *ntor_key_seed, size_t seed_len,
int is_service_side)
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
index 8738438eb2..35eab75695 100644
--- a/src/or/hs_circuit.h
+++ b/src/or/hs_circuit.h
@@ -16,10 +16,19 @@
#include "hs_service.h"
/* Circuit API. */
+int hs_circ_service_intro_has_opened(hs_service_t *service,
+ hs_service_intro_point_t *ip,
+ const hs_service_descriptor_t *desc,
+ origin_circuit_t *circ);
int hs_circ_launch_intro_point(hs_service_t *service,
const hs_service_intro_point_t *ip,
extend_info_t *ei, time_t now);
+/* Cell API. */
+void hs_circ_send_establish_intro(const hs_service_t *service,
+ hs_service_intro_point_t *ip,
+ origin_circuit_t *circ);
+
/* e2e circuit API. */
int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 06ab7b9836..4cd808133c 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -12,6 +12,7 @@
#include "circpathbias.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuituse.h"
#include "config.h"
#include "main.h"
#include "networkstatus.h"
@@ -338,13 +339,72 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy)
static void
service_intro_point_add(digest256map_t *map, hs_service_intro_point_t *ip)
{
- uint8_t key[DIGEST256_LEN] = {0};
-
tor_assert(map);
tor_assert(ip);
- memcpy(key, ip->auth_key_kp.pubkey.pubkey, sizeof(key));
- digest256map_set(map, key, ip);
+ digest256map_set(map, ip->auth_key_kp.pubkey.pubkey, ip);
+}
+
+/* For a given service, remove the intro point from that service which will
+ * look in both descriptors. */
+static void
+service_intro_point_remove(const hs_service_t *service,
+ const hs_service_intro_point_t *ip)
+{
+ tor_assert(service);
+ tor_assert(ip);
+
+ /* Trying all descriptors. */
+ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
+ /* We'll try to remove the descriptor on both descriptors which is not
+ * very expensive to do instead of doing loopup + remove. */
+ digest256map_remove(desc->intro_points.map,
+ ip->auth_key_kp.pubkey.pubkey);
+ } FOR_EACH_DESCRIPTOR_END;
+}
+
+/* For a given service and authentication key, return the intro point or NULL
+ * if not found. This will check both descriptors in the service. */
+static hs_service_intro_point_t *
+service_intro_point_find(const hs_service_t *service,
+ const ed25519_public_key_t *auth_key)
+{
+ hs_service_intro_point_t *ip = NULL;
+
+ tor_assert(service);
+ tor_assert(auth_key);
+
+ /* Trying all descriptors. */
+ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
+ if ((ip = digest256map_get(desc->intro_points.map,
+ auth_key->pubkey)) != NULL) {
+ break;
+ }
+ } FOR_EACH_DESCRIPTOR_END;
+
+ return ip;
+}
+
+/* For a given service and intro point, return the descriptor for which the
+ * intro point is assigned to. NULL is returned if not found. */
+static hs_service_descriptor_t *
+service_desc_find_by_intro(const hs_service_t *service,
+ const hs_service_intro_point_t *ip)
+{
+ hs_service_descriptor_t *descp = NULL;
+
+ tor_assert(service);
+ tor_assert(ip);
+
+ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
+ if (digest256map_get(desc->intro_points.map,
+ ip->auth_key_kp.pubkey.pubkey)) {
+ descp = desc;
+ break;
+ }
+ } FOR_EACH_DESCRIPTOR_END;
+
+ return descp;
}
/* From a given intro point, return the first link specifier of type
@@ -790,7 +850,6 @@ service_descriptor_new(void)
return sdesc;
}
-#if 0
/* Copy the descriptor link specifier object from src to dst. */
static void
link_specifier_copy(hs_desc_link_specifier_t *dst,
@@ -916,8 +975,6 @@ build_desc_intro_points(const hs_service_t *service,
} DIGEST256MAP_FOREACH_END;
}
-#endif /* build_desc_intro_points is disabled because not used */
-
/* Populate the descriptor encrypted section fomr the given service object.
* This will generate a valid list of introduction points that can be used
* after for circuit creation. Return 0 on success else -1 on error. */
@@ -1635,14 +1692,105 @@ run_upload_descriptor_event(time_t now)
/* Run v3+ check. */
FOR_EACH_SERVICE_BEGIN(service) {
/* XXX: Upload if needed the descriptor(s). Update next upload time. */
- (void) service;
+ /* XXX: Build the descriptor intro points list with
+ * build_desc_intro_points() once we have enough circuit opened. */
+ build_desc_intro_points(service, NULL, now);
} FOR_EACH_SERVICE_END;
}
+/* Called when the introduction point circuit is done building and ready to be
+ * used. */
+static void
+service_intro_circ_has_opened(origin_circuit_t *circ)
+{
+ int close_reason;
+ hs_service_t *service;
+ hs_service_intro_point_t *ip;
+ hs_service_descriptor_t *desc = NULL;
+
+ tor_assert(circ);
+ tor_assert(circ->cpath);
+ /* Getting here means this is a v3 intro circuit. */
+ tor_assert(circ->hs_ident);
+ tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
+
+ /* Get service object from the circuit identifier. */
+ service = find_service(hs_service_map, &circ->hs_ident->identity_pk);
+ if (service == NULL) {
+ log_warn(LD_REND, "Unknown service identity key %s on the introduction "
+ "circuit %u. Can't find onion service.",
+ safe_str_client(ed25519_fmt(&circ->hs_ident->identity_pk)),
+ TO_CIRCUIT(circ)->n_circ_id);
+ close_reason = END_CIRC_REASON_NOSUCHSERVICE;
+ goto err;
+ }
+
+ /* From the service object, get the intro point object of that circuit. The
+ * following will query both descriptors intro points list. */
+ ip = service_intro_point_find(service, &circ->hs_ident->intro_auth_pk);
+ if (ip == NULL) {
+ log_warn(LD_REND, "Unknown authentication key on the introduction "
+ "circuit %u for service %s",
+ TO_CIRCUIT(circ)->n_circ_id,
+ safe_str_client(service->onion_address));
+ /* Closing this circuit because we don't recognize the key. */
+ close_reason = END_CIRC_REASON_NOSUCHSERVICE;
+ goto err;
+ }
+ /* We can't have an IP object without a descriptor. */
+ desc = service_desc_find_by_intro(service, ip);
+ tor_assert(desc);
+
+ if (hs_circ_service_intro_has_opened(service, ip, desc, circ)) {
+ /* Getting here means that the circuit has been re-purposed because we
+ * have enough intro circuit opened. Remove the IP from the service. */
+ service_intro_point_remove(service, ip);
+ service_intro_point_free(ip);
+ }
+
+ goto done;
+
+ err:
+ /* Close circuit, we can't use it. */
+ circuit_mark_for_close(TO_CIRCUIT(circ), close_reason);
+ done:
+ return;
+}
+
+static void
+service_rendezvous_circ_has_opened(origin_circuit_t *circ)
+{
+ tor_assert(circ);
+ /* XXX: Implement rendezvous support. */
+}
+
/* ========== */
/* Public API */
/* ========== */
+/* Called when any kind of hidden service circuit is done building thus
+ * opened. This is the entry point from the circuit subsystem. */
+void
+hs_service_circuit_has_opened(origin_circuit_t *circ)
+{
+ tor_assert(circ);
+
+ /* Handle both version. v2 uses rend_data and v3 uses the hs circuit
+ * identifier hs_ident. Can't be both. */
+ switch (TO_CIRCUIT(circ)->purpose) {
+ case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
+ (circ->hs_ident) ? service_intro_circ_has_opened(circ) :
+ rend_service_intro_has_opened(circ);
+ break;
+ case CIRCUIT_PURPOSE_S_CONNECT_REND:
+ (circ->hs_ident) ? service_rendezvous_circ_has_opened(circ) :
+ rend_service_rendezvous_has_opened(circ);
+ break;
+ default:
+ tor_assert(0);
+ }
+}
+
/* Load and/or generate keys for all onion services including the client
* authorization if any. Return 0 on success, -1 on failure. */
int
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index 476fee72ff..96df09493e 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -103,6 +103,9 @@ typedef struct hs_service_descriptor_t {
* hs_service_intropoints_t object indexed by authentication key (the RSA
* key if the node is legacy). */
hs_service_intropoints_t intro_points;
+
+ /* The time period number this descriptor has been created for. */
+ uint64_t time_period_num;
} hs_service_descriptor_t;
/* Service key material. */
@@ -228,6 +231,7 @@ void hs_service_stage_services(const smartlist_t *service_list);
int hs_service_load_all_keys(void);
void hs_service_run_scheduled_events(time_t now);
+void hs_service_circuit_has_opened(origin_circuit_t *circ);
/* 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
diff --git a/src/or/include.am b/src/or/include.am
index 15b86ef50b..8db5be095a 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -54,6 +54,7 @@ LIBTOR_A_SOURCES = \
src/or/ext_orport.c \
src/or/hibernate.c \
src/or/hs_cache.c \
+ src/or/hs_cell.c \
src/or/hs_circuit.c \
src/or/hs_circuitmap.c \
src/or/hs_client.c \
@@ -184,11 +185,12 @@ ORHEADERS = \
src/or/entrynodes.h \
src/or/hibernate.h \
src/or/hs_cache.h \
+ src/or/hs_cell.h \
+ src/or/hs_config.h \
src/or/hs_circuit.h \
src/or/hs_circuitmap.h \
src/or/hs_client.h \
src/or/hs_common.h \
- src/or/hs_config.h \
src/or/hs_descriptor.h \
src/or/hs_ident.h \
src/or/hs_intropoint.h \
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 4641e110d8..8239803fb2 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -3116,10 +3116,11 @@ count_intro_point_circuits(const rend_service_t *service)
crypto material. On success, fill cell_body_out and return the number
of bytes written. On fail, return -1.
*/
-STATIC ssize_t
-encode_establish_intro_cell_legacy(char *cell_body_out,
- size_t cell_body_out_len,
- crypto_pk_t *intro_key, char *rend_circ_nonce)
+ssize_t
+rend_service_encode_establish_intro_cell(char *cell_body_out,
+ size_t cell_body_out_len,
+ crypto_pk_t *intro_key,
+ const char *rend_circ_nonce)
{
int retval = -1;
int r;
@@ -3256,7 +3257,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
/* Send the ESTABLISH_INTRO cell */
{
ssize_t len;
- len = encode_establish_intro_cell_legacy(buf, sizeof(buf),
+ len = rend_service_encode_establish_intro_cell(buf, sizeof(buf),
circuit->intro_key,
circuit->cpath->prev->rend_circ_nonce);
if (len < 0) {
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index 4a06657eab..78f4b92c2e 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -126,10 +126,6 @@ STATIC int rend_service_verify_single_onion_poison(
STATIC int rend_service_poison_new_single_onion_dir(
const rend_service_t *s,
const or_options_t* options);
-STATIC ssize_t encode_establish_intro_cell_legacy(char *cell_body_out,
- size_t cell_body_out_len,
- crypto_pk_t *intro_key,
- char *rend_circ_nonce);
#ifdef TOR_UNIT_TESTS
STATIC void set_rend_service_list(smartlist_t *new_list);
@@ -172,6 +168,10 @@ rend_intro_cell_t * rend_service_begin_parse_intro(const uint8_t *request,
char **err_msg_out);
int rend_service_parse_intro_plaintext(rend_intro_cell_t *intro,
char **err_msg_out);
+ssize_t rend_service_encode_establish_intro_cell(char *cell_body_out,
+ size_t cell_body_out_len,
+ crypto_pk_t *intro_key,
+ const char *rend_circ_nonce);
int rend_service_validate_intro_late(const rend_intro_cell_t *intro,
char **err_msg_out);
void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index c6197875b5..076d125ffc 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -488,10 +488,10 @@ helper_establish_intro_v2(or_circuit_t *intro_circ)
key1 = pk_generate(0);
/* Use old circuit_key_material why not */
- cell_len = encode_establish_intro_cell_legacy((char*)cell_body,
- sizeof(cell_body),
- key1,
- (char *) circuit_key_material);
+ cell_len = rend_service_encode_establish_intro_cell(
+ (char*)cell_body,
+ sizeof(cell_body), key1,
+ (char *) circuit_key_material);
tt_int_op(cell_len, >, 0);
/* Receive legacy establish_intro */