|
@@ -1763,7 +1763,6 @@ service_desc_schedule_upload(hs_service_descriptor_t *desc,
|
|
|
/* Update the given descriptor from the given service. The possible update
|
|
|
* actions includes:
|
|
|
* - Picking missing intro points if needed.
|
|
|
- * - Incrementing the revision counter if needed.
|
|
|
*/
|
|
|
static void
|
|
|
update_service_descriptor(hs_service_t *service,
|
|
@@ -2338,187 +2337,6 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
-/** Return a newly-allocated string for our state file which contains revision
|
|
|
- * counter information for <b>desc</b>. The format is:
|
|
|
- *
|
|
|
- * HidServRevCounter <blinded_pubkey> <rev_counter>
|
|
|
- */
|
|
|
-STATIC char *
|
|
|
-encode_desc_rev_counter_for_state(const hs_service_descriptor_t *desc)
|
|
|
-{
|
|
|
- char *state_str = NULL;
|
|
|
- char blinded_pubkey_b64[ED25519_BASE64_LEN+1];
|
|
|
- uint64_t rev_counter = desc->desc->plaintext_data.revision_counter;
|
|
|
- const ed25519_public_key_t *blinded_pubkey = &desc->blinded_kp.pubkey;
|
|
|
-
|
|
|
- /* Turn the blinded key into b64 so that we save it on state */
|
|
|
- tor_assert(blinded_pubkey);
|
|
|
- if (ed25519_public_to_base64(blinded_pubkey_b64, blinded_pubkey) < 0) {
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- /* Format is: <blinded key> <rev counter> */
|
|
|
- tor_asprintf(&state_str, "%s %" PRIu64, blinded_pubkey_b64, rev_counter);
|
|
|
-
|
|
|
- log_info(LD_GENERAL, "[!] Adding rev counter %" PRIu64 " for %s!",
|
|
|
- rev_counter, blinded_pubkey_b64);
|
|
|
-
|
|
|
- done:
|
|
|
- return state_str;
|
|
|
-}
|
|
|
-
|
|
|
-/** Update HS descriptor revision counters in our state by removing the old
|
|
|
- * ones and writing down the ones that are currently active. */
|
|
|
-static void
|
|
|
-update_revision_counters_in_state(void)
|
|
|
-{
|
|
|
- config_line_t *lines = NULL;
|
|
|
- config_line_t **nextline = &lines;
|
|
|
- or_state_t *state = get_or_state();
|
|
|
-
|
|
|
- /* Prepare our state structure with the rev counters */
|
|
|
- FOR_EACH_SERVICE_BEGIN(service) {
|
|
|
- FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
|
|
|
- /* We don't want to save zero counters */
|
|
|
- if (desc->desc->plaintext_data.revision_counter == 0) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- *nextline = tor_malloc_zero(sizeof(config_line_t));
|
|
|
- (*nextline)->key = tor_strdup("HidServRevCounter");
|
|
|
- (*nextline)->value = encode_desc_rev_counter_for_state(desc);
|
|
|
- nextline = &(*nextline)->next;
|
|
|
- } FOR_EACH_DESCRIPTOR_END;
|
|
|
- } FOR_EACH_SERVICE_END;
|
|
|
-
|
|
|
- /* Remove the old rev counters, and replace them with the new ones */
|
|
|
- config_free_lines(state->HidServRevCounter);
|
|
|
- state->HidServRevCounter = lines;
|
|
|
-
|
|
|
- /* Set the state as dirty since we just edited it */
|
|
|
- if (!get_options()->AvoidDiskWrites) {
|
|
|
- or_state_mark_dirty(state, 0);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/** Scan the string <b>state_line</b> for the revision counter of the service
|
|
|
- * with <b>blinded_pubkey</b>. Set <b>service_found_out</b> to True if the
|
|
|
- * line is relevant to this service, and return the cached revision
|
|
|
- * counter. Else set <b>service_found_out</b> to False. */
|
|
|
-STATIC uint64_t
|
|
|
-check_state_line_for_service_rev_counter(const char *state_line,
|
|
|
- const ed25519_public_key_t *blinded_pubkey,
|
|
|
- int *service_found_out)
|
|
|
-{
|
|
|
- smartlist_t *items = NULL;
|
|
|
- int ok;
|
|
|
- ed25519_public_key_t pubkey_in_state;
|
|
|
- uint64_t rev_counter = 0;
|
|
|
-
|
|
|
- tor_assert(service_found_out);
|
|
|
- tor_assert(state_line);
|
|
|
- tor_assert(blinded_pubkey);
|
|
|
-
|
|
|
- /* Assume that the line is not for this service */
|
|
|
- *service_found_out = 0;
|
|
|
-
|
|
|
- /* Start parsing the state line */
|
|
|
- items = smartlist_new();
|
|
|
- smartlist_split_string(items, state_line, NULL,
|
|
|
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
|
|
|
- if (smartlist_len(items) < 2) {
|
|
|
- log_warn(LD_GENERAL, "Incomplete rev counter line. Ignoring.");
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- char *b64_key_str = smartlist_get(items, 0);
|
|
|
- char *saved_rev_counter_str = smartlist_get(items, 1);
|
|
|
-
|
|
|
- /* Parse blinded key to check if it's for this hidden service */
|
|
|
- if (ed25519_public_from_base64(&pubkey_in_state, b64_key_str) < 0) {
|
|
|
- log_warn(LD_GENERAL, "Unable to base64 key in revcount line. Ignoring.");
|
|
|
- goto done;
|
|
|
- }
|
|
|
- /* State line not for this hidden service */
|
|
|
- if (!ed25519_pubkey_eq(&pubkey_in_state, blinded_pubkey)) {
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- rev_counter = tor_parse_uint64(saved_rev_counter_str,
|
|
|
- 10, 0, UINT64_MAX, &ok, NULL);
|
|
|
- if (!ok) {
|
|
|
- log_warn(LD_GENERAL, "Unable to parse rev counter. Ignoring.");
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- /* Since we got this far, the line was for this service */
|
|
|
- *service_found_out = 1;
|
|
|
-
|
|
|
- log_info(LD_GENERAL, "Found rev counter for %s: %" PRIu64,
|
|
|
- b64_key_str, rev_counter);
|
|
|
-
|
|
|
- done:
|
|
|
- tor_assert(items);
|
|
|
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
|
|
|
- smartlist_free(items);
|
|
|
-
|
|
|
- return rev_counter;
|
|
|
-}
|
|
|
-
|
|
|
-/** Dig into our state file and find the current revision counter for the
|
|
|
- * service with blinded key <b>blinded_pubkey</b>. If no revision counter is
|
|
|
- * found, return 0. */
|
|
|
-static uint64_t
|
|
|
-get_rev_counter_for_service(const ed25519_public_key_t *blinded_pubkey)
|
|
|
-{
|
|
|
- or_state_t *state = get_or_state();
|
|
|
- config_line_t *line;
|
|
|
-
|
|
|
- /* Set default value for rev counters (if not found) to 0 */
|
|
|
- uint64_t final_rev_counter = 0;
|
|
|
-
|
|
|
- for (line = state->HidServRevCounter ; line ; line = line->next) {
|
|
|
- int service_found = 0;
|
|
|
- uint64_t rev_counter = 0;
|
|
|
-
|
|
|
- tor_assert(!strcmp(line->key, "HidServRevCounter"));
|
|
|
-
|
|
|
- /* Scan all the HidServRevCounter lines till we find the line for this
|
|
|
- service: */
|
|
|
- rev_counter = check_state_line_for_service_rev_counter(line->value,
|
|
|
- blinded_pubkey,
|
|
|
- &service_found);
|
|
|
- if (service_found) {
|
|
|
- final_rev_counter = rev_counter;
|
|
|
- goto done;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- done:
|
|
|
- return final_rev_counter;
|
|
|
-}
|
|
|
-
|
|
|
-/** Update the value of the revision counter for <b>hs_desc</b> and save it on
|
|
|
- our state file. */
|
|
|
-static void
|
|
|
-increment_descriptor_revision_counter(hs_descriptor_t *hs_desc)
|
|
|
-{
|
|
|
- /* Find stored rev counter if it exists */
|
|
|
- uint64_t rev_counter =
|
|
|
- get_rev_counter_for_service(&hs_desc->plaintext_data.blinded_pubkey);
|
|
|
-
|
|
|
- /* Increment the revision counter of <b>hs_desc</b> so the next update (which
|
|
|
- * will trigger an upload) will have the right value. We do this at this
|
|
|
- * stage to only do it once because a descriptor can have many updates before
|
|
|
- * being uploaded. By doing it at upload, we are sure to only increment by 1
|
|
|
- * and thus avoid leaking how many operations we made on the descriptor from
|
|
|
- * the previous one before uploading. */
|
|
|
- rev_counter++;
|
|
|
- hs_desc->plaintext_data.revision_counter = rev_counter;
|
|
|
-
|
|
|
- update_revision_counters_in_state();
|
|
|
-}
|
|
|
-
|
|
|
/** Set the revision counter in <b>hs_desc</b>. We do this by encrypting a
|
|
|
* timestamp using an OPE scheme and using the ciphertext as our revision
|
|
|
* counter.
|
|
@@ -2664,9 +2482,6 @@ upload_descriptor_to_all(const hs_service_t *service,
|
|
|
safe_str_client(service->onion_address), fmt_next_time);
|
|
|
}
|
|
|
|
|
|
- /* Update the revision counter of this descriptor */
|
|
|
- increment_descriptor_revision_counter(desc->desc);
|
|
|
-
|
|
|
smartlist_free(responsible_dirs);
|
|
|
return;
|
|
|
}
|