Commit a395d1aa authored by Nick Mathewson's avatar Nick Mathewson 🥔
Browse files

Merge branch 'underpinning_squashed'

parents 2d139f77 51d18aeb
Loading
Loading
Loading
Loading

changes/bug17135

0 → 100644
+7 −0
Original line number Diff line number Diff line
  o Major features (Ed25519 keys, keypinning)
    - The key-pinning option on directory authorities is now
      advisory-only by default. In a future version, or when the
      AuthDirPinKeys option is set, pins are enforced again.
      Disabling key-pinning seemed like a good idea so that we can
      survive the fallout of any usability problems associated with
      ed25519 keys. Closes ticket 17135.
+7 −0
Original line number Diff line number Diff line
@@ -2081,6 +2081,13 @@ on the public Tor network.
    or more is always sufficient to satisfy the bandwidth requirement
    for the Guard flag. (Default: 250 KBytes)

[[AuthDirPinKeys]] **AuthDirPinKeys** **0**|**1**::
    Authoritative directories only. If non-zero, do not allow any relay to
    publish a descriptor if any other relay has reserved its <Ed25519,RSA>
    identity keypair. In all cases, Tor records every keypair it accepts
    in a journal if it is new, or if it differs from the most recently
    accepted pinning for one of the keys it contains. (Default: 0)

[[BridgePassword]] **BridgePassword** __Password__::
    If set, contains an HTTP authenticator that tells a bridge authority to
    serve all requested bridge information. Used by the (only partially
+1 −0
Original line number Diff line number Diff line
@@ -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"),
+17 −10
Original line number Diff line number Diff line
@@ -248,6 +248,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
                          int severity)
{
  char d[DIGEST_LEN];
  const int key_pinning = get_options()->AuthDirPinKeys;

  if (crypto_pk_get_digest(router->identity_pkey, d)) {
    log_warn(LD_BUG,"Error computing fingerprint");
@@ -261,15 +262,17 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
    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_fn(severity, LD_DIR,
             "Descriptor from router %s has an Ed25519 key, "
               "but the <rsa,ed25519> keys don't match what they were before.",
               router_describe(router));
      if (key_pinning) {
        if (msg) {
          *msg = "Ed25519 identity key or RSA identity key has changed.";
        }
        return FP_REJECT;
      }
    }
  } else {
    /* No ed25519 key */
    if (KEYPIN_MISMATCH == keypin_check_lone_rsa(
@@ -277,13 +280,15 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
      log_fn(severity, LD_DIR,
               "Descriptor from router %s has no Ed25519 key, "
               "when we previously knew an Ed25519 for it. Ignoring for now, "
               "since Tor 0.2.6 is under development.",
               "since Ed25519 keys are fairly new.",
               router_describe(router));
#ifdef DISABLE_DISABLING_ED25519
      if (key_pinning) {
        if (msg) {
          *msg = "Ed25519 identity key has disappeared.";
        }
        return FP_REJECT;
      }
#endif
    }
  }
@@ -582,6 +587,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
  char *desc, *nickname;
  const size_t desclen = ri->cache_info.signed_descriptor_len +
      ri->cache_info.annotations_len;
  const int key_pinning = get_options()->AuthDirPinKeys;
  *msg = NULL;

  /* If it's too big, refuse it now. Otherwise we'll cache it all over the
@@ -626,7 +632,8 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
  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);
      ri->signing_key_cert->signing_key.pubkey,
      ! key_pinning);
  } else {
    keypin_status = keypin_check_lone_rsa(
      (const uint8_t*)ri->cache_info.identity_digest);
@@ -635,7 +642,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
      keypin_status = KEYPIN_NOT_FOUND;
#endif
  }
  if (keypin_status == KEYPIN_MISMATCH) {
  if (keypin_status == KEYPIN_MISMATCH && key_pinning) {
    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);
+85 −27
Original line number Diff line number Diff line
@@ -48,7 +48,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);
                                     const int do_not_add,
                                     const int replace);
static int keypin_add_or_replace_entry_in_map(keypin_ent_t *ent);

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,12 +102,17 @@ HT_GENERATE2(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
 * return KEYPIN_FOUND. If we find an entry that matches one key but
 * not the other, return KEYPIN_MISMATCH.  If we have no entry for either
 * key, add such an entry to the table and return KEYPIN_ADDED.
 *
 * If <b>replace_existing_entry</b> is true, then any time we would have said
 * KEYPIN_FOUND, we instead add this entry anyway and return KEYPIN_ADDED.
 */
int
keypin_check_and_add(const uint8_t *rsa_id_digest,
                     const uint8_t *ed25519_id_key)
                     const uint8_t *ed25519_id_key,
                     const int replace_existing_entry)
{
  return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 0);
  return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 0,
                                   replace_existing_entry);
}

