diff --git a/src/or/hs_service.c b/src/or/hs_service.c index b5649e2636..76b1634561 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -91,7 +91,8 @@ static smartlist_t *hs_service_staging_list; static int consider_republishing_hs_descriptors = 0; /* Static declaration. */ -static void set_descriptor_revision_counter(hs_descriptor_t *hs_desc); +static void set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc, + time_t now, bool is_current); static void move_descriptors(hs_service_t *src, hs_service_t *dst); /* Helper: Function to compare two objects in the service map. Return 1 if the @@ -1420,11 +1421,15 @@ build_service_desc_keys(const hs_service_t *service, * the update function. On success, desc_out will point to the newly allocated * descriptor object. * + * If is_current is true, this is the current service descriptor, + * otherwise it's the next one. + * * This can error if we are unable to create keys or certificate. */ static void build_service_descriptor(hs_service_t *service, time_t now, uint64_t time_period_num, - hs_service_descriptor_t **desc_out) + hs_service_descriptor_t **desc_out, + bool is_current) { char *encoded_desc; hs_service_descriptor_t *desc; @@ -1449,7 +1454,7 @@ build_service_descriptor(hs_service_t *service, time_t now, } /* Set the revision counter for this descriptor */ - set_descriptor_revision_counter(desc->desc); + set_descriptor_revision_counter(desc, now, is_current); /* Let's make sure that we've created a descriptor that can actually be * encoded properly. This function also checks if the encoded output is @@ -1515,9 +1520,9 @@ build_descriptors_for_new_service(hs_service_t *service, time_t now) /* Build descriptors. */ build_service_descriptor(service, now, current_desc_tp, - &service->desc_current); + &service->desc_current, 1); build_service_descriptor(service, now, next_desc_tp, - &service->desc_next); + &service->desc_next, 0); log_info(LD_REND, "Hidden service %s has just started. Both descriptors " "built. Now scheduled for upload.", safe_str_client(service->onion_address)); @@ -1548,7 +1553,7 @@ build_all_descriptors(time_t now) if (service->desc_next == NULL) { build_service_descriptor(service, now, hs_get_next_time_period_num(0), - &service->desc_next); + &service->desc_next, 0); log_info(LD_REND, "Hidden service %s next descriptor successfully " "built. Now scheduled for upload.", safe_str_client(service->onion_address)); @@ -2514,16 +2519,94 @@ increment_descriptor_revision_counter(hs_descriptor_t *hs_desc) update_revision_counters_in_state(); } -/** Set the revision counter in hs_desc, using the state file to find - * the current counter value if it exists. */ +/** Set the revision counter in hs_desc. We do this by encrypting a + * timestamp using an OPE scheme and using the ciphertext as our revision + * counter. + * + * If is_current is true, then this is the current HS descriptor, + * otherwise it's the next one. */ static void -set_descriptor_revision_counter(hs_descriptor_t *hs_desc) +set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc, time_t now, + bool is_current) { - /* Find stored rev counter if it exists */ - uint64_t rev_counter = - get_rev_counter_for_service(&hs_desc->plaintext_data.blinded_pubkey); + uint64_t rev_counter = 0; - hs_desc->plaintext_data.revision_counter = rev_counter; + /* Get current time */ + time_t srv_start = 0; + + /* As our revision counter plaintext value, we use the seconds since the + * start of the SR protocol run that is relevant to this descriptor. This is + * guaranteed to be a positive value since we need the SRV to start making a + * descriptor (so that we know where to upload it). + * + * Depending on whether we are building the current or the next descriptor, + * services use a different SRV value. See [SERVICEUPLOAD] in + * rend-spec-v3.txt: + * + * In particular, for the current descriptor (aka first descriptor), Tor + * always uses the previous SRV for uploading the descriptor, and hence we + * should use the start time of the previous protocol run here. + * + * Whereas for the next descriptor (aka second descriptor), Tor always uses + * the current SRV for uploading the descriptor. and hence we use the start + * time of the current protocol run. + */ + if (is_current) { + srv_start = sr_state_get_start_time_of_previous_protocol_run(now); + } else { + srv_start = sr_state_get_start_time_of_current_protocol_run(now); + } + + log_info(LD_REND, "Setting rev counter for TP #%u: " + "SRV started at %d, now %d (%s)", + (unsigned) hs_desc->time_period_num, (int)srv_start, + (int)now, is_current ? "current" : "next"); + + tor_assert_nonfatal(now >= srv_start); + + /* Compute seconds elapsed since the start of the time period. That's the + * number of seconds of how long this blinded key has been active. */ + time_t seconds_since_start_of_srv = now - srv_start; + + /* Increment by one so that we are definitely sure this is strictly + * positive and not zero. */ + seconds_since_start_of_srv++; + + /* Check for too big inputs. */ + if (BUG(seconds_since_start_of_srv > OPE_INPUT_MAX)) { + seconds_since_start_of_srv = OPE_INPUT_MAX; + } + + /* Now we compute the actual revision counter value by encrypting the + plaintext using an OPE construction: */ + + /* First, compute OPE key as: K = H("rev-counter-generation" | S) */ + uint8_t key[DIGEST256_LEN]; + { + crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA3_256); + const char ope_key_prefix[] = "rev-counter-generation"; + ed25519_secret_key_t *eph_privkey = &hs_desc->blinded_kp.seckey; + crypto_digest_add_bytes(digest, ope_key_prefix, sizeof(ope_key_prefix)); + crypto_digest_add_bytes(digest, (char*)eph_privkey->seckey, + sizeof(eph_privkey->seckey)); + crypto_digest_get_digest(digest, (char *)key, sizeof(key)); + crypto_digest_free(digest); + } + + { /* Now encrypt the revision counter! */ + crypto_ope_t *ope = NULL; + ope = crypto_ope_new(key); + rev_counter = crypto_ope_encrypt(ope, (int) seconds_since_start_of_srv); + crypto_ope_free(ope); + } + + /* The OPE module returns UINT64_MAX in case of errors. */ + tor_assert_nonfatal(rev_counter < UINT64_MAX); + + log_info(LD_REND, "Encrypted revision counter %d to %ld", + (int) seconds_since_start_of_srv, (long int) rev_counter); + + hs_desc->desc->plaintext_data.revision_counter = rev_counter; } /* Encode and sign the service descriptor desc and upload it to the diff --git a/src/or/or.h b/src/or/or.h index 528159b4c6..4f071889a2 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -79,6 +79,7 @@ #include "or/replaycache.h" #include "lib/crypt_ops/crypto_curve25519.h" #include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_ope.h" #include "tor_queue.h" #include "common/token_bucket.h" #include "common/util_format.h"