[tor-commits] [tor/master] Tie key-pinning logic into directory authority operation

nickm at torproject.org nickm at torproject.org
Thu May 28 15:06:54 UTC 2015


commit 592a43910706a67048c7d05e45d35dc79712820a
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Oct 8 08:32:00 2014 -0400

    Tie key-pinning logic into directory authority operation
    
    With this patch:
      * Authorities load the key-pinning log at startup.
      * Authorities open a key-pinning log for writing at startup.
      * Authorities reject any router with an ed25519 key where they have
        previously seen that ed25519 key with a different RSA key, or vice
        versa.
      * Authorities warn about, but *do not* reject, RSA-only descriptors
        when the RSA key has previously gone along with an Ed25519 key.
        (We should make this a 'reject' too, but we can't do that until we're
        sure there's no legit reason to downgrade to 0.2.5.)
---
 src/or/dirserv.c |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/or/keypin.c  |   28 ++++++++++++++++++++++++
 src/or/keypin.h  |    2 ++
 src/or/main.c    |   19 ++++++++++++++++
 src/or/router.c  |    3 ++-
 5 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index e5a5b54..f26a6bb 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -18,6 +18,7 @@
 #include "dirserv.h"
 #include "dirvote.h"
 #include "hibernate.h"
+#include "keypin.h"
 #include "microdesc.h"
 #include "networkstatus.h"
 #include "nodelist.h"
@@ -27,6 +28,7 @@
 #include "routerlist.h"
 #include "routerparse.h"
 #include "routerset.h"
+#include "torcert.h"
 
 /**
  * \file dirserv.c
@@ -225,6 +227,16 @@ dirserv_load_fingerprint_file(void)
   return 0;
 }
 
+/* If this is set, then we don't allow routers that have advertised an Ed25519
+ * identity to stop doing so.  This is going to be essential for good identity
+ * security: otherwise anybody who can attack RSA-1024 but not Ed25519 could
+ * just sign fake descriptors missing the Ed25519 key.  But we won't actually
+ * be able to prevent that kind of thing until we're confident that there
+ * isn't actually a legit reason to downgrade to 0.2.5.  So for now, we have
+ * to leave this #undef.
+ */
+#undef DISABLE_DISABLING_ED25519
+
 /** Check whether <b>router</b> has a nickname/identity key combination that
  * we recognize from the fingerprint list, or an IP we automatically act on
  * according to our configuration.  Return the appropriate router status.
@@ -243,6 +255,36 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg)
     return FP_REJECT;
   }
 
+  if (router->signing_key_cert) {
+    /* This has an ed25519 identity key. */
+    if (KEYPIN_MISMATCH ==
+        keypin_check((const uint8_t*)router->cache_info.identity_digest,
+                     router->signing_key_cert->signing_key.pubkey)) {
+      if (msg) {
+        *msg = "Ed25519 identity key or RSA identity key has changed.";
+      }
+      log_warn(LD_DIR, "Router %s uploaded a descriptor with a Ed25519 key "
+               "but the <rsa,ed25519> keys don't match what they were before.",
+               router_describe(router));
+      return FP_REJECT;
+    }
+  } else {
+    /* No ed25519 key */
+    if (KEYPIN_MISMATCH == keypin_check_lone_rsa(
+                        (const uint8_t*)router->cache_info.identity_digest)) {
+      log_warn(LD_DIR, "Router %s uploaded a descriptor with no Ed25519 key, "
+               "when we previously knew an Ed25519 for it. Ignoring for now, "
+               "since Tor 0.2.6 is under development.",
+               router_describe(router));
+#ifdef DISABLE_DISABLING_ED25519
+      if (msg) {
+        *msg = "Ed25519 identity key has disappeared.";
+      }
+      return FP_REJECT;
+#endif
+    }
+  }
+
   return dirserv_get_status_impl(d, router->nickname,
                                  router->addr, router->or_port,
                                  router->platform, msg, 1);
@@ -578,6 +620,28 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
     return ROUTER_IS_ALREADY_KNOWN;
   }
 
+  /* Do keypinning again ... this time, to add the pin if appropriate */
+  int keypin_status;
+  if (ri->signing_key_cert) {
+    keypin_status = keypin_check_and_add(
+      (const uint8_t*)ri->cache_info.identity_digest,
+      ri->signing_key_cert->signing_key.pubkey);
+  } else {
+    keypin_status = keypin_check_lone_rsa(
+      (const uint8_t*)ri->cache_info.identity_digest);
+#ifndef DISABLE_DISABLING_ED25519
+    if (keypin_status == KEYPIN_MISMATCH)
+      keypin_status = KEYPIN_NOT_FOUND;
+#endif
+  }
+  if (keypin_status == KEYPIN_MISMATCH) {
+    log_info(LD_DIRSERV, "Dropping descriptor from %s (source: %s) because "
+             "its key did not match an older RSA/Ed25519 keypair",
+             router_describe(ri), source);
+    *msg = "Looks like your keypair does not match its older value.";
+    return ROUTER_AUTHDIR_REJECTS;
+  }
+
   /* Make a copy of desc, since router_add_to_routerlist might free
    * ri and its associated signed_descriptor_t. */
   desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);