/**
@@ -116,7 +123,7 @@ 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);
  return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 1, 0);
}

/**
@@ -125,7 +132,8 @@ keypin_check(const uint8_t *rsa_id_digest,
static int
keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
                          const uint8_t *ed25519_id_key,
                          int do_not_add)
                          const int do_not_add,
                          const int replace)
{
  keypin_ent_t search, *ent;
  memset(&search, 0, sizeof(search));
@@ -139,11 +147,13 @@ keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
    if (tor_memeq(ent->ed25519_key, ed25519_id_key,sizeof(ent->ed25519_key))) {
      return KEYPIN_FOUND; /* Match on both keys. Great. */
    } else {
      if (!replace)
        return KEYPIN_MISMATCH; /* Found RSA with different Ed key */
    }
  }

  /* See if we know a different RSA key for this ed key */
  if (! replace) {
    ent = HT_FIND(edmap, &the_ed_map, &search);
    if (ent) {
      /* If we got here, then the ed key matches and the RSA doesn't */
@@ -152,13 +162,19 @@ keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
      tor_assert(fast_memneq(ent->rsa_id, rsa_id_digest, sizeof(ent->rsa_id)));
      return KEYPIN_MISMATCH;
    }
  }

  /* 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);
  int r = keypin_add_or_replace_entry_in_map(ent);
  if (! replace) {
    tor_assert(r == 1);
  } else {
    tor_assert(r != 0);
  }
  keypin_journal_append_entry(rsa_id_digest, ed25519_id_key);
  return KEYPIN_ADDED;
}
@@ -173,6 +189,57 @@ keypin_add_entry_to_map, (keypin_ent_t *ent))
  HT_INSERT(edmap, &the_ed_map, ent);
}

/**
 * Helper: add 'ent' to the maps, replacing any entries that contradict it.
 * Take ownership of 'ent', freeing it if needed.
 *
 * Return 0 if the entry was a duplicate, -1 if there was a conflict,
 * and 1 if there was no conflict.
 */
static int
keypin_add_or_replace_entry_in_map(keypin_ent_t *ent)
{
  int r = 1;
  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);
    return 0;
  } 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);
    r = -1;
    /* Fall through */
  }

  keypin_add_entry_to_map(ent);
  return r;
}

/**
 * Check whether we already have an entry in the key pinning table for a
 * router with RSA ID digest <b>rsa_id_digest</b>.  If we have no such entry,
@@ -321,22 +388,13 @@ 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)) {
    const int r = keypin_add_or_replace_entry_in_map(ent);
    if (r == 0) {
      ++n_duplicates;
      } else {
        ++n_conflicts;
      }
      tor_free(ent);
      continue;
    } else if (HT_FIND(edmap, &the_ed_map, ent)) {
      tor_free(ent);
    } else if (r == -1) {
      ++n_conflicts;
      continue;
    }

    keypin_add_entry_to_map(ent);
    ++n_entries;
  }

Loading