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:
Nick Mathewson 2007-06-04 22:29:00 +00:00
parent 8d1224eb51
commit 8b0e6a4466
6 changed files with 285 additions and 161 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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);