diff --git a/src/or/keypin.c b/src/or/keypin.c
index 87e49cd..7b0c0c7 100644
--- a/src/or/keypin.c
+++ b/src/or/keypin.c
@@ -44,6 +44,9 @@
 
 static int keypin_journal_append_entry(const uint8_t *rsa_id_digest,
                                        const uint8_t *ed25519_id_key);
+static int keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
+                                     const uint8_t *ed25519_id_key,
+                                     int do_not_add);
 
 static HT_HEAD(rsamap, keypin_ent_st) the_rsa_map = HT_INITIALIZER();
 static HT_HEAD(edmap, keypin_ent_st) the_ed_map = HT_INITIALIZER();
@@ -100,6 +103,28 @@ int
 keypin_check_and_add(const uint8_t *rsa_id_digest,
                      const uint8_t *ed25519_id_key)
 {
+  return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 0);
+}
+
+/**
+ * As keypin_check_and_add, but do not add.  Return KEYPIN_NOT_FOUND if
+ * we would add.
+ */
+int
+keypin_check(const uint8_t *rsa_id_digest,
+             const uint8_t *ed25519_id_key)
+{
+  return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 1);
+}
+
+/**
+ * Helper: implements keypin_check and keypin_check_and_add.
+ */
+static int
+keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
+                          const uint8_t *ed25519_id_key,
+                          int do_not_add)
+{
   keypin_ent_t search, *ent;
   memset(&search, 0, sizeof(search));
   memcpy(search.rsa_id, rsa_id_digest, sizeof(search.rsa_id));
@@ -127,6 +152,9 @@ keypin_check_and_add(const uint8_t *rsa_id_digest,
   }
 
   /* Okay, this one is new to us. */
+  if (do_not_add)
+    return KEYPIN_NOT_FOUND;
+
   ent = tor_memdup(&search, sizeof(search));
   keypin_add_entry_to_map(ent);
   keypin_journal_append_entry(rsa_id_digest, ed25519_id_key);
diff --git a/src/or/keypin.h b/src/or/keypin.h
index 16a0775..2a5b3f1 100644
--- a/src/or/keypin.h
+++ b/src/or/keypin.h
@@ -8,6 +8,8 @@
 
 int keypin_check_and_add(const uint8_t *rsa_id_digest,
                          const uint8_t *ed25519_id_key);
+int keypin_check(const uint8_t *rsa_id_digest,
+                 const uint8_t *ed25519_id_key);
 
 int keypin_open_journal(const char *fname);
 int keypin_close_journal(void);
diff --git a/src/or/main.c b/src/or/main.c
index 8b82a31..70d075f 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -37,6 +37,7 @@
 #include "entrynodes.h"
 #include "geoip.h"
 #include "hibernate.h"
+#include "keypin.h"
 #include "main.h"
 #include "microdesc.h"
 #include "networkstatus.h"
@@ -1998,6 +1999,23 @@ do_main_loop(void)
   /* initialize the bootstrap status events to know we're starting up */
   control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
 
+  /* Initialize the keypinning log. */
+  if (authdir_mode_v3(get_options())) {
+    char *fname = get_datadir_fname("key-pinning-entries");
+    int r = 0;
+    if (keypin_load_journal(fname)<0) {
+      log_err(LD_DIR, "Error loading key-pinning journal: %s",strerror(errno));
+      r = -1;
+    }
+    if (keypin_open_journal(fname)<0) {
+      log_err(LD_DIR, "Error opening key-pinning journal: %s",strerror(errno));
+      r = -1;
+    }
+    tor_free(fname);
+    if (r)
+      return r;
+  }
+
   if (trusted_dirs_reload_certs()) {
     log_warn(LD_DIR,
              "Couldn't load all cached v3 certificates. Starting anyway.");
@@ -2707,6 +2725,7 @@ tor_cleanup(void)
     or_state_save(now);
     if (authdir_mode_tests_reachability(options))
       rep_hist_record_mtbf_data(now, 0);
+    keypin_close_journal();
   }
 #ifdef USE_DMALLOC
   dmalloc_log_stats();
diff --git a/src/or/router.c b/src/or/router.c
index 97c2b83..242ec05 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -2343,7 +2343,8 @@ router_dump_router_to_string(routerinfo_t *router,
         !ed25519_pubkey_eq(&router->signing_key_cert->signed_key,
                            &signing_keypair->pubkey)) {
       log_warn(LD_BUG, "Tried to sign a router descriptor with a mismatched "
-               "ed25519 key chain");
+               "ed25519 key chain %d",
+               router->signing_key_cert->signing_key_included);
       goto err;
     }
   }





More information about the tor-commits mailing list