[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r13304: Fix bug 571: associate certificates with keys, not dirserver (in tor/trunk: . src/or)



Author: nickm
Date: 2008-01-26 18:18:30 -0500 (Sat, 26 Jan 2008)
New Revision: 13304

Modified:
   tor/trunk/ChangeLog
   tor/trunk/src/or/directory.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/routerlist.c
   tor/trunk/src/or/routerparse.c
Log:
Fix bug 571: associate certificates with keys, not dirservers, so that we can have certificates for dirservers we do not recognize.

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2008-01-26 23:00:21 UTC (rev 13303)
+++ tor/trunk/ChangeLog	2008-01-26 23:18:30 UTC (rev 13304)
@@ -1,4 +1,8 @@
 Changes in version 0.2.0.19-alpha - 2008-0?-??
+  o Minor bugfixes:
+    - Directory caches now fetch certificates from all authorities
+      listed in a networkstatus consensus, even when they do not
+      recognize them.  Fixes bug 571.  Bugfix on 0.2.0.x.
 
 
 Changes in version 0.2.0.18-alpha - 2008-01-25

Modified: tor/trunk/src/or/directory.c
===================================================================
--- tor/trunk/src/or/directory.c	2008-01-26 23:00:21 UTC (rev 13303)
+++ tor/trunk/src/or/directory.c	2008-01-26 23:18:30 UTC (rev 13304)
@@ -601,9 +601,7 @@
                                        failed, NULL, 1, 0);
   SMARTLIST_FOREACH(failed, char *, cp,
   {
-    trusted_dir_server_t *dir = trusteddirserver_get_by_v3_auth_digest(cp);
-    if (dir)
-      download_status_failed(&dir->cert_dl_status, status);
+    authority_cert_dl_failed(cp, status);
     tor_free(cp);
   });
   smartlist_free(failed);
