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

[or-cvs] [tor/master] Parse detached signature documents with multiple flavors and algorithms.



Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Wed, 16 Sep 2009 12:34:44 -0400
Subject: Parse detached signature documents with multiple flavors and algorithms.
Commit: 5576a3a094de49246e501bb24d1b3dc3a5d610b9

---
 src/common/crypto.c  |   12 ++++
 src/common/crypto.h  |    1 +
 src/or/routerparse.c |  160 +++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 146 insertions(+), 27 deletions(-)

diff --git a/src/common/crypto.c b/src/common/crypto.c
index ac0e628..f335f99 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1481,6 +1481,18 @@ crypto_digest_algorithm_get_name(digest_algorithm_t alg)
   }
 }
 
+/** DOCDOC */
+int
+crypto_digest_algorithm_parse_name(const char *name)
+{
+  if (!strcmp(name, "sha1"))
+    return DIGEST_SHA1;
+  else if (!strcmp(name, "sha256"))
+    return DIGEST_SHA256;
+  else
+    return -1;
+}
+
 /** Intermediate information about the digest of a stream of data. */
 struct crypto_digest_env_t {
   union {
diff --git a/src/common/crypto.h b/src/common/crypto.h
index ed84680..c0a4526 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -177,6 +177,7 @@ int crypto_digest256(char *digest, const char *m, size_t len,
                      digest_algorithm_t algorithm);
 int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
 const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
+int crypto_digest_algorithm_parse_name(const char *name);
 crypto_digest_env_t *crypto_new_digest_env(void);
 crypto_digest_env_t *crypto_new_digest256_env(digest_algorithm_t algorithm);
 void crypto_free_digest_env(crypto_digest_env_t *digest);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 285a550..21fe5f7 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -106,6 +106,8 @@ typedef enum {
   K_PARAMS,
   K_VOTE_DIGEST,
   K_CONSENSUS_DIGEST,
+  K_ADDITIONAL_DIGEST,
+  K_ADDITIONAL_SIGNATURE,
   K_CONSENSUS_METHODS,
   K_CONSENSUS_METHOD,
   K_LEGACY_DIR_KEY,
@@ -490,10 +492,12 @@ static token_rule_t networkstatus_vote_footer_token_table[] = {
 /** List of tokens allowable in detached networkstatus signature documents. */
 static token_rule_t networkstatus_detached_signature_token_table[] = {
   T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1),       NO_OBJ ),
+  T("additional-digest",       K_ADDITIONAL_DIGEST,GE(3),       NO_OBJ ),
   T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
   T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
-  T1N("directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
+  T("additional-signature",  K_ADDITIONAL_SIGNATURE, GE(4),   NEED_OBJ ),
+  T1N("directory-signature", K_DIRECTORY_SIGNATURE,  GE(2),   NEED_OBJ ),
   END_OF_TABLE
 };
 
@@ -2771,6 +2775,31 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
   return ns;
 }
 
+/** DOCDOC */
+static digests_t *
+detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name)
+{
+  digests_t *d = strmap_get(sigs->digests, flavor_name);
+  if (!d) {
+    d = tor_malloc_zero(sizeof(digests_t));
+    strmap_set(sigs->digests, flavor_name, d);
+  }
+  return d;
+}
+
+/** DOCDOC */
+static smartlist_t *
+detached_get_signatures(ns_detached_signatures_t *sigs,
+                        const char *flavor_name)
+{
+  smartlist_t *sl = strmap_get(sigs->signatures, flavor_name);
+  if (!sl) {
+    sl = smartlist_create();
+    strmap_set(sigs->signatures, flavor_name, sl);
+  }
+  return sl;
+}
+
 /** Parse a detached v3 networkstatus signature document between <b>s</b> and
  * <b>eos</b> and return the result.  Return -1 on failure. */
 ns_detached_signatures_t *
@@ -2780,19 +2809,13 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
    * networkstatus_parse_vote_from_string(). */
   directory_token_t *tok;
   memarea_t *area = NULL;
-  const char *flavor = "ns";
   digests_t *digests;
-  smartlist_t *sig_list;
 
   smartlist_t *tokens = smartlist_create();
   ns_detached_signatures_t *sigs =
     tor_malloc_zero(sizeof(ns_detached_signatures_t));
   sigs->digests = strmap_new();
   sigs->signatures = strmap_new();
-  digests = tor_malloc_zero(sizeof(digests_t));
-  sig_list = smartlist_create();
-  strmap_set(sigs->digests, flavor, digests);
-  strmap_set(sigs->signatures, flavor, sig_list);
 
   if (!eos)
     eos = s + strlen(s);
@@ -2804,18 +2827,57 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
     goto err;
   }
 
