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.)
This commit is contained in:
Nick Mathewson 2014-10-08 08:32:00 -04:00
parent eacbe03c71
commit 592a439107
5 changed files with 115 additions and 1 deletions

View File

@ -18,6 +18,7 @@
#include "dirserv.h" #include "dirserv.h"
#include "dirvote.h" #include "dirvote.h"
#include "hibernate.h" #include "hibernate.h"
#include "keypin.h"
#include "microdesc.h" #include "microdesc.h"
#include "networkstatus.h" #include "networkstatus.h"
#include "nodelist.h" #include "nodelist.h"
@ -27,6 +28,7 @@
#include "routerlist.h" #include "routerlist.h"
#include "routerparse.h" #include "routerparse.h"
#include "routerset.h" #include "routerset.h"
#include "torcert.h"
/** /**
* \file dirserv.c * \file dirserv.c
@ -225,6 +227,16 @@ dirserv_load_fingerprint_file(void)
return 0; 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 /** 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 * we recognize from the fingerprint list, or an IP we automatically act on
* according to our configuration. Return the appropriate router status. * 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; 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, return dirserv_get_status_impl(d, router->nickname,
router->addr, router->or_port, router->addr, router->or_port,
router->platform, msg, 1); 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; 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 /* Make a copy of desc, since router_add_to_routerlist might free
* ri and its associated signed_descriptor_t. */ * ri and its associated signed_descriptor_t. */
desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen); desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);

View File

@ -44,6 +44,9 @@
static int keypin_journal_append_entry(const uint8_t *rsa_id_digest, static int keypin_journal_append_entry(const uint8_t *rsa_id_digest,
const uint8_t *ed25519_id_key); 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(rsamap, keypin_ent_st) the_rsa_map = HT_INITIALIZER();
static HT_HEAD(edmap, keypin_ent_st) the_ed_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 int
keypin_check_and_add(const uint8_t *rsa_id_digest, keypin_check_and_add(const uint8_t *rsa_id_digest,
const uint8_t *ed25519_id_key) 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; keypin_ent_t search, *ent;
memset(&search, 0, sizeof(search)); 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. */ /* Okay, this one is new to us. */
if (do_not_add)
return KEYPIN_NOT_FOUND;
ent = tor_memdup(&search, sizeof(search)); ent = tor_memdup(&search, sizeof(search));
keypin_add_entry_to_map(ent); keypin_add_entry_to_map(ent);
keypin_journal_append_entry(rsa_id_digest, ed25519_id_key); keypin_journal_append_entry(rsa_id_digest, ed25519_id_key);

View File

@ -8,6 +8,8 @@
int keypin_check_and_add(const uint8_t *rsa_id_digest, int keypin_check_and_add(const uint8_t *rsa_id_digest,
const uint8_t *ed25519_id_key); 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_open_journal(const char *fname);
int keypin_close_journal(void); int keypin_close_journal(void);

View File

@ -37,6 +37,7 @@
#include "entrynodes.h" #include "entrynodes.h"
#include "geoip.h" #include "geoip.h"
#include "hibernate.h" #include "hibernate.h"
#include "keypin.h"
#include "main.h" #include "main.h"
#include "microdesc.h" #include "microdesc.h"
#include "networkstatus.h" #include "networkstatus.h"
@ -1998,6 +1999,23 @@ do_main_loop(void)
/* initialize the bootstrap status events to know we're starting up */ /* initialize the bootstrap status events to know we're starting up */
control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0); 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()) { if (trusted_dirs_reload_certs()) {
log_warn(LD_DIR, log_warn(LD_DIR,
"Couldn't load all cached v3 certificates. Starting anyway."); "Couldn't load all cached v3 certificates. Starting anyway.");
@ -2707,6 +2725,7 @@ tor_cleanup(void)
or_state_save(now); or_state_save(now);
if (authdir_mode_tests_reachability(options)) if (authdir_mode_tests_reachability(options))
rep_hist_record_mtbf_data(now, 0); rep_hist_record_mtbf_data(now, 0);
keypin_close_journal();
} }
#ifdef USE_DMALLOC #ifdef USE_DMALLOC
dmalloc_log_stats(); dmalloc_log_stats();

View File

@ -2343,7 +2343,8 @@ router_dump_router_to_string(routerinfo_t *router,
!ed25519_pubkey_eq(&router->signing_key_cert->signed_key, !ed25519_pubkey_eq(&router->signing_key_cert->signed_key,
&signing_keypair->pubkey)) { &signing_keypair->pubkey)) {
log_warn(LD_BUG, "Tried to sign a router descriptor with a mismatched " 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; goto err;
} }
} }