aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-09-23 15:23:04 -0400
committerNick Mathewson <nickm@torproject.org>2009-10-15 15:17:13 -0400
commita19981725d167927d32ef2a31c7a7968be3d95b6 (patch)
tree9033267c02ab111346921025b04af53939f00e13 /src
parent0bce0161dded650ac6fa665a7b861d6faac9e91c (diff)
downloadtor-a19981725d167927d32ef2a31c7a7968be3d95b6.tar.gz
tor-a19981725d167927d32ef2a31c7a7968be3d95b6.zip
Parse detached signatures and microdesc networkstatuses correctly.
Diffstat (limited to 'src')
-rw-r--r--src/or/networkstatus.c12
-rw-r--r--src/or/or.h1
-rw-r--r--src/or/routerparse.c115
-rw-r--r--src/test/test_dir.c87
4 files changed, 170 insertions, 45 deletions
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 616726525b..93a21ebb74 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1983,6 +1983,18 @@ networkstatus_get_flavor_name(consensus_flavor_t flav)
}
}
+/** DOCDOC return -1 on unknown */
+int
+networkstatus_parse_flavor_name(const char *flavname)
+{
+ if (!strcmp(flavname, "ns"))
+ return FLAV_NS;
+ else if (!strcmp(flavname, "microdesc"))
+ return FLAV_MICRODESC;
+ else
+ return -1;
+}
+
/** If <b>question</b> is a string beginning with "ns/" in a format the
* control interface expects for a GETINFO question, set *<b>answer</b> to a
* newly-allocated string containing networkstatus lines for the appropriate
diff --git a/src/or/or.h b/src/or/or.h
index d9b10c663d..a92b0b5e30 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -4211,6 +4211,7 @@ int32_t networkstatus_get_param(networkstatus_t *ns, const char *param_name,
int getinfo_helper_networkstatus(control_connection_t *conn,
const char *question, char **answer);
const char *networkstatus_get_flavor_name(consensus_flavor_t flav);
+int networkstatus_parse_flavor_name(const char *flavname);
void document_signature_free(document_signature_t *sig);
document_signature_t *document_signature_dup(const document_signature_t *sig);
void networkstatus_free_all(void);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 21fe5f7d23..c6278c6efe 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -321,7 +321,7 @@ static token_rule_t extrainfo_token_table[] = {
* documents. */
static token_rule_t rtrstatus_token_table[] = {
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
- T1( "r", K_R, GE(8), NO_OBJ ),
+ T1( "r", K_R, GE(7), NO_OBJ ),
T1( "s", K_S, ARGS, NO_OBJ ),
T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
T01("w", K_W, ARGS, NO_OBJ ),
@@ -1900,22 +1900,29 @@ find_start_of_next_routerstatus(const char *s)
* If <b>consensus_method</b> is nonzero, this routerstatus is part of a
* consensus, and we should parse it according to the method used to
* make that consensus.
+ *
+ * DOCDOC flav
**/
static routerstatus_t *
routerstatus_parse_entry_from_string(memarea_t *area,
const char **s, smartlist_t *tokens,
networkstatus_t *vote,
vote_routerstatus_t *vote_rs,
- int consensus_method)
+ int consensus_method,
+ consensus_flavor_t flav)
{
const char *eos, *s_dup = *s;
routerstatus_t *rs = NULL;
directory_token_t *tok;
char timebuf[ISO_TIME_LEN+1];
struct in_addr in;
+ int offset = 0;
tor_assert(tokens);
tor_assert(bool_eq(vote, vote_rs));
+ if (!consensus_method)
+ flav = FLAV_NS;
+
eos = find_start_of_next_routerstatus(*s);
if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) {
@@ -1927,7 +1934,15 @@ routerstatus_parse_entry_from_string(memarea_t *area,
goto err;
}
tok = find_by_keyword(tokens, K_R);
- tor_assert(tok->n_args >= 8);
+ tor_assert(tok->n_args >= 7);
+ if (flav == FLAV_NS) {
+ if (tok->n_args < 8) {
+ log_warn(LD_DIR, "Too few arguments to r");
+ goto err;
+ }
+ } else {
+ offset = -1;
+ }
if (vote_rs) {
rs = &vote_rs->status;
} else {
@@ -1948,29 +1963,34 @@ routerstatus_parse_entry_from_string(memarea_t *area,
goto err;
}
- if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
- log_warn(LD_DIR, "Error decoding descriptor digest %s",
- escaped(tok->args[2]));
- goto err;
+ if (flav == FLAV_NS) {
+ if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
+ log_warn(LD_DIR, "Error decoding descriptor digest %s",
+ escaped(tok->args[2]));
+ goto err;
+ }
}
if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
- tok->args[3], tok->args[4]) < 0 ||
+ tok->args[3+offset], tok->args[4+offset]) < 0 ||
parse_iso_time(timebuf, &rs->published_on)<0) {
- log_warn(LD_DIR, "Error parsing time '%s %s'",
- tok->args[3], tok->args[4]);
+ log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]",
+ tok->args[3+offset], tok->args[4+offset],
+ offset, (int)flav);
goto err;
}
- if (tor_inet_aton(tok->args[5], &in) == 0) {
+ if (tor_inet_aton(tok->args[5+offset], &in) == 0) {
log_warn(LD_DIR, "Error parsing router address in network-status %s",
- escaped(tok->args[5]));
+ escaped(tok->args[5+offset]));
goto err;
}
rs->addr = ntohl(in.s_addr);
- rs->or_port =(uint16_t) tor_parse_long(tok->args[6],10,0,65535,NULL,NULL);
- rs->dir_port = (uint16_t) tor_parse_long(tok->args[7],10,0,65535,NULL,NULL);
+ rs->or_port = (uint16_t) tor_parse_long(tok->args[6+offset],
+ 10,0,65535,NULL,NULL);
+ rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset],
+ 10,0,65535,NULL,NULL);
tok = find_opt_by_keyword(tokens, K_S);
if (tok && vote) {
@@ -2267,7 +2287,7 @@ networkstatus_v2_parse_from_string(const char *s)
while (!strcmpstart(s, "r ")) {
routerstatus_t *rs;
if ((rs = routerstatus_parse_entry_from_string(area, &s, tokens,
- NULL, NULL, 0)))
+ NULL, NULL, 0, 0)))
smartlist_add(ns->entries, rs);
}
smartlist_sort(ns->entries, compare_routerstatus_entries);
@@ -2329,6 +2349,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
struct in_addr in;
int i, inorder, n_signatures = 0;
memarea_t *area = NULL, *rs_area = NULL;
+ consensus_flavor_t flav = FLAV_NS;
+
tor_assert(s);
if (eos_out)
@@ -2352,6 +2374,22 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
ns = tor_malloc_zero(sizeof(networkstatus_t));
memcpy(&ns->digests, &ns_digests, sizeof(ns_digests));
+ tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
+ tor_assert(tok);
+ if (tok->n_args > 1) {
+ int flavor = networkstatus_parse_flavor_name(tok->args[1]);
+ if (flavor < 0) {
+ log_warn(LD_DIR, "Can't parse document with unknown flavor %s",
+ escaped(tok->args[2]));
+ goto err;
+ }
+ ns->flavor = flav = flavor;
+ }
+ if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
+ log_warn(LD_DIR, "Flavor found on non-consenus networkstatus.");
+ goto err;
+ }
+
if (ns_type != NS_TYPE_CONSENSUS) {
const char *end_of_cert = NULL;
if (!(cert = strstr(s, "\ndir-key-certificate-version")))
@@ -2598,7 +2636,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
if (ns->type != NS_TYPE_CONSENSUS) {
vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
if (routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, ns,
- rs, 0))
+ rs, 0, 0))
smartlist_add(ns->routerstatus_list, rs);
else {
tor_free(rs->version);
@@ -2608,7 +2646,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
routerstatus_t *rs;
if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens,
NULL, NULL,
- ns->consensus_method)))
+ ns->consensus_method,
+ flav)))
smartlist_add(ns->routerstatus_list, rs);
}
}
@@ -2645,10 +2684,29 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
char declared_identity[DIGEST_LEN];
networkstatus_voter_info_t *v;
document_signature_t *sig;
+ const char *id_hexdigest = NULL;
+ const char *sk_hexdigest = NULL;
+ digest_algorithm_t alg = DIGEST_SHA1;
tok = _tok;
if (tok->tp != K_DIRECTORY_SIGNATURE)
continue;
tor_assert(tok->n_args >= 2);
+ if (tok->n_args == 2) {
+ id_hexdigest = tok->args[0];
+ sk_hexdigest = tok->args[1];
+ } else {
+ const char *algname = tok->args[0];
+ int a;
+ id_hexdigest = tok->args[1];
+ sk_hexdigest = tok->args[2];
+ a = crypto_digest_algorithm_parse_name(algname);
+ if (a<0) {
+ log_warn(LD_DIR, "Unknown digest algorithm %s; skipping",
+ escaped(algname));
+ continue;
+ }
+ alg = a;
+ }
if (!tok->object_type ||
strcmp(tok->object_type, "SIGNATURE") ||
@@ -2657,11 +2715,11 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
goto err;
}
- if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
+ if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
base16_decode(declared_identity, sizeof(declared_identity),
- tok->args[0], HEX_DIGEST_LEN) < 0) {
+ id_hexdigest, HEX_DIGEST_LEN) < 0) {
log_warn(LD_DIR, "Error decoding declared identity %s in "
- "network-status vote.", escaped(tok->args[0]));
+ "network-status vote.", escaped(id_hexdigest));
goto err;
}
if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
@@ -2671,12 +2729,12 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
}
sig = tor_malloc_zero(sizeof(document_signature_t));
memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN);
- sig->alg = DIGEST_SHA1;
- if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
+ sig->alg = alg;
+ if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
base16_decode(sig->signing_key_digest, sizeof(sig->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]));
+ sk_hexdigest, HEX_DIGEST_LEN) < 0) {
+ log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
+ "network-status vote.", escaped(sk_hexdigest));
tor_free(sig);
goto err;
}
@@ -2716,7 +2774,6 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
}
sig->signature = tor_memdup(tok->object_body, tok->object_size);
sig->signature_len = (int) tok->object_size;
-
}
smartlist_add(v->sigs, sig);
@@ -2950,10 +3007,10 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
"network-status vote.", escaped(id_hexdigest));
goto err;
}
- if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
+ if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
base16_decode(sk_digest, sizeof(sk_digest),
sk_hexdigest, HEX_DIGEST_LEN) < 0) {
- log_warn(LD_DIR, "Error decoding declared digest %s in "
+ log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
"network-status vote.", escaped(sk_hexdigest));
goto err;
}
@@ -2974,7 +3031,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
}
sig = tor_malloc_zero(sizeof(document_signature_t));
- sig->alg = DIGEST_SHA1;
+ sig->alg = alg;
memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN);
if (tok->object_size >= INT_MAX) {
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 13b46c63c3..68dbbb45a4 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -559,16 +559,18 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
return r;
}
-/** Helper: get a detached signatures document for a single FLAV_NS
- * consensus. */
+/** Helper: get a detached signatures document for one or two
+ * consensuses. */
static char *
-get_detached_sigs(networkstatus_t *ns)
+get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2)
{
char *r;
smartlist_t *sl;
tor_assert(ns && ns->flavor == FLAV_NS);
sl = smartlist_create();
smartlist_add(sl,ns);
+ if (ns2)
+ smartlist_add(sl,ns2);
r = networkstatus_get_detached_signatures(sl);
smartlist_free(sl);
return r;
@@ -587,7 +589,8 @@ test_dir_v3_networkstatus(void)
time_t now = time(NULL);
networkstatus_voter_info_t *voter;
document_signature_t *sig;
- networkstatus_t *vote=NULL, *v1=NULL, *v2=NULL, *v3=NULL, *con=NULL;
+ networkstatus_t *vote=NULL, *v1=NULL, *v2=NULL, *v3=NULL, *con=NULL,
+ *con_md=NULL;
vote_routerstatus_t *vrs;
routerstatus_t *rs;
char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp;
@@ -596,7 +599,9 @@ test_dir_v3_networkstatus(void)
/* For generating the two other consensuses. */
char *detached_text1=NULL, *detached_text2=NULL;
char *consensus_text2=NULL, *consensus_text3=NULL;
- networkstatus_t *con2=NULL, *con3=NULL;
+ char *consensus_text_md2=NULL, *consensus_text_md3=NULL;
+ char *consensus_text_md=NULL;
+ networkstatus_t *con2=NULL, *con_md2=NULL, *con3=NULL, *con_md3=NULL;
ns_detached_signatures_t *dsig1=NULL, *dsig2=NULL;
/* Parse certificates and keys. */
@@ -882,6 +887,17 @@ test_dir_v3_networkstatus(void)
test_assert(con);
//log_notice(LD_GENERAL, "<<%s>>\n<<%s>>\n<<%s>>\n",
// v1_text, v2_text, v3_text);
+ consensus_text_md = networkstatus_compute_consensus(votes, 3,
+ cert3->identity_key,
+ sign_skey_3,
+ "AAAAAAAAAAAAAAAAAAAA",
+ sign_skey_leg1,
+ FLAV_MICRODESC);
+ test_assert(consensus_text_md);
+ con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL,
+ NS_TYPE_CONSENSUS);
+ test_assert(con_md);
+ test_eq(con_md->flavor, FLAV_MICRODESC);
/* Check consensus contents. */
test_assert(con->type == NS_TYPE_CONSENSUS);
@@ -956,19 +972,11 @@ test_dir_v3_networkstatus(void)
test_assert(rs->is_valid);
test_assert(!rs->is_named);
/* XXXX check version */
- // x231
- // x213
/* Check signatures. the first voter is a pseudo-entry with a legacy key.
* The second one hasn't signed. The fourth one has signed: validate it. */
voter = smartlist_get(con->voters, 1);
test_eq(smartlist_len(voter->sigs), 0);
-#if 0
- sig = smartlist_get(voter->sigs, 1);
- test_assert(!sig->signature);
- test_assert(!sig->good_signature);
- test_assert(!sig->bad_signature);
-#endif
voter = smartlist_get(con->voters, 3);
test_eq(smartlist_len(voter->sigs), 1);
@@ -990,26 +998,45 @@ test_dir_v3_networkstatus(void)
cert2->identity_key,
sign_skey_2, NULL,NULL,
FLAV_NS);
+ consensus_text_md2 = networkstatus_compute_consensus(votes, 3,
+ cert2->identity_key,
+ sign_skey_2, NULL,NULL,
+ FLAV_MICRODESC);
smartlist_shuffle(votes);
consensus_text3 = networkstatus_compute_consensus(votes, 3,
cert1->identity_key,
sign_skey_1, NULL,NULL,
FLAV_NS);
+ consensus_text_md3 = networkstatus_compute_consensus(votes, 3,
+ cert1->identity_key,
+ sign_skey_1, NULL,NULL,
+ FLAV_MICRODESC);
test_assert(consensus_text2);
test_assert(consensus_text3);
+ test_assert(consensus_text_md2);
+ test_assert(consensus_text_md3);
con2 = networkstatus_parse_vote_from_string(consensus_text2, NULL,
NS_TYPE_CONSENSUS);
con3 = networkstatus_parse_vote_from_string(consensus_text3, NULL,
NS_TYPE_CONSENSUS);
+ con_md2 = networkstatus_parse_vote_from_string(consensus_text_md2, NULL,
+ NS_TYPE_CONSENSUS);
+ con_md3 = networkstatus_parse_vote_from_string(consensus_text_md3, NULL,
+ NS_TYPE_CONSENSUS);
test_assert(con2);
test_assert(con3);
+ test_assert(con_md2);
+ test_assert(con_md3);
/* All three should have the same digest. */
test_memeq(&con->digests, &con2->digests, sizeof(digests_t));
test_memeq(&con->digests, &con3->digests, sizeof(digests_t));
+ test_memeq(&con_md->digests, &con_md2->digests, sizeof(digests_t));
+ test_memeq(&con_md->digests, &con_md3->digests, sizeof(digests_t));
+
/* Extract a detached signature from con3. */
- detached_text1 = get_detached_sigs(con3);
+ detached_text1 = get_detached_sigs(con3, con_md3);
tor_assert(detached_text1);
/* Try to parse it. */
dsig1 = networkstatus_parse_detached_signatures(detached_text1, NULL);
@@ -1024,6 +1051,11 @@ test_dir_v3_networkstatus(void)
test_assert(dsig_digests);
test_memeq(dsig_digests->d[DIGEST_SHA1], con3->digests.d[DIGEST_SHA1],
DIGEST_LEN);
+ dsig_digests = strmap_get(dsig1->digests, "microdesc");
+ test_assert(dsig_digests);
+ test_memeq(dsig_digests->d[DIGEST_SHA256],
+ con_md3->digests.d[DIGEST_SHA256],
+ DIGEST256_LEN);
}
{
smartlist_t *dsig_signatures = strmap_get(dsig1->signatures, "ns");
@@ -1032,13 +1064,24 @@ test_dir_v3_networkstatus(void)
sig = smartlist_get(dsig_signatures, 0);
test_memeq(sig->identity_digest, cert1->cache_info.identity_digest,
DIGEST_LEN);
+ test_eq(sig->alg, DIGEST_SHA1);
+
+ dsig_signatures = strmap_get(dsig1->signatures, "microdesc");
+ test_assert(dsig_signatures);
+ test_eq(1, smartlist_len(dsig_signatures));
+ sig = smartlist_get(dsig_signatures, 0);
+ test_memeq(sig->identity_digest, cert1->cache_info.identity_digest,
+ DIGEST_LEN);
+ test_eq(sig->alg, DIGEST_SHA256);
}
/* Try adding it to con2. */
- detached_text2 = get_detached_sigs(con2);
+ detached_text2 = get_detached_sigs(con2,con_md2);
test_eq(1, networkstatus_add_detached_signatures(con2, dsig1, &msg));
tor_free(detached_text2);
- detached_text2 = get_detached_sigs(con2);
+ test_eq(1, networkstatus_add_detached_signatures(con_md2, dsig1, &msg));
+ tor_free(detached_text2);
+ detached_text2 = get_detached_sigs(con2,con_md2);
//printf("\n<%s>\n", detached_text2);
dsig2 = networkstatus_parse_detached_signatures(detached_text2, NULL);
test_assert(dsig2);
@@ -1052,6 +1095,9 @@ test_dir_v3_networkstatus(void)
*/
test_eq(2,
smartlist_len((smartlist_t*)strmap_get(dsig2->signatures, "ns")));
+ test_eq(2,
+ smartlist_len((smartlist_t*)strmap_get(dsig2->signatures,
+ "microdesc")));
/* Try adding to con2 twice; verify that nothing changes. */
test_eq(0, networkstatus_add_detached_signatures(con2, dsig1, &msg));
@@ -1075,6 +1121,7 @@ test_dir_v3_networkstatus(void)
tor_free(v2_text);
tor_free(v3_text);
tor_free(consensus_text);
+ tor_free(consensus_text_md);
if (vote)
networkstatus_vote_free(vote);
@@ -1086,6 +1133,8 @@ test_dir_v3_networkstatus(void)
networkstatus_vote_free(v3);
if (con)
networkstatus_vote_free(con);
+ if (con_md)
+ networkstatus_vote_free(con_md);
if (sign_skey_1)
crypto_free_pk_env(sign_skey_1);
if (sign_skey_2)
@@ -1103,12 +1152,18 @@ test_dir_v3_networkstatus(void)
tor_free(consensus_text2);
tor_free(consensus_text3);
+ tor_free(consensus_text_md2);
+ tor_free(consensus_text_md3);
tor_free(detached_text1);
tor_free(detached_text2);
if (con2)
networkstatus_vote_free(con2);
if (con3)
networkstatus_vote_free(con3);
+ if (con_md2)
+ networkstatus_vote_free(con_md2);
+ if (con_md3)
+ networkstatus_vote_free(con_md3);
if (dsig1)
ns_detached_signatures_free(dsig1);
if (dsig2)