-  tok = find_by_keyword(tokens, K_CONSENSUS_DIGEST);
-  if (strlen(tok->args[0]) != HEX_DIGEST_LEN) {
-    log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
-             "networkstatus signatures");
-    goto err;
-  }
-  if (base16_decode(digests->d[DIGEST_SHA1], DIGEST_LEN,
-                    tok->args[0], strlen(tok->args[0])) < 0) {
-    log_warn(LD_DIR, "Bad encoding on on consensus-digest in detached "
-             "networkstatus signatures");
-    goto err;
-  }
+  /* Grab all the digest-like tokens. */
+  SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
+    const char *algname;
+    digest_algorithm_t alg;
+    const char *flavor;
+    const char *hexdigest;
+    size_t expected_length;
+
+    tok = _tok;
+
+    if (tok->tp == K_CONSENSUS_DIGEST) {
+      algname = "sha1";
+      alg = DIGEST_SHA1;
+      flavor = "ns";
+      hexdigest = tok->args[0];
+    } else if (tok->tp == K_ADDITIONAL_DIGEST) {
+      int a = crypto_digest_algorithm_parse_name(tok->args[1]);
+      if (a<0) {
+        log_warn(LD_DIR, "Unrecognized algorithm name %s", tok->args[0]);
+        continue;
+      }
+      alg = (digest_algorithm_t) a;
+      flavor = tok->args[0];
+      algname = tok->args[1];
+      hexdigest = tok->args[2];
+    } else {
+      continue;
+    }
+
+    expected_length =
+      (alg == DIGEST_SHA1) ? HEX_DIGEST_LEN : HEX_DIGEST256_LEN;
+
+    if (strlen(hexdigest) != expected_length) {
+      log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
+               "networkstatus signatures");
+      goto err;
+    }
+    digests = detached_get_digests(sigs, flavor);
+    tor_assert(digests);
+    if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) {
+      log_warn(LD_DIR, "Multiple digests for %s with %s on detached "
+               "signatures document", flavor, algname);
+      continue;
+    }
+    if (base16_decode(digests->d[alg], DIGEST256_LEN,
+                      hexdigest, strlen(hexdigest)) < 0) {
+      log_warn(LD_DIR, "Bad encoding on on consensus-digest in detached "
+               "networkstatus signatures");
+      goto err;
+    }
+  } SMARTLIST_FOREACH_END(_tok);
 
   tok = find_by_keyword(tokens, K_VALID_AFTER);
   if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
@@ -2836,14 +2898,43 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
   }
 
   SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
+    const char *id_hexdigest;
+    const char *sk_hexdigest;
+    const char *algname;
+    const char *flavor;
+    digest_algorithm_t alg;
+
     char id_digest[DIGEST_LEN];
     char sk_digest[DIGEST_LEN];
+    smartlist_t *siglist;
     document_signature_t *sig;
+    int is_duplicate;
 
     tok = _tok;
-    if (tok->tp != K_DIRECTORY_SIGNATURE)
+    if (tok->tp == K_DIRECTORY_SIGNATURE) {
+      tor_assert(tok->n_args >= 2);
+      flavor = "ns";
+      algname = "sha1";
+      id_hexdigest = tok->args[0];
+      sk_hexdigest = tok->args[1];
+    } else if (tok->tp == K_ADDITIONAL_SIGNATURE) {
+      tor_assert(tok->n_args >= 4);
+      flavor = tok->args[0];
+      algname = tok->args[1];
+      id_hexdigest = tok->args[2];
+      sk_hexdigest = tok->args[3];
+    } else {
       continue;
-    tor_assert(tok->n_args >= 2);
+    }
+
+    {
+      int a = crypto_digest_algorithm_parse_name(algname);
+      if (a<0) {
+        log_warn(LD_DIR, "Unrecognized algorithm name %s", algname);
+        continue;
+      }
+      alg = (digest_algorithm_t) a;
+    }
 
     if (!tok->object_type ||
         strcmp(tok->object_type, "SIGNATURE") ||
@@ -2852,21 +2943,36 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
       goto err;
     }
 
-    if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
+    if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
         base16_decode(id_digest, sizeof(id_digest),
-                      tok->args[0], HEX_DIGEST_LEN) < 0) {
+                      id_hexdigest, HEX_DIGEST_LEN) < 0) {
       log_warn(LD_DIR, "Error decoding declared identity %s in "
-               "network-status vote.", escaped(tok->args[0]));
+               "network-status vote.", escaped(id_hexdigest));
       goto err;
     }
     if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
         base16_decode(sk_digest, sizeof(sk_digest),
-                      tok->args[1], HEX_DIGEST_LEN) < 0) {
+                      sk_hexdigest, HEX_DIGEST_LEN) < 0) {
       log_warn(LD_DIR, "Error decoding declared digest %s in "
-               "network-status vote.", escaped(tok->args[1]));
+               "network-status vote.", escaped(sk_hexdigest));
       goto err;
     }
 
+    siglist = detached_get_signatures(sigs, flavor);
+    is_duplicate = 0;
+    SMARTLIST_FOREACH(siglist, document_signature_t *, s, {
+      if (s->alg == alg &&
+          !memcmp(id_digest, s->identity_digest, DIGEST_LEN) &&
+          !memcmp(sk_digest, s->signing_key_digest, DIGEST_LEN)) {
+        is_duplicate = 1;
+      }
+    });
+    if (is_duplicate) {
+      log_warn(LD_DIR, "Two signatures with identical keys and algorithm "
+               "found.");
+      continue;
+    }
+
     sig = tor_malloc_zero(sizeof(document_signature_t));
     sig->alg = DIGEST_SHA1;
     memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
@@ -2878,7 +2984,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
     sig->signature = tor_memdup(tok->object_body, tok->object_size);
     sig->signature_len = (int) tok->object_size;
 
-    smartlist_add(sig_list, sig);
+    smartlist_add(siglist, sig);
   } SMARTLIST_FOREACH_END(_tok);
 
   goto done;
-- 
1.5.6.5