aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2004-10-07 21:10:40 +0000
committerNick Mathewson <nickm@torproject.org>2004-10-07 21:10:40 +0000
commitc7e8c2098abd93bf24439f869016c385067e5e5b (patch)
tree21d86b8e9fded68a0f26cce7407a9b6ad1c53374
parent7b98fb58ebb99c660814e5f758e284071c903ca4 (diff)
downloadtor-c7e8c2098abd93bf24439f869016c385067e5e5b.tar
tor-c7e8c2098abd93bf24439f869016c385067e5e5b.tar.gz
Include a dir-signing-key token in directories to tell the parsing entity which key is being used to sign. This is the first step in obsoleting the dirservers file.
svn:r2428
-rw-r--r--src/or/dirserv.c16
-rw-r--r--src/or/routerlist.c1
-rw-r--r--src/or/routerparse.c140
-rw-r--r--src/or/test.c6
4 files changed, 138 insertions, 25 deletions
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index a9e37c707..39dc7bc89 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -552,7 +552,7 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
crypto_pk_env_t *private_key)
{
char *cp, *eos;
- char *identity_pkey; /* Identity key, PEM-encoded. */
+ char *identity_pkey; /* Identity key, DER64-encoded. */
char digest[20];
char signature[128];
char published[33];
@@ -764,20 +764,32 @@ static int generate_runningrouters(crypto_pk_env_t *private_key)
char published[33];
size_t len;
time_t published_on;
+ char *identity_pkey; /* Identity key, DER64-encoded. */
len = 1024+(MAX_HEX_NICKNAME_LEN+2)*smartlist_len(descriptor_list);
s = tor_malloc_zero(len);
if (list_running_servers(&cp))
return -1;
+ /* ASN.1-encode the public key. This is a temporary measure; once
+ * everyone is running 0.0.9pre3 or later, we can shift to using a
+ * PEM-encoded key instead.
+ */
+ if(crypto_pk_DER64_encode_public_key(private_key, &identity_pkey)<0) {
+ log_fn(LOG_WARN,"write identity_pkey to string failed!");
+ tor_free(cp);
+ return -1;
+ }
published_on = time(NULL);
format_iso_time(published, published_on);
sprintf(s, "network-status\n"
"published %s\n"
"running-routers %s\n"
+ "opt dir-signing-key %s\n"
"directory-signature %s\n"
"-----BEGIN SIGNATURE-----\n",
- published, cp, options.Nickname);
+ published, cp, identity_pkey, options.Nickname);
tor_free(cp);
+ tor_free(identity_pkey);
if (router_get_runningrouters_hash(s,digest)) {
log_fn(LOG_WARN,"couldn't compute digest");
return -1;
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index cb63ee507..66a8d7c5e 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -512,6 +512,7 @@ routerinfo_t *router_get_by_digest(const char *digest) {
routerinfo_t *router;
tor_assert(digest);
+ if (!routerlist) return NULL;
for(i=0;i<smartlist_len(routerlist->routers);i++) {
router = smartlist_get(routerlist->routers, i);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 9f8ae7dde..4ce8684bb 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -40,6 +40,7 @@ typedef enum {
K_CONTACT,
K_NETWORK_STATUS,
K_UPTIME,
+ K_DIR_SIGNING_KEY,
_UNRECOGNIZED,
_ERR,
_EOF,
@@ -113,6 +114,7 @@ static struct {
{ "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANY },
{ "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ, DIR_ONLY },
{ "uptime", K_UPTIME, ARGS, NO_OBJ, RTR_ONLY },
+ { "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK, DIR_ONLY },
{ NULL, -1 }
};
@@ -130,8 +132,9 @@ static int tokenize_string(const char *start, const char *end,
static directory_token_t *get_next_token(const char **s, where_syntax where);
static int check_directory_signature(const char *digest,
directory_token_t *tok,
- crypto_pk_env_t *pkey);
-
+ crypto_pk_env_t *pkey,
+ crypto_pk_env_t *declared_key);
+static crypto_pk_env_t *find_dir_signing_key(const char *str);
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
* <b>s</b>. Return 0 on success, nonzero on failure.
@@ -298,6 +301,7 @@ router_parse_routerlist_from_directory(const char *str,
const char *end, *cp;
smartlist_t *tokens = NULL;
char dirnickname[MAX_NICKNAME_LEN+1];
+ crypto_pk_env_t *declared_key = NULL;
if (router_get_dir_hash(str, digest)) {
log_fn(LOG_WARN, "Unable to compute digest of directory");
@@ -324,9 +328,9 @@ router_parse_routerlist_from_directory(const char *str,
if(tok->tp != K_DIRECTORY_SIGNATURE) {
log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
}
- if (check_directory_signature(digest, tok, pkey)<0) {
+ declared_key = find_dir_signing_key(str);
+ if (check_directory_signature(digest, tok, pkey, declared_key)<0)
goto err;
- }
/* now we know tok->n_args == 1, so it's safe to access tok->args[0] */
strlcpy(dirnickname, tok->args[0], sizeof(dirnickname));
@@ -439,6 +443,7 @@ router_parse_routerlist_from_directory(const char *str,
routerlist_free(new_dir);
tor_free(versions);
done:
+ if (declared_key) crypto_free_pk_env(declared_key);
if (tokens) {
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
smartlist_free(tokens);
@@ -458,7 +463,7 @@ router_parse_runningrouters(const char *str)
directory_token_t *tok;
time_t published_on;
int i;
-
+ crypto_pk_env_t *declared_key = NULL;
smartlist_t *tokens = NULL;
if (router_get_runningrouters_hash(str, digest)) {
@@ -505,15 +510,16 @@ router_parse_runningrouters(const char *str)
log_fn(LOG_WARN, "Missing signature on directory");
goto err;
}
- if (check_directory_signature(digest, tok, NULL)<0) {
+ declared_key = find_dir_signing_key(str);
+ if (check_directory_signature(digest, tok, NULL, declared_key) < 0)
goto err;
- }
goto done;
err:
running_routers_free(new_list);
new_list = NULL;
done:
+ if (declared_key) crypto_free_pk_env(declared_key);
if (tokens) {
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
smartlist_free(tokens);
@@ -521,9 +527,91 @@ router_parse_runningrouters(const char *str)
return new_list;
}
+/** Given a directory or running-routers string in <b>str</b>, try to
+ * find the its dir-signing-key token (if any). If this token is
+ * present, extract and return the key. Return NULL on failure. */
+static crypto_pk_env_t *find_dir_signing_key(const char *str)
+{
+ const char *cp;
+ directory_token_t *tok;
+ crypto_pk_env_t *key = NULL;
+
+ /* Is there a dir-signing-key in the directory? */
+ cp = strstr(str, "\nopt dir-signing-key");
+ if (!cp)
+ cp = strstr(str, "\ndir-signing-key");
+ if (!cp)
+ return NULL;
+ ++cp; /* Now cp points to the start of the token. */
+
+ tok = get_next_token(&cp, DIR_ONLY);
+ if (!tok) {
+ log_fn(LOG_WARN, "Unparseable dir-signing-key token");
+ return NULL;
+ }
+ if (tok->tp != K_DIR_SIGNING_KEY) {
+ log_fn(LOG_WARN, "Dir-signing-key token did not parse as expected");
+ return NULL;
+ }
+
+ if (tok->key) {
+ key = tok->key;
+ tok->key = NULL; /* steal reference. */
+ } else if (tok->n_args >= 1) {
+ key = crypto_pk_DER64_decode_public_key(tok->args[0]);
+ if (!key) {
+ log_fn(LOG_WARN, "Unparseable dir-signing-key argument");
+ return NULL;
+ }
+ } else {
+ log_fn(LOG_WARN, "Dir-signing-key token contained no key");
+ return NULL;
+ }
+
+ token_free(tok);
+ return key;
+}
+
+/** Return true iff <b>key</b> is allowed to sign directories.
+ */
+static int dir_signing_key_is_trusted(crypto_pk_env_t *key)
+{
+ char digest[DIGEST_LEN];
+ routerinfo_t *r;
+ if (!key) return 0;
+ if (crypto_pk_get_digest(key, digest) < 0) {
+ log_fn(LOG_WARN, "Error computing dir-signing-key digest");
+ return 0;
+ }
+ if (!(r = router_get_by_digest(digest))) {
+ log_fn(LOG_WARN, "No router known with given dir-signing-key digest");
+ return 0;
+ }
+ if (! r->is_trusted_dir) {
+ log_fn(LOG_WARN, "Listed dir-signing-key is not trusted");
+ return 0;
+ }
+ return 1;
+}
+
+/** Check whether the K_DIRECTORY_SIGNATURE token in <b>tok</b> has a
+ * good signature for <b>digest</b>.
+ *
+ * If <b>declared_key</b> is set, the directory has declared what key
+ * was used to sign it, so we will use that key only if it is an
+ * authoritative directory signing key.
+ *
+ * Otherwise, try to look up the router whose nickname is given in the
+ * directory-signature token. If this fails, or the named router is
+ * not authoritative, try to use pkey.
+ *
+ * (New callers should always use <b>declared_key</b> when possible;
+ * <b>pkey is only for debugging.)
+ */
static int check_directory_signature(const char *digest,
- directory_token_t *tok,
- crypto_pk_env_t *pkey)
+ directory_token_t *tok,
+ crypto_pk_env_t *pkey,
+ crypto_pk_env_t *declared_key)
{
char signed_digest[PK_BYTES];
routerinfo_t *r;
@@ -533,21 +621,27 @@ static int check_directory_signature(const char *digest,
return -1;
}
- r = router_get_by_nickname(tok->args[0]);
- log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
- if (r && r->is_trusted_dir) {
- pkey = r->identity_pkey;
- } else if (!r && pkey) {
- /* pkey provided for debugging purposes. */
- } else if (!r) {
- log_fn(LOG_WARN, "Directory was signed by unrecognized server %s",
- tok->args[0]);
- return -1;
- } else if (r && !r->is_trusted_dir) {
- log_fn(LOG_WARN, "Directory was signed by non-trusted server %s",
- tok->args[0]);
- return -1;
+ if (declared_key) {
+ if (dir_signing_key_is_trusted(declared_key))
+ pkey = declared_key;
+ } else {
+ r = router_get_by_nickname(tok->args[0]);
+ log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
+ if (r && r->is_trusted_dir) {
+ pkey = r->identity_pkey;
+ } else if (!r && pkey) {
+ /* pkey provided for debugging purposes. */
+ } else if (!r) {
+ log_fn(LOG_WARN, "Directory was signed by unrecognized server %s",
+ tok->args[0]);
+ return -1;
+ } else if (r && !r->is_trusted_dir) {
+ log_fn(LOG_WARN, "Directory was signed by non-trusted server %s",
+ tok->args[0]);
+ return -1;
+ }
}
+
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
log_fn(LOG_WARN, "Bad object type or length on directory signature");
return -1;
diff --git a/src/or/test.c b/src/or/test.c
index 48a30cec6..ed89df1f3 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -619,6 +619,12 @@ test_util() {
test_eq(5, tor_strstrip(buf, "!? "));
test_streq(buf, "Testing123");
+ /* Test tor_strpartition() */
+ test_assert(! tor_strpartition(buf, sizeof(buf), "abcdefg", "##", 3));
+ test_streq(buf, "abc##def##g");
+ test_assert(! tor_strpartition(buf, sizeof(buf), "abcdefghi", "##", 3));
+ test_streq(buf, "abc##def##ghi##");
+
/* XXXX test older functions. */
smartlist_free(sl);
}