diff --git a/doc/TODO b/doc/TODO index 98f32308b1..b2daf9defd 100644 --- a/doc/TODO +++ b/doc/TODO @@ -55,7 +55,7 @@ Things we'd like to do in 0.2.0.x: unreachable is bunk -- it's leftover from the time when all servers ran 24/7. now it triggers every time a server goes away and then returns before the old descriptor has expired. - - Update dir-spec with decisions made on these issues: + o Update dir-spec with decisions made on these issues: o clients don't log as loudly when they receive them o they don't count toward the 3-strikes rule D But eventually, we give up after getting a lot of 503s. @@ -67,8 +67,8 @@ Things we'd like to do in 0.2.0.x: D They can 503 client descriptor requests when they feel like it. How can they distinguish? Not implemented for now, maybe should abandon. - - describe our 302 not modified behaviors. - - and document a bit more -- e.g. it looks like we return an empty + o describe our 302 not modified behaviors. + o and document a bit more -- e.g. it looks like we return an empty 200 OK when somebody asks us for a networkstatus and we don't have it? @@ -84,7 +84,7 @@ Things we'd like to do in 0.2.0.x: - Get authorities voting . Code to manage key certificates - Download as needed. - - Serve list as needed. + o Serve list as needed. o Avoid double-checking signatures every time we get a vote. - Warn about expired stuff. - Fix all XXXX020s in vote code diff --git a/doc/spec/dir-spec.txt b/doc/spec/dir-spec.txt index bdb69e6a50..7c3a321739 100644 --- a/doc/spec/dir-spec.txt +++ b/doc/spec/dir-spec.txt @@ -1242,6 +1242,14 @@ $Id$ available at: http:///tor/keys/authority.z + The key certificate for an authority whose authority identity fingerprint + is should be available at: + http:///tor/keys/fp/.z + + The key certificate whose signing key is should be available at: + http:///tor/keys/fp/.z + [XXX020 cross-certify?] + The most recent descriptor for a server whose identity key has a fingerprint of should be available at: http:///tor/server/fp/.z diff --git a/src/or/directory.c b/src/or/directory.c index e964ed33ef..3082078d48 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1737,7 +1737,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, const char *body, size_t body_len) { size_t dlen; - char *url = NULL; + char *url = NULL; /* XXX020 every exit point needs to free url. this + * function should use 'goto done' for that. */ or_options_t *options = get_options(); time_t if_modified_since = 0; char *header; @@ -2007,6 +2008,84 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, return 0; } + if (!strcmpstart(url,"/tor/keys/")) { + smartlist_t *certs = smartlist_create(); + int compressed; + ssize_t len = -1; + url += strlen("/tor/keys/"); + compressed = !strcmpend(url, ".z"); + if (compressed) + url[strlen(url)-2] = '\0'; + if (!strcmp(url, "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, + if (cert->cache_info.published_on >= if_modified_since) + smartlist_add(certs, cert)); + }); + } else if (!strcmp(url, "authority")) { + authority_cert_t *cert = get_my_v3_authority_cert(); + if (cert) + smartlist_add(certs, cert); + } else if (!strcmpstart(url, "fp/")) { + smartlist_t *fps = smartlist_create(); + dir_split_resource_into_fingerprints(url, fps, NULL, 1, 1); + SMARTLIST_FOREACH(fps, char *, d, { + authority_cert_t *c = authority_cert_get_newest_by_id(d); + if (c) smartlist_add(certs, c); + tor_free(d); + }); + smartlist_free(fps); + } else if (!strcmpstart(url, "sk/")) { + smartlist_t *fps = smartlist_create(); + dir_split_resource_into_fingerprints(url, fps, NULL, 1, 1); + SMARTLIST_FOREACH(fps, char *, d, { + authority_cert_t *c = authority_cert_get_by_sk_digest(d); + if (c) smartlist_add(certs, c); + tor_free(d); + }); + smartlist_free(fps); + } else { + write_http_status_line(conn, 400, "Bad request"); + tor_free(url); + smartlist_free(certs); + return 0; + } + if (!smartlist_len(certs)) { + write_http_status_line(conn, 404, "Not found"); + tor_free(url); + smartlist_free(certs); + return 0; + } + if (!compressed) { + len = 0; + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + len += c->cache_info.signed_descriptor_len); + } + write_http_response_header(conn, len, + compressed?"application/octet-stream":"text/plain", + compressed?"deflate":"identity", + 60*60); + if (compressed) { + conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body, + c->cache_info.signed_descriptor_len, + conn, 0)); + connection_write_to_buf_zlib("", 0, conn, 1); + } else { + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + connection_write_to_buf(c->cache_info.signed_descriptor_body, + c->cache_info.signed_descriptor_len, + TO_CONN(conn))); + } + smartlist_free(certs); + tor_free(url); + } + if (options->HSAuthoritativeDir && (!strcmpstart(url,"/tor/rendezvous/") || !strcmpstart(url,"/tor/rendezvous1/"))) { diff --git a/src/or/or.h b/src/or/or.h index 3f2340f8f5..f6d7907a90 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3355,6 +3355,8 @@ trusted_dir_server_t *router_get_trusteddirserver_by_digest( const char *digest); trusted_dir_server_t *trusteddirserver_get_by_v3_auth_digest( const char *digest); +authority_cert_t *authority_cert_get_newest_by_id(const char *id_digest); +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 routerlist_add_family(smartlist_t *sl, routerinfo_t *router); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 4bdd88fb11..f2d8b438f6 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -337,6 +337,41 @@ trusted_dirs_remove_old_certs(void) trusted_dirs_flush_certs_to_disk(); } +/** DOCDOC */ +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); + authority_cert_t *best = NULL; + if (!ds || !ds->v3_certs) + return NULL; + SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert, + { + if (!best || cert->cache_info.published_on > best->cache_info.published_on) + best = cert; + }); + return best; +} + +/** DOCDOC */ +authority_cert_t * +authority_cert_get_by_sk_digest(const char *sk_digest) +{ + if (!trusted_dir_servers) + return NULL; + SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds, + { + if (!ds->v3_certs) + return NULL; + SMARTLIST_FOREACH(ds->v3_certs, authority_cert_t *, cert, + { + if (!memcmp(cert->signing_key_digest, sk_digest, DIGEST_LEN)) + return cert; + }); + }); + return NULL; +} + /** Return the v3 authority certificate with signing key matching * sk_digest, for the authority with identity digest id_digest. * Return NULL if no such authority is known. */