mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
prop250: Add memory and disk state in new files
This commit introduces two new files with their header. "shared_random.c" contains basic functions to initialize the state and allow commit decoding for the disk state to be able to parse them from disk. "shared_random_state.c" contains everything that has to do with the state for both our memory and disk. Lots of helper functions as well as a mechanism to query the state in a synchronized way. Signed-off-by: David Goulet <dgoulet@torproject.org> Signed-off-by: George Kadianakis <desnacked@riseup.net>
This commit is contained in:
+50
-38
@@ -2511,50 +2511,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 = {0};
|
||||
|
||||
/** 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 +2580,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 +2588,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>. */
|
||||
|
||||
@@ -121,12 +121,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,
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
/* Copyright (c) 2016, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file shared_random.c
|
||||
*
|
||||
* \brief Functions and data structure needed to accomplish the shared
|
||||
* random protocol as defined in proposal #250.
|
||||
**/
|
||||
|
||||
#define SHARED_RANDOM_PRIVATE
|
||||
|
||||
#include "or.h"
|
||||
#include "shared_random.h"
|
||||
#include "config.h"
|
||||
#include "confparse.h"
|
||||
#include "networkstatus.h"
|
||||
#include "routerkeys.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "shared_random_state.h"
|
||||
|
||||
/* Allocate a new commit object and initializing it with <b>identity</b>
|
||||
* that MUST be provided. The digest algorithm is set to the default one
|
||||
* that is supported. The rest is uninitialized. This never returns NULL. */
|
||||
static sr_commit_t *
|
||||
commit_new(const char *rsa_identity_fpr)
|
||||
{
|
||||
sr_commit_t *commit;
|
||||
|
||||
tor_assert(rsa_identity_fpr);
|
||||
|
||||
commit = tor_malloc_zero(sizeof(*commit));
|
||||
commit->alg = SR_DIGEST_ALG;
|
||||
strlcpy(commit->rsa_identity_fpr, rsa_identity_fpr,
|
||||
sizeof(commit->rsa_identity_fpr));
|
||||
return commit;
|
||||
}
|
||||
|
||||
/* Parse the encoded commit. The format is:
|
||||
* base64-encode( TIMESTAMP || H(REVEAL) )
|
||||
*
|
||||
* If successfully decoded and parsed, commit is updated and 0 is returned.
|
||||
* On error, return -1. */
|
||||
STATIC int
|
||||
commit_decode(const char *encoded, sr_commit_t *commit)
|
||||
{
|
||||
int decoded_len = 0;
|
||||
size_t offset = 0;
|
||||
/* XXX: Needs two extra bytes for the base64 decode calculation matches
|
||||
* the binary length once decoded. #17868. */
|
||||
char b64_decoded[SR_COMMIT_LEN + 2];
|
||||
|
||||
tor_assert(encoded);
|
||||
tor_assert(commit);
|
||||
|
||||
if (strlen(encoded) > SR_COMMIT_BASE64_LEN) {
|
||||
/* This means that if we base64 decode successfully the reveiced commit,
|
||||
* we'll end up with a bigger decoded commit thus unusable. */
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Decode our encoded commit. Let's be careful here since _encoded_ is
|
||||
* coming from the network in a dirauth vote so we expect nothing more
|
||||
* than the base64 encoded length of a commit. */
|
||||
decoded_len = base64_decode(b64_decoded, sizeof(b64_decoded),
|
||||
encoded, strlen(encoded));
|
||||
if (decoded_len < 0) {
|
||||
log_warn(LD_BUG, "SR: Commit from authority %s can't be decoded.",
|
||||
commit->rsa_identity_fpr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (decoded_len != SR_COMMIT_LEN) {
|
||||
log_warn(LD_BUG, "SR: Commit from authority %s decoded length doesn't "
|
||||
"match the expected length (%d vs %d).",
|
||||
commit->rsa_identity_fpr, decoded_len, SR_COMMIT_LEN);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* First is the timestamp (8 bytes). */
|
||||
commit->commit_ts = (time_t) tor_ntohll(get_uint64(b64_decoded));
|
||||
offset += sizeof(uint64_t);
|
||||
/* Next is hashed reveal. */
|
||||
memcpy(commit->hashed_reveal, b64_decoded + offset,
|
||||
sizeof(commit->hashed_reveal));
|
||||
/* Copy the base64 blob to the commit. Useful for voting. */
|
||||
strlcpy(commit->encoded_commit, encoded, sizeof(commit->encoded_commit));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse the b64 blob at <b>encoded</b> containing reveal information and
|
||||
* store the information in-place in <b>commit</b>. Return 0 on success else
|
||||
* a negative value. */
|
||||
STATIC int
|
||||
reveal_decode(const char *encoded, sr_commit_t *commit)
|
||||
{
|
||||
int decoded_len = 0;
|
||||
/* XXX: Needs two extra bytes for the base64 decode calculation matches
|
||||
* the binary length once decoded. #17868. */
|
||||
char b64_decoded[SR_REVEAL_LEN + 2];
|
||||
|
||||
tor_assert(encoded);
|
||||
tor_assert(commit);
|
||||
|
||||
if (strlen(encoded) > SR_REVEAL_BASE64_LEN) {
|
||||
/* This means that if we base64 decode successfully the received reveal
|
||||
* value, we'll end up with a bigger decoded value thus unusable. */
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Decode our encoded reveal. Let's be careful here since _encoded_ is
|
||||
* coming from the network in a dirauth vote so we expect nothing more
|
||||
* than the base64 encoded length of our reveal. */
|
||||
decoded_len = base64_decode(b64_decoded, sizeof(b64_decoded),
|
||||
encoded, strlen(encoded));
|
||||
if (decoded_len < 0) {
|
||||
log_warn(LD_BUG, "SR: Reveal from authority %s can't be decoded.",
|
||||
commit->rsa_identity_fpr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (decoded_len != SR_REVEAL_LEN) {
|
||||
log_warn(LD_BUG, "SR: Reveal from authority %s decoded length is "
|
||||
"doesn't match the expected length (%d vs %d)",
|
||||
commit->rsa_identity_fpr, decoded_len, SR_REVEAL_LEN);
|
||||
goto error;
|
||||
}
|
||||
|
||||
commit->reveal_ts = (time_t) tor_ntohll(get_uint64(b64_decoded));
|
||||
/* Copy the last part, the random value. */
|
||||
memcpy(commit->random_number, b64_decoded + 8,
|
||||
sizeof(commit->random_number));
|
||||
/* Also copy the whole message to use during verification */
|
||||
strlcpy(commit->encoded_reveal, encoded, sizeof(commit->encoded_reveal));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Cleanup both our global state and disk state. */
|
||||
static void
|
||||
sr_cleanup(void)
|
||||
{
|
||||
sr_state_free();
|
||||
}
|
||||
|
||||
/* Free a commit object. */
|
||||
void
|
||||
sr_commit_free(sr_commit_t *commit)
|
||||
{
|
||||
if (commit == NULL) {
|
||||
return;
|
||||
}
|
||||
/* Make sure we do not leave OUR random number in memory. */
|
||||
memwipe(commit->random_number, 0, sizeof(commit->random_number));
|
||||
tor_free(commit);
|
||||
}
|
||||
|
||||
/* Parse a list of arguments from a SRV value either from a vote, consensus
|
||||
* or from our disk state and return a newly allocated srv object. NULL is
|
||||
* returned on error.
|
||||
*
|
||||
* The arguments' order:
|
||||
* num_reveals, value
|
||||
*/
|
||||
sr_srv_t *
|
||||
sr_parse_srv(const smartlist_t *args)
|
||||
{
|
||||
char *value;
|
||||
int num_reveals, ok;
|
||||
sr_srv_t *srv = NULL;
|
||||
|
||||
tor_assert(args);
|
||||
|
||||
if (smartlist_len(args) < 2) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* First argument is the number of reveal values */
|
||||
num_reveals = (int)tor_parse_long(smartlist_get(args, 0),
|
||||
10, 0, INT32_MAX, &ok, NULL);
|
||||
if (!ok) {
|
||||
goto end;
|
||||
}
|
||||
srv = tor_malloc_zero(sizeof(*srv));
|
||||
srv->num_reveals = num_reveals;
|
||||
|
||||
/* Second and last argument is the shared random value it self. */
|
||||
value = smartlist_get(args, 1);
|
||||
base16_decode((char *) srv->value, sizeof(srv->value), value,
|
||||
HEX_DIGEST256_LEN);
|
||||
end:
|
||||
return srv;
|
||||
}
|
||||
|
||||
/* Parse a commit from a vote or from our disk state and return a newly
|
||||
* allocated commit object. NULL is returned on error.
|
||||
*
|
||||
* The commit's data is in <b>args</b> and the order matters very much:
|
||||
* algname, RSA fingerprint, commit value[, reveal value]
|
||||
*/
|
||||
sr_commit_t *
|
||||
sr_parse_commit(const smartlist_t *args)
|
||||
{
|
||||
char *value;
|
||||
digest_algorithm_t alg;
|
||||
const char *rsa_identity_fpr;
|
||||
sr_commit_t *commit = NULL;
|
||||
|
||||
if (smartlist_len(args) < 3) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* First argument is the algorithm. */
|
||||
value = smartlist_get(args, 0);
|
||||
alg = crypto_digest_algorithm_parse_name(value);
|
||||
if (alg != SR_DIGEST_ALG) {
|
||||
log_warn(LD_BUG, "SR: Commit algorithm %s is not recognized.",
|
||||
escaped(value));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Second argument is the RSA fingerprint of the auth */
|
||||
rsa_identity_fpr = smartlist_get(args, 1);
|
||||
if (base16_decode(digest, DIGEST_LEN, rsa_identity_fpr,
|
||||
HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "SR: RSA fingerprint '%s' not decodable",
|
||||
rsa_identity_fpr);
|
||||
goto error;
|
||||
}
|
||||
/* Let's make sure, for extra safety, that this fingerprint is known to
|
||||
* us. Even though this comes from a vote, doesn't hurt to be
|
||||
* extracareful. */
|
||||
if (trusteddirserver_get_by_v3_auth_digest(digest) == NULL) {
|
||||
log_warn(LD_DIR, "SR: Fingerprint %s is not from a recognized "
|
||||
"authority. Discarding commit.",
|
||||
rsa_identity_fpr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Allocate commit since we have a valid identity now. */
|
||||
commit = commit_new(rsa_identity_fpr);
|
||||
|
||||
/* Third argument is the commitment value base64-encoded. */
|
||||
value = smartlist_get(args, 2);
|
||||
if (commit_decode(value, commit) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* (Optional) Fourth argument is the revealed value. */
|
||||
if (smartlist_len(args) > 3) {
|
||||
value = smartlist_get(args, 3);
|
||||
if (reveal_decode(value, commit) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return commit;
|
||||
|
||||
error:
|
||||
sr_commit_free(commit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize shared random subsystem. This MUST be called early in the boot
|
||||
* process of tor. Return 0 on success else -1 on error. */
|
||||
int
|
||||
sr_init(int save_to_disk)
|
||||
{
|
||||
return sr_state_init(save_to_disk, 1);
|
||||
}
|
||||
|
||||
/* Save our state to disk and cleanup everything. */
|
||||
void
|
||||
sr_save_and_cleanup(void)
|
||||
{
|
||||
sr_state_save();
|
||||
sr_cleanup();
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/* 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_8(version) | PREV_SRV */
|
||||
#define SR_SRV_MSG_LEN \
|
||||
(SR_SRV_TOKEN_LEN + 1 + 1 + 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)
|
||||
|
||||
/* 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. */
|
||||
int 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;
|
||||
|
||||
/* Commit owner info */
|
||||
|
||||
/* The RSA identity fingerprint of the authority. */
|
||||
char rsa_identity_fpr[FINGERPRINT_LEN + 1];
|
||||
|
||||
/* Commitment information */
|
||||
|
||||
/* Timestamp of reveal. Correspond to TIMESTAMP. */
|
||||
time_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. */
|
||||
time_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_commit_free(sr_commit_t *commit);
|
||||
|
||||
/* Private methods (only used by shared_random_state.c): */
|
||||
|
||||
sr_commit_t *sr_parse_commit(const smartlist_t *args);
|
||||
sr_srv_t *sr_parse_srv(const smartlist_t *args);
|
||||
|
||||
#ifdef SHARED_RANDOM_PRIVATE
|
||||
|
||||
/* Decode. */
|
||||
STATIC int commit_decode(const char *encoded, sr_commit_t *commit);
|
||||
STATIC int reveal_decode(const char *encoded, sr_commit_t *commit);
|
||||
|
||||
#endif /* SHARED_RANDOM_PRIVATE */
|
||||
|
||||
#endif /* TOR_SHARED_RANDOM_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,126 @@
|
||||
/* 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_ALL = 3,
|
||||
SR_STATE_ACTION_SAVE = 4,
|
||||
} 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. */
|
||||
uint8_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. */
|
||||
int 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: */
|
||||
|
||||
/* 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);
|
||||
sr_srv_t *sr_state_get_previous_srv(void);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
#endif /* SHARED_RANDOM_STATE_PRIVATE */
|
||||
|
||||
#endif /* TOR_SHARED_RANDOM_STATE_H */
|
||||
Reference in New Issue
Block a user