[or-cvs] Include a dir-signing-key token in directories to tell the ...

Nick Mathewson nickm at seul.org
Thu Oct 7 21:10:42 UTC 2004


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv18912/src/or

Modified Files:
	dirserv.c routerlist.c routerparse.c test.c 
Log Message:
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.

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dirserv.c,v
retrieving revision 1.90
retrieving revision 1.91
diff -u -d -r1.90 -r1.91
--- dirserv.c	7 Oct 2004 03:11:42 -0000	1.90
+++ dirserv.c	7 Oct 2004 21:10:40 -0000	1.91
@@ -552,7 +552,7 @@
                                  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 @@
   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;

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerlist.c,v
retrieving revision 1.147
retrieving revision 1.148
diff -u -d -r1.147 -r1.148
--- routerlist.c	7 Oct 2004 20:22:58 -0000	1.147
+++ routerlist.c	7 Oct 2004 21:10:40 -0000	1.148
@@ -512,6 +512,7 @@
   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);

Index: routerparse.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerparse.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- routerparse.c	6 Oct 2004 13:28:34 -0000	1.45
+++ routerparse.c	7 Oct 2004 21:10:40 -0000	1.46
@@ -40,6 +40,7 @@
   K_CONTACT,
   K_NETWORK_STATUS,
   K_UPTIME,
+  K_DIR_SIGNING_KEY,
   _UNRECOGNIZED,
   _ERR,
   _EOF,
@@ -113,6 +114,7 @@
   { "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 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 @@
   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 @@
   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 @@
     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 @@
   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 @@
     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 @@
   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 @@
     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;

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.119
retrieving revision 1.120
diff -u -d -r1.119 -r1.120
--- test.c	7 Oct 2004 03:11:42 -0000	1.119
+++ test.c	7 Oct 2004 21:10:40 -0000	1.120
@@ -619,6 +619,12 @@
   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);
 }



More information about the tor-commits mailing list