Merge remote-tracking branch 'dgoulet/ticket16943_029_05-squashed'

Trivial Conflicts:
	src/or/or.h
	src/or/routerparse.c
This commit is contained in:
Nick Mathewson
2016-07-01 15:29:05 -04:00
27 changed files with 4888 additions and 68 deletions
+21
View File
@@ -5687,3 +5687,24 @@ clamp_double_to_int64(double number)
return signbit(number) ? INT64_MIN : INT64_MAX;
}
/** Return a uint64_t value from <b>a</b> in network byte order. */
uint64_t
tor_htonll(uint64_t a)
{
#ifdef WORDS_BIGENDIAN
/* Big endian. */
return a;
#else /* WORDS_BIGENDIAN */
/* Little endian. The worst... */
return htonl((uint32_t)(a>>32)) |
(((uint64_t)htonl((uint32_t)a))<<32);
#endif /* WORDS_BIGENDIAN */
}
/** Return a uint64_t value from <b>a</b> in host byte order. */
uint64_t
tor_ntohll(uint64_t a)
{
return tor_htonll(a);
}
+2
View File
@@ -61,6 +61,8 @@ void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS)
void *tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
void tor_free_(void *mem);
uint64_t tor_htonll(uint64_t a);
uint64_t tor_ntohll(uint64_t a);
#ifdef USE_DMALLOC
extern int dmalloc_free(const char *file, const int line, void *pnt,
const int func_id);
+1
View File
@@ -440,6 +440,7 @@ static config_var_t option_vars_[] = {
V(UseNTorHandshake, AUTOBOOL, "1"),
V(User, STRING, NULL),
V(UserspaceIOCPBuffers, BOOL, "0"),
V(AuthDirSharedRandomness, BOOL, "1"),
OBSOLETE("V1AuthoritativeDirectory"),
OBSOLETE("V2AuthoritativeDirectory"),
VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"),
+5
View File
@@ -30,6 +30,7 @@
#include "routerlist.h"
#include "routerparse.h"
#include "routerset.h"
#include "shared_random.h"
#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
#ifndef OPENBSD
@@ -2026,6 +2027,10 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
update_microdescs_from_networkstatus(now);
update_microdesc_downloads(now);
directory_info_has_arrived(now, 0, 0);
if (authdir_mode_v3(get_options())) {
sr_act_post_consensus(
networkstatus_get_latest_consensus_by_flavor(FLAV_NS));
}
log_info(LD_DIR, "Successfully loaded consensus.");
}
+131 -54
View File
@@ -15,10 +15,12 @@
#include "policies.h"
#include "rephist.h"
#include "router.h"
#include "routerkeys.h"
#include "routerlist.h"
#include "routerparse.h"
#include "entrynodes.h" /* needed for guardfraction methods */
#include "torcert.h"
#include "shared_random_state.h"
/**
* \file dirvote.c
@@ -73,6 +75,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
char digest[DIGEST_LEN];
uint32_t addr;
char *client_versions_line = NULL, *server_versions_line = NULL;
char *shared_random_vote_str = NULL;
networkstatus_voter_info_t *voter;
char *status = NULL;
@@ -114,6 +117,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
packages = tor_strdup("");
}
/* Get shared random commitments/reveals line(s). */
shared_random_vote_str = sr_get_string_for_vote();
{
char published[ISO_TIME_LEN+1];
char va[ISO_TIME_LEN+1];
@@ -153,7 +159,8 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
"flag-thresholds %s\n"
"params %s\n"
"dir-source %s %s %s %s %d %d\n"
"contact %s\n",
"contact %s\n"
"%s", /* shared randomness information */
v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion",
methods,
published, va, fu, vu,
@@ -166,12 +173,15 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
params,
voter->nickname, fingerprint, voter->address,
fmt_addr32(addr), voter->dir_port, voter->or_port,
voter->contact);
voter->contact,
shared_random_vote_str ?
shared_random_vote_str : "");
tor_free(params);
tor_free(flags);
tor_free(flag_thresholds);
tor_free(methods);
tor_free(shared_random_vote_str);
if (!tor_digest_is_zero(voter->legacy_id_digest)) {
char fpbuf[HEX_DIGEST_LEN+1];
@@ -608,15 +618,47 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning)
return result;
}
/** Given a list of K=V values, return the int32_t value corresponding to
* KEYWORD=, or default_val if no such value exists, or if the value is
* corrupt.
*/
STATIC int32_t
dirvote_get_intermediate_param_value(const smartlist_t *param_list,
const char *keyword,
int32_t default_val)
{
unsigned int n_found = 0;
int32_t value = default_val;
SMARTLIST_FOREACH_BEGIN(param_list, const char *, k_v_pair) {
if (!strcmpstart(k_v_pair, keyword) && k_v_pair[strlen(keyword)] == '=') {
const char *integer_str = &k_v_pair[strlen(keyword)+1];
int ok;
value = (int32_t)
tor_parse_long(integer_str, 10, INT32_MIN, INT32_MAX, &ok, NULL);
if (BUG(! ok))
return default_val;
++n_found;
}
} SMARTLIST_FOREACH_END(k_v_pair);
if (n_found == 1)
return value;
else if (BUG(n_found > 1))
return default_val;
else
return default_val;
}
/** Minimum number of directory authorities voting for a parameter to
* include it in the consensus, if consensus method 12 or later is to be
* used. See proposal 178 for details. */
#define MIN_VOTES_FOR_PARAM 3
/** Helper: given a list of valid networkstatus_t, return a new string
/** Helper: given a list of valid networkstatus_t, return a new smartlist
* containing the contents of the consensus network parameter set.
*/
STATIC char *
STATIC smartlist_t *
dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
{
int i;
@@ -625,7 +667,6 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
int cur_param_len;
const char *cur_param;
const char *eq;
char *result;
const int n_votes = smartlist_len(votes);
smartlist_t *output;
@@ -647,8 +688,7 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
if (smartlist_len(param_list) == 0) {
tor_free(vals);
smartlist_free(param_list);
return NULL;
return param_list;
}
smartlist_sort_strings(param_list);
@@ -696,12 +736,9 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
}
} SMARTLIST_FOREACH_END(param);
result = smartlist_join_strings(output, " ", 0, NULL);
SMARTLIST_FOREACH(output, char *, cp, tor_free(cp));
smartlist_free(output);
smartlist_free(param_list);
tor_free(vals);
return result;
return output;
}
#define RANGE_CHECK(a,b,c,d,e,f,g,mx) \
@@ -1148,6 +1185,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
char *packages = NULL;
int added_weights = 0;
dircollator_t *collator = NULL;
smartlist_t *param_list = NULL;
tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
tor_assert(total_authorities >= smartlist_len(votes));
tor_assert(total_authorities > 0);
@@ -1292,14 +1331,31 @@ networkstatus_compute_consensus(smartlist_t *votes,
tor_free(flaglist);
}
params = dirvote_compute_params(votes, consensus_method,
total_authorities);
if (params) {
param_list = dirvote_compute_params(votes, consensus_method,
total_authorities);
if (smartlist_len(param_list)) {
params = smartlist_join_strings(param_list, " ", 0, NULL);
smartlist_add(chunks, tor_strdup("params "));
smartlist_add(chunks, params);
smartlist_add(chunks, tor_strdup("\n"));
}
if (consensus_method >= MIN_METHOD_FOR_SHARED_RANDOM) {
int num_dirauth = get_n_authorities(V3_DIRINFO);
/* Default value of this is 2/3 of the total number of authorities. For
* instance, if we have 9 dirauth, the default value is 6. The following
* calculation will round it down. */
int32_t num_srv_agreements =
dirvote_get_intermediate_param_value(param_list,
"AuthDirNumSRVAgreements",
(num_dirauth * 2) / 3);
/* Add the shared random value. */
char *srv_lines = sr_get_string_for_consensus(votes, num_srv_agreements);
if (srv_lines != NULL) {
smartlist_add(chunks, srv_lines);
}
}
/* Sort the votes. */
smartlist_sort(votes, compare_votes_by_authority_id_);
/* Add the authority sections. */
@@ -1351,7 +1407,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
if (consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW) {
char *max_unmeasured_param = NULL;
/* XXXX Extract this code into a common function */
/* XXXX Extract this code into a common function. Or don't! see #19011 */
if (params) {
if (strcmpstart(params, "maxunmeasuredbw=") == 0)
max_unmeasured_param = params;
@@ -1906,7 +1962,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
// Parse params, extract BW_WEIGHT_SCALE if present
// DO NOT use consensus_param_bw_weight_scale() in this code!
// The consensus is not formed yet!
/* XXXX Extract this code into a common function */
/* XXXX Extract this code into a common function. Or not: #19011. */
if (params) {
if (strcmpstart(params, "bwweightscale=") == 0)
bw_weight_param = params;
@@ -2026,6 +2082,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_free(flags);
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
smartlist_free(chunks);
SMARTLIST_FOREACH(param_list, char *, cp, tor_free(cp));
smartlist_free(param_list);
return result;
}
@@ -2511,50 +2569,60 @@ dirvote_get_start_of_next_interval(time_t now, int interval, int offset)
return next;
}
/** Scheduling information for a voting interval. */
static struct {
/** When do we generate and distribute our vote for this interval? */
time_t voting_starts;
/** When do we send an HTTP request for any votes that we haven't
* been posted yet?*/
time_t fetch_missing_votes;
/** When do we give up on getting more votes and generate a consensus? */
time_t voting_ends;
/** When do we send an HTTP request for any signatures we're expecting to
* see on the consensus? */
time_t fetch_missing_signatures;
/** When do we publish the consensus? */
time_t interval_starts;
/* Using the time <b>now</b>, return the next voting valid-after time. */
time_t
get_next_valid_after_time(time_t now)
{
time_t next_valid_after_time;
const or_options_t *options = get_options();
voting_schedule_t *new_voting_schedule =
get_voting_schedule(options, now, LOG_INFO);
tor_assert(new_voting_schedule);
/* True iff we have generated and distributed our vote. */
int have_voted;
/* True iff we've requested missing votes. */
int have_fetched_missing_votes;
/* True iff we have built a consensus and sent the signatures around. */
int have_built_consensus;
/* True iff we've fetched missing signatures. */
int have_fetched_missing_signatures;
/* True iff we have published our consensus. */
int have_published_consensus;
} voting_schedule = {0,0,0,0,0,0,0,0,0,0};
next_valid_after_time = new_voting_schedule->interval_starts;
tor_free(new_voting_schedule);
return next_valid_after_time;
}
static voting_schedule_t voting_schedule;
/** Set voting_schedule to hold the timing for the next vote we should be
* doing. */
void
dirvote_recalculate_timing(const or_options_t *options, time_t now)
{
voting_schedule_t *new_voting_schedule;
if (!authdir_mode_v3(options)) {
return;
}
/* get the new voting schedule */
new_voting_schedule = get_voting_schedule(options, now, LOG_NOTICE);
tor_assert(new_voting_schedule);
/* Fill in the global static struct now */
memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule));
tor_free(new_voting_schedule);
}
/* Populate and return a new voting_schedule_t that can be used to schedule
* voting. The object is allocated on the heap and it's the responsibility of
* the caller to free it. Can't fail. */
voting_schedule_t *
get_voting_schedule(const or_options_t *options, time_t now, int severity)
{
int interval, vote_delay, dist_delay;
time_t start;
time_t end;
networkstatus_t *consensus;
voting_schedule_t *new_voting_schedule;
if (!authdir_mode_v3(options))
return;
new_voting_schedule = tor_malloc_zero(sizeof(voting_schedule_t));
consensus = networkstatus_get_live_consensus(now);
memset(&voting_schedule, 0, sizeof(voting_schedule));
if (consensus) {
interval = (int)( consensus->fresh_until - consensus->valid_after );
vote_delay = consensus->vote_seconds;
@@ -2570,7 +2638,7 @@ dirvote_recalculate_timing(const or_options_t *options, time_t now)
if (vote_delay + dist_delay > interval/2)
vote_delay = dist_delay = interval / 4;
start = voting_schedule.interval_starts =
start = new_voting_schedule->interval_starts =
dirvote_get_start_of_next_interval(now,interval,
options->TestingV3AuthVotingStartOffset);
end = dirvote_get_start_of_next_interval(start+1, interval,
@@ -2578,18 +2646,20 @@ dirvote_recalculate_timing(const or_options_t *options, time_t now)
tor_assert(end > start);
voting_schedule.fetch_missing_signatures = start - (dist_delay/2);
voting_schedule.voting_ends = start - dist_delay;
voting_schedule.fetch_missing_votes = start - dist_delay - (vote_delay/2);
voting_schedule.voting_starts = start - dist_delay - vote_delay;
new_voting_schedule->fetch_missing_signatures = start - (dist_delay/2);
new_voting_schedule->voting_ends = start - dist_delay;
new_voting_schedule->fetch_missing_votes = start - dist_delay - (vote_delay/2);
new_voting_schedule->voting_starts = start - dist_delay - vote_delay;
{
char tbuf[ISO_TIME_LEN+1];
format_iso_time(tbuf, voting_schedule.interval_starts);
log_notice(LD_DIR,"Choosing expected valid-after time as %s: "
"consensus_set=%d, interval=%d",
tbuf, consensus?1:0, interval);
format_iso_time(tbuf, new_voting_schedule->interval_starts);
tor_log(severity, LD_DIR,"Choosing expected valid-after time as %s: "
"consensus_set=%d, interval=%d",
tbuf, consensus?1:0, interval);
}
return new_voting_schedule;
}
/** Entry point: Take whatever voting actions are pending as of <b>now</b>. */
@@ -2638,6 +2708,9 @@ dirvote_act(const or_options_t *options, time_t now)
dirvote_publish_consensus();
dirvote_clear_votes(0);
voting_schedule.have_published_consensus = 1;
/* Update our shared random state with the consensus just published. */
sr_act_post_consensus(
networkstatus_get_latest_consensus_by_flavor(FLAV_NS));
/* XXXX We will want to try again later if we haven't got enough
* signatures yet. Implement this if it turns out to ever happen. */
dirvote_recalculate_timing(options, now);
@@ -2977,6 +3050,10 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
}
} SMARTLIST_FOREACH_END(v);
/* This a valid vote, update our shared random state. */
sr_handle_received_commits(vote->sr_info.commits,
vote->cert->identity_key);
pending_vote = tor_malloc_zero(sizeof(pending_vote_t));
pending_vote->vote_body = new_cached_dir(tor_strndup(vote_body,
end_of_vote-vote_body),
+43 -2
View File
@@ -55,7 +55,7 @@
#define MIN_SUPPORTED_CONSENSUS_METHOD 13
/** The highest consensus method that we currently support. */
#define MAX_SUPPORTED_CONSENSUS_METHOD 22
#define MAX_SUPPORTED_CONSENSUS_METHOD 23
/** Lowest consensus method where microdesc consensuses omit any entry
* with no microdesc. */
@@ -90,10 +90,15 @@
* ed25519 identities in microdescriptors. (Broken; see
* consensus_method_is_supported() for more info.) */
#define MIN_METHOD_FOR_ED25519_ID_IN_MD 21
/** Lowest consensus method where authorities vote on ed25519 ids and ensure
* ed25519 id consistency. */
#define MIN_METHOD_FOR_ED25519_ID_VOTING 22
/** Lowest consensus method where authorities may include a shared random
* value(s). */
#define MIN_METHOD_FOR_SHARED_RANDOM 23
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
* get confused with the above macros.) */
@@ -121,12 +126,44 @@ void ns_detached_signatures_free(ns_detached_signatures_t *s);
authority_cert_t *authority_cert_dup(authority_cert_t *cert);
/* vote scheduling */
/** Scheduling information for a voting interval. */
typedef struct {
/** When do we generate and distribute our vote for this interval? */
time_t voting_starts;
/** When do we send an HTTP request for any votes that we haven't
* been posted yet?*/
time_t fetch_missing_votes;
/** When do we give up on getting more votes and generate a consensus? */
time_t voting_ends;
/** When do we send an HTTP request for any signatures we're expecting to
* see on the consensus? */
time_t fetch_missing_signatures;
/** When do we publish the consensus? */
time_t interval_starts;
/* True iff we have generated and distributed our vote. */
int have_voted;
/* True iff we've requested missing votes. */
int have_fetched_missing_votes;
/* True iff we have built a consensus and sent the signatures around. */
int have_built_consensus;
/* True iff we've fetched missing signatures. */
int have_fetched_missing_signatures;
/* True iff we have published our consensus. */
int have_published_consensus;
} voting_schedule_t;
voting_schedule_t *get_voting_schedule(const or_options_t *options,
time_t now, int severity);
void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out);
time_t dirvote_get_start_of_next_interval(time_t now,
int interval,
int offset);
void dirvote_recalculate_timing(const or_options_t *options, time_t now);
void dirvote_act(const or_options_t *options, time_t now);
time_t get_next_valid_after_time(time_t now);
/* invoked on timers and by outside triggers. */
struct pending_vote_t * dirvote_add_vote(const char *vote_body,
@@ -173,9 +210,13 @@ document_signature_t *voter_get_sig_by_algorithm(
digest_algorithm_t alg);
#ifdef DIRVOTE_PRIVATE
STATIC int32_t dirvote_get_intermediate_param_value(
const smartlist_t *param_list,
const char *keyword,
int32_t default_val);
STATIC char *format_networkstatus_vote(crypto_pk_t *private_key,
networkstatus_t *v3_ns);
STATIC char *dirvote_compute_params(smartlist_t *votes, int method,
STATIC smartlist_t *dirvote_compute_params(smartlist_t *votes, int method,
int total_authorities);
STATIC char *compute_consensus_package_lines(smartlist_t *votes);
STATIC char *make_consensus_method_list(int low, int high, const char *sep);
+4
View File
@@ -62,6 +62,8 @@ LIBTOR_A_SOURCES = \
src/or/onion.c \
src/or/onion_fast.c \
src/or/onion_tap.c \
src/or/shared_random.c \
src/or/shared_random_state.c \
src/or/transports.c \
src/or/periodic.c \
src/or/policies.c \
@@ -173,6 +175,8 @@ ORHEADERS = \
src/or/onion_ntor.h \
src/or/onion_tap.h \
src/or/or.h \
src/or/shared_random.h \
src/or/shared_random_state.h \
src/or/transports.h \
src/or/periodic.h \
src/or/policies.h \
+13
View File
@@ -57,6 +57,7 @@
#include "routerlist.h"
#include "routerparse.h"
#include "scheduler.h"
#include "shared_random.h"
#include "statefile.h"
#include "status.h"
#include "util_process.h"
@@ -2447,6 +2448,13 @@ do_main_loop(void)
cpu_init();
}
/* Setup shared random protocol subsystem. */
if (authdir_mode_publishes_statuses(get_options())) {
if (sr_init(1) < 0) {
return -1;
}
}
/* set up once-a-second callback. */
if (! second_timer) {
struct timeval one_second;
@@ -3214,6 +3222,9 @@ tor_cleanup(void)
accounting_record_bandwidth_usage(now, get_or_state());
or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */
or_state_save(now);
if (authdir_mode(options)) {
sr_save_and_cleanup();
}
if (authdir_mode_tests_reachability(options))
rep_hist_record_mtbf_data(now, 0);
keypin_close_journal();
@@ -3372,6 +3383,7 @@ sandbox_init_filter(void)
OPEN_DATADIR_SUFFIX("cached-extrainfo.new", ".tmp");
OPEN_DATADIR("cached-extrainfo.tmp.tmp");
OPEN_DATADIR_SUFFIX("state", ".tmp");
OPEN_DATADIR_SUFFIX("sr-state", ".tmp");
OPEN_DATADIR_SUFFIX("unparseable-desc", ".tmp");
OPEN_DATADIR_SUFFIX("v3-status-votes", ".tmp");
OPEN_DATADIR("key-pinning-journal");
@@ -3424,6 +3436,7 @@ sandbox_init_filter(void)
RENAME_SUFFIX("cached-extrainfo", ".new");
RENAME_SUFFIX("cached-extrainfo.new", ".tmp");
RENAME_SUFFIX("state", ".tmp");
RENAME_SUFFIX("sr-state", ".tmp");
RENAME_SUFFIX("unparseable-desc", ".tmp");
RENAME_SUFFIX("v3-status-votes", ".tmp");
+14 -4
View File
@@ -32,7 +32,9 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
#include "shared_random.h"
#include "transports.h"
#include "torcert.h"
/** Map from lowercase nickname to identity digest of named server, if any. */
static strmap_t *named_server_map = NULL;
@@ -320,6 +322,14 @@ networkstatus_vote_free(networkstatus_t *ns)
digestmap_free(ns->desc_digest_map, NULL);
if (ns->sr_info.commits) {
SMARTLIST_FOREACH(ns->sr_info.commits, sr_commit_t *, c,
sr_commit_free(c));
smartlist_free(ns->sr_info.commits);
}
tor_free(ns->sr_info.previous_srv);
tor_free(ns->sr_info.current_srv);
memwipe(ns, 11, sizeof(*ns));
tor_free(ns);
}
@@ -1264,8 +1274,8 @@ networkstatus_get_dl_status_by_flavor_running,(consensus_flavor_t flavor))
/** Return the most recent consensus that we have downloaded, or NULL if we
* don't have one. */
networkstatus_t *
networkstatus_get_latest_consensus(void)
MOCK_IMPL(networkstatus_t *,
networkstatus_get_latest_consensus,(void))
{
return current_consensus;
}
@@ -1287,8 +1297,8 @@ networkstatus_get_latest_consensus_by_flavor,(consensus_flavor_t f))
/** Return the most recent consensus that we have downloaded, or NULL if it is
* no longer live. */
networkstatus_t *
networkstatus_get_live_consensus(time_t now)
MOCK_IMPL(networkstatus_t *,
networkstatus_get_live_consensus,(time_t now))
{
if (current_consensus &&
current_consensus->valid_after <= now &&
+2 -2
View File
@@ -75,10 +75,10 @@ void update_certificate_downloads(time_t now);
int consensus_is_waiting_for_certs(void);
int client_would_use_router(const routerstatus_t *rs, time_t now,
const or_options_t *options);
networkstatus_t *networkstatus_get_latest_consensus(void);
MOCK_DECL(networkstatus_t *,networkstatus_get_latest_consensus,(void));
MOCK_DECL(networkstatus_t *,networkstatus_get_latest_consensus_by_flavor,
(consensus_flavor_t f));
networkstatus_t *networkstatus_get_live_consensus(time_t now);
MOCK_DECL(networkstatus_t *, networkstatus_get_live_consensus,(time_t now));
networkstatus_t *networkstatus_get_reasonably_live_consensus(time_t now,
int flavor);
MOCK_DECL(int, networkstatus_consensus_is_bootstrapping,(time_t now));
+21
View File
@@ -2523,6 +2523,18 @@ typedef struct networkstatus_voter_info_t {
smartlist_t *sigs;
} networkstatus_voter_info_t;
typedef struct networkstatus_sr_info_t {
/* Indicate if the dirauth partitipates in the SR protocol with its vote.
* This is tied to the SR flag in the vote. */
unsigned int participate:1;
/* Both vote and consensus: Current and previous SRV. If list is empty,
* this means none were found in either the consensus or vote. */
struct sr_srv_t *previous_srv;
struct sr_srv_t *current_srv;
/* Vote only: List of commitments. */
smartlist_t *commits;
} networkstatus_sr_info_t;
/** Enumerates the possible seriousness values of a networkstatus document. */
typedef enum {
NS_TYPE_VOTE,
@@ -2605,6 +2617,9 @@ typedef struct networkstatus_t {
/** If present, a map from descriptor digest to elements of
* routerstatus_list. */
digestmap_t *desc_digest_map;
/** Contains the shared random protocol data from a vote or consensus. */
networkstatus_sr_info_t sr_info;
} networkstatus_t;
/** A set of signatures for a networkstatus consensus. Unless otherwise
@@ -4503,6 +4518,12 @@ typedef struct {
* lifetime of this Tor process.
*/
uint64_t MaxUnparseableDescSizeToLog;
/** Bool (default: 1): Switch for the shared random protocol. Only
* relevant to a directory authority. If off, the authority won't
* participate in the protocol. If on (default), a flag is added to the
* vote indicating participation. */
int AuthDirSharedRandomness;
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
+2 -2
View File
@@ -1645,8 +1645,8 @@ router_digest_is_fallback_dir(const char *digest)
* v3 identity key hashes to <b>digest</b>, or NULL if no such authority
* is known.
*/
dir_server_t *
trusteddirserver_get_by_v3_auth_digest(const char *digest)
MOCK_IMPL(dir_server_t *,
trusteddirserver_get_by_v3_auth_digest, (const char *digest))
{
if (!trusted_dir_servers)
return NULL;
+2 -1
View File
@@ -52,7 +52,8 @@ dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
dir_server_t *router_get_fallback_dirserver_by_digest(
const char *digest);
int router_digest_is_fallback_dir(const char *digest);
dir_server_t *trusteddirserver_get_by_v3_auth_digest(const char *d);
MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest,
(const char *d));
const routerstatus_t *router_pick_trusteddirserver(dirinfo_type_t type,
int flags);
const routerstatus_t *router_pick_fallback_dirserver(dirinfo_type_t type,
+158
View File
@@ -29,6 +29,7 @@
#include "entrynodes.h"
#include "torcert.h"
#include "sandbox.h"
#include "shared_random.h"
#undef log
#include <math.h>
@@ -146,6 +147,11 @@ typedef enum {
K_CONSENSUS_METHOD,
K_LEGACY_DIR_KEY,
K_DIRECTORY_FOOTER,
K_SIGNING_CERT_ED,
K_SR_FLAG,
K_COMMIT,
K_PREVIOUS_SRV,
K_CURRENT_SRV,
K_PACKAGE,
A_PURPOSE,
@@ -447,6 +453,11 @@ static token_rule_t networkstatus_token_table[] = {
T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
T01("params", K_PARAMS, ARGS, NO_OBJ ),
T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
T01("signing-ed25519", K_SIGNING_CERT_ED, NO_ARGS , NEED_OBJ ),
T01("shared-rand-participate",K_SR_FLAG, NO_ARGS, NO_OBJ ),
T0N("shared-rand-commit", K_COMMIT, GE(3), NO_OBJ ),
T01("shared-rand-previous-value", K_PREVIOUS_SRV,EQ(2), NO_OBJ ),
T01("shared-rand-current-value", K_CURRENT_SRV, EQ(2), NO_OBJ ),
T0N("package", K_PACKAGE, CONCAT_ARGS, NO_OBJ ),
CERTIFICATE_MEMBERS
@@ -486,6 +497,9 @@ static token_rule_t networkstatus_consensus_token_table[] = {
T01("consensus-method", K_CONSENSUS_METHOD, EQ(1), NO_OBJ),
T01("params", K_PARAMS, ARGS, NO_OBJ ),
T01("shared-rand-previous-value", K_PREVIOUS_SRV, EQ(2), NO_OBJ ),
T01("shared-rand-current-value", K_CURRENT_SRV, EQ(2), NO_OBJ ),
END_OF_TABLE
};
@@ -3391,6 +3405,134 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method)
return valid;
}
/** Parse and extract all SR commits from <b>tokens</b> and place them in
* <b>ns</b>. */
static void
extract_shared_random_commits(networkstatus_t *ns, smartlist_t *tokens)
{
smartlist_t *chunks = NULL;
tor_assert(ns);
tor_assert(tokens);
/* Commits are only present in a vote. */
tor_assert(ns->type == NS_TYPE_VOTE);
ns->sr_info.commits = smartlist_new();
smartlist_t *commits = find_all_by_keyword(tokens, K_COMMIT);
/* It's normal that a vote might contain no commits even if it participates
* in the SR protocol. Don't treat it as an error. */
if (commits == NULL) {
goto end;
}
/* Parse the commit. We do NO validation of number of arguments or ordering
* for forward compatibility, it's the parse commit job to inform us if it's
* supported or not. */
chunks = smartlist_new();
SMARTLIST_FOREACH_BEGIN(commits, directory_token_t *, tok) {
/* Extract all arguments and put them in the chunks list. */
for (int i = 0; i < tok->n_args; i++) {
smartlist_add(chunks, tok->args[i]);
}
sr_commit_t *commit = sr_parse_commit(chunks);
smartlist_clear(chunks);
if (commit == NULL) {
/* Get voter identity so we can warn that this dirauth vote contains
* commit we can't parse. */
networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
tor_assert(voter);
log_warn(LD_DIR, "SR: Unable to parse commit %s from vote of voter %s.",
escaped(tok->object_body),
hex_str(voter->identity_digest,
sizeof(voter->identity_digest)));
/* Commitment couldn't be parsed. Continue onto the next commit because
* this one could be unsupported for instance. */
continue;
}
/* Add newly created commit object to the vote. */
smartlist_add(ns->sr_info.commits, commit);
} SMARTLIST_FOREACH_END(tok);
end:
smartlist_free(chunks);
smartlist_free(commits);
}
/** Check if a shared random value of type <b>srv_type</b> is in
* <b>tokens</b>. If there is, parse it and set it to <b>srv_out</b>. Return
* -1 on failure, 0 on success. The resulting srv is allocated on the heap and
* it's the responsibility of the caller to free it. */
static int
extract_one_srv(smartlist_t *tokens, directory_keyword srv_type,
sr_srv_t **srv_out)
{
int ret = -1;
directory_token_t *tok;
sr_srv_t *srv = NULL;
smartlist_t *chunks;
tor_assert(tokens);
chunks = smartlist_new();
tok = find_opt_by_keyword(tokens, srv_type);
if (!tok) {
/* That's fine, no SRV is allowed. */
ret = 0;
goto end;
}
for (int i = 0; i < tok->n_args; i++) {
smartlist_add(chunks, tok->args[i]);
}
srv = sr_parse_srv(chunks);
if (srv == NULL) {
log_warn(LD_DIR, "SR: Unparseable SRV %s", escaped(tok->object_body));
goto end;
}
/* All is good. */
*srv_out = srv;
ret = 0;
end:
smartlist_free(chunks);
return ret;
}
/** Extract any shared random values found in <b>tokens</b> and place them in
* the networkstatus <b>ns</b>. */
static void
extract_shared_random_srvs(networkstatus_t *ns, smartlist_t *tokens)
{
const char *voter_identity;
networkstatus_voter_info_t *voter;
tor_assert(ns);
tor_assert(tokens);
/* Can be only one of them else code flow. */
tor_assert(ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS);
if (ns->type == NS_TYPE_VOTE) {
voter = smartlist_get(ns->voters, 0);
tor_assert(voter);
voter_identity = hex_str(voter->identity_digest,
sizeof(voter->identity_digest));
} else {
/* Consensus has multiple voters so no specific voter. */
voter_identity = "consensus";
}
/* We extract both and on error, everything is stopped because it means
* the votes is malformed for the shared random value(s). */
if (extract_one_srv(tokens, K_PREVIOUS_SRV, &ns->sr_info.previous_srv) < 0) {
log_warn(LD_DIR, "SR: Unable to parse previous SRV from %s",
voter_identity);
/* Maybe we have a chance with the current SRV so let's try it anyway. */
}
if (extract_one_srv(tokens, K_CURRENT_SRV, &ns->sr_info.current_srv) < 0) {
log_warn(LD_DIR, "SR: Unable to parse current SRV from %s",
voter_identity);
}
}
/** Parse a v3 networkstatus vote, opinion, or consensus (depending on
* ns_type), from <b>s</b>, and return the result. Return NULL on failure. */
networkstatus_t *
@@ -3735,6 +3877,22 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
}
}
/* If this is a vote document, check if information about the shared
randomness protocol is included, and extract it. */
if (ns->type == NS_TYPE_VOTE) {
/* Does this authority participates in the SR protocol? */
tok = find_opt_by_keyword(tokens, K_SR_FLAG);
if (tok) {
ns->sr_info.participate = 1;
/* Get the SR commitments and reveals from the vote. */
extract_shared_random_commits(ns, tokens);
}
}
/* For both a vote and consensus, extract the shared random values. */
if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS) {
extract_shared_random_srvs(ns, tokens);
}
/* Parse routerstatus lines. */
rs_tokens = smartlist_new();
rs_area = memarea_new();
File diff suppressed because it is too large Load Diff
+166
View File
@@ -0,0 +1,166 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SHARED_RANDOM_H
#define TOR_SHARED_RANDOM_H
/*
* This file contains ABI/API of the shared random protocol defined in
* proposal #250. Every public functions and data structure are namespaced
* with "sr_" which stands for shared random.
*/
#include "or.h"
/* Protocol version */
#define SR_PROTO_VERSION 1
/* Default digest algorithm. */
#define SR_DIGEST_ALG DIGEST_SHA3_256
/* Invariant token in the SRV calculation. */
#define SR_SRV_TOKEN "shared-random"
/* Don't count the NUL terminated byte even though the TOKEN has it. */
#define SR_SRV_TOKEN_LEN (sizeof(SR_SRV_TOKEN) - 1)
/* Length of the random number (in bytes). */
#define SR_RANDOM_NUMBER_LEN 32
/* Size of a decoded commit value in a vote or state. It's a hash and a
* timestamp. It adds up to 40 bytes. */
#define SR_COMMIT_LEN (sizeof(uint64_t) + DIGEST256_LEN)
/* Size of a decoded reveal value from a vote or state. It's a 64 bit
* timestamp and the hashed random number. This adds up to 40 bytes. */
#define SR_REVEAL_LEN (sizeof(uint64_t) + DIGEST256_LEN)
/* Size of SRV message length. The construction is has follow:
* "shared-random" | INT_8(reveal_num) | INT_4(version) | PREV_SRV */
#define SR_SRV_MSG_LEN \
(SR_SRV_TOKEN_LEN + sizeof(uint64_t) + sizeof(uint32_t) + DIGEST256_LEN)
/* Length of base64 encoded commit NOT including the NULL terminated byte.
* Formula is taken from base64_encode_size. */
#define SR_COMMIT_BASE64_LEN \
(((SR_COMMIT_LEN - 1) / 3) * 4 + 4)
/* Length of base64 encoded reveal NOT including the NULL terminated byte.
* Formula is taken from base64_encode_size. This adds up to 56 bytes. */
#define SR_REVEAL_BASE64_LEN \
(((SR_REVEAL_LEN - 1) / 3) * 4 + 4)
/* Length of base64 encoded shared random value. It's 32 bytes long so 44
* bytes from the base64_encode_size formula. That includes the '='
* character at the end. */
#define SR_SRV_VALUE_BASE64_LEN \
(((DIGEST256_LEN - 1) / 3) * 4 + 4)
/* Assert if commit valid flag is not set. */
#define ASSERT_COMMIT_VALID(c) tor_assert((c)->valid)
/* Protocol phase. */
typedef enum {
/* Commitment phase */
SR_PHASE_COMMIT = 1,
/* Reveal phase */
SR_PHASE_REVEAL = 2,
} sr_phase_t;
/* A shared random value (SRV). */
typedef struct sr_srv_t {
/* The number of reveal values used to derive this SRV. */
uint64_t num_reveals;
/* The actual value. This is the stored result of SHA3-256. */
uint8_t value[DIGEST256_LEN];
} sr_srv_t;
/* A commit (either ours or from another authority). */
typedef struct sr_commit_t {
/* Hashing algorithm used. */
digest_algorithm_t alg;
/* Indicate if this commit has been verified thus valid. */
unsigned int valid:1;
/* Commit owner info */
/* The RSA identity key of the authority. */
char rsa_identity[DIGEST_LEN];
/* Commitment information */
/* Timestamp of reveal. Correspond to TIMESTAMP. */
uint64_t reveal_ts;
/* H(REVEAL) as found in COMMIT message. */
char hashed_reveal[DIGEST256_LEN];
/* Base64 encoded COMMIT. We use this to put it in our vote. */
char encoded_commit[SR_COMMIT_BASE64_LEN + 1];
/* Reveal information */
/* H(RN) which is what we used as the random value for this commit. We
* don't use the raw bytes since those are sent on the network thus
* avoiding possible information leaks of our PRNG. */
uint8_t random_number[SR_RANDOM_NUMBER_LEN];
/* Timestamp of commit. Correspond to TIMESTAMP. */
uint64_t commit_ts;
/* This is the whole reveal message. We use it during verification */
char encoded_reveal[SR_REVEAL_BASE64_LEN + 1];
} sr_commit_t;
/* API */
/* Public methods: */
int sr_init(int save_to_disk);
void sr_save_and_cleanup(void);
void sr_act_post_consensus(const networkstatus_t *consensus);
void sr_handle_received_commits(smartlist_t *commits,
crypto_pk_t *voter_key);
sr_commit_t *sr_parse_commit(const smartlist_t *args);
sr_srv_t *sr_parse_srv(const smartlist_t *args);
char *sr_get_string_for_vote(void);
char *sr_get_string_for_consensus(const smartlist_t *votes,
int32_t num_srv_agreements);
void sr_commit_free(sr_commit_t *commit);
void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv);
/* Private methods (only used by shared_random_state.c): */
static inline
const char *sr_commit_get_rsa_fpr(const sr_commit_t *commit)
{
return hex_str((const char *) commit->rsa_identity,
sizeof(commit->rsa_identity));
}
void sr_compute_srv(void);
sr_commit_t *sr_generate_our_commit(time_t timestamp,
const authority_cert_t *my_rsa_cert);
#ifdef SHARED_RANDOM_PRIVATE
/* Encode */
STATIC int reveal_encode(const sr_commit_t *commit, char *dst, size_t len);
STATIC int commit_encode(const sr_commit_t *commit, char *dst, size_t len);
/* Decode. */
STATIC int commit_decode(const char *encoded, sr_commit_t *commit);
STATIC int reveal_decode(const char *encoded, sr_commit_t *commit);
STATIC int commit_has_reveal_value(const sr_commit_t *commit);
STATIC int verify_commit_and_reveal(const sr_commit_t *commit);
STATIC sr_srv_t *get_majority_srv_from_votes(const smartlist_t *votes,
int current);
STATIC void save_commit_to_state(sr_commit_t *commit);
STATIC sr_srv_t *srv_dup(const sr_srv_t *orig);
STATIC int commitments_are_the_same(const sr_commit_t *commit_one,
const sr_commit_t *commit_two);
STATIC int commit_is_authoritative(const sr_commit_t *commit,
const char *voter_key);
STATIC int should_keep_commit(const sr_commit_t *commit,
const char *voter_key,
sr_phase_t phase);
STATIC void save_commit_during_reveal_phase(const sr_commit_t *commit);
#endif /* SHARED_RANDOM_PRIVATE */
#ifdef TOR_UNIT_TESTS
void set_num_srv_agreements(int32_t value);
#endif /* TOR_UNIT_TESTS */
#endif /* TOR_SHARED_RANDOM_H */
File diff suppressed because it is too large Load Diff
+146
View File
@@ -0,0 +1,146 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SHARED_RANDOM_STATE_H
#define TOR_SHARED_RANDOM_STATE_H
#include "shared_random.h"
/* Action that can be performed on the state for any objects. */
typedef enum {
SR_STATE_ACTION_GET = 1,
SR_STATE_ACTION_PUT = 2,
SR_STATE_ACTION_DEL = 3,
SR_STATE_ACTION_DEL_ALL = 4,
SR_STATE_ACTION_SAVE = 5,
} sr_state_action_t;
/* Object in the state that can be queried through the state API. */
typedef enum {
/* Will return a single commit using an authority identity key. */
SR_STATE_OBJ_COMMIT,
/* Returns the entire list of commits from the state. */
SR_STATE_OBJ_COMMITS,
/* Return the current SRV object pointer. */
SR_STATE_OBJ_CURSRV,
/* Return the previous SRV object pointer. */
SR_STATE_OBJ_PREVSRV,
/* Return the phase. */
SR_STATE_OBJ_PHASE,
/* Get or Put the valid after time. */
SR_STATE_OBJ_VALID_AFTER,
} sr_state_object_t;
/* State of the protocol. It's also saved on disk in fname. This data
* structure MUST be synchronized at all time with the one on disk. */
typedef struct sr_state_t {
/* Filename of the state file on disk. */
char *fname;
/* Version of the protocol. */
uint32_t version;
/* The valid-after of the voting period we have prepared the state for. */
time_t valid_after;
/* Until when is this state valid? */
time_t valid_until;
/* Protocol phase. */
sr_phase_t phase;
/* Number of runs completed. */
uint64_t n_protocol_runs;
/* The number of commitment rounds we've performed in this protocol run. */
unsigned int n_commit_rounds;
/* The number of reveal rounds we've performed in this protocol run. */
unsigned int n_reveal_rounds;
/* A map of all the received commitments for this protocol run. This is
* indexed by authority RSA identity digest. */
digestmap_t *commits;
/* Current and previous shared random value. */
sr_srv_t *previous_srv;
sr_srv_t *current_srv;
/* Indicate if the state contains an SRV that was _just_ generated. This is
* used during voting so that we know whether to use the super majority rule
* or not when deciding on keeping it for the consensus. It is _always_ set
* to 0 post consensus.
*
* EDGE CASE: if an authority computes a new SRV then immediately reboots
* and, once back up, votes for the current round, it won't know if the
* SRV is fresh or not ultimately making it _NOT_ use the super majority
* when deciding to put or not the SRV in the consensus. This is for now
* an acceptable very rare edge case. */
unsigned int is_srv_fresh:1;
} sr_state_t;
/* Persistent state of the protocol, as saved to disk. */
typedef struct sr_disk_state_t {
uint32_t magic_;
/* Version of the protocol. */
uint32_t Version;
/* Version of our running tor. */
char *TorVersion;
/* Creation time of this state */
time_t ValidAfter;
/* State valid until? */
time_t ValidUntil;
/* All commits seen that are valid. */
config_line_t *Commit;
/* Previous and current shared random value. */
config_line_t *SharedRandValues;
/* Extra Lines for configuration we might not know. */
config_line_t *ExtraLines;
} sr_disk_state_t;
/* API */
/* Public methods: */
void sr_state_update(time_t valid_after);
/* Private methods (only used by shared-random.c): */
void sr_state_set_valid_after(time_t valid_after);
sr_phase_t sr_state_get_phase(void);
const sr_srv_t *sr_state_get_previous_srv(void);
const sr_srv_t *sr_state_get_current_srv(void);
void sr_state_set_previous_srv(const sr_srv_t *srv);
void sr_state_set_current_srv(const sr_srv_t *srv);
void sr_state_clean_srvs(void);
digestmap_t *sr_state_get_commits(void);
sr_commit_t *sr_state_get_commit(const char *rsa_fpr);
void sr_state_add_commit(sr_commit_t *commit);
void sr_state_delete_commits(void);
void sr_state_copy_reveal_info(sr_commit_t *saved_commit,
const sr_commit_t *commit);
unsigned int sr_state_srv_is_fresh(void);
void sr_state_set_fresh_srv(void);
void sr_state_unset_fresh_srv(void);
int sr_state_init(int save_to_disk, int read_from_disk);
int sr_state_is_initialized(void);
void sr_state_save(void);
void sr_state_free(void);
#ifdef SHARED_RANDOM_STATE_PRIVATE
STATIC int disk_state_load_from_disk_impl(const char *fname);
STATIC sr_phase_t get_sr_protocol_phase(time_t valid_after);
STATIC time_t get_state_valid_until_time(time_t now);
STATIC const char *get_phase_str(sr_phase_t phase);
STATIC void reset_state_for_new_protocol_run(time_t valid_after);
STATIC void new_protocol_run(time_t valid_after);
STATIC void state_rotate_srv(void);
STATIC int is_phase_transition(sr_phase_t next_phase);
#endif /* SHARED_RANDOM_STATE_PRIVATE */
#ifdef TOR_UNIT_TESTS
STATIC void set_sr_phase(sr_phase_t phase);
STATIC sr_state_t *get_sr_state(void);
#endif /* TOR_UNIT_TESTS */
#endif /* TOR_SHARED_RANDOM_STATE_H */
+1
View File
@@ -116,6 +116,7 @@ src_test_test_SOURCES = \
src/test/test_routerlist.c \
src/test/test_routerset.c \
src/test/test_scheduler.c \
src/test/test_shared_random.c \
src/test/test_socks.c \
src/test/test_status.c \
src/test/test_threads.c \
+71
View File
@@ -0,0 +1,71 @@
# This is a reference implementation of the SRV calculation for prop250. We
# use it to generate a test vector for the test_sr_compute_srv() unittest.
# (./test shared-random/sr_compute_srv)
#
# Here is the SRV computation formula:
#
# HASHED_REVEALS = H(ID_a | R_a | ID_b | R_b | ..)
#
# SRV = SHA3-256("shared-random" | INT_8(reveal_num) | INT_4(version) |
# HASHED_REVEALS | previous_SRV)
#
import sys
import hashlib
import struct
# Python 3.6+, the SHA3 is available in hashlib natively. Else this requires
# the pysha3 package (pip install pysha3).
if sys.version_info < (3, 6):
import sha3
# Test vector to make sure the right sha3 version will be used. pysha3 < 1.0
# used the old Keccak implementation. During the finalization of SHA3, NIST
# changed the delimiter suffix from 0x01 to 0x06. The Keccak sponge function
# stayed the same. pysha3 1.0 provides the previous Keccak hash, too.
TEST_VALUE = "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51"
if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest():
print("pysha3 version is < 1.0. Please install from:")
print("https://github.com/tiran/pysha3https://github.com/tiran/pysha3")
sys.exit(1)
# In this example, we use three reveal values.
reveal_num = 3
version = 1
# We set directly the ascii value because memset(buf, 'A', 20) makes it to 20
# times "41" in the final string.
# Identity and reveal value of dirauth a
ID_a = 20 * "41" # RSA identity of 40 base16 bytes.
R_a = 56 * 'A' # 56 base64 characters
# Identity and reveal value of dirauth b
ID_b = 20 * "42" # RSA identity of 40 base16 bytes.
R_b = 56 * 'B' # 56 base64 characters
# Identity and reveal value of dirauth c
ID_c = 20 * "43" # RSA identity of 40 base16 bytes.
R_c = 56 * 'C' # 56 base64 characters
# Concatenate them all together and hash them to form HASHED_REVEALS.
REVEALS = (ID_a + R_a + ID_b + R_b + ID_c + R_c).encode()
hashed_reveals_object = hashlib.sha3_256(REVEALS)
hashed_reveals = hashed_reveals_object.digest()
previous_SRV = (32 * 'Z').encode()
# Now form the message.
#srv_msg = struct.pack('13sQL256ss', "shared-random", reveal_num, version,
# hashed_reveals, previous_SRV)
invariant_token = b"shared-random"
srv_msg = invariant_token + \
struct.pack('!QL', reveal_num, version) + \
hashed_reveals + \
previous_SRV
# Now calculate the HMAC
srv = hashlib.sha3_256(srv_msg)
print("%s" % srv.hexdigest().upper())
# 2A9B1D6237DAB312A40F575DA85C147663E7ED3F80E9555395F15B515C74253D
+1
View File
@@ -1170,6 +1170,7 @@ struct testgroup_t testgroups[] = {
{ "routerset/" , routerset_tests },
{ "scheduler/", scheduler_tests },
{ "socks/", socks_tests },
{ "shared-random/", sr_tests },
{ "status/" , status_tests },
{ "tortls/", tortls_tests },
{ "util/", util_tests },
+1
View File
@@ -225,6 +225,7 @@ extern struct testcase_t util_format_tests[];
extern struct testcase_t util_process_tests[];
extern struct testcase_t dns_tests[];
extern struct testcase_t handle_tests[];
extern struct testcase_t sr_tests[];
extern struct testcase_t slow_crypto_tests[];
extern struct testcase_t slow_util_tests[];
+84 -3
View File
@@ -31,6 +31,7 @@
#include "routerlist.h"
#include "routerparse.h"
#include "routerset.h"
#include "shared_random_state.h"
#include "test.h"
#include "test_dir_common.h"
#include "torcert.h"
@@ -1436,6 +1437,19 @@ test_dir_measured_bw_kb_cache(void *arg)
return;
}
static char *
my_dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
{
smartlist_t *s = dirvote_compute_params(votes, method, total_authorities);
tor_assert(s);
char *res = smartlist_join_strings(s, " ", 0, NULL);
SMARTLIST_FOREACH(s, char *, cp, tor_free(cp));
smartlist_free(s);
return res;
}
#define dirvote_compute_params my_dirvote_compute_params
static void
test_dir_param_voting(void *arg)
{
@@ -1545,6 +1559,43 @@ test_dir_param_voting(void *arg)
return;
}
static void
test_dir_param_voting_lookup(void *arg)
{
(void)arg;
smartlist_t *lst = smartlist_new();
smartlist_split_string(lst,
"moomin=9 moomin=10 moomintroll=5 fred "
"jack= electricity=sdk opa=6z abc=9 abcd=99",
NULL, 0, 0);
tt_int_op(1000,
OP_EQ, dirvote_get_intermediate_param_value(lst, "ab", 1000));
tt_int_op(9, OP_EQ, dirvote_get_intermediate_param_value(lst, "abc", 1000));
tt_int_op(99, OP_EQ, dirvote_get_intermediate_param_value(lst, "abcd", 1000));
/* moomin appears twice. */
tt_int_op(-100, OP_EQ,
dirvote_get_intermediate_param_value(lst, "moomin", -100));
/* fred and jack are truncated */
tt_int_op(-100, OP_EQ,
dirvote_get_intermediate_param_value(lst, "fred", -100));
tt_int_op(-100, OP_EQ,
dirvote_get_intermediate_param_value(lst, "jack", -100));
/* electricity and opa aren't integers. */
tt_int_op(-100, OP_EQ,
dirvote_get_intermediate_param_value(lst, "electricity", -100));
tt_int_op(-100, OP_EQ,
dirvote_get_intermediate_param_value(lst, "opa", -100));
done:
SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp));
smartlist_free(lst);
}
#undef dirvote_compute_params
/** Helper: Test that two networkstatus_voter_info_t do in fact represent the
* same voting authority, and that they do in fact have all the same
* information. */
@@ -1789,6 +1840,15 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
return;
}
static authority_cert_t *mock_cert;
static authority_cert_t *
get_my_v3_authority_cert_m(void)
{
tor_assert(mock_cert);
return mock_cert;
}
/** Run a unit tests for generating and parsing networkstatuses, with
* the supply test fns. */
static void
@@ -1832,10 +1892,30 @@ test_a_networkstatus(
tt_assert(rs_test);
tt_assert(vrs_test);
tt_assert(!dir_common_authority_pk_init(&cert1, &cert2, &cert3,
&sign_skey_1, &sign_skey_2,
&sign_skey_3));
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
/* Parse certificates and keys. */
cert1 = mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
tt_assert(cert1);
cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL);
tt_assert(cert2);
cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL);
tt_assert(cert3);
sign_skey_1 = crypto_pk_new();
sign_skey_2 = crypto_pk_new();
sign_skey_3 = crypto_pk_new();
sign_skey_leg1 = pk_generate(4);
sr_state_init(0, 0);
tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
AUTHORITY_SIGNKEY_1, -1));
tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_2,
AUTHORITY_SIGNKEY_2, -1));
tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_3,
AUTHORITY_SIGNKEY_3, -1));
tt_assert(!crypto_pk_cmp_keys(sign_skey_1, cert1->signing_key));
tt_assert(!crypto_pk_cmp_keys(sign_skey_2, cert2->signing_key));
tt_assert(!dir_common_construct_vote_1(&vote, cert1, sign_skey_1, vrs_gen,
&v1, &n_vrs, now, 1));
@@ -5287,6 +5367,7 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(measured_bw_kb),
DIR_LEGACY(measured_bw_kb_cache),
DIR_LEGACY(param_voting),
DIR(param_voting_lookup, 0),
DIR_LEGACY(v3_networkstatus),
DIR(random_weighted, 0),
DIR(scale_bw, 0),
+17
View File
@@ -19,13 +19,24 @@
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
#include "shared_random.h"
#include "test.h"
#include "test_dir_common.h"
void construct_consensus(char **consensus_text_md);
static authority_cert_t *mock_cert;
static authority_cert_t *
get_my_v3_authority_cert_m(void)
{
tor_assert(mock_cert);
return mock_cert;
}
/* 4 digests + 3 sep + pre + post + NULL */
static char output[4*BASE64_DIGEST256_LEN+3+2+2+1];
@@ -227,6 +238,12 @@ test_router_pick_directory_server_impl(void *arg)
tt_assert(networkstatus_consensus_is_bootstrapping(now + 2*24*60*60));
tt_assert(networkstatus_consensus_is_bootstrapping(now - 2*24*60*60));
/* Init SR subsystem. */
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
sr_init(0);
UNMOCK(get_my_v3_authority_cert);
/* No consensus available, fail early */
rs = router_pick_directory_server_impl(V3_DIRINFO, (const int) 0, NULL);
tt_assert(rs == NULL);
File diff suppressed because it is too large Load Diff