aboutsummaryrefslogtreecommitdiff
path: root/src/or/networkstatus.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2007-10-22 17:31:26 +0000
committerNick Mathewson <nickm@torproject.org>2007-10-22 17:31:26 +0000
commit09bce19884d9b07a83979a6b6f0abb1789a3b9b3 (patch)
treee9d316e6aef1f6a95f0d98326aa32bcc88915c1d /src/or/networkstatus.c
parent4bab46d5d797c9a2f88fbf5dfb9ea0d91d384ee7 (diff)
downloadtor-09bce19884d9b07a83979a6b6f0abb1789a3b9b3.tar.gz
tor-09bce19884d9b07a83979a6b6f0abb1789a3b9b3.zip
r16042@catbus: nickm | 2007-10-22 13:30:49 -0400
Move functions into and out of dirvote.c so that it contains all the v3 authority functionality, and no non-authority functionality. svn:r12107
Diffstat (limited to 'src/or/networkstatus.c')
-rw-r--r--src/or/networkstatus.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index a9efd8d92e..657895915b 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -210,6 +210,214 @@ networkstatus_v2_free(networkstatus_v2_t *ns)
tor_free(ns);
}
+/** Clear all storage held in <b>ns</b>. */
+void
+networkstatus_vote_free(networkstatus_vote_t *ns)
+{
+ if (!ns)
+ return;
+
+ tor_free(ns->client_versions);
+ tor_free(ns->server_versions);
+ if (ns->known_flags) {
+ SMARTLIST_FOREACH(ns->known_flags, char *, c, tor_free(c));
+ smartlist_free(ns->known_flags);
+ }
+ 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);
+
+ if (ns->routerstatus_list) {
+ if (ns->is_vote) {
+ SMARTLIST_FOREACH(ns->routerstatus_list, vote_routerstatus_t *, rs,
+ {
+ tor_free(rs->version);
+ tor_free(rs);
+ });
+ } else {
+ SMARTLIST_FOREACH(ns->routerstatus_list, routerstatus_t *, rs,
+ tor_free(rs));
+ }
+
+ smartlist_free(ns->routerstatus_list);
+ }
+ if (ns->desc_digest_map)
+ digestmap_free(ns->desc_digest_map, NULL);
+
+ memset(ns, 11, sizeof(*ns));
+ tor_free(ns);
+}
+
+/** Return the voter info from <b>vote</b> for the voter whose identity digest
+ * is <b>identity</b>, or NULL if no such voter is associated with
+ * <b>vote</b>. */
+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;
+}
+
+/** Check whether the signature on <b>voter</b> is correctly signed by
+ * the signing key of <b>cert</b>. Return -1 if <b>cert</b> doesn't match the
+ * signing key; otherwise set the good_signature or bad_signature flag on
+ * <b>voter</b>, and return 0. */
+/* (private; exposed for testing.) */
+int
+networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
+ networkstatus_voter_info_t *voter,
+ authority_cert_t *cert)
+{
+ char d[DIGEST_LEN];
+ char *signed_digest;
+ size_t signed_digest_len;
+ if (crypto_pk_get_digest(cert->signing_key, d)<0)
+ return -1;
+ if (memcmp(voter->signing_key_digest, d, DIGEST_LEN))
+ return -1;
+ signed_digest_len = crypto_pk_keysize(cert->signing_key);
+ signed_digest = tor_malloc(signed_digest_len);
+ if (crypto_pk_public_checksig(cert->signing_key,
+ signed_digest,
+ voter->signature,
+ voter->signature_len) != DIGEST_LEN ||
+ memcmp(signed_digest, consensus->networkstatus_digest, DIGEST_LEN)) {
+ log_warn(LD_DIR, "Got a bad signature on a networkstatus vote");
+ voter->bad_signature = 1;
+ } else {
+ voter->good_signature = 1;
+ }
+ return 0;
+}
+
+/** Given a v3 networkstatus consensus in <b>consensus</b>, check every
+ * as-yet-unchecked signature on <b>consensus</b>. Return 1 if there is a
+ * signature from every recognized authority on it, 0 if there are
+ * enough good signatures from recognized authorities on it, -1 if we might
+ * get enough good signatures by fetching missing certificates, and -2
+ * otherwise. Log messages at INFO or WARN: if <b>warn</b> is over 1, warn
+ * about every problem; if warn is at least 1, warn only if we can't get
+ * enough signatures; if warn is negative, log nothing at all. */
+int
+networkstatus_check_consensus_signature(networkstatus_vote_t *consensus,
+ int warn)
+{
+ int n_good = 0;
+ int n_missing_key = 0;
+ int n_bad = 0;
+ int n_unknown = 0;
+ int n_no_signature = 0;
+ int n_v3_authorities = get_n_authorities(V3_AUTHORITY);
+ int n_required = n_v3_authorities/2 + 1;
+ smartlist_t *need_certs_from = smartlist_create();
+ smartlist_t *unrecognized = smartlist_create();
+ smartlist_t *missing_authorities = smartlist_create();
+ int severity;
+
+ tor_assert(! consensus->is_vote);
+
+ SMARTLIST_FOREACH(consensus->voters, networkstatus_voter_info_t *, voter,
+ {
+ if (!voter->good_signature && !voter->bad_signature && voter->signature) {
+ /* we can try to check the signature. */
+ authority_cert_t *cert =
+ authority_cert_get_by_digests(voter->identity_digest,
+ voter->signing_key_digest);
+ if (! cert) {
+ if (!trusteddirserver_get_by_v3_auth_digest(voter->identity_digest)) {
+ smartlist_add(unrecognized, voter);
+ ++n_unknown;
+ } else {
+ smartlist_add(need_certs_from, voter);
+ ++n_missing_key;
+ }
+ continue;
+ }
+ if (networkstatus_check_voter_signature(consensus, voter, cert) < 0) {
+ smartlist_add(need_certs_from, voter);
+ ++n_missing_key;
+ continue;
+ }
+ }
+ if (voter->good_signature)
+ ++n_good;
+ else if (voter->bad_signature)
+ ++n_bad;
+ else
+ ++n_no_signature;
+ });
+
+ /* Now see whether we're missing any voters entirely. */
+ SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
+ trusted_dir_server_t *, ds,
+ {
+ if ((ds->type & V3_AUTHORITY) &&
+ !networkstatus_get_voter_by_id(consensus, ds->v3_identity_digest))
+ smartlist_add(missing_authorities, ds);
+ });
+
+ if (warn > 1 || (warn >= 0 && n_good < n_required))
+ severity = LOG_WARN;
+ else
+ severity = LOG_INFO;
+
+ if (warn >= 0) {
+ SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter,
+ {
+ log(severity, LD_DIR, "Consensus includes unrecognized authority '%s' "
+ "at %s:%d (contact %s; identity %s)",
+ voter->nickname, voter->address, (int)voter->dir_port,
+ voter->contact?voter->contact:"n/a",
+ hex_str(voter->identity_digest, DIGEST_LEN));
+ });
+ SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter,
+ {
+ log_info(LD_DIR, "Looks like we need to download a new certificate "
+ "from authority '%s' at %s:%d (contact %s; identity %s)",
+ voter->nickname, voter->address, (int)voter->dir_port,
+ voter->contact?voter->contact:"n/a",
+ hex_str(voter->identity_digest, DIGEST_LEN));
+ });
+ SMARTLIST_FOREACH(missing_authorities, trusted_dir_server_t *, ds,
+ {
+ log(severity, LD_DIR, "Consensus does not include configured "
+ "authority '%s' at %s:%d (identity %s)",
+ ds->nickname, ds->address, (int)ds->dir_port,
+ hex_str(ds->v3_identity_digest, DIGEST_LEN));
+ });
+ log(severity, LD_DIR,
+ "%d unknown, %d missing key, %d good, %d bad, %d no signature, "
+ "%d required", n_unknown, n_missing_key, n_good, n_bad,
+ n_no_signature, n_required);
+ }
+
+ smartlist_free(unrecognized);
+ smartlist_free(need_certs_from);
+ smartlist_free(missing_authorities);
+
+ if (n_good == n_v3_authorities)
+ return 1;
+ else if (n_good >= n_required)
+ return 0;
+ else if (n_good + n_missing_key >= n_required)
+ return -1;
+ else
+ return -2;
+}
+
/** Helper: return a newly allocated string containing the name of the filename
* where we plan to cache the network status with the given identity digest. */
char *