Merge branch 'maint-0.2.8'

This commit is contained in:
Nick Mathewson 2016-05-17 19:48:49 -04:00
commit a7f6e434be
7 changed files with 56 additions and 27 deletions

7
changes/bug17150 Normal file
View File

@ -0,0 +1,7 @@
o Minor bugfixes (directory warnings):
- When fetching extrainfo documents, compare their SHA256 digests
and Ed25519 signing key certificates
with the routerinfo that led us to fetch them, rather than
with the most recent routerinfo. Otherwise we generate many
spurious warnings about mismatches. Fixes bug 17150; bugfix
on 0.2.7.2-alpha.

View File

@ -691,12 +691,14 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
static was_router_added_t static was_router_added_t
dirserv_add_extrainfo(extrainfo_t *ei, const char **msg) dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
{ {
const routerinfo_t *ri; routerinfo_t *ri;
int r; int r;
tor_assert(msg); tor_assert(msg);
*msg = NULL; *msg = NULL;
ri = router_get_by_id_digest(ei->cache_info.identity_digest); /* Needs to be mutable so routerinfo_incompatible_with_extrainfo
* can mess with some of the flags in ri->cache_info. */
ri = router_get_mutable_by_digest(ei->cache_info.identity_digest);
if (!ri) { if (!ri) {
*msg = "No corresponding router descriptor for extra-info descriptor"; *msg = "No corresponding router descriptor for extra-info descriptor";
extrainfo_free(ei); extrainfo_free(ei);
@ -716,7 +718,8 @@ dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
return ROUTER_BAD_EI; return ROUTER_BAD_EI;
} }
if ((r = routerinfo_incompatible_with_extrainfo(ri, ei, NULL, msg))) { if ((r = routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei,
&ri->cache_info, msg))) {
extrainfo_free(ei); extrainfo_free(ei);
return r < 0 ? ROUTER_IS_ALREADY_KNOWN : ROUTER_BAD_EI; return r < 0 ? ROUTER_IS_ALREADY_KNOWN : ROUTER_BAD_EI;
} }

View File

@ -2070,6 +2070,10 @@ typedef struct signed_descriptor_t {
time_t published_on; time_t published_on;
/** For routerdescs only: digest of the corresponding extrainfo. */ /** For routerdescs only: digest of the corresponding extrainfo. */
char extra_info_digest[DIGEST_LEN]; char extra_info_digest[DIGEST_LEN];
/** For routerdescs only: A SHA256-digest of the extrainfo (if any) */
char extra_info_digest256[DIGEST256_LEN];
/** Certificate for ed25519 signing key. */
struct tor_cert_st *signing_key_cert;
/** For routerdescs only: Status of downloading the corresponding /** For routerdescs only: Status of downloading the corresponding
* extrainfo. */ * extrainfo. */
download_status_t ei_dl_status; download_status_t ei_dl_status;
@ -2101,8 +2105,6 @@ typedef int16_t country_t;
/** Information about another onion router in the network. */ /** Information about another onion router in the network. */
typedef struct { typedef struct {
signed_descriptor_t cache_info; signed_descriptor_t cache_info;
/** A SHA256-digest of the extrainfo (if any) */
char extra_info_digest256[DIGEST256_LEN];
char *nickname; /**< Human-readable OR name. */ char *nickname; /**< Human-readable OR name. */
uint32_t addr; /**< IPv4 address of OR, in host order. */ uint32_t addr; /**< IPv4 address of OR, in host order. */
@ -2120,7 +2122,8 @@ typedef struct {
crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */
/** Public curve25519 key for onions */ /** Public curve25519 key for onions */
curve25519_public_key_t *onion_curve25519_pkey; curve25519_public_key_t *onion_curve25519_pkey;
/** Certificate for ed25519 signing key */ /** Certificate for ed25519 signing key
* (XXXX duplicated in cache_info.) */
struct tor_cert_st *signing_key_cert; struct tor_cert_st *signing_key_cert;
/** What's the earliest expiration time on all the certs in this /** What's the earliest expiration time on all the certs in this
* routerinfo? */ * routerinfo? */
@ -2197,7 +2200,8 @@ typedef struct extrainfo_t {
uint8_t digest256[DIGEST256_LEN]; uint8_t digest256[DIGEST256_LEN];
/** The router's nickname. */ /** The router's nickname. */
char nickname[MAX_NICKNAME_LEN+1]; char nickname[MAX_NICKNAME_LEN+1];
/** Certificate for ed25519 signing key */ /** Certificate for ed25519 signing key
* (XXXX duplicated in cache_info.) */
struct tor_cert_st *signing_key_cert; struct tor_cert_st *signing_key_cert;
/** True iff we found the right key for this extra-info, verified the /** True iff we found the right key for this extra-info, verified the
* signature, and found it to be bad. */ * signature, and found it to be bad. */

View File

@ -2038,6 +2038,7 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
return -1; return -1;
} }
ri->signing_key_cert = tor_cert_dup(get_master_signing_key_cert()); ri->signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
ri->cache_info.signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
get_platform_str(platform, sizeof(platform)); get_platform_str(platform, sizeof(platform));
ri->platform = tor_strdup(platform); ri->platform = tor_strdup(platform);
@ -2130,6 +2131,8 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname)); strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname));
ei->cache_info.published_on = ri->cache_info.published_on; ei->cache_info.published_on = ri->cache_info.published_on;
ei->signing_key_cert = tor_cert_dup(get_master_signing_key_cert()); ei->signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
ei->cache_info.signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest, memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest,
DIGEST_LEN); DIGEST_LEN);
if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body, if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body,
@ -2155,7 +2158,7 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
memcpy(ri->cache_info.extra_info_digest, memcpy(ri->cache_info.extra_info_digest,
ei->cache_info.signed_descriptor_digest, ei->cache_info.signed_descriptor_digest,
DIGEST_LEN); DIGEST_LEN);
memcpy(ri->extra_info_digest256, memcpy(ri->cache_info.extra_info_digest256,
ei->digest256, ei->digest256,
DIGEST256_LEN); DIGEST256_LEN);
} else { } else {
@ -2196,7 +2199,8 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
ri->cache_info.signed_descriptor_digest); ri->cache_info.signed_descriptor_digest);
if (ei) { if (ei) {
tor_assert(! routerinfo_incompatible_with_extrainfo(ri, ei, NULL, NULL)); tor_assert(! routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei,
&ri->cache_info, NULL));
} }
*r = ri; *r = ri;
@ -2670,9 +2674,9 @@ router_dump_router_to_string(routerinfo_t *router,
char extra_info_digest[HEX_DIGEST_LEN+1]; char extra_info_digest[HEX_DIGEST_LEN+1];
base16_encode(extra_info_digest, sizeof(extra_info_digest), base16_encode(extra_info_digest, sizeof(extra_info_digest),
router->cache_info.extra_info_digest, DIGEST_LEN); router->cache_info.extra_info_digest, DIGEST_LEN);
if (!tor_digest256_is_zero(router->extra_info_digest256)) { if (!tor_digest256_is_zero(router->cache_info.extra_info_digest256)) {
char d256_64[BASE64_DIGEST256_LEN+1]; char d256_64[BASE64_DIGEST256_LEN+1];
digest256_to_base64(d256_64, router->extra_info_digest256); digest256_to_base64(d256_64, router->cache_info.extra_info_digest256);
tor_asprintf(&extra_info_line, "extra-info-digest %s %s\n", tor_asprintf(&extra_info_line, "extra-info-digest %s %s\n",
extra_info_digest, d256_64); extra_info_digest, d256_64);
} else { } else {

View File

@ -2954,6 +2954,7 @@ routerinfo_free(routerinfo_t *router)
if (router->identity_pkey) if (router->identity_pkey)
crypto_pk_free(router->identity_pkey); crypto_pk_free(router->identity_pkey);
tor_cert_free(router->signing_key_cert); tor_cert_free(router->signing_key_cert);
tor_cert_free(router->cache_info.signing_key_cert);
if (router->declared_family) { if (router->declared_family) {
SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s)); SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s));
smartlist_free(router->declared_family); smartlist_free(router->declared_family);
@ -2973,6 +2974,7 @@ extrainfo_free(extrainfo_t *extrainfo)
if (!extrainfo) if (!extrainfo)
return; return;
tor_cert_free(extrainfo->signing_key_cert); tor_cert_free(extrainfo->signing_key_cert);
tor_cert_free(extrainfo->cache_info.signing_key_cert);
tor_free(extrainfo->cache_info.signed_descriptor_body); tor_free(extrainfo->cache_info.signed_descriptor_body);
tor_free(extrainfo->pending_sig); tor_free(extrainfo->pending_sig);
@ -3182,7 +3184,7 @@ extrainfo_insert,(routerlist_t *rl, extrainfo_t *ei, int warn_if_incompatible))
"Mismatch in digest in extrainfo map."); "Mismatch in digest in extrainfo map.");
goto done; goto done;
} }
if (routerinfo_incompatible_with_extrainfo(ri, ei, sd, if (routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei, sd,
&compatibility_error_msg)) { &compatibility_error_msg)) {
char d1[HEX_DIGEST_LEN+1], d2[HEX_DIGEST_LEN+1]; char d1[HEX_DIGEST_LEN+1], d2[HEX_DIGEST_LEN+1];
r = (ri->cache_info.extrainfo_is_bogus) ? r = (ri->cache_info.extrainfo_is_bogus) ?
@ -5221,25 +5223,32 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
return 1; return 1;
} }
/** Check whether <b>ri</b> (a.k.a. sd) is a router compatible with the /** Check whether <b>sd</b> describes a router descriptor compatible with the
* extrainfo document * extrainfo document <b>ei</b>.
* <b>ei</b>. If no router is compatible with <b>ei</b>, <b>ei</b> should be *
* <b>identity_pkey</b> (which must also be provided) is RSA1024 identity key
* for the router. We use it to check the signature of the extrainfo document,
* if it has not already been checked.
*
* If no router is compatible with <b>ei</b>, <b>ei</b> should be
* dropped. Return 0 for "compatible", return 1 for "reject, and inform * dropped. Return 0 for "compatible", return 1 for "reject, and inform
* whoever uploaded <b>ei</b>, and return -1 for "reject silently.". If * whoever uploaded <b>ei</b>, and return -1 for "reject silently.". If
* <b>msg</b> is present, set *<b>msg</b> to a description of the * <b>msg</b> is present, set *<b>msg</b> to a description of the
* incompatibility (if any). * incompatibility (if any).
*
* Set the extrainfo_is_bogus field in <b>sd</b> if the digests matched
* but the extrainfo was nonetheless incompatible.
**/ **/
int int
routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri, routerinfo_incompatible_with_extrainfo(const crypto_pk_t *identity_pkey,
extrainfo_t *ei, extrainfo_t *ei,
signed_descriptor_t *sd, signed_descriptor_t *sd,
const char **msg) const char **msg)
{ {
int digest_matches, digest256_matches, r=1; int digest_matches, digest256_matches, r=1;
tor_assert(ri); tor_assert(identity_pkey);
tor_assert(sd);
tor_assert(ei); tor_assert(ei);
if (!sd)
sd = (signed_descriptor_t*)&ri->cache_info;
if (ei->bad_sig) { if (ei->bad_sig) {
if (msg) *msg = "Extrainfo signature was bad, or signed with wrong key."; if (msg) *msg = "Extrainfo signature was bad, or signed with wrong key.";
@ -5251,27 +5260,27 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri,
/* Set digest256_matches to 1 if the digest is correct, or if no /* Set digest256_matches to 1 if the digest is correct, or if no
* digest256 was in the ri. */ * digest256 was in the ri. */
digest256_matches = tor_memeq(ei->digest256, digest256_matches = tor_memeq(ei->digest256,
ri->extra_info_digest256, DIGEST256_LEN); sd->extra_info_digest256, DIGEST256_LEN);
digest256_matches |= digest256_matches |=
tor_mem_is_zero(ri->extra_info_digest256, DIGEST256_LEN); tor_mem_is_zero(sd->extra_info_digest256, DIGEST256_LEN);
/* The identity must match exactly to have been generated at the same time /* The identity must match exactly to have been generated at the same time
* by the same router. */ * by the same router. */
if (tor_memneq(ri->cache_info.identity_digest, if (tor_memneq(sd->identity_digest,
ei->cache_info.identity_digest, ei->cache_info.identity_digest,
DIGEST_LEN)) { DIGEST_LEN)) {
if (msg) *msg = "Extrainfo nickname or identity did not match routerinfo"; if (msg) *msg = "Extrainfo nickname or identity did not match routerinfo";
goto err; /* different servers */ goto err; /* different servers */
} }
if (! tor_cert_opt_eq(ri->signing_key_cert, ei->signing_key_cert)) { if (! tor_cert_opt_eq(sd->signing_key_cert, ei->signing_key_cert)) {
if (msg) *msg = "Extrainfo signing key cert didn't match routerinfo"; if (msg) *msg = "Extrainfo signing key cert didn't match routerinfo";
goto err; /* different servers */ goto err; /* different servers */
} }
if (ei->pending_sig) { if (ei->pending_sig) {
char signed_digest[128]; char signed_digest[128];
if (crypto_pk_public_checksig(ri->identity_pkey, if (crypto_pk_public_checksig(identity_pkey,
signed_digest, sizeof(signed_digest), signed_digest, sizeof(signed_digest),
ei->pending_sig, ei->pending_sig_len) != DIGEST_LEN || ei->pending_sig, ei->pending_sig_len) != DIGEST_LEN ||
tor_memneq(signed_digest, ei->cache_info.signed_descriptor_digest, tor_memneq(signed_digest, ei->cache_info.signed_descriptor_digest,
@ -5282,7 +5291,7 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri,
goto err; /* Bad signature, or no match. */ goto err; /* Bad signature, or no match. */
} }
ei->cache_info.send_unencrypted = ri->cache_info.send_unencrypted; ei->cache_info.send_unencrypted = sd->send_unencrypted;
tor_free(ei->pending_sig); tor_free(ei->pending_sig);
} }

View File

@ -192,7 +192,7 @@ void update_extrainfo_downloads(time_t now);
void router_reset_descriptor_download_failures(void); void router_reset_descriptor_download_failures(void);
int router_differences_are_cosmetic(const routerinfo_t *r1, int router_differences_are_cosmetic(const routerinfo_t *r1,
const routerinfo_t *r2); const routerinfo_t *r2);
int routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri, int routerinfo_incompatible_with_extrainfo(const crypto_pk_t *ri,
extrainfo_t *ei, extrainfo_t *ei,
signed_descriptor_t *sd, signed_descriptor_t *sd,
const char **msg); const char **msg);

View File

@ -1406,6 +1406,7 @@ router_parse_entry_from_string(const char *s, const char *end,
goto err; goto err;
} }
router->signing_key_cert = cert; /* makes sure it gets freed. */ router->signing_key_cert = cert; /* makes sure it gets freed. */
router->cache_info.signing_key_cert = tor_cert_dup(cert);
if (cert->cert_type != CERT_TYPE_ID_SIGNING || if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
! cert->signing_key_included) { ! cert->signing_key_included) {
@ -1600,7 +1601,7 @@ router_parse_entry_from_string(const char *s, const char *end,
} }
if (tok->n_args >= 2) { if (tok->n_args >= 2) {
if (digest256_from_base64(router->extra_info_digest256, tok->args[1]) if (digest256_from_base64(router->cache_info.extra_info_digest256, tok->args[1])
< 0) { < 0) {
log_warn(LD_DIR, "Invalid extra info digest256 %s", log_warn(LD_DIR, "Invalid extra info digest256 %s",
escaped(tok->args[1])); escaped(tok->args[1]));
@ -1787,6 +1788,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
goto err; goto err;
} }
extrainfo->signing_key_cert = cert; /* makes sure it gets freed. */ extrainfo->signing_key_cert = cert; /* makes sure it gets freed. */
extrainfo->cache_info.signing_key_cert = tor_cert_dup(cert);
if (cert->cert_type != CERT_TYPE_ID_SIGNING || if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
! cert->signing_key_included) { ! cert->signing_key_included) {
log_warn(LD_DIR, "Invalid form for ed25519 cert"); log_warn(LD_DIR, "Invalid form for ed25519 cert");