@@ -2494,14 +2492,7 @@
     smartlist_t *certs = smartlist_create();
     ssize_t len = -1;
     if (!strcmp(url, "/tor/keys/all")) {
-      SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
-                        trusted_dir_server_t *, ds,
-      {
-        if (!ds->v3_certs)
-          continue;
-        SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
-                          smartlist_add(certs, cert));
-      });
+      authority_cert_get_all(certs);
     } else if (!strcmp(url, "/tor/keys/authority")) {
       authority_cert_t *cert = get_my_v3_authority_cert();
       if (cert)

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2008-01-26 23:00:21 UTC (rev 13303)
+++ tor/trunk/src/or/or.h	2008-01-26 23:18:30 UTC (rev 13304)
@@ -3030,6 +3030,10 @@
 char *directory_dump_request_log(void);
 int router_supports_extrainfo(const char *identity_digest, int is_authority);
 
+void directory_post_to_hs_dir(smartlist_t *descs, const char *service_id,
+                              int seconds_valid);
+int directory_get_from_hs_dir(const char *desc_id, const char *query);
+
 time_t download_status_increment_failure(download_status_t *dls,
                                          int status_code, const char *item,
                                          int server, time_t now);
@@ -3813,9 +3817,11 @@
   /** What kind of authority is this? (Bitfield.) */
   authority_type_t type;
 
+#if 0
   smartlist_t *v3_certs; /**< V3 key certificates for this authority */
   download_status_t cert_dl_status; /**< Status of downloading this server's
                                * latest certificate. */
+#endif
   download_status_t v2_ns_dl_status; /**< Status of downloading this server's
                                * v2 network status. */
   time_t addr_current_at; /**< When was the document that we derived the
@@ -3840,6 +3846,8 @@
 authority_cert_t *authority_cert_get_by_sk_digest(const char *sk_digest);
 authority_cert_t *authority_cert_get_by_digests(const char *id_digest,
                                                 const char *sk_digest);
+void authority_cert_get_all(smartlist_t *certs_out);
+void authority_cert_dl_failed(const char *id_digest, int status);
 void authority_certs_fetch_missing(networkstatus_vote_t *status, time_t now);
 int router_reload_router_list(void);
 smartlist_t *router_get_trusted_dir_servers(void);

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2008-01-26 23:00:21 UTC (rev 13303)
+++ tor/trunk/src/or/routerlist.c	2008-01-26 23:18:30 UTC (rev 13304)
@@ -47,8 +47,16 @@
 /** Global list of a trusted_dir_server_t object for each trusted directory
  * server. */
 static smartlist_t *trusted_dir_servers = NULL;
-/** True iff the key certificate in at least one member of
- * <b>trusted_dir_server_t</b> has changed since we last flushed the
+
+/** DOCDOC */
+typedef struct cert_list_t {
+  download_status_t dl_status;
+  smartlist_t *certs;
+} cert_list_t;
+/** Map from v3 identity key digest to cert_list_t. */
+static digestmap_t *trusted_dir_certs = NULL;
+/** True iff any key certificate in at least one member of
+ * <b>trusted_dir_certs</b> has changed since we last flushed the
  * certificates to disk. */
 static int trusted_dir_servers_certs_changed = 0;
 
@@ -80,6 +88,22 @@
 
 #define get_n_v2_authorities() get_n_authorities(V2_AUTHORITY)
 
+/** DOCDOC */
+static cert_list_t *
+get_cert_list(const char *id_digest)
+{
+  cert_list_t *cl;
+  if (!trusted_dir_certs)
+    trusted_dir_certs = digestmap_new();
+  cl = digestmap_get(trusted_dir_certs, id_digest);
+  if (!cl) {
+    cl = tor_malloc_zero(sizeof(cert_list_t));
+    cl->certs = smartlist_create();
+    digestmap_set(trusted_dir_certs, id_digest, cl);
+  }
+  return cl;
+}
+
 /** Reload the cached v3 key certificates from the cached-certs file in
  * the data directory. Return 0 on success, -1 on failure. */
 int
@@ -108,6 +132,7 @@
 trusted_dirs_load_certs_from_string(const char *contents, int from_store)
 {
   trusted_dir_server_t *ds;
+  cert_list_t *cl;
   const char *s, *eos;
 
   for (s = contents; *s; s = eos) {
@@ -117,17 +142,20 @@
       break;
     ds = trusteddirserver_get_by_v3_auth_digest(
                                        cert->cache_info.identity_digest);
-    if (!ds) {
-      log_info(LD_DIR, "Found %s certificate whose key didn't match "
-               "any v3 authority we recognized; skipping.",
-               from_store ? "cached" : "downloaded");
-      authority_cert_free(cert);
-      continue;
+
+#if 0
+    if (drop_unknown && !ds) {
+        log_info(LD_DIR, "Found %s certificate whose key didn't match "
+                 "any v3 authority we recognized; skipping.",
+                 from_store ? "cached" : "downloaded");
+        authority_cert_free(cert);
+        continue;
+      }
     }
-    if (!ds->v3_certs)
-      ds->v3_certs = smartlist_create();
+#endif
+    cl = get_cert_list(cert->cache_info.identity_digest);
 
-    SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, c,
+    SMARTLIST_FOREACH(cl->certs, authority_cert_t *, c,
       {
         if (!memcmp(c->cache_info.signed_descriptor_digest,
                     cert->cache_info.signed_descriptor_digest,
@@ -145,12 +173,19 @@
     if (found)
       continue;
 
-    log_info(LD_DIR, "Adding %s certificate for directory authority %s with "
-             "signing key %s", from_store ? "cached" : "downloaded",
-             ds->nickname, hex_str(cert->signing_key_digest,DIGEST_LEN));
+    if (ds) {
+      log_info(LD_DIR, "Adding %s certificate for directory authority %s with "
+               "signing key %s", from_store ? "cached" : "downloaded",
+               ds->nickname, hex_str(cert->signing_key_digest,DIGEST_LEN));
+    } else {
+      log_info(LD_DIR, "Adding %s certificate for unrecognized directory "
+               "authority with signing key %s",
+               from_store ? "cached" : "downloaded",
+               hex_str(cert->signing_key_digest,DIGEST_LEN));
+    }
 
-    smartlist_add(ds->v3_certs, cert);
-    if (cert->cache_info.published_on > ds->addr_current_at) {
+    smartlist_add(cl->certs, cert);
+    if (ds && cert->cache_info.published_on > ds->addr_current_at) {
       /* Check to see whether we should update our view of the authority's
        * address. */
       if (cert->addr && cert->dir_port &&
@@ -185,23 +220,20 @@
   char *filename;
   smartlist_t *chunks;
 
-  if (!trusted_dir_servers_certs_changed)
+  if (!trusted_dir_servers_certs_changed || !trusted_dir_certs)
     return;
 
   chunks = smartlist_create();
-
-  SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
-  {
-      if (ds->v3_certs) {
-        SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
+  DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) {
+    SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
           {
             sized_chunk_t *c = tor_malloc(sizeof(sized_chunk_t));
             c->bytes = cert->cache_info.signed_descriptor_body;
             c->len = cert->cache_info.signed_descriptor_len;
             smartlist_add(chunks, c);
           });
-      }
-  });
+  } DIGESTMAP_FOREACH_END
+
   filename = get_datadir_fname("cached-certs");
   if (write_chunks_to_file(filename, chunks, 0)) {
     log_warn(LD_FS, "Error writing certificates to disk.");
@@ -221,23 +253,23 @@
 trusted_dirs_remove_old_certs(void)
 {
 #define OLD_CERT_LIFETIME (48*60*60)
-  SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
-    {
-      authority_cert_t *newest = NULL;
-      if (!ds->v3_certs)
-        continue;
-      SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
+  if (!trusted_dir_certs)
+    return;
+
+  DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) {
+    authority_cert_t *newest = NULL;
+    SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
           if (!newest || (cert->cache_info.published_on >
                           newest->cache_info.published_on))
             newest = cert);
-      SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
+    SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
           if (newest && (newest->cache_info.published_on >
                          cert->cache_info.published_on + OLD_CERT_LIFETIME)) {
-            SMARTLIST_DEL_CURRENT(ds->v3_certs, cert);
+            SMARTLIST_DEL_CURRENT(cl->certs, cert);
             authority_cert_free(cert);
             trusted_dir_servers_certs_changed = 1;
           });
-    });
+  } DIGESTMAP_FOREACH_END
 #undef OLD_CERT_LIFETIME
 
   trusted_dirs_flush_certs_to_disk();
@@ -249,11 +281,11 @@
 authority_cert_t *
 authority_cert_get_newest_by_id(const char *id_digest)
 {
-  trusted_dir_server_t *ds = trusteddirserver_get_by_v3_auth_digest(id_digest);
+  cert_list_t *cl;
   authority_cert_t *best = NULL;
-  if (!ds || !ds->v3_certs)
+  if (!trusted_dir_certs || !(cl = digestmap_get(trusted_dir_certs, id_digest)))
     return NULL;
-  SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
+  SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
   {
     if (!best || cert->cache_info.published_on > best->cache_info.published_on)
       best = cert;
@@ -267,18 +299,16 @@
 authority_cert_t *
 authority_cert_get_by_sk_digest(const char *sk_digest)
 {
-  if (!trusted_dir_servers)
+  if (!trusted_dir_certs)
     return NULL;
-  SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
-  {
-    if (!ds->v3_certs)
-      continue;
-    SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
+
+  DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) {
+    SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
     {
       if (!memcmp(cert->signing_key_digest, sk_digest, DIGEST_LEN))
         return cert;
     });
-  });
+  } DIGESTMAP_FOREACH_END
   return NULL;
 }
 
@@ -289,17 +319,40 @@
 authority_cert_get_by_digests(const char *id_digest,
                               const char *sk_digest)
 {
-  trusted_dir_server_t *ds = trusteddirserver_get_by_v3_auth_digest(id_digest);
-
-  if (!ds || !ds->v3_certs)
+  cert_list_t *cl;
+  if (!trusted_dir_certs || !(cl = digestmap_get(trusted_dir_certs, id_digest)))
     return NULL;
-  SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
+  SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
     if (!memcmp(cert->signing_key_digest, sk_digest, DIGEST_LEN))
       return cert; );
 
   return NULL;
 }
 
+/** DOCDOC */
+void
+authority_cert_get_all(smartlist_t *certs_out)
+{
+  if (!trusted_dir_certs)
+    return;
+
+  DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) {
+    SMARTLIST_FOREACH(cl->certs, authority_cert_t *, c,
+                      smartlist_add(certs_out, c));
+  } DIGESTMAP_FOREACH_END
+}
+
+/** DOCDOC */
+void
+authority_cert_dl_failed(const char *id_digest, int status)
+{
+  cert_list_t *cl;
+  if (!trusted_dir_certs || !(cl = digestmap_get(trusted_dir_certs, id_digest)))
+    return;
+
+  download_status_failed(&cl->dl_status, status);
+}
+
 /** How many times will we try to fetch a certificate before giving up? */
 #define MAX_CERT_DL_FAILURES 8
 
@@ -315,6 +368,8 @@
   digestmap_t *pending;
   smartlist_t *missing_digests;
   char *resource = NULL;
+  cert_list_t *cl;
+  const int cache = directory_caches_dir_info(get_options());
 
   if (should_delay_dir_fetches(get_options()))
     return;
@@ -326,24 +381,22 @@
   if (status) {
     SMARTLIST_FOREACH(status->voters, networkstatus_voter_info_t *, voter,
       {
-        trusted_dir_server_t *ds
-          = trusteddirserver_get_by_v3_auth_digest(voter->identity_digest);
-        if (!ds) /* XXXX020 This is wrong!!  If we're a cache, we should
-                  * download unrecognized signing keys so we can serve
-                  * them. */
-          continue;
         if (tor_digest_is_zero(voter->signing_key_digest))
           continue; /* This authority never signed this consensus, so don't
                      * go looking for a cert with key digest 0000000000. */
+        if (!cache &&
+            !trusteddirserver_get_by_v3_auth_digest(voter->identity_digest))
+          continue; /* We are not a cache, and we don't know this authority.*/
+        cl = get_cert_list(voter->identity_digest);
         if (authority_cert_get_by_digests(voter->identity_digest,
                                           voter->signing_key_digest)) {
-          download_status_reset(&ds->cert_dl_status);
+          download_status_reset(&cl->dl_status);
           continue;
         }
-        if (download_status_is_ready(&ds->cert_dl_status, now,
+        if (download_status_is_ready(&cl->dl_status, now,
                                      MAX_CERT_DL_FAILURES)) {
-          log_notice(LD_DIR, "We're missing a certificate from authority %s "
-                     "with signing key %s: launching request.", ds->nickname,
+          log_notice(LD_DIR, "We're missing a certificate from authority "
+                     "with signing key %s: launching request.",
                      hex_str(voter->signing_key_digest, DIGEST_LEN));
           smartlist_add(missing_digests, voter->identity_digest);
         }
@@ -356,19 +409,18 @@
         continue;
       if (smartlist_digest_isin(missing_digests, ds->v3_identity_digest))
         continue;
-      if (!ds->v3_certs)
-        ds->v3_certs = smartlist_create();
-      SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
+      cl = get_cert_list(ds->v3_identity_digest);
+      SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
         {
           if (!ftime_definitely_after(now, cert->expires)) {
             /* It's not expired, and we weren't looking for something to
              * verify a consensus with.  Call it done. */
-            download_status_reset(&ds->cert_dl_status);
+            download_status_reset(&cl->dl_status);
             found = 1;
             break;
           }
         });
-      if (!found && download_status_is_ready(&ds->cert_dl_status, now,
+      if (!found && download_status_is_ready(&cl->dl_status, now,
                                              MAX_CERT_DL_FAILURES)) {
         log_notice(LD_DIR, "No current certificate known for authority %s; "
                    "launching request.", ds->nickname);
@@ -3403,11 +3455,6 @@
 static void
 trusted_dir_server_free(trusted_dir_server_t *ds)
 {
-  if (ds->v3_certs) {
-    SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert,
-                      authority_cert_free(cert));
-    smartlist_free(ds->v3_certs);
-  }
   tor_free(ds->nickname);
   tor_free(ds->description);
   tor_free(ds->address);

Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c	2008-01-26 23:00:21 UTC (rev 13303)
+++ tor/trunk/src/or/routerparse.c	2008-01-26 23:18:30 UTC (rev 13304)
@@ -1433,14 +1433,13 @@
 authority_cert_t *
 authority_cert_parse_from_string(const char *s, const char **end_of_string)
 {
-  authority_cert_t *cert = NULL;
+  authority_cert_t *cert = NULL, *old_cert;
   smartlist_t *tokens = NULL;
   char digest[DIGEST_LEN];
   directory_token_t *tok;
   char fp_declared[DIGEST_LEN];
   char *eos;
   size_t len;
-  trusted_dir_server_t *ds;
   int found;
 
   s = eat_whitespace(s);
@@ -1531,22 +1530,19 @@
   }
 
   /* If we already have this cert, don't bother checking the signature. */
-  ds = trusteddirserver_get_by_v3_auth_digest(
-                                     cert->cache_info.identity_digest);
+  old_cert = authority_cert_get_by_digests(
+                                     cert->cache_info.identity_digest,
+                                     cert->signing_key_digest);
   found = 0;
-  if (ds && ds->v3_certs) {
-    SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, c,
-      {
-        /* XXXX020 can we just compare signed_descriptor_digest ? */
-        if (c->cache_info.signed_descriptor_len == len &&
-            c->cache_info.signed_descriptor_body &&
-            !memcmp(s, c->cache_info.signed_descriptor_body, len)) {
-          log_debug(LD_DIR, "We already checked the signature on this "
-                    "certificate; no need to do so again.");
-          found = 1;
-          break;
-        }
-      });
+  if (old_cert) {
+    /* XXXX020 can we just compare signed_descriptor_digest ? */
+    if (old_cert->cache_info.signed_descriptor_len == len &&
+        old_cert->cache_info.signed_descriptor_body &&
+        !memcmp(s, old_cert->cache_info.signed_descriptor_body, len)) {
+      log_debug(LD_DIR, "We already checked the signature on this "
+                "certificate; no need to do so again.");
+      found = 1;
+    }
   }
   if (!found) {
     if (check_signature_token(digest, tok, cert->identity_key, 0,