Commit 592a4391 authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

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.)
parent eacbe03c
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -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);
+28 −0
Original line number Diff line number Diff line
@@ -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();
@@ -99,6 +102,28 @@ HT_GENERATE2(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
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));
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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);
+19 −0
Original line number Diff line number Diff line
@@ -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();
+2 −1
Original line number Diff line number Diff line
@@ -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;
    }
  }