mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
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:
parent
eacbe03c71
commit
592a439107
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user