mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 23:53:32 +01:00
Merge branch 'bug25552_ope_squashed'
This commit is contained in:
commit
e2b744ce38
5
changes/bug25552
Normal file
5
changes/bug25552
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
o Major feature (onion services):
|
||||||
|
- Improve revision counter generation in next-gen onion services. Onion
|
||||||
|
services can now scale by hosting multiple instances on different hosts
|
||||||
|
without synchronization between them, which was previously impossible
|
||||||
|
because descriptors would get rejected by HSDirs. Addresses ticket 25552.
|
@ -168,7 +168,7 @@ voting_schedule_get_next_valid_after_time(void)
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
if (need_to_recalculate_voting_schedule) {
|
if (need_to_recalculate_voting_schedule) {
|
||||||
voting_schedule_recalculate_timing(get_options(), now);
|
voting_schedule_recalculate_timing(get_options(), approx_time());
|
||||||
voting_schedule.created_on_demand = 1;
|
voting_schedule.created_on_demand = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,8 +1102,7 @@ hs_in_period_between_tp_and_srv,(const networkstatus_t *consensus, time_t now))
|
|||||||
/* Get start time of next TP and of current SRV protocol run, and check if we
|
/* Get start time of next TP and of current SRV protocol run, and check if we
|
||||||
* are between them. */
|
* are between them. */
|
||||||
valid_after = consensus->valid_after;
|
valid_after = consensus->valid_after;
|
||||||
srv_start_time =
|
srv_start_time = sr_state_get_start_time_of_current_protocol_run();
|
||||||
sr_state_get_start_time_of_current_protocol_run(valid_after);
|
|
||||||
tp_start_time = hs_get_start_time_of_next_time_period(srv_start_time);
|
tp_start_time = hs_get_start_time_of_next_time_period(srv_start_time);
|
||||||
|
|
||||||
if (valid_after >= srv_start_time && valid_after < tp_start_time) {
|
if (valid_after >= srv_start_time && valid_after < tp_start_time) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "core/mainloop/connection.h"
|
#include "core/mainloop/connection.h"
|
||||||
#include "lib/crypt_ops/crypto_rand.h"
|
#include "lib/crypt_ops/crypto_rand.h"
|
||||||
#include "lib/crypt_ops/crypto_util.h"
|
#include "lib/crypt_ops/crypto_util.h"
|
||||||
|
#include "lib/crypt_ops/crypto_ope.h"
|
||||||
#include "feature/dircache/directory.h"
|
#include "feature/dircache/directory.h"
|
||||||
#include "core/mainloop/main.h"
|
#include "core/mainloop/main.h"
|
||||||
#include "feature/nodelist/networkstatus.h"
|
#include "feature/nodelist/networkstatus.h"
|
||||||
@ -102,7 +103,8 @@ static smartlist_t *hs_service_staging_list;
|
|||||||
static int consider_republishing_hs_descriptors = 0;
|
static int consider_republishing_hs_descriptors = 0;
|
||||||
|
|
||||||
/* Static declaration. */
|
/* 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);
|
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
|
/* Helper: Function to compare two objects in the service map. Return 1 if the
|
||||||
@ -443,7 +445,7 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy)
|
|||||||
if (BUG(intro_point_max_lifetime < intro_point_min_lifetime)) {
|
if (BUG(intro_point_max_lifetime < intro_point_min_lifetime)) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
ip->time_to_expire = time(NULL) +
|
ip->time_to_expire = approx_time() +
|
||||||
crypto_rand_int_range(intro_point_min_lifetime,intro_point_max_lifetime);
|
crypto_rand_int_range(intro_point_min_lifetime,intro_point_max_lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1084,6 +1086,7 @@ service_descriptor_free_(hs_service_descriptor_t *desc)
|
|||||||
SMARTLIST_FOREACH(desc->previous_hsdirs, char *, s, tor_free(s));
|
SMARTLIST_FOREACH(desc->previous_hsdirs, char *, s, tor_free(s));
|
||||||
smartlist_free(desc->previous_hsdirs);
|
smartlist_free(desc->previous_hsdirs);
|
||||||
}
|
}
|
||||||
|
crypto_ope_free(desc->ope_cipher);
|
||||||
tor_free(desc);
|
tor_free(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,13 +1391,30 @@ build_service_desc_plaintext(const hs_service_t *service,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compute the descriptor's OPE cipher for encrypting revision counters. */
|
||||||
|
static crypto_ope_t *
|
||||||
|
generate_ope_cipher_for_desc(const hs_service_descriptor_t *hs_desc)
|
||||||
|
{
|
||||||
|
/* Compute OPE key as H("rev-counter-generation" | blinded privkey) */
|
||||||
|
uint8_t key[DIGEST256_LEN];
|
||||||
|
crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA3_256);
|
||||||
|
const char ope_key_prefix[] = "rev-counter-generation";
|
||||||
|
const 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);
|
||||||
|
|
||||||
|
return crypto_ope_new(key);
|
||||||
|
}
|
||||||
|
|
||||||
/* For the given service and descriptor object, create the key material which
|
/* For the given service and descriptor object, create the key material which
|
||||||
* is the blinded keypair and the descriptor signing keypair. Return 0 on
|
* is the blinded keypair and the descriptor signing keypair. Return 0 on
|
||||||
* success else -1 on error where the generated keys MUST be ignored. */
|
* success else -1 on error where the generated keys MUST be ignored. */
|
||||||
static int
|
static int
|
||||||
build_service_desc_keys(const hs_service_t *service,
|
build_service_desc_keys(const hs_service_t *service,
|
||||||
hs_service_descriptor_t *desc,
|
hs_service_descriptor_t *desc)
|
||||||
uint64_t time_period_num)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
ed25519_keypair_t kp;
|
ed25519_keypair_t kp;
|
||||||
@ -1410,10 +1430,17 @@ build_service_desc_keys(const hs_service_t *service,
|
|||||||
memcpy(&kp.pubkey, &service->keys.identity_pk, sizeof(kp.pubkey));
|
memcpy(&kp.pubkey, &service->keys.identity_pk, sizeof(kp.pubkey));
|
||||||
memcpy(&kp.seckey, &service->keys.identity_sk, sizeof(kp.seckey));
|
memcpy(&kp.seckey, &service->keys.identity_sk, sizeof(kp.seckey));
|
||||||
/* Build blinded keypair for this time period. */
|
/* Build blinded keypair for this time period. */
|
||||||
hs_build_blinded_keypair(&kp, NULL, 0, time_period_num, &desc->blinded_kp);
|
hs_build_blinded_keypair(&kp, NULL, 0, desc->time_period_num,
|
||||||
|
&desc->blinded_kp);
|
||||||
/* Let's not keep too much traces of our keys in memory. */
|
/* Let's not keep too much traces of our keys in memory. */
|
||||||
memwipe(&kp, 0, sizeof(kp));
|
memwipe(&kp, 0, sizeof(kp));
|
||||||
|
|
||||||
|
/* Compute the OPE cipher struct (it's tied to the current blinded key) */
|
||||||
|
log_info(LD_GENERAL,
|
||||||
|
"Getting OPE for TP#%u", (unsigned) desc->time_period_num);
|
||||||
|
tor_assert_nonfatal(!desc->ope_cipher);
|
||||||
|
desc->ope_cipher = generate_ope_cipher_for_desc(desc);
|
||||||
|
|
||||||
/* No need for extra strong, this is a temporary key only for this
|
/* No need for extra strong, this is a temporary key only for this
|
||||||
* descriptor. Nothing long term. */
|
* descriptor. Nothing long term. */
|
||||||
if (ed25519_keypair_generate(&desc->signing_kp, 0) < 0) {
|
if (ed25519_keypair_generate(&desc->signing_kp, 0) < 0) {
|
||||||
@ -1444,10 +1471,12 @@ build_service_descriptor(hs_service_t *service, time_t now,
|
|||||||
tor_assert(desc_out);
|
tor_assert(desc_out);
|
||||||
|
|
||||||
desc = service_descriptor_new();
|
desc = service_descriptor_new();
|
||||||
|
|
||||||
|
/* Set current time period */
|
||||||
desc->time_period_num = time_period_num;
|
desc->time_period_num = time_period_num;
|
||||||
|
|
||||||
/* Create the needed keys so we can setup the descriptor content. */
|
/* Create the needed keys so we can setup the descriptor content. */
|
||||||
if (build_service_desc_keys(service, desc, time_period_num) < 0) {
|
if (build_service_desc_keys(service, desc) < 0) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
/* Setup plaintext descriptor content. */
|
/* Setup plaintext descriptor content. */
|
||||||
@ -1459,9 +1488,6 @@ build_service_descriptor(hs_service_t *service, time_t now,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the revision counter for this descriptor */
|
|
||||||
set_descriptor_revision_counter(desc->desc);
|
|
||||||
|
|
||||||
/* Let's make sure that we've created a descriptor that can actually be
|
/* 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
|
* encoded properly. This function also checks if the encoded output is
|
||||||
* decodable after. */
|
* decodable after. */
|
||||||
@ -1769,7 +1795,6 @@ service_desc_schedule_upload(hs_service_descriptor_t *desc,
|
|||||||
/* Update the given descriptor from the given service. The possible update
|
/* Update the given descriptor from the given service. The possible update
|
||||||
* actions includes:
|
* actions includes:
|
||||||
* - Picking missing intro points if needed.
|
* - Picking missing intro points if needed.
|
||||||
* - Incrementing the revision counter if needed.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
update_service_descriptor(hs_service_t *service,
|
update_service_descriptor(hs_service_t *service,
|
||||||
@ -1933,19 +1958,12 @@ cleanup_intro_points(hs_service_t *service, time_t now)
|
|||||||
/* Set the next rotation time of the descriptors for the given service for the
|
/* Set the next rotation time of the descriptors for the given service for the
|
||||||
* time now. */
|
* time now. */
|
||||||
static void
|
static void
|
||||||
set_rotation_time(hs_service_t *service, time_t now)
|
set_rotation_time(hs_service_t *service)
|
||||||
{
|
{
|
||||||
time_t valid_after;
|
|
||||||
const networkstatus_t *ns = networkstatus_get_live_consensus(now);
|
|
||||||
if (ns) {
|
|
||||||
valid_after = ns->valid_after;
|
|
||||||
} else {
|
|
||||||
valid_after = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
tor_assert(service);
|
tor_assert(service);
|
||||||
|
|
||||||
service->state.next_rotation_time =
|
service->state.next_rotation_time =
|
||||||
sr_state_get_start_time_of_current_protocol_run(valid_after) +
|
sr_state_get_start_time_of_current_protocol_run() +
|
||||||
sr_state_get_protocol_run_duration();
|
sr_state_get_protocol_run_duration();
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -2012,7 +2030,7 @@ should_rotate_descriptors(hs_service_t *service, time_t now)
|
|||||||
* will be freed, the next one put in as the current and finally the next
|
* will be freed, the next one put in as the current and finally the next
|
||||||
* descriptor pointer is NULLified. */
|
* descriptor pointer is NULLified. */
|
||||||
static void
|
static void
|
||||||
rotate_service_descriptors(hs_service_t *service, time_t now)
|
rotate_service_descriptors(hs_service_t *service)
|
||||||
{
|
{
|
||||||
if (service->desc_current) {
|
if (service->desc_current) {
|
||||||
/* Close all IP circuits for the descriptor. */
|
/* Close all IP circuits for the descriptor. */
|
||||||
@ -2027,7 +2045,7 @@ rotate_service_descriptors(hs_service_t *service, time_t now)
|
|||||||
service->desc_next = NULL;
|
service->desc_next = NULL;
|
||||||
|
|
||||||
/* We've just rotated, set the next time for the rotation. */
|
/* We've just rotated, set the next time for the rotation. */
|
||||||
set_rotation_time(service, now);
|
set_rotation_time(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rotate descriptors for each service if needed. A non existing current
|
/* Rotate descriptors for each service if needed. A non existing current
|
||||||
@ -2055,7 +2073,7 @@ rotate_all_descriptors(time_t now)
|
|||||||
service->desc_current, service->desc_next,
|
service->desc_current, service->desc_next,
|
||||||
safe_str_client(service->onion_address));
|
safe_str_client(service->onion_address));
|
||||||
|
|
||||||
rotate_service_descriptors(service, now);
|
rotate_service_descriptors(service);
|
||||||
} FOR_EACH_SERVICE_END;
|
} FOR_EACH_SERVICE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2077,7 +2095,7 @@ run_housekeeping_event(time_t now)
|
|||||||
/* Set the next rotation time of the descriptors. If it's Oct 25th
|
/* Set the next rotation time of the descriptors. If it's Oct 25th
|
||||||
* 23:47:00, the next rotation time is when the next SRV is computed
|
* 23:47:00, the next rotation time is when the next SRV is computed
|
||||||
* which is at Oct 26th 00:00:00 that is in 13 minutes. */
|
* which is at Oct 26th 00:00:00 that is in 13 minutes. */
|
||||||
set_rotation_time(service, now);
|
set_rotation_time(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cleanup invalid intro points from the service descriptor. */
|
/* Cleanup invalid intro points from the service descriptor. */
|
||||||
@ -2326,13 +2344,17 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
|
|||||||
int is_next_desc = (service->desc_next == desc);
|
int is_next_desc = (service->desc_next == desc);
|
||||||
const uint8_t *idx = (is_next_desc) ? hsdir->hsdir_index.store_second:
|
const uint8_t *idx = (is_next_desc) ? hsdir->hsdir_index.store_second:
|
||||||
hsdir->hsdir_index.store_first;
|
hsdir->hsdir_index.store_first;
|
||||||
|
char *blinded_pubkey_log_str =
|
||||||
|
tor_strdup(hex_str((char*)&desc->blinded_kp.pubkey.pubkey, 32));
|
||||||
log_info(LD_REND, "Service %s %s descriptor of revision %" PRIu64
|
log_info(LD_REND, "Service %s %s descriptor of revision %" PRIu64
|
||||||
" initiated upload request to %s with index %s",
|
" initiated upload request to %s with index %s (%s)",
|
||||||
safe_str_client(service->onion_address),
|
safe_str_client(service->onion_address),
|
||||||
(is_next_desc) ? "next" : "current",
|
(is_next_desc) ? "next" : "current",
|
||||||
desc->desc->plaintext_data.revision_counter,
|
desc->desc->plaintext_data.revision_counter,
|
||||||
safe_str_client(node_describe(hsdir)),
|
safe_str_client(node_describe(hsdir)),
|
||||||
safe_str_client(hex_str((const char *) idx, 32)));
|
safe_str_client(hex_str((const char *) idx, 32)),
|
||||||
|
safe_str_client(blinded_pubkey_log_str));
|
||||||
|
tor_free(blinded_pubkey_log_str);
|
||||||
|
|
||||||
/* Fire a UPLOAD control port event. */
|
/* Fire a UPLOAD control port event. */
|
||||||
hs_control_desc_event_upload(service->onion_address, hsdir->identity,
|
hs_control_desc_event_upload(service->onion_address, hsdir->identity,
|
||||||
@ -2344,197 +2366,77 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return a newly-allocated string for our state file which contains revision
|
/** Set the revision counter in <b>hs_desc</b>. We do this by encrypting a
|
||||||
* counter information for <b>desc</b>. The format is:
|
* timestamp using an OPE scheme and using the ciphertext as our revision
|
||||||
|
* counter.
|
||||||
*
|
*
|
||||||
* HidServRevCounter <blinded_pubkey> <rev_counter>
|
* If <b>is_current</b> is true, then this is the current HS descriptor,
|
||||||
*/
|
* otherwise it's the next one. */
|
||||||
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
|
static void
|
||||||
update_revision_counters_in_state(void)
|
set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc, time_t now,
|
||||||
|
bool is_current)
|
||||||
{
|
{
|
||||||
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;
|
uint64_t rev_counter = 0;
|
||||||
|
|
||||||
tor_assert(service_found_out);
|
/* Get current time */
|
||||||
tor_assert(state_line);
|
time_t srv_start = 0;
|
||||||
tor_assert(blinded_pubkey);
|
|
||||||
|
|
||||||
/* Assume that the line is not for this service */
|
/* As our revision counter plaintext value, we use the seconds since the
|
||||||
*service_found_out = 0;
|
* 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
|
||||||
/* Start parsing the state line */
|
* descriptor (so that we know where to upload it).
|
||||||
items = smartlist_new();
|
*
|
||||||
smartlist_split_string(items, state_line, NULL,
|
* Depending on whether we are building the current or the next descriptor,
|
||||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
|
* services use a different SRV value. See [SERVICEUPLOAD] in
|
||||||
if (smartlist_len(items) < 2) {
|
* rend-spec-v3.txt:
|
||||||
log_warn(LD_GENERAL, "Incomplete rev counter line. Ignoring.");
|
*
|
||||||
goto done;
|
* 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();
|
||||||
|
} else {
|
||||||
|
srv_start = sr_state_get_start_time_of_current_protocol_run();
|
||||||
}
|
}
|
||||||
|
|
||||||
char *b64_key_str = smartlist_get(items, 0);
|
log_info(LD_REND, "Setting rev counter for TP #%u: "
|
||||||
char *saved_rev_counter_str = smartlist_get(items, 1);
|
"SRV started at %d, now %d (%s)",
|
||||||
|
(unsigned) hs_desc->time_period_num, (int)srv_start,
|
||||||
|
(int)now, is_current ? "current" : "next");
|
||||||
|
|
||||||
/* Parse blinded key to check if it's for this hidden service */
|
tor_assert_nonfatal(now >= srv_start);
|
||||||
if (ed25519_public_from_base64(&pubkey_in_state, b64_key_str) < 0) {
|
|
||||||
log_warn(LD_GENERAL, "Unable to base64 key in revcount line. Ignoring.");
|
/* Compute seconds elapsed since the start of the time period. That's the
|
||||||
goto done;
|
* number of seconds of how long this blinded key has been active. */
|
||||||
}
|
time_t seconds_since_start_of_srv = now - srv_start;
|
||||||
/* State line not for this hidden service */
|
|
||||||
if (!ed25519_pubkey_eq(&pubkey_in_state, blinded_pubkey)) {
|
/* Increment by one so that we are definitely sure this is strictly
|
||||||
goto done;
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
rev_counter = tor_parse_uint64(saved_rev_counter_str,
|
/* Now we compute the final revision counter value by encrypting the
|
||||||
10, 0, UINT64_MAX, &ok, NULL);
|
plaintext using our OPE cipher: */
|
||||||
if (!ok) {
|
tor_assert(hs_desc->ope_cipher);
|
||||||
log_warn(LD_GENERAL, "Unable to parse rev counter. Ignoring.");
|
rev_counter = crypto_ope_encrypt(hs_desc->ope_cipher,
|
||||||
goto done;
|
(int) seconds_since_start_of_srv);
|
||||||
}
|
|
||||||
|
|
||||||
/* Since we got this far, the line was for this service */
|
/* The OPE module returns CRYPTO_OPE_ERROR in case of errors. */
|
||||||
*service_found_out = 1;
|
tor_assert_nonfatal(rev_counter < CRYPTO_OPE_ERROR);
|
||||||
|
|
||||||
log_info(LD_GENERAL, "Found rev counter for %s: %" PRIu64,
|
log_info(LD_REND, "Encrypted revision counter %d to %ld",
|
||||||
b64_key_str, rev_counter);
|
(int) seconds_since_start_of_srv, (long int) rev_counter);
|
||||||
|
|
||||||
done:
|
hs_desc->desc->plaintext_data.revision_counter = rev_counter;
|
||||||
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>, using the state file to find
|
|
||||||
* the current counter value if it exists. */
|
|
||||||
static void
|
|
||||||
set_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);
|
|
||||||
|
|
||||||
hs_desc->plaintext_data.revision_counter = rev_counter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode and sign the service descriptor desc and upload it to the
|
/* Encode and sign the service descriptor desc and upload it to the
|
||||||
@ -2592,9 +2494,6 @@ upload_descriptor_to_all(const hs_service_t *service,
|
|||||||
safe_str_client(service->onion_address), fmt_next_time);
|
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);
|
smartlist_free(responsible_dirs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2734,6 +2633,10 @@ run_upload_descriptor_event(time_t now)
|
|||||||
* accurate because all circuits have been established. */
|
* accurate because all circuits have been established. */
|
||||||
build_desc_intro_points(service, desc, now);
|
build_desc_intro_points(service, desc, now);
|
||||||
|
|
||||||
|
/* Set the desc revision counter right before uploading */
|
||||||
|
set_descriptor_revision_counter(desc, approx_time(),
|
||||||
|
service->desc_current == desc);
|
||||||
|
|
||||||
upload_descriptor_to_all(service, desc);
|
upload_descriptor_to_all(service, desc);
|
||||||
} FOR_EACH_DESCRIPTOR_END;
|
} FOR_EACH_DESCRIPTOR_END;
|
||||||
} FOR_EACH_SERVICE_END;
|
} FOR_EACH_SERVICE_END;
|
||||||
|
@ -131,6 +131,10 @@ typedef struct hs_service_descriptor_t {
|
|||||||
* from this list, this means we received new dirinfo and we need to
|
* from this list, this means we received new dirinfo and we need to
|
||||||
* reupload our descriptor. */
|
* reupload our descriptor. */
|
||||||
smartlist_t *previous_hsdirs;
|
smartlist_t *previous_hsdirs;
|
||||||
|
|
||||||
|
/** The OPE cipher for encrypting revision counters for this descriptor.
|
||||||
|
* Tied to the descriptor blinded key. */
|
||||||
|
struct crypto_ope_t *ope_cipher;
|
||||||
} hs_service_descriptor_t;
|
} hs_service_descriptor_t;
|
||||||
|
|
||||||
/* Service key material. */
|
/* Service key material. */
|
||||||
@ -346,19 +350,10 @@ STATIC void build_all_descriptors(time_t now);
|
|||||||
STATIC void update_all_descriptors(time_t now);
|
STATIC void update_all_descriptors(time_t now);
|
||||||
STATIC void run_upload_descriptor_event(time_t now);
|
STATIC void run_upload_descriptor_event(time_t now);
|
||||||
|
|
||||||
STATIC char *
|
|
||||||
encode_desc_rev_counter_for_state(const hs_service_descriptor_t *desc);
|
|
||||||
|
|
||||||
STATIC void service_descriptor_free_(hs_service_descriptor_t *desc);
|
STATIC void service_descriptor_free_(hs_service_descriptor_t *desc);
|
||||||
#define service_descriptor_free(d) \
|
#define service_descriptor_free(d) \
|
||||||
FREE_AND_NULL(hs_service_descriptor_t, \
|
FREE_AND_NULL(hs_service_descriptor_t, \
|
||||||
service_descriptor_free_, (d))
|
service_descriptor_free_, (d))
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
write_address_to_file(const hs_service_t *service, const char *fname_);
|
write_address_to_file(const hs_service_t *service, const char *fname_);
|
||||||
|
|
||||||
@ -375,4 +370,3 @@ STATIC int service_desc_hsdirs_changed(const hs_service_t *service,
|
|||||||
#endif /* defined(HS_SERVICE_PRIVATE) */
|
#endif /* defined(HS_SERVICE_PRIVATE) */
|
||||||
|
|
||||||
#endif /* !defined(TOR_HS_SERVICE_H) */
|
#endif /* !defined(TOR_HS_SERVICE_H) */
|
||||||
|
|
||||||
|
@ -222,24 +222,44 @@ sr_parse_srv(const smartlist_t *args)
|
|||||||
return srv;
|
return srv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the start time of the current SR protocol run. For example, if the
|
/** Return the start time of the current SR protocol run using the times from
|
||||||
* time is 23/06/2017 23:47:08 and a full SR protocol run is 24 hours, this
|
* the current consensus. For example, if the latest consensus valid-after is
|
||||||
* function should return 23/06/2017 00:00:00. */
|
* 23/06/2017 23:00:00 and a full SR protocol run is 24 hours, this function
|
||||||
|
* returns 23/06/2017 00:00:00. */
|
||||||
time_t
|
time_t
|
||||||
sr_state_get_start_time_of_current_protocol_run(time_t now)
|
sr_state_get_start_time_of_current_protocol_run(void)
|
||||||
{
|
{
|
||||||
int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
|
int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
|
||||||
int voting_interval = get_voting_interval();
|
int voting_interval = get_voting_interval();
|
||||||
/* Find the time the current round started. */
|
/* Find the time the current round started. */
|
||||||
time_t beginning_of_current_round = get_start_time_of_current_round();
|
time_t beginning_of_curr_round = get_start_time_of_current_round();
|
||||||
|
|
||||||
/* Get current SR protocol round */
|
/* Get current SR protocol round */
|
||||||
int current_round = (now / voting_interval) % total_rounds;
|
int curr_round_slot;
|
||||||
|
curr_round_slot = (beginning_of_curr_round / voting_interval) % total_rounds;
|
||||||
|
|
||||||
/* Get start time by subtracting the time elapsed from the beginning of the
|
/* Get start time by subtracting the time elapsed from the beginning of the
|
||||||
protocol run */
|
protocol run */
|
||||||
time_t time_elapsed_since_start_of_run = current_round * voting_interval;
|
time_t time_elapsed_since_start_of_run = curr_round_slot * voting_interval;
|
||||||
return beginning_of_current_round - time_elapsed_since_start_of_run;
|
|
||||||
|
log_debug(LD_GENERAL, "Current SRV proto run: Start of current round: %u. "
|
||||||
|
"Time elapsed: %u (%d)", (unsigned) beginning_of_curr_round,
|
||||||
|
(unsigned) time_elapsed_since_start_of_run, voting_interval);
|
||||||
|
|
||||||
|
return beginning_of_curr_round - time_elapsed_since_start_of_run;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the start time of the previous SR protocol run. See
|
||||||
|
* sr_state_get_start_time_of_current_protocol_run() for more details. */
|
||||||
|
time_t
|
||||||
|
sr_state_get_start_time_of_previous_protocol_run(void)
|
||||||
|
{
|
||||||
|
time_t start_time_of_current_run =
|
||||||
|
sr_state_get_start_time_of_current_protocol_run();
|
||||||
|
|
||||||
|
/* We get the start time of previous protocol run, by getting the start time
|
||||||
|
* of current run and the subtracting a full protocol run from that. */
|
||||||
|
return start_time_of_current_run - sr_state_get_protocol_run_duration();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the time (in seconds) it takes to complete a full SR protocol phase
|
/** Return the time (in seconds) it takes to complete a full SR protocol phase
|
||||||
|
@ -34,7 +34,8 @@ sr_srv_t *sr_parse_srv(const smartlist_t *args);
|
|||||||
/* Number of phase we have in a protocol. */
|
/* Number of phase we have in a protocol. */
|
||||||
#define SHARED_RANDOM_N_PHASES 2
|
#define SHARED_RANDOM_N_PHASES 2
|
||||||
|
|
||||||
time_t sr_state_get_start_time_of_current_protocol_run(time_t now);
|
time_t sr_state_get_start_time_of_current_protocol_run(void);
|
||||||
|
time_t sr_state_get_start_time_of_previous_protocol_run(void);
|
||||||
unsigned int sr_state_get_phase_duration(void);
|
unsigned int sr_state_get_phase_duration(void);
|
||||||
unsigned int sr_state_get_protocol_run_duration(void);
|
unsigned int sr_state_get_protocol_run_duration(void);
|
||||||
time_t get_start_time_of_current_round(void);
|
time_t get_start_time_of_current_round(void);
|
||||||
|
185
src/lib/crypt_ops/crypto_ope.c
Normal file
185
src/lib/crypt_ops/crypto_ope.c
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
/* Copyright (c) 2018, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A rudimentary order-preserving encryption scheme.
|
||||||
|
*
|
||||||
|
* To compute the encryption of N, this scheme uses an AES-CTR stream to
|
||||||
|
* generate M-byte values, and adds the first N of them together. (+1 each to
|
||||||
|
* insure that the ciphertexts are strictly decreasing.)
|
||||||
|
*
|
||||||
|
* We use this for generating onion service revision counters based on the
|
||||||
|
* current time, without leaking the amount of skew in our view of the current
|
||||||
|
* time. MUCH more analysis would be needed before using it for anything
|
||||||
|
* else!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
|
||||||
|
#define CRYPTO_OPE_PRIVATE
|
||||||
|
#include "lib/crypt_ops/crypto_ope.h"
|
||||||
|
#include "lib/crypt_ops/crypto.h"
|
||||||
|
#include "lib/crypt_ops/crypto_util.h"
|
||||||
|
#include "lib/log/util_bug.h"
|
||||||
|
#include "lib/malloc/malloc.h"
|
||||||
|
#include "lib/arch/bytes.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How infrequent should the precomputed values be for this encryption?
|
||||||
|
* The choice of this value creates a space/time tradeoff.
|
||||||
|
*
|
||||||
|
* Note that this value must be a multiple of 16; see
|
||||||
|
* ope_get_cipher()
|
||||||
|
*/
|
||||||
|
#define SAMPLE_INTERVAL 1024
|
||||||
|
/** Number of precomputed samples to make for each OPE key. */
|
||||||
|
#define N_SAMPLES (OPE_INPUT_MAX / SAMPLE_INTERVAL)
|
||||||
|
|
||||||
|
struct crypto_ope_t {
|
||||||
|
/** An AES key for use with this object. */
|
||||||
|
uint8_t key[OPE_KEY_LEN];
|
||||||
|
/** Cached intermediate encryption values at SAMPLE_INTERVAL,
|
||||||
|
* SAMPLE_INTERVAL*2,...SAMPLE_INTERVAL*N_SAMPLES */
|
||||||
|
uint64_t samples[N_SAMPLES];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The type to add up in order to produce our OPE ciphertexts */
|
||||||
|
typedef uint16_t ope_val_t;
|
||||||
|
|
||||||
|
#ifdef WORDS_BIG_ENDIAN
|
||||||
|
/** Convert an OPE value to little-endian */
|
||||||
|
static inline ope_val_t
|
||||||
|
ope_val_to_le(ope_val_t x)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
((x) >> 8) |
|
||||||
|
(((x)&0xff) << 8);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define ope_val_to_le(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new AES256-CTR stream cipher object for <b>ope</b>, ready to yield
|
||||||
|
* bytes from the stream at position <b>initial_idx</b>.
|
||||||
|
*
|
||||||
|
* Note that because the index is converted directly to an IV, it must be a
|
||||||
|
* multiple of the AES block size (16).
|
||||||
|
*/
|
||||||
|
STATIC crypto_cipher_t *
|
||||||
|
ope_get_cipher(const crypto_ope_t *ope, uint32_t initial_idx)
|
||||||
|
{
|
||||||
|
uint8_t iv[CIPHER_IV_LEN];
|
||||||
|
tor_assert((initial_idx & 0xf) == 0);
|
||||||
|
uint32_t n = tor_htonl(initial_idx >> 4);
|
||||||
|
memset(iv, 0, sizeof(iv));
|
||||||
|
memcpy(iv + CIPHER_IV_LEN - sizeof(n), &n, sizeof(n));
|
||||||
|
|
||||||
|
return crypto_cipher_new_with_iv_and_bits(ope->key,
|
||||||
|
iv,
|
||||||
|
OPE_KEY_LEN * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve and add the next <b>n</b> values from the stream cipher <b>c</b>,
|
||||||
|
* and return their sum.
|
||||||
|
*
|
||||||
|
* Note that values are taken in little-endian order (for performance on
|
||||||
|
* prevalent hardware), and are mapped from range 0..2^n-1 to range 1..2^n (so
|
||||||
|
* that each input encrypts to a different output).
|
||||||
|
*
|
||||||
|
* NOTE: this function is not constant-time.
|
||||||
|
*/
|
||||||
|
STATIC uint64_t
|
||||||
|
sum_values_from_cipher(crypto_cipher_t *c, size_t n)
|
||||||
|
{
|
||||||
|
#define BUFSZ 256
|
||||||
|
ope_val_t buf[BUFSZ];
|
||||||
|
uint64_t total = 0;
|
||||||
|
unsigned i;
|
||||||
|
while (n >= BUFSZ) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
crypto_cipher_crypt_inplace(c, (char*)buf, BUFSZ*sizeof(ope_val_t));
|
||||||
|
|
||||||
|
for (i = 0; i < BUFSZ; ++i) {
|
||||||
|
total += ope_val_to_le(buf[i]);
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
n -= BUFSZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, n*sizeof(ope_val_t));
|
||||||
|
crypto_cipher_crypt_inplace(c, (char*)buf, n*sizeof(ope_val_t));
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
total += ope_val_to_le(buf[i]);
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new crypto_ope_t object, using the provided 256-bit key.
|
||||||
|
*/
|
||||||
|
crypto_ope_t *
|
||||||
|
crypto_ope_new(const uint8_t *key)
|
||||||
|
{
|
||||||
|
crypto_ope_t *ope = tor_malloc_zero(sizeof(crypto_ope_t));
|
||||||
|
memcpy(ope->key, key, OPE_KEY_LEN);
|
||||||
|
|
||||||
|
crypto_cipher_t *cipher = ope_get_cipher(ope, 0);
|
||||||
|
|
||||||
|
uint64_t v = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < N_SAMPLES; ++i) {
|
||||||
|
v += sum_values_from_cipher(cipher, SAMPLE_INTERVAL);
|
||||||
|
ope->samples[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_cipher_free(cipher);
|
||||||
|
return ope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Free all storage held in <>ope</b>. */
|
||||||
|
void
|
||||||
|
crypto_ope_free_(crypto_ope_t *ope)
|
||||||
|
{
|
||||||
|
if (!ope)
|
||||||
|
return;
|
||||||
|
memwipe(ope, 0, sizeof(*ope));
|
||||||
|
tor_free(ope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the encrypted value corresponding to <b>input</b>. The input value
|
||||||
|
* must be in range 1..OPE_INPUT_MAX. Returns CRYPTO_OPE_ERROR on an invalid
|
||||||
|
* input.
|
||||||
|
*
|
||||||
|
* NOTE: this function is not constant-time.
|
||||||
|
*/
|
||||||
|
uint64_t
|
||||||
|
crypto_ope_encrypt(const crypto_ope_t *ope, int plaintext)
|
||||||
|
{
|
||||||
|
if (plaintext <= 0 || plaintext > OPE_INPUT_MAX)
|
||||||
|
return CRYPTO_OPE_ERROR;
|
||||||
|
|
||||||
|
const int sample_idx = (plaintext / SAMPLE_INTERVAL);
|
||||||
|
const int starting_iv = sample_idx * SAMPLE_INTERVAL;
|
||||||
|
const int remaining_values = plaintext - starting_iv;
|
||||||
|
uint64_t v;
|
||||||
|
if (sample_idx == 0) {
|
||||||
|
v = 0;
|
||||||
|
} else {
|
||||||
|
v = ope->samples[sample_idx - 1];
|
||||||
|
}
|
||||||
|
crypto_cipher_t *cipher = ope_get_cipher(ope, starting_iv*sizeof(ope_val_t));
|
||||||
|
|
||||||
|
v += sum_values_from_cipher(cipher, remaining_values);
|
||||||
|
|
||||||
|
crypto_cipher_free(cipher);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
46
src/lib/crypt_ops/crypto_ope.h
Normal file
46
src/lib/crypt_ops/crypto_ope.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* Copyright (c) 2018, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#ifndef CRYPTO_OPE_H
|
||||||
|
#define CRYPTO_OPE_H
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include "lib/cc/torint.h"
|
||||||
|
#include "lib/crypt_ops/crypto_ope.h"
|
||||||
|
#include "lib/testsupport/testsupport.h"
|
||||||
|
|
||||||
|
/** Length of OPE key, in bytes. */
|
||||||
|
#define OPE_KEY_LEN 32
|
||||||
|
|
||||||
|
/** Largest value that can be passed to crypto_ope_encrypt().
|
||||||
|
*
|
||||||
|
* Expressed as 2^18 because the OPE system prefers powers of two.
|
||||||
|
*
|
||||||
|
* The current max value stands for about 70 hours. The rationale here is as
|
||||||
|
* follows: The rev counter is the time of seconds since the start of an SRV
|
||||||
|
* period. SRVs are useful for about 48 hours (that's how long they stick
|
||||||
|
* around on the consensus). Let's also add 12 hours of drift for clock skewed
|
||||||
|
* services that might be using an old consensus and we arrive to 60
|
||||||
|
* hours. The max value should be beyond that.
|
||||||
|
*/
|
||||||
|
#define OPE_INPUT_MAX (1<<18)
|
||||||
|
|
||||||
|
#define CRYPTO_OPE_ERROR UINT64_MAX
|
||||||
|
|
||||||
|
typedef struct crypto_ope_t crypto_ope_t;
|
||||||
|
|
||||||
|
crypto_ope_t *crypto_ope_new(const uint8_t *key);
|
||||||
|
void crypto_ope_free_(crypto_ope_t *ope);
|
||||||
|
#define crypto_ope_free(ope) \
|
||||||
|
FREE_AND_NULL(crypto_ope_t, crypto_ope_free_, (ope))
|
||||||
|
|
||||||
|
uint64_t crypto_ope_encrypt(const crypto_ope_t *ope, int plaintext);
|
||||||
|
|
||||||
|
#ifdef CRYPTO_OPE_PRIVATE
|
||||||
|
struct aes_cnt_cipher;
|
||||||
|
STATIC struct aes_cnt_cipher *ope_get_cipher(const crypto_ope_t *ope,
|
||||||
|
uint32_t initial_idx);
|
||||||
|
STATIC uint64_t sum_values_from_cipher(struct aes_cnt_cipher *c, size_t n);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -14,6 +14,7 @@ src_lib_libtor_crypt_ops_a_SOURCES = \
|
|||||||
src/lib/crypt_ops/crypto_ed25519.c \
|
src/lib/crypt_ops/crypto_ed25519.c \
|
||||||
src/lib/crypt_ops/crypto_format.c \
|
src/lib/crypt_ops/crypto_format.c \
|
||||||
src/lib/crypt_ops/crypto_hkdf.c \
|
src/lib/crypt_ops/crypto_hkdf.c \
|
||||||
|
src/lib/crypt_ops/crypto_ope.c \
|
||||||
src/lib/crypt_ops/crypto_openssl_mgt.c \
|
src/lib/crypt_ops/crypto_openssl_mgt.c \
|
||||||
src/lib/crypt_ops/crypto_pwbox.c \
|
src/lib/crypt_ops/crypto_pwbox.c \
|
||||||
src/lib/crypt_ops/crypto_rand.c \
|
src/lib/crypt_ops/crypto_rand.c \
|
||||||
@ -38,6 +39,7 @@ noinst_HEADERS += \
|
|||||||
src/lib/crypt_ops/crypto.h \
|
src/lib/crypt_ops/crypto.h \
|
||||||
src/lib/crypt_ops/crypto_hkdf.h \
|
src/lib/crypt_ops/crypto_hkdf.h \
|
||||||
src/lib/crypt_ops/crypto_openssl_mgt.h \
|
src/lib/crypt_ops/crypto_openssl_mgt.h \
|
||||||
|
src/lib/crypt_ops/crypto_ope.h \
|
||||||
src/lib/crypt_ops/crypto_pwbox.h \
|
src/lib/crypt_ops/crypto_pwbox.h \
|
||||||
src/lib/crypt_ops/crypto_rand.h \
|
src/lib/crypt_ops/crypto_rand.h \
|
||||||
src/lib/crypt_ops/crypto_rsa.h \
|
src/lib/crypt_ops/crypto_rsa.h \
|
||||||
|
@ -117,6 +117,7 @@ src_test_test_SOURCES += \
|
|||||||
src/test/test_controller.c \
|
src/test/test_controller.c \
|
||||||
src/test/test_controller_events.c \
|
src/test/test_controller_events.c \
|
||||||
src/test/test_crypto.c \
|
src/test/test_crypto.c \
|
||||||
|
src/test/test_crypto_ope.c \
|
||||||
src/test/test_crypto_openssl.c \
|
src/test/test_crypto_openssl.c \
|
||||||
src/test/test_data.c \
|
src/test/test_data.c \
|
||||||
src/test/test_dir.c \
|
src/test/test_dir.c \
|
||||||
|
40
src/test/ope_ref.py
Normal file
40
src/test/ope_ref.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# Copyright 2018, The Tor Project, Inc. See LICENSE for licensing info.
|
||||||
|
|
||||||
|
# Reference implementation for our rudimentary OPE code, used to
|
||||||
|
# generate test vectors. See crypto_ope.c for more details.
|
||||||
|
|
||||||
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||||
|
from cryptography.hazmat.primitives.ciphers.algorithms import AES
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
|
||||||
|
from binascii import a2b_hex
|
||||||
|
|
||||||
|
#randomly generated and values.
|
||||||
|
KEY = a2b_hex(
|
||||||
|
"19e05891d55232c08c2cad91d612fdb9cbd6691949a0742434a76c80bc6992fe")
|
||||||
|
PTS = [ 121132, 82283, 72661, 72941, 123122, 12154, 121574, 11391, 65845,
|
||||||
|
86301, 61284, 70505, 30438, 60150, 114800, 109403, 21893, 123569,
|
||||||
|
95617, 48561, 53334, 92746, 7110, 9612, 106958, 46889, 87790, 68878,
|
||||||
|
47917, 121128, 108602, 28217, 69498, 63870, 57542, 122148, 46254,
|
||||||
|
42850, 92661, 57720]
|
||||||
|
|
||||||
|
IV = b'\x00' * 16
|
||||||
|
|
||||||
|
backend = default_backend()
|
||||||
|
|
||||||
|
def words():
|
||||||
|
cipher = Cipher(algorithms.AES(KEY), modes.CTR(IV), backend=backend)
|
||||||
|
e = cipher.encryptor()
|
||||||
|
while True:
|
||||||
|
v = e.update(b'\x00\x00')
|
||||||
|
yield v[0] + 256 * v[1] + 1
|
||||||
|
|
||||||
|
def encrypt(n):
|
||||||
|
return sum(w for w, _ in zip(words(), range(n)))
|
||||||
|
|
||||||
|
def example(n):
|
||||||
|
return ' {{ {}, UINT64_C({}) }},'.format(n, encrypt(n))
|
||||||
|
|
||||||
|
for v in PTS:
|
||||||
|
print(example(v))
|
@ -865,6 +865,7 @@ struct testgroup_t testgroups[] = {
|
|||||||
{ "control/", controller_tests },
|
{ "control/", controller_tests },
|
||||||
{ "control/event/", controller_event_tests },
|
{ "control/event/", controller_event_tests },
|
||||||
{ "crypto/", crypto_tests },
|
{ "crypto/", crypto_tests },
|
||||||
|
{ "crypto/ope/", crypto_ope_tests },
|
||||||
{ "crypto/openssl/", crypto_openssl_tests },
|
{ "crypto/openssl/", crypto_openssl_tests },
|
||||||
{ "dir/", dir_tests },
|
{ "dir/", dir_tests },
|
||||||
{ "dir_handle_get/", dir_handle_get_tests },
|
{ "dir_handle_get/", dir_handle_get_tests },
|
||||||
|
@ -203,6 +203,7 @@ extern struct testcase_t container_tests[];
|
|||||||
extern struct testcase_t controller_tests[];
|
extern struct testcase_t controller_tests[];
|
||||||
extern struct testcase_t controller_event_tests[];
|
extern struct testcase_t controller_event_tests[];
|
||||||
extern struct testcase_t crypto_tests[];
|
extern struct testcase_t crypto_tests[];
|
||||||
|
extern struct testcase_t crypto_ope_tests[];
|
||||||
extern struct testcase_t crypto_openssl_tests[];
|
extern struct testcase_t crypto_openssl_tests[];
|
||||||
extern struct testcase_t dir_tests[];
|
extern struct testcase_t dir_tests[];
|
||||||
extern struct testcase_t dir_handle_get_tests[];
|
extern struct testcase_t dir_handle_get_tests[];
|
||||||
|
152
src/test/test_crypto_ope.c
Normal file
152
src/test/test_crypto_ope.c
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/* Copyright (c) 2001-2004, Roger Dingledine.
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2017, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
|
||||||
|
#define CRYPTO_OPE_PRIVATE
|
||||||
|
|
||||||
|
#include "lib/crypt_ops/crypto_ope.h"
|
||||||
|
#include "lib/crypt_ops/crypto.h"
|
||||||
|
#include "lib/encoding/binascii.h"
|
||||||
|
#include "test/test.h"
|
||||||
|
#include "tinytest.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_crypto_ope_consistency(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
crypto_ope_t *ope = NULL;
|
||||||
|
crypto_cipher_t *aes = NULL;
|
||||||
|
const int TEST_VALS[] = { 5, 500, 1023, 1024, 1025, 2046, 2047, 2048, 2049,
|
||||||
|
10000, OPE_INPUT_MAX };
|
||||||
|
unsigned i;
|
||||||
|
const uint8_t key[32] = "A fixed key, chosen arbitrarily.";
|
||||||
|
|
||||||
|
ope = crypto_ope_new(key);
|
||||||
|
tt_assert(ope);
|
||||||
|
|
||||||
|
uint64_t last_val = 0;
|
||||||
|
for (i = 0; i < ARRAY_LENGTH(TEST_VALS); ++i) {
|
||||||
|
aes = ope_get_cipher(ope, 0);
|
||||||
|
int val = TEST_VALS[i];
|
||||||
|
uint64_t v1 = crypto_ope_encrypt(ope, val);
|
||||||
|
uint64_t v2 = sum_values_from_cipher(aes, val);
|
||||||
|
tt_u64_op(v1, OP_EQ, v2);
|
||||||
|
tt_u64_op(v2, OP_GT, last_val);
|
||||||
|
last_val = v2;
|
||||||
|
crypto_cipher_free(aes);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
crypto_cipher_free(aes);
|
||||||
|
crypto_ope_free(ope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_crypto_ope_oob(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
crypto_ope_t *ope = NULL;
|
||||||
|
const uint8_t key[32] = "A fixed key, chosen arbitrarily.";
|
||||||
|
ope = crypto_ope_new(key);
|
||||||
|
|
||||||
|
tt_u64_op(UINT64_MAX, OP_EQ, crypto_ope_encrypt(ope,INT_MIN));
|
||||||
|
tt_u64_op(UINT64_MAX, OP_EQ, crypto_ope_encrypt(ope,-100));
|
||||||
|
tt_u64_op(UINT64_MAX, OP_EQ, crypto_ope_encrypt(ope,0));
|
||||||
|
tt_u64_op(UINT64_MAX, OP_NE, crypto_ope_encrypt(ope,1));
|
||||||
|
tt_u64_op(UINT64_MAX, OP_NE, crypto_ope_encrypt(ope,7000));
|
||||||
|
tt_u64_op(UINT64_MAX, OP_NE, crypto_ope_encrypt(ope,OPE_INPUT_MAX));
|
||||||
|
tt_u64_op(UINT64_MAX, OP_EQ, crypto_ope_encrypt(ope,OPE_INPUT_MAX+1));
|
||||||
|
tt_u64_op(UINT64_MAX, OP_EQ, crypto_ope_encrypt(ope,INT_MAX));
|
||||||
|
done:
|
||||||
|
crypto_ope_free(ope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char OPE_TEST_KEY[] =
|
||||||
|
"19e05891d55232c08c2cad91d612fdb9cbd6691949a0742434a76c80bc6992fe";
|
||||||
|
|
||||||
|
/* generated by a separate python implementation. */
|
||||||
|
static const struct {
|
||||||
|
int v;
|
||||||
|
uint64_t r;
|
||||||
|
} OPE_TEST_VECTORS[] = {
|
||||||
|
{ 121132, UINT64_C(3971694514) },
|
||||||
|
{ 82283, UINT64_C(2695743564) },
|
||||||
|
{ 72661, UINT64_C(2381548866) },
|
||||||
|
{ 72941, UINT64_C(2390408421) },
|
||||||
|
{ 123122, UINT64_C(4036781069) },
|
||||||
|
{ 12154, UINT64_C(402067100) },
|
||||||
|
{ 121574, UINT64_C(3986197593) },
|
||||||
|
{ 11391, UINT64_C(376696838) },
|
||||||
|
{ 65845, UINT64_C(2161801517) },
|
||||||
|
{ 86301, UINT64_C(2828270975) },
|
||||||
|
{ 61284, UINT64_C(2013616892) },
|
||||||
|
{ 70505, UINT64_C(2313368870) },
|
||||||
|
{ 30438, UINT64_C(1001394664) },
|
||||||
|
{ 60150, UINT64_C(1977329668) },
|
||||||
|
{ 114800, UINT64_C(3764946628) },
|
||||||
|
{ 109403, UINT64_C(3585352477) },
|
||||||
|
{ 21893, UINT64_C(721388468) },
|
||||||
|
{ 123569, UINT64_C(4051780471) },
|
||||||
|
{ 95617, UINT64_C(3134921876) },
|
||||||
|
{ 48561, UINT64_C(1597596985) },
|
||||||
|
{ 53334, UINT64_C(1753691710) },
|
||||||
|
{ 92746, UINT64_C(3040874493) },
|
||||||
|
{ 7110, UINT64_C(234966492) },
|
||||||
|
{ 9612, UINT64_C(318326551) },
|
||||||
|
{ 106958, UINT64_C(3506124249) },
|
||||||
|
{ 46889, UINT64_C(1542219146) },
|
||||||
|
{ 87790, UINT64_C(2877361609) },
|
||||||
|
{ 68878, UINT64_C(2260369112) },
|
||||||
|
{ 47917, UINT64_C(1576681737) },
|
||||||
|
{ 121128, UINT64_C(3971553290) },
|
||||||
|
{ 108602, UINT64_C(3559176081) },
|
||||||
|
{ 28217, UINT64_C(929692460) },
|
||||||
|
{ 69498, UINT64_C(2280554161) },
|
||||||
|
{ 63870, UINT64_C(2098322675) },
|
||||||
|
{ 57542, UINT64_C(1891698992) },
|
||||||
|
{ 122148, UINT64_C(4004515805) },
|
||||||
|
{ 46254, UINT64_C(1521227949) },
|
||||||
|
{ 42850, UINT64_C(1408996941) },
|
||||||
|
{ 92661, UINT64_C(3037901517) },
|
||||||
|
{ 57720, UINT64_C(1897369989) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_crypto_ope_vectors(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
uint8_t key[32];
|
||||||
|
crypto_ope_t *ope = NULL, *ope2 = NULL;
|
||||||
|
|
||||||
|
base16_decode((char*)key, 32, OPE_TEST_KEY, strlen(OPE_TEST_KEY));
|
||||||
|
|
||||||
|
ope = crypto_ope_new(key);
|
||||||
|
key[8] += 1;
|
||||||
|
ope2 = crypto_ope_new(key);
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < ARRAY_LENGTH(OPE_TEST_VECTORS); ++i) {
|
||||||
|
int val = OPE_TEST_VECTORS[i].v;
|
||||||
|
uint64_t res = OPE_TEST_VECTORS[i].r;
|
||||||
|
|
||||||
|
tt_u64_op(crypto_ope_encrypt(ope, val), OP_EQ, res);
|
||||||
|
tt_u64_op(crypto_ope_encrypt(ope2, val), OP_NE, res);
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
crypto_ope_free(ope);
|
||||||
|
crypto_ope_free(ope2);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct testcase_t crypto_ope_tests[] = {
|
||||||
|
{ "consistency", test_crypto_ope_consistency, 0, NULL, NULL },
|
||||||
|
{ "oob", test_crypto_ope_oob, 0, NULL, NULL },
|
||||||
|
{ "vectors", test_crypto_ope_vectors, 0, NULL, NULL },
|
||||||
|
END_OF_TESTCASES
|
||||||
|
};
|
@ -1344,6 +1344,10 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
|
|||||||
&mock_service_ns->fresh_until);
|
&mock_service_ns->fresh_until);
|
||||||
voting_schedule_recalculate_timing(get_options(),
|
voting_schedule_recalculate_timing(get_options(),
|
||||||
mock_service_ns->valid_after);
|
mock_service_ns->valid_after);
|
||||||
|
/* Check that service is in the right time period point */
|
||||||
|
tt_int_op(hs_in_period_between_tp_and_srv(mock_service_ns, 0), OP_EQ,
|
||||||
|
cfg->service_in_new_tp);
|
||||||
|
|
||||||
/* Set client consensus time. */
|
/* Set client consensus time. */
|
||||||
set_consensus_times(cfg->client_valid_after,
|
set_consensus_times(cfg->client_valid_after,
|
||||||
&mock_client_ns->valid_after);
|
&mock_client_ns->valid_after);
|
||||||
@ -1353,10 +1357,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
|
|||||||
&mock_client_ns->fresh_until);
|
&mock_client_ns->fresh_until);
|
||||||
voting_schedule_recalculate_timing(get_options(),
|
voting_schedule_recalculate_timing(get_options(),
|
||||||
mock_client_ns->valid_after);
|
mock_client_ns->valid_after);
|
||||||
|
/* Check that client is in the right time period point */
|
||||||
/* New time period checks for this scenario. */
|
|
||||||
tt_int_op(hs_in_period_between_tp_and_srv(mock_service_ns, 0), OP_EQ,
|
|
||||||
cfg->service_in_new_tp);
|
|
||||||
tt_int_op(hs_in_period_between_tp_and_srv(mock_client_ns, 0), OP_EQ,
|
tt_int_op(hs_in_period_between_tp_and_srv(mock_client_ns, 0), OP_EQ,
|
||||||
cfg->client_in_new_tp);
|
cfg->client_in_new_tp);
|
||||||
|
|
||||||
@ -1367,7 +1368,8 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
|
|||||||
mock_service_ns->sr_info.previous_srv = cfg->service_previous_srv;
|
mock_service_ns->sr_info.previous_srv = cfg->service_previous_srv;
|
||||||
|
|
||||||
/* Initialize a service to get keys. */
|
/* Initialize a service to get keys. */
|
||||||
service = helper_init_service(time(NULL));
|
update_approx_time(mock_service_ns->valid_after);
|
||||||
|
service = helper_init_service(mock_service_ns->valid_after+1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* === Client setup ===
|
* === Client setup ===
|
||||||
|
@ -1044,7 +1044,7 @@ static void
|
|||||||
test_rotate_descriptors(void *arg)
|
test_rotate_descriptors(void *arg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
time_t next_rotation_time, now = time(NULL);
|
time_t next_rotation_time, now;
|
||||||
hs_service_t *service;
|
hs_service_t *service;
|
||||||
hs_service_descriptor_t *desc_next;
|
hs_service_descriptor_t *desc_next;
|
||||||
|
|
||||||
@ -1068,6 +1068,9 @@ test_rotate_descriptors(void *arg)
|
|||||||
tt_int_op(ret, OP_EQ, 0);
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
|
voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
|
||||||
|
|
||||||
|
update_approx_time(mock_ns.valid_after+1);
|
||||||
|
now = mock_ns.valid_after+1;
|
||||||
|
|
||||||
/* Create a service with a default descriptor and state. It's added to the
|
/* Create a service with a default descriptor and state. It's added to the
|
||||||
* global map. */
|
* global map. */
|
||||||
service = helper_create_service();
|
service = helper_create_service();
|
||||||
@ -1106,6 +1109,9 @@ test_rotate_descriptors(void *arg)
|
|||||||
tt_int_op(ret, OP_EQ, 0);
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
|
voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
|
||||||
|
|
||||||
|
update_approx_time(mock_ns.valid_after+1);
|
||||||
|
now = mock_ns.valid_after+1;
|
||||||
|
|
||||||
/* Note down what to expect for the next rotation time which is 01:00 + 23h
|
/* Note down what to expect for the next rotation time which is 01:00 + 23h
|
||||||
* meaning 00:00:00. */
|
* meaning 00:00:00. */
|
||||||
next_rotation_time = mock_ns.valid_after + (23 * 60 * 60);
|
next_rotation_time = mock_ns.valid_after + (23 * 60 * 60);
|
||||||
@ -1168,6 +1174,9 @@ test_build_update_descriptors(void *arg)
|
|||||||
tt_int_op(ret, OP_EQ, 0);
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
|
voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
|
||||||
|
|
||||||
|
update_approx_time(mock_ns.valid_after+1);
|
||||||
|
now = mock_ns.valid_after+1;
|
||||||
|
|
||||||
/* Create a service without a current descriptor to trigger a build. */
|
/* Create a service without a current descriptor to trigger a build. */
|
||||||
service = helper_create_service();
|
service = helper_create_service();
|
||||||
tt_assert(service);
|
tt_assert(service);
|
||||||
@ -1309,6 +1318,9 @@ test_build_update_descriptors(void *arg)
|
|||||||
&mock_ns.fresh_until);
|
&mock_ns.fresh_until);
|
||||||
tt_int_op(ret, OP_EQ, 0);
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
update_approx_time(mock_ns.valid_after+1);
|
||||||
|
now = mock_ns.valid_after+1;
|
||||||
|
|
||||||
/* Create a service without a current descriptor to trigger a build. */
|
/* Create a service without a current descriptor to trigger a build. */
|
||||||
service = helper_create_service();
|
service = helper_create_service();
|
||||||
tt_assert(service);
|
tt_assert(service);
|
||||||
@ -1363,7 +1375,7 @@ static void
|
|||||||
test_upload_descriptors(void *arg)
|
test_upload_descriptors(void *arg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
time_t now = time(NULL);
|
time_t now;
|
||||||
hs_service_t *service;
|
hs_service_t *service;
|
||||||
|
|
||||||
(void) arg;
|
(void) arg;
|
||||||
@ -1382,6 +1394,10 @@ test_upload_descriptors(void *arg)
|
|||||||
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
|
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
|
||||||
&mock_ns.fresh_until);
|
&mock_ns.fresh_until);
|
||||||
tt_int_op(ret, OP_EQ, 0);
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
|
||||||
|
|
||||||
|
update_approx_time(mock_ns.valid_after+1);
|
||||||
|
now = mock_ns.valid_after+1;
|
||||||
|
|
||||||
/* Create a service with no descriptor. It's added to the global map. */
|
/* Create a service with no descriptor. It's added to the global map. */
|
||||||
service = hs_service_new(get_options());
|
service = hs_service_new(get_options());
|
||||||
@ -1416,66 +1432,6 @@ test_upload_descriptors(void *arg)
|
|||||||
UNMOCK(get_or_state);
|
UNMOCK(get_or_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test the functions that save and load HS revision counters to state. */
|
|
||||||
static void
|
|
||||||
test_revision_counter_state(void *arg)
|
|
||||||
{
|
|
||||||
char *state_line_one = NULL;
|
|
||||||
char *state_line_two = NULL;
|
|
||||||
|
|
||||||
hs_service_descriptor_t *desc_one = service_descriptor_new();
|
|
||||||
hs_service_descriptor_t *desc_two = service_descriptor_new();
|
|
||||||
|
|
||||||
(void) arg;
|
|
||||||
|
|
||||||
/* Prepare both descriptors */
|
|
||||||
desc_one->desc->plaintext_data.revision_counter = 42;
|
|
||||||
desc_two->desc->plaintext_data.revision_counter = 240;
|
|
||||||
memset(&desc_one->blinded_kp.pubkey.pubkey, 66,
|
|
||||||
sizeof(desc_one->blinded_kp.pubkey.pubkey));
|
|
||||||
memset(&desc_two->blinded_kp.pubkey.pubkey, 240,
|
|
||||||
sizeof(desc_one->blinded_kp.pubkey.pubkey));
|
|
||||||
|
|
||||||
/* Turn the descriptor rev counters into state lines */
|
|
||||||
state_line_one = encode_desc_rev_counter_for_state(desc_one);
|
|
||||||
tt_str_op(state_line_one, OP_EQ,
|
|
||||||
"QkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkI 42");
|
|
||||||
|
|
||||||
state_line_two = encode_desc_rev_counter_for_state(desc_two);
|
|
||||||
tt_str_op(state_line_two, OP_EQ,
|
|
||||||
"8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PA 240");
|
|
||||||
|
|
||||||
/* Now let's test our state parsing function: */
|
|
||||||
int service_found;
|
|
||||||
uint64_t cached_rev_counter;
|
|
||||||
|
|
||||||
/* First's try with wrong pubkey and check that no service was found */
|
|
||||||
cached_rev_counter =check_state_line_for_service_rev_counter(state_line_one,
|
|
||||||
&desc_two->blinded_kp.pubkey,
|
|
||||||
&service_found);
|
|
||||||
tt_int_op(service_found, OP_EQ, 0);
|
|
||||||
tt_u64_op(cached_rev_counter, OP_EQ, 0);
|
|
||||||
|
|
||||||
/* Now let's try with the right pubkeys */
|
|
||||||
cached_rev_counter =check_state_line_for_service_rev_counter(state_line_one,
|
|
||||||
&desc_one->blinded_kp.pubkey,
|
|
||||||
&service_found);
|
|
||||||
tt_int_op(service_found, OP_EQ, 1);
|
|
||||||
tt_u64_op(cached_rev_counter, OP_EQ, 42);
|
|
||||||
|
|
||||||
cached_rev_counter =check_state_line_for_service_rev_counter(state_line_two,
|
|
||||||
&desc_two->blinded_kp.pubkey,
|
|
||||||
&service_found);
|
|
||||||
tt_int_op(service_found, OP_EQ, 1);
|
|
||||||
tt_u64_op(cached_rev_counter, OP_EQ, 240);
|
|
||||||
|
|
||||||
done:
|
|
||||||
tor_free(state_line_one);
|
|
||||||
tor_free(state_line_two);
|
|
||||||
service_descriptor_free(desc_one);
|
|
||||||
service_descriptor_free(desc_two);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Global vars used by test_rendezvous1_parsing() */
|
/** Global vars used by test_rendezvous1_parsing() */
|
||||||
static char rend1_payload[RELAY_PAYLOAD_SIZE];
|
static char rend1_payload[RELAY_PAYLOAD_SIZE];
|
||||||
static size_t rend1_payload_len = 0;
|
static size_t rend1_payload_len = 0;
|
||||||
@ -1629,8 +1585,6 @@ struct testcase_t hs_service_tests[] = {
|
|||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "upload_descriptors", test_upload_descriptors, TT_FORK,
|
{ "upload_descriptors", test_upload_descriptors, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "revision_counter_state", test_revision_counter_state, TT_FORK,
|
|
||||||
NULL, NULL },
|
|
||||||
{ "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK,
|
{ "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
|
|
||||||
|
@ -259,8 +259,7 @@ test_get_start_time_of_current_run(void *arg)
|
|||||||
¤t_time);
|
¤t_time);
|
||||||
tt_int_op(retval, OP_EQ, 0);
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
voting_schedule_recalculate_timing(get_options(), current_time);
|
voting_schedule_recalculate_timing(get_options(), current_time);
|
||||||
run_start_time =
|
run_start_time = sr_state_get_start_time_of_current_protocol_run();
|
||||||
sr_state_get_start_time_of_current_protocol_run(current_time);
|
|
||||||
|
|
||||||
/* Compare it with the correct result */
|
/* Compare it with the correct result */
|
||||||
format_iso_time(tbuf, run_start_time);
|
format_iso_time(tbuf, run_start_time);
|
||||||
@ -272,8 +271,7 @@ test_get_start_time_of_current_run(void *arg)
|
|||||||
¤t_time);
|
¤t_time);
|
||||||
tt_int_op(retval, OP_EQ, 0);
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
voting_schedule_recalculate_timing(get_options(), current_time);
|
voting_schedule_recalculate_timing(get_options(), current_time);
|
||||||
run_start_time =
|
run_start_time = sr_state_get_start_time_of_current_protocol_run();
|
||||||
sr_state_get_start_time_of_current_protocol_run(current_time);
|
|
||||||
|
|
||||||
/* Compare it with the correct result */
|
/* Compare it with the correct result */
|
||||||
format_iso_time(tbuf, run_start_time);
|
format_iso_time(tbuf, run_start_time);
|
||||||
@ -285,8 +283,7 @@ test_get_start_time_of_current_run(void *arg)
|
|||||||
¤t_time);
|
¤t_time);
|
||||||
tt_int_op(retval, OP_EQ, 0);
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
voting_schedule_recalculate_timing(get_options(), current_time);
|
voting_schedule_recalculate_timing(get_options(), current_time);
|
||||||
run_start_time =
|
run_start_time = sr_state_get_start_time_of_current_protocol_run();
|
||||||
sr_state_get_start_time_of_current_protocol_run(current_time);
|
|
||||||
|
|
||||||
/* Compare it with the correct result */
|
/* Compare it with the correct result */
|
||||||
format_iso_time(tbuf, run_start_time);
|
format_iso_time(tbuf, run_start_time);
|
||||||
@ -308,8 +305,7 @@ test_get_start_time_of_current_run(void *arg)
|
|||||||
¤t_time);
|
¤t_time);
|
||||||
tt_int_op(retval, OP_EQ, 0);
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
voting_schedule_recalculate_timing(get_options(), current_time);
|
voting_schedule_recalculate_timing(get_options(), current_time);
|
||||||
run_start_time =
|
run_start_time = sr_state_get_start_time_of_current_protocol_run();
|
||||||
sr_state_get_start_time_of_current_protocol_run(current_time);
|
|
||||||
|
|
||||||
/* Compare it with the correct result */
|
/* Compare it with the correct result */
|
||||||
format_iso_time(tbuf, run_start_time);
|
format_iso_time(tbuf, run_start_time);
|
||||||
@ -342,7 +338,7 @@ test_get_start_time_functions(void *arg)
|
|||||||
|
|
||||||
voting_schedule_recalculate_timing(get_options(), now);
|
voting_schedule_recalculate_timing(get_options(), now);
|
||||||
time_t start_time_of_protocol_run =
|
time_t start_time_of_protocol_run =
|
||||||
sr_state_get_start_time_of_current_protocol_run(now);
|
sr_state_get_start_time_of_current_protocol_run();
|
||||||
tt_assert(start_time_of_protocol_run);
|
tt_assert(start_time_of_protocol_run);
|
||||||
|
|
||||||
/* Check that the round start time of the beginning of the run, is itself */
|
/* Check that the round start time of the beginning of the run, is itself */
|
||||||
|
Loading…
Reference in New Issue
Block a user