aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/TODO8
-rw-r--r--doc/spec/dir-spec.txt8
-rw-r--r--src/or/directory.c81
-rw-r--r--src/or/or.h2
-rw-r--r--src/or/routerlist.c35
5 files changed, 129 insertions, 5 deletions
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://<hostname>/tor/keys/authority.z
+ The key certificate for an authority whose authority identity fingerprint
+ is <F> should be available at:
+ http://<hostname>/tor/keys/fp/<F>.z
+
+ The key certificate whose signing key is <F> should be available at:
+ http://<hostname>/tor/keys/fp/<F>.z
+ [XXX020 cross-certify?]
+
The most recent descriptor for a server whose identity key has a
fingerprint of <F> should be available at:
http://<hostname>/tor/server/fp/<F>.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
* <b>sk_digest</b>, for the authority with identity digest <b>id_digest</b>.
* Return NULL if no such authority is known. */