mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
Merge branch 'ticket22029_attempt_squashed'
This commit is contained in:
commit
93894fb770
5
changes/bug22029
Normal file
5
changes/bug22029
Normal file
@ -0,0 +1,5 @@
|
||||
o Major features (directory authority, ed25519):
|
||||
Add support for banning a relay's ed25519 keys in the approved-routers
|
||||
file. This will allow us to migrate away from RSA keys in the future.
|
||||
Previously, only RSA keys could be banned in approved-routers. Resolves
|
||||
ticket 22029. Patch by Neel Chauhan.
|
@ -3623,13 +3623,14 @@ __DataDirectory__/**`hashed-fingerprint`**::
|
||||
identity key. (That is, the hash of the hash of the identity key.)
|
||||
|
||||
__DataDirectory__/**`approved-routers`**::
|
||||
Only used by authoritative directory servers. This file lists the status of
|
||||
routers by their identity fingerprint. Each line lists a status and a
|
||||
fingerprint separated by whitespace. See your **`fingerprint`** file in the
|
||||
__DataDirectory__ for an example line. If the status is **!reject**, then
|
||||
the descriptors from the given identity (fingerprint) are rejected by this
|
||||
server. If it is **!invalid**, then the descriptors are accepted but marked
|
||||
in the directory as not valid, that is, not recommended.
|
||||
Only used by authoritative directory servers. This file lists the status
|
||||
and a fingerprint/pubkey. Each line lists a status and a fingerprint
|
||||
separated by whitespace. See your **fingerprint** file in the
|
||||
__DataDirectory__ for an example fingerprint line. If the status is
|
||||
**!reject** then descriptors from the given identity (fingerprint/pubkey)
|
||||
are rejected by this server. If it is **!invalid** then descriptors are
|
||||
accepted but marked in the directory as not valid, that is, not
|
||||
recommended.
|
||||
|
||||
__DataDirectory__/**`v3-status-votes`**::
|
||||
Only for v3 authoritative directory servers. This file contains status
|
||||
|
@ -12,6 +12,8 @@
|
||||
* them make those decisions.
|
||||
**/
|
||||
|
||||
#define PROCESS_DESCS_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirauth/process_descs.h"
|
||||
|
||||
@ -23,6 +25,7 @@
|
||||
#include "feature/dirclient/dlstatus.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/nodelist/describe.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerinfo.h"
|
||||
@ -34,44 +37,25 @@
|
||||
#include "core/or/tor_version_st.h"
|
||||
#include "feature/nodelist/extrainfo_st.h"
|
||||
#include "feature/nodelist/node_st.h"
|
||||
#include "feature/nodelist/microdesc_st.h"
|
||||
#include "feature/nodelist/routerinfo_st.h"
|
||||
#include "feature/nodelist/routerstatus_st.h"
|
||||
#include "feature/nodelist/vote_routerstatus_st.h"
|
||||
|
||||
#include "lib/encoding/confline.h"
|
||||
#include "lib/crypt_ops/crypto_format.h"
|
||||
|
||||
/** How far in the future do we allow a router to get? (seconds) */
|
||||
#define ROUTER_ALLOW_SKEW (60*60*12)
|
||||
|
||||
static void directory_remove_invalid(void);
|
||||
struct authdir_config_t;
|
||||
static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
|
||||
const char **msg);
|
||||
static uint32_t
|
||||
dirserv_get_status_impl(const char *fp, const char *nickname,
|
||||
uint32_t addr, uint16_t or_port,
|
||||
const char *platform, const char **msg,
|
||||
int severity);
|
||||
|
||||
/* 1 Historically used to indicate Named */
|
||||
#define RTR_INVALID 2 /**< Believed invalid. */
|
||||
#define RTR_REJECT 4 /**< We will not publish this router. */
|
||||
/* 8 Historically used to avoid using this as a dir. */
|
||||
#define RTR_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
|
||||
/* 32 Historically used to indicade Unnamed */
|
||||
|
||||
/** Target of status_by_digest map. */
|
||||
typedef uint32_t rtr_flags_t;
|
||||
|
||||
static void add_fingerprint_to_dir(const char *fp,
|
||||
struct authdir_config_t *list,
|
||||
rtr_flags_t add_status);
|
||||
|
||||
/** List of nickname-\>identity fingerprint mappings for all the routers
|
||||
* that we name. Used to prevent router impersonation. */
|
||||
typedef struct authdir_config_t {
|
||||
strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */
|
||||
digestmap_t *status_by_digest; /**< Map from digest to rtr_flags_t. */
|
||||
} authdir_config_t;
|
||||
dirserv_get_status_impl(const char *id_digest,
|
||||
const ed25519_public_key_t *ed25519_public_key,
|
||||
const char *nickname, uint32_t addr, uint16_t or_port,
|
||||
const char *platform, const char **msg, int severity);
|
||||
|
||||
/** Should be static; exposed for testing. */
|
||||
static authdir_config_t *fingerprint_list = NULL;
|
||||
@ -83,16 +67,35 @@ authdir_config_new(void)
|
||||
authdir_config_t *list = tor_malloc_zero(sizeof(authdir_config_t));
|
||||
list->fp_by_name = strmap_new();
|
||||
list->status_by_digest = digestmap_new();
|
||||
list->status_by_digest256 = digest256map_new();
|
||||
return list;
|
||||
}
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
|
||||
/** Initialize fingerprint_list to a new authdir_config_t. Used for tests. */
|
||||
void
|
||||
authdir_init_fingerprint_list(void)
|
||||
{
|
||||
fingerprint_list = authdir_config_new();
|
||||
}
|
||||
|
||||
/* Return the current fingerprint_list. Used for tests. */
|
||||
authdir_config_t *
|
||||
authdir_return_fingerprint_list(void)
|
||||
{
|
||||
return fingerprint_list;
|
||||
}
|
||||
|
||||
#endif /* defined(TOR_UNIT_TESTS) */
|
||||
|
||||
/** Add the fingerprint <b>fp</b> to the smartlist of fingerprint_entry_t's
|
||||
* <b>list</b>, or-ing the currently set status flags with
|
||||
* <b>add_status</b>.
|
||||
*/
|
||||
/* static */ void
|
||||
add_fingerprint_to_dir(const char *fp, authdir_config_t *list,
|
||||
rtr_flags_t add_status)
|
||||
int
|
||||
add_rsa_fingerprint_to_dir(const char *fp, authdir_config_t *list,
|
||||
rtr_flags_t add_status)
|
||||
{
|
||||
char *fingerprint;
|
||||
char d[DIGEST_LEN];
|
||||
@ -107,7 +110,7 @@ add_fingerprint_to_dir(const char *fp, authdir_config_t *list,
|
||||
log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"",
|
||||
escaped(fp));
|
||||
tor_free(fingerprint);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = digestmap_get(list->status_by_digest, d);
|
||||
@ -118,13 +121,41 @@ add_fingerprint_to_dir(const char *fp, authdir_config_t *list,
|
||||
|
||||
tor_free(fingerprint);
|
||||
*status |= add_status;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Add the ed25519 key <b>edkey</b> to the smartlist of fingerprint_entry_t's
|
||||
* <b>list</b>, or-ing the currently set status flags with <b>add_status</b>.
|
||||
* Return -1 if we were unable to decode the key, else return 0.
|
||||
*/
|
||||
int
|
||||
add_ed25519_to_dir(const ed25519_public_key_t *edkey, authdir_config_t *list,
|
||||
rtr_flags_t add_status)
|
||||
{
|
||||
rtr_flags_t *status;
|
||||
|
||||
tor_assert(edkey);
|
||||
tor_assert(list);
|
||||
|
||||
if (ed25519_validate_pubkey(edkey) < 0) {
|
||||
log_warn(LD_DIRSERV, "Invalid ed25519 key \"%s\"", ed25519_fmt(edkey));
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = digest256map_get(list->status_by_digest256, edkey->pubkey);
|
||||
if (!status) {
|
||||
status = tor_malloc_zero(sizeof(rtr_flags_t));
|
||||
digest256map_set(list->status_by_digest256, edkey->pubkey, status);
|
||||
}
|
||||
|
||||
*status |= add_status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Add the fingerprint for this OR to the global list of recognized
|
||||
* identity key fingerprints. */
|
||||
int
|
||||
dirserv_add_own_fingerprint(crypto_pk_t *pk)
|
||||
dirserv_add_own_fingerprint(crypto_pk_t *pk, const ed25519_public_key_t *edkey)
|
||||
{
|
||||
char fp[FINGERPRINT_LEN+1];
|
||||
if (crypto_pk_get_fingerprint(pk, fp, 0)<0) {
|
||||
@ -133,7 +164,14 @@ dirserv_add_own_fingerprint(crypto_pk_t *pk)
|
||||
}
|
||||
if (!fingerprint_list)
|
||||
fingerprint_list = authdir_config_new();
|
||||
add_fingerprint_to_dir(fp, fingerprint_list, 0);
|
||||
if (add_rsa_fingerprint_to_dir(fp, fingerprint_list, 0) < 0) {
|
||||
log_err(LD_BUG, "Error adding RSA fingerprint");
|
||||
return -1;
|
||||
}
|
||||
if (add_ed25519_to_dir(edkey, fingerprint_list, 0) < 0) {
|
||||
log_err(LD_BUG, "Error adding ed25519 key");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -174,19 +212,11 @@ dirserv_load_fingerprint_file(void)
|
||||
fingerprint_list_new = authdir_config_new();
|
||||
|
||||
for (list=front; list; list=list->next) {
|
||||
char digest_tmp[DIGEST_LEN];
|
||||
rtr_flags_t add_status = 0;
|
||||
nickname = list->key; fingerprint = list->value;
|
||||
tor_strstrip(fingerprint, " "); /* remove spaces */
|
||||
if (strlen(fingerprint) != HEX_DIGEST_LEN ||
|
||||
base16_decode(digest_tmp, sizeof(digest_tmp),
|
||||
fingerprint, HEX_DIGEST_LEN) != sizeof(digest_tmp)) {
|
||||
log_notice(LD_CONFIG,
|
||||
"Invalid fingerprint (nickname '%s', "
|
||||
"fingerprint %s). Skipping.",
|
||||
nickname, fingerprint);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Determine what we should do with the relay with the nickname field. */
|
||||
if (!strcasecmp(nickname, "!reject")) {
|
||||
add_status = RTR_REJECT;
|
||||
} else if (!strcasecmp(nickname, "!badexit")) {
|
||||
@ -194,7 +224,34 @@ dirserv_load_fingerprint_file(void)
|
||||
} else if (!strcasecmp(nickname, "!invalid")) {
|
||||
add_status = RTR_INVALID;
|
||||
}
|
||||
add_fingerprint_to_dir(fingerprint, fingerprint_list_new, add_status);
|
||||
|
||||
/* Check if fingerprint is RSA or ed25519 by verifying it. */
|
||||
int ed25519_not_ok = -1, rsa_not_ok = -1;
|
||||
|
||||
/* Attempt to add the RSA key. */
|
||||
if (strlen(fingerprint) == HEX_DIGEST_LEN) {
|
||||
rsa_not_ok = add_rsa_fingerprint_to_dir(fingerprint,
|
||||
fingerprint_list_new,
|
||||
add_status);
|
||||
}
|
||||
|
||||
/* Check ed25519 key. We check the size to prevent buffer overflows.
|
||||
* If valid, attempt to add it, */
|
||||
ed25519_public_key_t ed25519_pubkey_tmp;
|
||||
if (strlen(fingerprint) == BASE64_DIGEST256_LEN) {
|
||||
if (!digest256_from_base64((char *) ed25519_pubkey_tmp.pubkey,
|
||||
fingerprint)) {
|
||||
ed25519_not_ok = add_ed25519_to_dir(&ed25519_pubkey_tmp,
|
||||
fingerprint_list_new, add_status);
|
||||
}
|
||||
}
|
||||
|
||||
/* If both keys are invalid (or missing), log and skip. */
|
||||
if (ed25519_not_ok && rsa_not_ok) {
|
||||
log_warn(LD_CONFIG, "Invalid fingerprint (nickname '%s', "
|
||||
"fingerprint %s). Skipping.", nickname, fingerprint);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
config_free_lines(front);
|
||||
@ -233,6 +290,8 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
|
||||
{
|
||||
char d[DIGEST_LEN];
|
||||
const int key_pinning = get_options()->AuthDirPinKeys;
|
||||
uint32_t r;
|
||||
ed25519_public_key_t *signing_key = NULL;
|
||||
|
||||
if (crypto_pk_get_digest(router->identity_pkey, d)) {
|
||||
log_warn(LD_BUG,"Error computing fingerprint");
|
||||
@ -241,10 +300,15 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
|
||||
return RTR_REJECT;
|
||||
}
|
||||
|
||||
/* Check for the more common reasons to reject a router first. */
|
||||
const uint32_t r = dirserv_get_status_impl(d, router->nickname,
|
||||
router->addr, router->or_port,
|
||||
router->platform, msg, severity);
|
||||
/* First, check for the more common reasons to reject a router. */
|
||||
if (router->cache_info.signing_key_cert) {
|
||||
/* This has an ed25519 identity key. */
|
||||
signing_key = &router->cache_info.signing_key_cert->signing_key;
|
||||
}
|
||||
r = dirserv_get_status_impl(d, signing_key, router->nickname, router->addr,
|
||||
router->or_port, router->platform, msg,
|
||||
severity);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@ -304,13 +368,15 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
|
||||
/** Return true if there is no point in downloading the router described by
|
||||
* <b>rs</b> because this directory would reject it. */
|
||||
int
|
||||
dirserv_would_reject_router(const routerstatus_t *rs)
|
||||
dirserv_would_reject_router(const routerstatus_t *rs,
|
||||
const vote_routerstatus_t *vrs)
|
||||
{
|
||||
uint32_t res;
|
||||
struct ed25519_public_key_t pk;
|
||||
memcpy(&pk.pubkey, vrs->ed25519_id, ED25519_PUBKEY_LEN);
|
||||
|
||||
res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
|
||||
rs->addr, rs->or_port,
|
||||
NULL, NULL, LOG_DEBUG);
|
||||
res = dirserv_get_status_impl(rs->identity_digest, &pk, rs->nickname,
|
||||
rs->addr, rs->or_port, NULL, NULL, LOG_DEBUG);
|
||||
|
||||
return (res & RTR_REJECT) != 0;
|
||||
}
|
||||
@ -357,15 +423,16 @@ dirserv_rejects_tor_version(const char *platform,
|
||||
}
|
||||
|
||||
/** Helper: As dirserv_router_get_status, but takes the router fingerprint
|
||||
* (hex, no spaces), nickname, address (used for logging only), IP address, OR
|
||||
* port and platform (logging only) as arguments.
|
||||
* (hex, no spaces), ed25519 key, nickname, address (used for logging only),
|
||||
* IP address, OR port and platform (logging only) as arguments.
|
||||
*
|
||||
* Log messages at 'severity'. (There's not much point in
|
||||
* logging that we're rejecting servers we'll not download.)
|
||||
*/
|
||||
static uint32_t
|
||||
dirserv_get_status_impl(const char *id_digest, const char *nickname,
|
||||
uint32_t addr, uint16_t or_port,
|
||||
dirserv_get_status_impl(const char *id_digest,
|
||||
const ed25519_public_key_t *ed25519_public_key,
|
||||
const char *nickname, uint32_t addr, uint16_t or_port,
|
||||
const char *platform, const char **msg, int severity)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
@ -398,16 +465,23 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
|
||||
if (status_by_digest)
|
||||
result |= *status_by_digest;
|
||||
|
||||
if (ed25519_public_key) {
|
||||
status_by_digest = digest256map_get(fingerprint_list->status_by_digest256,
|
||||
ed25519_public_key->pubkey);
|
||||
if (status_by_digest)
|
||||
result |= *status_by_digest;
|
||||
}
|
||||
|
||||
if (result & RTR_REJECT) {
|
||||
if (msg)
|
||||
*msg = "Fingerprint is marked rejected -- if you think this is a "
|
||||
"mistake please set a valid email address in ContactInfo and "
|
||||
"send an email to bad-relays@lists.torproject.org mentioning "
|
||||
"your fingerprint(s)?";
|
||||
*msg = "Fingerprint and/or ed25519 identity is marked rejected -- if "
|
||||
"you think this is a mistake please set a valid email address "
|
||||
"in ContactInfo and send an email to "
|
||||
"bad-relays@lists.torproject.org mentioning your fingerprint(s)?";
|
||||
return RTR_REJECT;
|
||||
} else if (result & RTR_INVALID) {
|
||||
if (msg)
|
||||
*msg = "Fingerprint is marked invalid";
|
||||
*msg = "Fingerprint and/or ed25519 identity is marked invalid";
|
||||
}
|
||||
|
||||
if (authdir_policy_badexit_address(addr, or_port)) {
|
||||
@ -446,6 +520,7 @@ dirserv_free_fingerprint_list(void)
|
||||
|
||||
strmap_free(fingerprint_list->fp_by_name, tor_free_);
|
||||
digestmap_free(fingerprint_list->status_by_digest, tor_free_);
|
||||
digest256map_free(fingerprint_list->status_by_digest256, tor_free_);
|
||||
tor_free(fingerprint_list);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,48 @@
|
||||
// for was_router_added_t.
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
|
||||
#include "src/lib/crypt_ops/crypto_ed25519.h"
|
||||
|
||||
struct authdir_config_t;
|
||||
|
||||
/** Target of status_by_digest map. */
|
||||
typedef uint32_t rtr_flags_t;
|
||||
|
||||
int add_rsa_fingerprint_to_dir(const char *fp, struct authdir_config_t *list,
|
||||
rtr_flags_t add_status);
|
||||
|
||||
int add_ed25519_to_dir(const ed25519_public_key_t *edkey,
|
||||
struct authdir_config_t *list,
|
||||
rtr_flags_t add_status);
|
||||
|
||||
/** List of nickname-\>identity fingerprint mappings for all the routers
|
||||
* that we name. Used to prevent router impersonation. */
|
||||
typedef struct authdir_config_t {
|
||||
strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */
|
||||
digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */
|
||||
digest256map_t *status_by_digest256; /**< Map from digest256 to
|
||||
* router_status_t. */
|
||||
} authdir_config_t;
|
||||
|
||||
#if defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS)
|
||||
|
||||
/* 1 Historically used to indicate Named */
|
||||
#define RTR_INVALID 2 /**< Believed invalid. */
|
||||
#define RTR_REJECT 4 /**< We will not publish this router. */
|
||||
/* 8 Historically used to avoid using this as a dir. */
|
||||
#define RTR_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
|
||||
/* 32 Historically used to indicade Unnamed */
|
||||
|
||||
#endif /* defined(TOR_UNIT_TESTS) */
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
|
||||
void authdir_init_fingerprint_list(void);
|
||||
|
||||
authdir_config_t *authdir_return_fingerprint_list(void);
|
||||
|
||||
#endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */
|
||||
|
||||
void dirserv_free_fingerprint_list(void);
|
||||
|
||||
#ifdef HAVE_MODULE_DIRAUTH
|
||||
@ -28,11 +70,13 @@ enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri,
|
||||
const char **msg,
|
||||
const char *source);
|
||||
|
||||
int dirserv_would_reject_router(const routerstatus_t *rs);
|
||||
int dirserv_would_reject_router(const routerstatus_t *rs,
|
||||
const vote_routerstatus_t *vrs);
|
||||
int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
|
||||
int complain,
|
||||
int *valid_out);
|
||||
int dirserv_add_own_fingerprint(crypto_pk_t *pk);
|
||||
int dirserv_add_own_fingerprint(crypto_pk_t *pk,
|
||||
const ed25519_public_key_t *edkey);
|
||||
uint32_t dirserv_router_get_status(const routerinfo_t *router,
|
||||
const char **msg,
|
||||
int severity);
|
||||
@ -68,9 +112,11 @@ dirserv_add_descriptor(routerinfo_t *ri,
|
||||
return (enum was_router_added_t)0;
|
||||
}
|
||||
static inline int
|
||||
dirserv_would_reject_router(const routerstatus_t *rs)
|
||||
dirserv_would_reject_router(const routerstatus_t *rs,
|
||||
const vote_routerstatus_t *vrs)
|
||||
{
|
||||
(void)rs;
|
||||
(void)vrs;
|
||||
return 0;
|
||||
}
|
||||
static inline int
|
||||
@ -85,9 +131,10 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
|
||||
return 0;
|
||||
}
|
||||
static inline int
|
||||
dirserv_add_own_fingerprint(crypto_pk_t *pk)
|
||||
dirserv_add_own_fingerprint(crypto_pk_t *pk, const ed25519_public_key_t *edkey)
|
||||
{
|
||||
(void)pk;
|
||||
(void)edkey;
|
||||
return 0;
|
||||
}
|
||||
static inline uint32_t
|
||||
|
@ -2558,8 +2558,15 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
|
||||
map = digestmap_new();
|
||||
list_pending_descriptor_downloads(map, 0);
|
||||
SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, void *, rsp) {
|
||||
routerstatus_t *rs =
|
||||
is_vote ? &(((vote_routerstatus_t *)rsp)->status) : rsp;
|
||||
routerstatus_t *rs;
|
||||
vote_routerstatus_t *vrs;
|
||||
if (is_vote) {
|
||||
rs = &(((vote_routerstatus_t *)rsp)->status);
|
||||
vrs = rsp;
|
||||
} else {
|
||||
rs = rsp;
|
||||
vrs = NULL;
|
||||
}
|
||||
signed_descriptor_t *sd;
|
||||
if ((sd = router_get_by_descriptor_digest(rs->descriptor_digest))) {
|
||||
const routerinfo_t *ri;
|
||||
@ -2584,7 +2591,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
|
||||
++n_delayed; /* Not ready for retry. */
|
||||
continue;
|
||||
}
|
||||
if (authdir && dirserv_would_reject_router(rs)) {
|
||||
if (authdir && is_vote && dirserv_would_reject_router(rs, vrs)) {
|
||||
++n_would_reject;
|
||||
continue; /* We would throw it out immediately. */
|
||||
}
|
||||
|
@ -1074,8 +1074,10 @@ init_keys(void)
|
||||
if (authdir_mode_v3(options)) {
|
||||
const char *m = NULL;
|
||||
routerinfo_t *ri;
|
||||
/* We need to add our own fingerprint so it gets recognized. */
|
||||
if (dirserv_add_own_fingerprint(get_server_identity_key())) {
|
||||
/* We need to add our own fingerprint and ed25519 key so it gets
|
||||
* recognized. */
|
||||
if (dirserv_add_own_fingerprint(get_server_identity_key(),
|
||||
get_master_identity_key())) {
|
||||
log_err(LD_GENERAL,"Error adding own fingerprint to set of relays");
|
||||
return -1;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/nodelist/node_select.h"
|
||||
@ -77,6 +78,7 @@
|
||||
#include "feature/nodelist/authority_cert_st.h"
|
||||
#include "feature/nodelist/document_signature_st.h"
|
||||
#include "feature/nodelist/extrainfo_st.h"
|
||||
#include "feature/nodelist/microdesc_st.h"
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
#include "feature/nodelist/networkstatus_voter_info_st.h"
|
||||
#include "feature/dirauth/ns_detached_signatures_st.h"
|
||||
@ -7208,6 +7210,300 @@ test_dir_format_versions_list(void *arg)
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
static void
|
||||
test_dir_add_fingerprint(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
authdir_config_t *list;
|
||||
int ret;
|
||||
ed25519_secret_key_t seckey;
|
||||
ed25519_public_key_t pubkey_good, pubkey_bad;
|
||||
|
||||
authdir_init_fingerprint_list();
|
||||
list = authdir_return_fingerprint_list();
|
||||
|
||||
setup_capture_of_logs(LOG_WARN);
|
||||
|
||||
/* RSA test - successful */
|
||||
ret = add_rsa_fingerprint_to_dir("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||
list, 0);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
/* RSA test - failure */
|
||||
ret = add_rsa_fingerprint_to_dir("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
|
||||
list, 0);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
|
||||
/* ed25519 test - successful */
|
||||
ed25519_secret_key_generate(&seckey, 0);
|
||||
ed25519_public_key_generate(&pubkey_good, &seckey);
|
||||
|
||||
ret = add_ed25519_to_dir(&pubkey_good, list, 0);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
|
||||
/* ed25519 test - failure */
|
||||
digest256_from_base64((char *) pubkey_bad.pubkey, "gibberish");
|
||||
|
||||
ret = add_ed25519_to_dir(&pubkey_bad, list, 0);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
|
||||
done:
|
||||
teardown_capture_of_logs();
|
||||
dirserv_free_fingerprint_list();
|
||||
}
|
||||
|
||||
static void
|
||||
test_dir_dirserv_load_fingerprint_file(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
char *fname = tor_strdup(get_fname("approved-routers"));
|
||||
|
||||
// Neither RSA nor ed25519
|
||||
const char *router_lines_invalid =
|
||||
"!badexit notafingerprint";
|
||||
const char *router_lines_too_long =
|
||||
"!badexit thisisareallylongstringthatislongerthanafingerprint\n";
|
||||
const char *router_lines_bad_fmt_str =
|
||||
"!badexit ABCDEFGH|%1$p|%2$p|%3$p|%4$p|%5$p|%6$p\n";
|
||||
const char *router_lines_valid_rsa =
|
||||
"!badexit AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n";
|
||||
const char *router_lines_invalid_rsa =
|
||||
"!badexit ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\n";
|
||||
const char *router_lines_valid_ed25519 =
|
||||
"!badexit wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n";
|
||||
const char *router_lines_invalid_ed25519 =
|
||||
"!badexit --fLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx--\n";
|
||||
|
||||
// Test: Invalid Fingerprint (not RSA or ed25519)
|
||||
setup_capture_of_logs(LOG_NOTICE);
|
||||
write_str_to_file(fname, router_lines_invalid, 0);
|
||||
tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
|
||||
expect_log_msg_containing("Invalid fingerprint");
|
||||
teardown_capture_of_logs();
|
||||
|
||||
// Test: Very long string (longer than RSA or ed25519 key)
|
||||
setup_capture_of_logs(LOG_NOTICE);
|
||||
write_str_to_file(fname, router_lines_too_long, 0);
|
||||
tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
|
||||
expect_log_msg_containing("Invalid fingerprint");
|
||||
teardown_capture_of_logs();
|
||||
|
||||
// Test: Formt string exploit
|
||||
setup_capture_of_logs(LOG_NOTICE);
|
||||
write_str_to_file(fname, router_lines_bad_fmt_str, 0);
|
||||
tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
|
||||
expect_log_msg_containing("Invalid fingerprint");
|
||||
teardown_capture_of_logs();
|
||||
|
||||
// Test: Valid RSA
|
||||
setup_capture_of_logs(LOG_NOTICE);
|
||||
write_str_to_file(fname, router_lines_valid_rsa, 0);
|
||||
tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
|
||||
teardown_capture_of_logs();
|
||||
|
||||
// Test: Invalid RSA
|
||||
setup_capture_of_logs(LOG_NOTICE);
|
||||
write_str_to_file(fname, router_lines_invalid_rsa, 0);
|
||||
tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
|
||||
expect_log_msg_containing("Invalid fingerprint");
|
||||
teardown_capture_of_logs();
|
||||
|
||||
// Test: Valid ed25519
|
||||
setup_capture_of_logs(LOG_NOTICE);
|
||||
write_str_to_file(fname, router_lines_valid_ed25519, 0);
|
||||
tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
|
||||
teardown_capture_of_logs();
|
||||
|
||||
// Test: Invalid ed25519
|
||||
setup_capture_of_logs(LOG_NOTICE);
|
||||
write_str_to_file(fname, router_lines_invalid_ed25519, 0);
|
||||
tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
|
||||
expect_log_msg_containing("Invalid fingerprint");
|
||||
teardown_capture_of_logs();
|
||||
|
||||
done:
|
||||
tor_free(fname);
|
||||
dirserv_free_fingerprint_list();
|
||||
}
|
||||
|
||||
#define RESET_FP_LIST(list) STMT_BEGIN \
|
||||
dirserv_free_fingerprint_list(); \
|
||||
authdir_init_fingerprint_list(); \
|
||||
list = authdir_return_fingerprint_list(); \
|
||||
STMT_END
|
||||
|
||||
static void
|
||||
test_dir_dirserv_router_get_status(void *arg)
|
||||
{
|
||||
authdir_config_t *list;
|
||||
routerinfo_t *ri = NULL;
|
||||
ed25519_keypair_t kp1, kp2;
|
||||
char d[DIGEST_LEN];
|
||||
char fp[HEX_DIGEST_LEN+1];
|
||||
int ret;
|
||||
const char *msg;
|
||||
time_t now = time(NULL);
|
||||
|
||||
(void)arg;
|
||||
|
||||
crypto_pk_t *pk = pk_generate(0);
|
||||
|
||||
authdir_init_fingerprint_list();
|
||||
list = authdir_return_fingerprint_list();
|
||||
|
||||
/* Set up the routerinfo */
|
||||
ri = tor_malloc_zero(sizeof(routerinfo_t));
|
||||
ri->addr = 0xc0a80001u;
|
||||
ri->or_port = 9001;
|
||||
ri->platform = tor_strdup("0.4.0.1-alpha");
|
||||
ri->nickname = tor_strdup("Jessica");
|
||||
ri->identity_pkey = crypto_pk_dup_key(pk);
|
||||
|
||||
curve25519_keypair_t ri_onion_keypair;
|
||||
curve25519_keypair_generate(&ri_onion_keypair, 0);
|
||||
ri->onion_curve25519_pkey = tor_memdup(&ri_onion_keypair.pubkey,
|
||||
sizeof(curve25519_public_key_t));
|
||||
|
||||
ed25519_secret_key_from_seed(&kp1.seckey,
|
||||
(const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
|
||||
ed25519_public_key_generate(&kp1.pubkey, &kp1.seckey);
|
||||
ed25519_secret_key_from_seed(&kp2.seckey,
|
||||
(const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
|
||||
ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
|
||||
ri->cache_info.signing_key_cert = tor_cert_create(&kp1,
|
||||
CERT_TYPE_ID_SIGNING,
|
||||
&kp2.pubkey,
|
||||
now, 86400,
|
||||
CERT_FLAG_INCLUDE_SIGNING_KEY);
|
||||
|
||||
crypto_pk_get_digest(ri->identity_pkey, d);
|
||||
base16_encode(fp, HEX_DIGEST_LEN + 1, d, DIGEST_LEN);
|
||||
|
||||
/* Try on an empty fingerprint list */
|
||||
ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
/* Try an accepted router */
|
||||
add_rsa_fingerprint_to_dir(fp, list, 0);
|
||||
ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
add_ed25519_to_dir(&kp1.pubkey, list, 0);
|
||||
ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
/* Try a rejected router */
|
||||
add_rsa_fingerprint_to_dir(fp, list, RTR_REJECT);
|
||||
ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
|
||||
tt_int_op(ret, OP_EQ, RTR_REJECT);
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
add_ed25519_to_dir(&kp1.pubkey, list, RTR_REJECT);
|
||||
ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
|
||||
tt_int_op(ret, OP_EQ, RTR_REJECT);
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
done:
|
||||
dirserv_free_fingerprint_list();
|
||||
routerinfo_free(ri);
|
||||
crypto_pk_free(pk);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dir_dirserv_would_reject_router(void *arg)
|
||||
{
|
||||
authdir_config_t *list;
|
||||
routerstatus_t rs;
|
||||
vote_routerstatus_t vrs;
|
||||
ed25519_keypair_t kp;
|
||||
char fp[HEX_DIGEST_LEN+1];
|
||||
|
||||
(void)arg;
|
||||
|
||||
authdir_init_fingerprint_list();
|
||||
list = authdir_return_fingerprint_list();
|
||||
|
||||
/* Set up the routerstatus */
|
||||
memset(&rs, 0, sizeof(rs));
|
||||
rs.addr = 0xc0a80001u;
|
||||
rs.or_port = 9001;
|
||||
strlcpy(rs.nickname, "Nicole", sizeof(rs.nickname));
|
||||
memcpy(rs.identity_digest, "Cloud nine is great ", DIGEST_LEN);
|
||||
|
||||
ed25519_secret_key_from_seed(&kp.seckey,
|
||||
(const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
|
||||
ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
|
||||
|
||||
base16_encode(fp, HEX_DIGEST_LEN + 1, rs.identity_digest, DIGEST_LEN);
|
||||
|
||||
/* Setup the vote_routerstatus_t. */
|
||||
memcpy(vrs.ed25519_id, &kp.pubkey, ED25519_PUBKEY_LEN);
|
||||
|
||||
/* Try an empty fingerprint list */
|
||||
tt_assert(!dirserv_would_reject_router(&rs, &vrs));
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
tt_assert(!dirserv_would_reject_router(&rs, &vrs));
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
/* Try an accepted router */
|
||||
add_rsa_fingerprint_to_dir(fp, list, 0);
|
||||
tt_assert(!dirserv_would_reject_router(&rs, &vrs));
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
add_ed25519_to_dir(&kp.pubkey, list, 0);
|
||||
tt_assert(!dirserv_would_reject_router(&rs, &vrs));
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
/* Try a rejected router */
|
||||
add_rsa_fingerprint_to_dir(fp, list, RTR_REJECT);
|
||||
tt_assert(dirserv_would_reject_router(&rs, &vrs));
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
add_ed25519_to_dir(&kp.pubkey, list, RTR_REJECT);
|
||||
tt_assert(dirserv_would_reject_router(&rs, &vrs));
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
done:
|
||||
dirserv_free_fingerprint_list();
|
||||
}
|
||||
|
||||
static void
|
||||
test_dir_dirserv_add_own_fingerprint(void *arg)
|
||||
{
|
||||
authdir_config_t *list;
|
||||
char digest[DIGEST_LEN];
|
||||
crypto_pk_t *pk = pk_generate(0);
|
||||
|
||||
(void)arg;
|
||||
|
||||
init_mock_ed_keys(pk);
|
||||
authdir_init_fingerprint_list();
|
||||
list = authdir_return_fingerprint_list();
|
||||
dirserv_add_own_fingerprint(pk, get_master_identity_key());
|
||||
|
||||
/* Check if we have a RSA key. */
|
||||
crypto_pk_get_digest(pk, digest);
|
||||
tt_assert(digestmap_get(list->status_by_digest, digest));
|
||||
|
||||
/* Check if we have a ed25519 key. */
|
||||
tt_assert(digest256map_get(list->status_by_digest256,
|
||||
get_master_identity_key()->pubkey));
|
||||
|
||||
RESET_FP_LIST(list);
|
||||
|
||||
done:
|
||||
dirserv_free_fingerprint_list();
|
||||
crypto_pk_free(pk);
|
||||
}
|
||||
|
||||
#ifndef COCCI
|
||||
#define DIR_LEGACY(name) \
|
||||
{ #name, test_dir_ ## name , TT_FORK, NULL, NULL }
|
||||
@ -7297,5 +7593,10 @@ struct testcase_t dir_tests[] = {
|
||||
DIR(platform_str, 0),
|
||||
DIR(networkstatus_consensus_has_ipv6, TT_FORK),
|
||||
DIR(format_versions_list, TT_FORK),
|
||||
DIR(add_fingerprint, TT_FORK),
|
||||
DIR(dirserv_load_fingerprint_file, TT_FORK),
|
||||
DIR(dirserv_router_get_status, TT_FORK),
|
||||
DIR(dirserv_would_reject_router, TT_FORK),
|
||||
DIR(dirserv_add_own_fingerprint, TT_FORK),
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user