Browse Source

Allow conflicts to occur in keypinning journal

When we find a conflict in the keypinning journal, treat the new
entry as superseding all old entries that overlap either of its
keys.

Also add a (not-yet-used) configuration option to disable keypinning
enforcement.
Nick Mathewson 8 years ago
parent
commit
c5e87e33c7
4 changed files with 39 additions and 15 deletions
  1. 1 0
      src/or/config.c
  2. 32 10
      src/or/keypin.c
  3. 1 0
      src/or/or.h
  4. 5 5
      src/test/test_keypin.c

+ 1 - 0
src/or/config.c

@@ -162,6 +162,7 @@ static config_var_t option_vars_[] = {
   V(AuthDirInvalidCCs,           CSV,      ""),
   V(AuthDirFastGuarantee,        MEMUNIT,  "100 KB"),
   V(AuthDirGuardBWGuarantee,     MEMUNIT,  "2 MB"),
+  V(AuthDirPinKeys,              BOOL,     "0"),
   V(AuthDirReject,               LINELIST, NULL),
   V(AuthDirRejectCCs,            CSV,      ""),
   OBSOLETE("AuthDirRejectUnlisted"),

+ 32 - 10
src/or/keypin.c

@@ -321,19 +321,41 @@ keypin_load_journal_impl(const char *data, size_t size)
       continue;
     }
 
-    const keypin_ent_t *ent2;
-    if ((ent2 = HT_FIND(rsamap, &the_rsa_map, ent))) {
-      if (fast_memeq(ent2->ed25519_key, ent->ed25519_key, DIGEST256_LEN)) {
-        ++n_duplicates;
-      } else {
-        ++n_conflicts;
-      }
+    keypin_ent_t *ent2 = HT_FIND(rsamap, &the_rsa_map, ent);
+    keypin_ent_t *ent3 = HT_FIND(edmap, &the_ed_map, ent);
+    if (ent2 &&
+        fast_memeq(ent2->ed25519_key, ent->ed25519_key, DIGEST256_LEN)) {
+      /* We already have this mapping stored. Ignore it. */
       tor_free(ent);
+      ++n_duplicates;
       continue;
-    } else if (HT_FIND(edmap, &the_ed_map, ent)) {
-      tor_free(ent);
+    } else if (ent2 || ent3) {
+      /* We have a conflict. (If we had no entry, we would have ent2 == ent3
+       * == NULL. If we had a non-conflicting duplicate, we would have found
+       * it above.)
+       *
+       * We respond by having this entry (ent) supersede all entries that it
+       * contradicts (ent2 and/or ent3). In other words, if we receive
+       * <rsa,ed>, we remove all <rsa,ed'> and all <rsa',ed>, for rsa'!=rsa
+       * and ed'!= ed.
+       */
+      const keypin_ent_t *t;
+      if (ent2) {
+        t = HT_REMOVE(rsamap, &the_rsa_map, ent2);
+        tor_assert(ent2 == t);
+        t = HT_REMOVE(edmap, &the_ed_map, ent2);
+        tor_assert(ent2 == t);
+      }
+      if (ent3 && ent2 != ent3) {
+        t = HT_REMOVE(rsamap, &the_rsa_map, ent3);
+        tor_assert(ent3 == t);
+        t = HT_REMOVE(edmap, &the_ed_map, ent3);
+        tor_assert(ent3 == t);
+        tor_free(ent3);
+      }
+      tor_free(ent2);
       ++n_conflicts;
-      continue;
+      /* Fall through */
     }
 
     keypin_add_entry_to_map(ent);

+ 1 - 0
src/or/or.h

@@ -3790,6 +3790,7 @@ typedef struct {
                                      * number of servers per IP address shared
                                      * with an authority. */
   int AuthDirHasIPv6Connectivity; /**< Boolean: are we on IPv6?  */
+  int AuthDirPinKeys; /**< Boolean: Do we enforce key-pinning? */
 
   /** If non-zero, always vote the Fast flag for any relay advertising
    * this amount of capacity or more. */

+ 5 - 5
src/test/test_keypin.c

@@ -108,21 +108,21 @@ test_keypin_parse_file(void *arg)
     ;
 
   tt_int_op(0, ==, keypin_load_journal_impl(data2, strlen(data2)));
-  tt_int_op(11, ==, smartlist_len(mock_addent_got));
+  tt_int_op(13, ==, smartlist_len(mock_addent_got));
   ent = smartlist_get(mock_addent_got, 9);
   tt_mem_op(ent->rsa_id, ==, "\"You have made a goo", 20);
   tt_mem_op(ent->ed25519_key, ==, "d beginning.\" But no more. Wizar", 32);
 
-  ent = smartlist_get(mock_addent_got, 10);
+  ent = smartlist_get(mock_addent_got, 12);
   tt_mem_op(ent->rsa_id, ==, "ds speak truth, and ", 20);
-  tt_mem_op(ent->ed25519_key, ==, "it was true that all the master\n", 32);
+  tt_mem_op(ent->ed25519_key, ==, "it was tru\xa5 that all the master\n", 32);
 
   /* File truncated before NL */
   const char data3[] =
     "Tm8gZHJhZ29uIGNhbiByZXNpc3Q IHRoZSBmYXNjaW5hdGlvbiBvZiByaWRkbGluZyB0YWw";
   tt_int_op(0, ==, keypin_load_journal_impl(data3, strlen(data3)));
-  tt_int_op(12, ==, smartlist_len(mock_addent_got));
-  ent = smartlist_get(mock_addent_got, 11);
+  tt_int_op(14, ==, smartlist_len(mock_addent_got));
+  ent = smartlist_get(mock_addent_got, 13);
   tt_mem_op(ent->rsa_id, ==, "No dragon can resist", 20);
   tt_mem_op(ent->ed25519_key, ==, " the fascination of riddling tal", 32);