mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
r13250@catbus: nickm | 2007-06-04 18:28:55 -0400
Adapt code to parse v3 networkstatus votes so it can also parse a consensus. Make networkstatus_vote_t the catch-all type for votes and conensuses. Correct/clarify the second argument to directory-signature. svn:r10491
This commit is contained in:
parent
8d1224eb51
commit
8b0e6a4466
4
doc/TODO
4
doc/TODO
@ -66,7 +66,7 @@ Things we'd like to do in 0.2.0.x:
|
||||
- Get authorities voting
|
||||
. Implement parsing for new document formats
|
||||
o Parse key certificates
|
||||
- Parse votes and consensuses
|
||||
o Parse votes and consensuses
|
||||
- Unit tests for above
|
||||
. Code to manage key certificates
|
||||
o Generate certificates
|
||||
@ -77,7 +77,7 @@ Things we'd like to do in 0.2.0.x:
|
||||
o Avoid double-checking signatures every time we get a vote.
|
||||
- Warn about expired stuff.
|
||||
o Code to generate votes
|
||||
- Code to generate consensus from a list of votes
|
||||
o Code to generate consensus from a list of votes
|
||||
- Add a signature to a consensus.
|
||||
- Code to check signatures on a consensus
|
||||
- Push/pull documents as appropriate.
|
||||
|
@ -759,10 +759,10 @@ $Id$
|
||||
[Exactly once, at start]
|
||||
|
||||
Describes this authority. The nickname is a convenient identifier
|
||||
for the authority. The identity is an uppercase hex fingerprint of the
|
||||
authority's current identity key. The address is the server's
|
||||
hostname. The IP is the server's current IP address, and dirport
|
||||
is its current directory port.
|
||||
for the authority. The identity is an uppercase hex fingerprint of
|
||||
the authority's current (v3 authority) identity key. The address is
|
||||
the server's hostname. The IP is the server's current IP address,
|
||||
and dirport is its current directory port. XXXXorport
|
||||
|
||||
"contact" SP string NL
|
||||
|
||||
@ -788,13 +788,6 @@ $Id$
|
||||
|
||||
As in the authority section of a vote.
|
||||
|
||||
"fingerprint" SP fingerprint NL
|
||||
|
||||
[Exactly once.]
|
||||
|
||||
An upper-case hex fingerprint, without spaces, of the authority's
|
||||
current identity key.
|
||||
|
||||
"vote-digest" SP digest NL
|
||||
|
||||
[Exactly once.]
|
||||
@ -861,17 +854,16 @@ $Id$
|
||||
The signature section contains the following item, which appears
|
||||
Exactly Once for a vote, and At Least Once for a consensus.
|
||||
|
||||
"directory-signature" SP identity SP digest NL Signature
|
||||
"directory-signature" SP identity SP signing-key-digest NL Signature
|
||||
|
||||
This is a signature of the status document, with the initial item
|
||||
"network-status-version", and the signature item
|
||||
"directory-signature", using the signing key. (In this case, we
|
||||
take the hash through the _space_ after directory-signature, not
|
||||
the newline: this ensures that all authorities sign the same
|
||||
thing.) "identity" is the hex-encoded digest of the authority
|
||||
identity key of the signing authority, and "digest" is the
|
||||
hex-encoded digest of the current authority signing key of the
|
||||
signing authority.
|
||||
"directory-signature", using the signing key. (In this case, we take
|
||||
the hash through the _space_ after directory-signature, not the
|
||||
newline: this ensures that all authorities sign the same thing.)
|
||||
"identity" is the hex-encoded digest of the authority identity key of
|
||||
the signing authority, and "signing-key-digest" is the hex-encoded
|
||||
digest of the current authority signing key of the signing authority.
|
||||
|
||||
3.3. Deciding how to vote.
|
||||
|
||||
|
@ -1897,19 +1897,19 @@ generate_networkstatus_opinion(int v2)
|
||||
}
|
||||
outp += strlen(outp);
|
||||
} else {
|
||||
char hex_digest[HEX_DIGEST_LEN+1];
|
||||
if (tor_snprintf(outp, endp-outp, "directory-signature %s ",
|
||||
fingerprint)<0) {
|
||||
char signing_key_fingerprint[FINGERPRINT_LEN+1];
|
||||
if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
|
||||
log_warn(LD_BUG, "Unable to start signature line.");
|
||||
goto done;
|
||||
}
|
||||
if (router_get_networkstatus_v3_hash(status, digest)<0) {
|
||||
log_warn(LD_BUG, "Unable to hash network status vote");
|
||||
outp += strlen(outp);
|
||||
|
||||
if (crypto_pk_get_fingerprint(private_key, signing_key_fingerprint, 0)<0) {
|
||||
log_warn(LD_BUG, "Unable to get fingerprint for signing key");
|
||||
goto done;
|
||||
}
|
||||
base16_encode(hex_digest, sizeof(hex_digest), digest, DIGEST_LEN);
|
||||
outp += strlen(outp);
|
||||
if (tor_snprintf(outp, endp-outp, "%s\n", hex_digest)<0) {
|
||||
if (tor_snprintf(outp, endp-outp, "%s %s\n", fingerprint,
|
||||
signing_key_fingerprint)<0) {
|
||||
log_warn(LD_BUG, "Unable to end signature line.");
|
||||
goto done;
|
||||
}
|
||||
|
@ -26,9 +26,15 @@ networkstatus_vote_free(networkstatus_vote_t *ns)
|
||||
tor_free(ns->known_flags[i]);
|
||||
tor_free(ns->known_flags);
|
||||
}
|
||||
tor_free(ns->nickname);
|
||||
tor_free(ns->address);
|
||||
tor_free(ns->contact);
|
||||
if (ns->voters) {
|
||||
SMARTLIST_FOREACH(ns->voters, networkstatus_voter_info_t *, voter,
|
||||
{
|
||||
tor_free(voter->nickname);
|
||||
tor_free(voter->address);
|
||||
tor_free(voter->contact);
|
||||
});
|
||||
smartlist_free(ns->voters);
|
||||
}
|
||||
if (ns->cert)
|
||||
authority_cert_free(ns->cert);
|
||||
|
||||
@ -46,6 +52,19 @@ networkstatus_vote_free(networkstatus_vote_t *ns)
|
||||
tor_free(ns);
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
networkstatus_voter_info_t *
|
||||
networkstatus_get_voter_by_id(networkstatus_vote_t *vote,
|
||||
const char *identity)
|
||||
{
|
||||
if (!vote || !vote->voters)
|
||||
return NULL;
|
||||
SMARTLIST_FOREACH(vote->voters, networkstatus_voter_info_t *, voter,
|
||||
if (!memcmp(voter->identity_digest, identity, DIGEST_LEN))
|
||||
return voter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
static int
|
||||
_compare_times(const void **_a, const void **_b)
|
||||
@ -92,12 +111,23 @@ median_int(smartlist_t *ints)
|
||||
return *(time_t*)smartlist_get(ints, idx);
|
||||
}
|
||||
|
||||
static networkstatus_voter_info_t *
|
||||
get_voter(const networkstatus_vote_t *vote)
|
||||
{
|
||||
tor_assert(vote);
|
||||
tor_assert(vote->is_vote);
|
||||
tor_assert(vote->voters);
|
||||
tor_assert(smartlist_len(vote->voters) == 1);
|
||||
return smartlist_get(vote->voters, 0);
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
static int
|
||||
_compare_votes_by_authority_id(const void **_a, const void **_b)
|
||||
{
|
||||
const networkstatus_vote_t *a = *_a, *b = *_b;
|
||||
return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
|
||||
return memcmp(get_voter(a)->identity_digest,
|
||||
get_voter(b)->identity_digest, DIGEST_LEN);
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
@ -193,7 +223,8 @@ compute_routerstatus_consensus(smartlist_t *votes)
|
||||
++cur_n;
|
||||
} else {
|
||||
if (cur_n > most_n ||
|
||||
(cur && cur_n == most_n && cur->status.published_on > most_published)) {
|
||||
(cur && cur_n == most_n &&
|
||||
cur->status.published_on > most_published)) {
|
||||
most = cur;
|
||||
most_n = cur_n;
|
||||
most_published = cur->status.published_on;
|
||||
@ -246,7 +277,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
}
|
||||
/* XXXX020 somebody needs to check vote authority. It could be this
|
||||
* function, it could be somebody else. */
|
||||
|
||||
flags = smartlist_create();
|
||||
|
||||
/* Compute medians of time-related things, and figure out how many
|
||||
@ -363,20 +393,23 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
char ip[INET_NTOA_BUF_LEN];
|
||||
char fingerprint[HEX_DIGEST_LEN+1];
|
||||
char votedigest[HEX_DIGEST_LEN+1];
|
||||
networkstatus_voter_info_t *voter = get_voter(v);
|
||||
|
||||
in.s_addr = htonl(v->addr);
|
||||
in.s_addr = htonl(voter->addr);
|
||||
tor_inet_ntoa(&in, ip, sizeof(ip));
|
||||
base16_encode(fingerprint, sizeof(fingerprint), v->identity_digest,
|
||||
base16_encode(fingerprint, sizeof(fingerprint), voter->identity_digest,
|
||||
DIGEST_LEN);
|
||||
base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
|
||||
DIGEST_LEN);
|
||||
base16_encode(votedigest, sizeof(votedigest), v->vote_digest, DIGEST_LEN);
|
||||
|
||||
tor_snprintf(buf, sizeof(buf),
|
||||
"dir-source %s %s %s %s %d %d\n"
|
||||
"contact %s\n"
|
||||
"vote-digest %s\n",
|
||||
v->nickname, fingerprint, v->address, ip, v->dir_port,
|
||||
v->or_port,
|
||||
v->contact,
|
||||
voter->nickname, fingerprint, voter->address, ip,
|
||||
voter->dir_port,
|
||||
voter->or_port,
|
||||
voter->contact,
|
||||
votedigest);
|
||||
smartlist_add(chunks, tor_strdup(buf));
|
||||
});
|
||||
@ -564,19 +597,21 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
{
|
||||
char digest[DIGEST_LEN];
|
||||
char fingerprint[HEX_DIGEST_LEN+1];
|
||||
char hex_digest[HEX_DIGEST_LEN+1];
|
||||
char signing_key_fingerprint[HEX_DIGEST_LEN+1];
|
||||
|
||||
char buf[4096];
|
||||
smartlist_add(chunks, tor_strdup("directory-signature "));
|
||||
|
||||
/* Compute the hash of the chunks. */
|
||||
hash_list_members(digest, chunks);
|
||||
|
||||
/* Get hex stuff as needed. */
|
||||
base16_encode(hex_digest, sizeof(hex_digest), digest, DIGEST_LEN);
|
||||
/* Get the fingerprints */
|
||||
crypto_pk_get_fingerprint(identity_key, fingerprint, 0);
|
||||
crypto_pk_get_fingerprint(signing_key, signing_key_fingerprint, 0);
|
||||
|
||||
/* add the junk that will go at the end of the line. */
|
||||
tor_snprintf(buf, sizeof(buf), "%s %s\n", hex_digest, fingerprint);
|
||||
tor_snprintf(buf, sizeof(buf), "%s %s\n", fingerprint,
|
||||
signing_key_fingerprint);
|
||||
/* And the signature. */
|
||||
/* XXXX020 check return */
|
||||
router_append_dirobj_signature(buf, sizeof(buf), digest, signing_key);
|
||||
@ -593,3 +628,4 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
45
src/or/or.h
45
src/or/or.h
@ -1300,9 +1300,28 @@ typedef struct vote_routerstatus_t {
|
||||
char *version;
|
||||
} vote_routerstatus_t;
|
||||
|
||||
/** DOCDOC */
|
||||
/* DOCDOC */
|
||||
typedef struct networkstatus_voter_info_t {
|
||||
char *nickname;
|
||||
char identity_digest[DIGEST_LEN];
|
||||
char *address;
|
||||
uint32_t addr;
|
||||
uint16_t dir_port;
|
||||
uint16_t or_port;
|
||||
char *contact;
|
||||
char vote_digest[DIGEST_LEN]; /* consensus only. */
|
||||
char signing_key_digest[DIGEST_LEN]; /* This part is _not_ signed. */
|
||||
|
||||
char *pending_signature;
|
||||
int pending_signature_len;
|
||||
int bad_signature;
|
||||
} networkstatus_voter_info_t;
|
||||
|
||||
/*XXXX020 rename to networkstatus_t once it works. */
|
||||
/** DOCDOC is vote or consensus. */
|
||||
typedef struct networkstatus_vote_t {
|
||||
time_t published;
|
||||
int is_vote;
|
||||
time_t published; /* vote only. */
|
||||
time_t valid_after;
|
||||
time_t fresh_until;
|
||||
time_t valid_until;
|
||||
@ -1313,20 +1332,12 @@ typedef struct networkstatus_vote_t {
|
||||
char *server_versions;
|
||||
char **known_flags; /* NULL-terminated */
|
||||
|
||||
char *nickname;
|
||||
char identity_digest[DIGEST_LEN];
|
||||
char *address;
|
||||
uint32_t addr;
|
||||
uint16_t dir_port;
|
||||
uint16_t or_port;
|
||||
smartlist_t *voters; /* list of networkstatus_voter_info_t */
|
||||
|
||||
struct authority_cert_t *cert;
|
||||
struct authority_cert_t *cert; /* vote only. */
|
||||
|
||||
char *contact;
|
||||
|
||||
char vote_digest[DIGEST_LEN];
|
||||
|
||||
smartlist_t *routerstatus_list;
|
||||
smartlist_t *routerstatus_list; /* holds vote_routerstatus_t if is_vote,
|
||||
* otherwise just routerstatus_t. */
|
||||
} networkstatus_vote_t;
|
||||
|
||||
/** Contents of a directory of onion routers. */
|
||||
@ -2718,6 +2729,9 @@ void networkstatus_vote_free(networkstatus_vote_t *ns);
|
||||
char *networkstatus_compute_consensus(smartlist_t *votes,
|
||||
crypto_pk_env_t *identity_key,
|
||||
crypto_pk_env_t *signing_key);
|
||||
networkstatus_voter_info_t *networkstatus_get_voter_by_id(
|
||||
networkstatus_vote_t *vote,
|
||||
const char *identity);
|
||||
|
||||
/********************************* dns.c ***************************/
|
||||
|
||||
@ -3383,7 +3397,8 @@ void assert_addr_policy_ok(addr_policy_t *t);
|
||||
void dump_distinct_digest_count(int severity);
|
||||
|
||||
networkstatus_t *networkstatus_parse_from_string(const char *s);
|
||||
networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s);
|
||||
networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s,
|
||||
int is_vote);
|
||||
|
||||
void authority_cert_free(authority_cert_t *cert);
|
||||
authority_cert_t *authority_cert_parse_from_string(const char *s,
|
||||
|
@ -311,12 +311,7 @@ static token_rule_t networkstatus_vote_token_table[] = {
|
||||
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* XXXX This stuff is commented out for now so we can avoid warnings about
|
||||
* unused variables. */
|
||||
|
||||
static token_rule_t status_consensus_table[] = {
|
||||
static token_rule_t networkstatus_consensus_token_table[] = {
|
||||
T1("network-status-version", K_NETWORK_STATUS_VERSION,
|
||||
GE(1), NO_OBJ ),
|
||||
T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
|
||||
@ -325,26 +320,19 @@ static token_rule_t status_consensus_table[] = {
|
||||
T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
|
||||
T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
|
||||
|
||||
CERTIFICATE_MEMBERS
|
||||
|
||||
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
|
||||
|
||||
T1N("dir-source", K_DIR_SOURCE, GE(3), NO_OBJ ),
|
||||
T1N("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
|
||||
T1N("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
|
||||
T1N("vote-digest", K_VOTE_DIGEST, GE(1), NO_OBJ ),
|
||||
|
||||
#if 0
|
||||
T1( "dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ ),
|
||||
T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
|
||||
#endif
|
||||
|
||||
T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
|
||||
T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
|
||||
|
||||
END_OF_TABLE
|
||||
};
|
||||
#endif
|
||||
|
||||
static token_rule_t networkstatus_vote_footer_token_table[] = {
|
||||
T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
|
||||
@ -1786,14 +1774,14 @@ networkstatus_parse_from_string(const char *s)
|
||||
|
||||
/** DOCDOC */
|
||||
networkstatus_vote_t *
|
||||
networkstatus_parse_vote_from_string(const char *s)
|
||||
networkstatus_parse_vote_from_string(const char *s, int is_vote)
|
||||
{
|
||||
smartlist_t *tokens = smartlist_create();
|
||||
smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
|
||||
networkstatus_voter_info_t *voter = NULL;
|
||||
networkstatus_vote_t *ns = NULL;
|
||||
char ns_digest[DIGEST_LEN], declared_identity[DIGEST_LEN],
|
||||
declared_digest[DIGEST_LEN];
|
||||
const char *cert, *end_of_cert = NULL, *end_of_header, *end_of_footer;
|
||||
char ns_digest[DIGEST_LEN];
|
||||
const char *cert, *end_of_header, *end_of_footer;
|
||||
directory_token_t *tok;
|
||||
int ok;
|
||||
struct in_addr in;
|
||||
@ -1806,31 +1794,46 @@ networkstatus_parse_vote_from_string(const char *s)
|
||||
|
||||
end_of_header = find_start_of_next_routerstatus(s);
|
||||
if (tokenize_string(s, end_of_header, tokens,
|
||||
networkstatus_vote_token_table)) {
|
||||
is_vote ? networkstatus_vote_token_table :
|
||||
networkstatus_consensus_token_table)) {
|
||||
log_warn(LD_DIR, "Error tokenizing network-status vote header.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ns = tor_malloc_zero(sizeof(networkstatus_vote_t));
|
||||
if (!(cert = strstr(s, "\ndir-key-certificate-version")))
|
||||
goto err;
|
||||
++cert;
|
||||
ns->cert = authority_cert_parse_from_string(cert, &end_of_cert);
|
||||
if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
|
||||
goto err;
|
||||
|
||||
if (is_vote) {
|
||||
const char *end_of_cert = NULL;
|
||||
if (!(cert = strstr(s, "\ndir-key-certificate-version")))
|
||||
goto err;
|
||||
++cert;
|
||||
ns->cert = authority_cert_parse_from_string(cert, &end_of_cert);
|
||||
if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_first_by_keyword(tokens, K_VOTE_STATUS);
|
||||
tor_assert(tok);
|
||||
tor_assert(tok->n_args);
|
||||
if (strcmp(tok->args[0], "vote")) {
|
||||
log_warn(LD_DIR, "Unrecognized vote status %s in network-status vote.",
|
||||
if (!strcmp(tok->args[0], "vote")) {
|
||||
ns->is_vote = 1;
|
||||
} else if (!strcmp(tok->args[0], "consensus")) {
|
||||
ns->is_vote = 0;
|
||||
} else {
|
||||
log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
|
||||
escaped(tok->args[0]));
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_first_by_keyword(tokens, K_PUBLISHED);
|
||||
if (parse_iso_time(tok->args[0], &ns->published))
|
||||
if (!bool_eq(ns->is_vote, is_vote)) {
|
||||
log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ns->is_vote) {
|
||||
tok = find_first_by_keyword(tokens, K_PUBLISHED);
|
||||
if (parse_iso_time(tok->args[0], &ns->published))
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_first_by_keyword(tokens, K_VALID_AFTER);
|
||||
if (parse_iso_time(tok->args[0], &ns->valid_after))
|
||||
@ -1870,55 +1873,105 @@ networkstatus_parse_vote_from_string(const char *s)
|
||||
ns->known_flags[tok->n_args] = NULL;
|
||||
tok->n_args = 0; /* suppress free of args members, but not of args itself. */
|
||||
|
||||
tok = find_first_by_keyword(tokens, K_DIR_SOURCE);
|
||||
tor_assert(tok);
|
||||
tor_assert(tok->n_args >= 6);
|
||||
ns->nickname = tor_strdup(tok->args[0]);
|
||||
if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
|
||||
base16_decode(ns->identity_digest, sizeof(ns->identity_digest),
|
||||
tok->args[1], HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "Error decoding identity digest %s in "
|
||||
"network-status vote.", escaped(tok->args[1]));
|
||||
goto err;
|
||||
}
|
||||
ns->address = tor_strdup(tok->args[2]);
|
||||
if (!tor_inet_aton(tok->args[3], &in)) {
|
||||
log_warn(LD_DIR, "Error decoding IP address %s in network-status vote.",
|
||||
escaped(tok->args[3]));
|
||||
goto err;
|
||||
}
|
||||
ns->dir_port = (uint64_t)
|
||||
(int) tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
|
||||
if (!ok)
|
||||
goto err;
|
||||
ns->or_port = (uint64_t)
|
||||
(int) tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
|
||||
if (!ok)
|
||||
goto err;
|
||||
ns->voters = smartlist_create();
|
||||
|
||||
tok = find_first_by_keyword(tokens, K_CONTACT);
|
||||
if (tok) {
|
||||
ns->contact = tor_strdup(tok->args[0]);
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, _tok,
|
||||
{
|
||||
tok = _tok;
|
||||
if (tok->tp == K_DIR_SOURCE) {
|
||||
tor_assert(tok->n_args >= 6);
|
||||
|
||||
if (voter)
|
||||
smartlist_add(ns->voters, voter);
|
||||
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
|
||||
|
||||
voter->nickname = tor_strdup(tok->args[0]);
|
||||
if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
|
||||
base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
|
||||
tok->args[1], HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "Error decoding identity digest %s in "
|
||||
"network-status vote.", escaped(tok->args[1]));
|
||||
goto err;
|
||||
}
|
||||
voter->address = tor_strdup(tok->args[2]);
|
||||
if (!tor_inet_aton(tok->args[3], &in)) {
|
||||
log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
|
||||
escaped(tok->args[3]));
|
||||
goto err;
|
||||
}
|
||||
voter->dir_port = (uint64_t)
|
||||
(int) tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
|
||||
if (!ok)
|
||||
goto err;
|
||||
voter->or_port = (uint64_t)
|
||||
(int) tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
|
||||
if (!ok)
|
||||
goto err;
|
||||
} else if (tok->tp == K_CONTACT) {
|
||||
if (!voter || voter->contact) {
|
||||
log_warn(LD_DIR, "contact element is out of place.");
|
||||
goto err;
|
||||
}
|
||||
voter->contact = tor_strdup(tok->args[0]);
|
||||
} else if (tok->tp == K_VOTE_DIGEST) {
|
||||
tor_assert(!is_vote);
|
||||
tor_assert(tok->n_args >= 1);
|
||||
if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
|
||||
log_warn(LD_DIR, "vote-digest element is out of place.");
|
||||
goto err;
|
||||
}
|
||||
if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
|
||||
base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
|
||||
tok->args[0], HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "Error decoding vote digest %s in "
|
||||
"network-status consensus.", escaped(tok->args[1]));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (voter) {
|
||||
smartlist_add(ns->voters, voter);
|
||||
voter = NULL;
|
||||
}
|
||||
if (smartlist_len(ns->voters) == 0) {
|
||||
log_warn(LD_DIR, "Missing dir-source elements in a vote networkstatus.");
|
||||
goto err;
|
||||
} else if (is_vote && smartlist_len(ns->voters) != 1) {
|
||||
log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Parse routerstatus lines. */
|
||||
rs_tokens = smartlist_create();
|
||||
s = end_of_header;
|
||||
ns->routerstatus_list = smartlist_create();
|
||||
|
||||
while (!strcmpstart(s, "r ")) {
|
||||
vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
|
||||
if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs))
|
||||
smartlist_add(ns->routerstatus_list, rs);
|
||||
else {
|
||||
tor_free(rs->version);
|
||||
tor_free(rs);
|
||||
if (is_vote) {
|
||||
vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
|
||||
if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs))
|
||||
smartlist_add(ns->routerstatus_list, rs);
|
||||
else {
|
||||
tor_free(rs->version);
|
||||
tor_free(rs);
|
||||
}
|
||||
} else {
|
||||
routerstatus_t *rs;
|
||||
if ((rs =routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL)))
|
||||
smartlist_add(ns->routerstatus_list, rs);
|
||||
}
|
||||
}
|
||||
for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
|
||||
vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
|
||||
vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
|
||||
if (memcmp(a->status.identity_digest, b->status.identity_digest,
|
||||
DIGEST_LEN) >= 0) {
|
||||
routerstatus_t *rs1, *rs2;
|
||||
if (is_vote) {
|
||||
vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
|
||||
vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
|
||||
rs1 = &a->status; rs2 = &b->status;
|
||||
} else {
|
||||
rs1 = smartlist_get(ns->routerstatus_list, i-1);
|
||||
rs2 = smartlist_get(ns->routerstatus_list, i);
|
||||
}
|
||||
if (memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN) >= 0) {
|
||||
log_warn(LD_DIR, "Vote networkstatus entries not sorted by identity "
|
||||
"digest");
|
||||
goto err;
|
||||
@ -1933,40 +1986,62 @@ networkstatus_parse_vote_from_string(const char *s)
|
||||
log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
|
||||
goto err;
|
||||
}
|
||||
if (!(tok = find_first_by_keyword(footer_tokens, K_DIRECTORY_SIGNATURE))) {
|
||||
log_warn(LD_DIR, "No signature on network-status vote.");
|
||||
goto err;
|
||||
}
|
||||
tor_assert(tok->n_args >= 2);
|
||||
if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
|
||||
base16_decode(declared_identity, sizeof(ns->identity_digest),
|
||||
tok->args[0], HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "Error decoding declared identity %s in "
|
||||
"network-status vote.", escaped(tok->args[1]));
|
||||
goto err;
|
||||
}
|
||||
if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
|
||||
base16_decode(declared_digest, sizeof(ns->identity_digest),
|
||||
tok->args[1], HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "Error decoding declared digest %s in "
|
||||
"network-status vote.", escaped(tok->args[1]));
|
||||
goto err;
|
||||
}
|
||||
memcpy(ns->vote_digest, declared_digest, DIGEST_LEN);
|
||||
if (memcmp(declared_identity, ns->cert->cache_info.identity_digest,
|
||||
DIGEST_LEN)) {
|
||||
log_warn(LD_DIR, "Digest mismatch between declared and actual on "
|
||||
"network-status vote.");
|
||||
goto err;
|
||||
}
|
||||
if (memcmp(declared_digest, ns_digest, DIGEST_LEN)) {
|
||||
log_warn(LD_DIR, "Digest mismatch between declared and actual on "
|
||||
"network-status vote.");
|
||||
goto err;
|
||||
}
|
||||
if (check_signature_token(ns_digest, tok, ns->cert->signing_key, 0,
|
||||
"network-status vote"))
|
||||
goto err;
|
||||
|
||||
SMARTLIST_FOREACH(footer_tokens, directory_token_t *, _tok,
|
||||
{
|
||||
char declared_identity[DIGEST_LEN];
|
||||
networkstatus_voter_info_t *v;
|
||||
tok = _tok;
|
||||
if (tok->tp != K_DIRECTORY_SIGNATURE)
|
||||
continue;
|
||||
tor_assert(tok->n_args >= 2);
|
||||
|
||||
if (!tok->object_type ||
|
||||
strcmp(tok->object_type, "SIGNATURE") ||
|
||||
tok->object_size < 128 || tok->object_size > 512) {
|
||||
log_warn(LD_DIR, "Bad object type or length on directory-signature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
|
||||
base16_decode(declared_identity, sizeof(declared_identity),
|
||||
tok->args[0], HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "Error decoding declared identity %s in "
|
||||
"network-status vote.", escaped(tok->args[0]));
|
||||
goto err;
|
||||
}
|
||||
if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
|
||||
log_warn(LD_DIR, "ID on signature on network-status vote does not match"
|
||||
"any declared directory source.");
|
||||
goto err;
|
||||
}
|
||||
if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
|
||||
base16_decode(v->signing_key_digest, sizeof(v->signing_key_digest),
|
||||
tok->args[1], HEX_DIGEST_LEN) < 0) {
|
||||
log_warn(LD_DIR, "Error decoding declared digest %s in "
|
||||
"network-status vote.", escaped(tok->args[1]));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (is_vote &&
|
||||
memcmp(declared_identity, ns->cert->cache_info.identity_digest,
|
||||
DIGEST_LEN)) {
|
||||
log_warn(LD_DIR, "Digest mismatch between declared and actual on "
|
||||
"network-status vote.");
|
||||
goto err;
|
||||
/* XXXX020 also check cert against dir-source line. */
|
||||
}
|
||||
|
||||
if (is_vote) {
|
||||
if (check_signature_token(ns_digest, tok, ns->cert->signing_key, 0,
|
||||
"network-status vote"))
|
||||
goto err;
|
||||
} else {
|
||||
v->pending_signature = tor_memdup(tok->object_body,
|
||||
tok->object_size);
|
||||
v->pending_signature_len = tok->object_size;
|
||||
}
|
||||
});
|
||||
|
||||
/* XXXX020 check dates for plausibility. ??? */
|
||||
|
||||
@ -1980,6 +2055,12 @@ networkstatus_parse_vote_from_string(const char *s)
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
|
||||
smartlist_free(tokens);
|
||||
}
|
||||
if (voter) {
|
||||
tor_free(voter->nickname);
|
||||
tor_free(voter->address);
|
||||
tor_free(voter->contact);
|
||||
tor_free(voter);
|
||||
}
|
||||
if (rs_tokens) {
|
||||
SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_free(t));
|
||||
smartlist_free(rs_tokens);
|
||||
|
Loading…
Reference in New Issue
Block a user