aboutsummaryrefslogtreecommitdiff
path: root/src/feature/relay/router.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/relay/router.c')
-rw-r--r--src/feature/relay/router.c230
1 files changed, 171 insertions, 59 deletions
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 25bb1835c2..ab0762e17e 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -284,19 +284,17 @@ construct_ntor_key_map(void)
{
di_digest256_map_t *m = NULL;
- if (!fast_mem_is_zero((const char*)
- curve25519_onion_key.pubkey.public_key,
- CURVE25519_PUBKEY_LEN)) {
- dimap_add_entry(&m,
- curve25519_onion_key.pubkey.public_key,
+ const uint8_t *cur_pk = curve25519_onion_key.pubkey.public_key;
+ const uint8_t *last_pk = last_curve25519_onion_key.pubkey.public_key;
+
+ if (!fast_mem_is_zero((const char *)cur_pk, CURVE25519_PUBKEY_LEN)) {
+ dimap_add_entry(&m, cur_pk,
tor_memdup(&curve25519_onion_key,
sizeof(curve25519_keypair_t)));
}
- if (!fast_mem_is_zero((const char*)
- last_curve25519_onion_key.pubkey.public_key,
- CURVE25519_PUBKEY_LEN)) {
- dimap_add_entry(&m,
- last_curve25519_onion_key.pubkey.public_key,
+ if (!fast_mem_is_zero((const char*)last_pk, CURVE25519_PUBKEY_LEN) &&
+ tor_memneq(cur_pk, last_pk, CURVE25519_PUBKEY_LEN)) {
+ dimap_add_entry(&m, last_pk,
tor_memdup(&last_curve25519_onion_key,
sizeof(curve25519_keypair_t)));
}
@@ -3113,33 +3111,22 @@ load_stats_file(const char *filename, const char *end_line, time_t now,
return r;
}
-/** Write the contents of <b>extrainfo</b>, to * *<b>s_out</b>, signing them
- * with <b>ident_key</b>.
- *
- * If ExtraInfoStatistics is 1, also write aggregated statistics and related
- * configuration data before signing. Most statistics also have an option that
- * enables or disables that particular statistic.
- *
- * Return 0 on success, negative on failure. */
-int
-extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
- crypto_pk_t *ident_key,
- const ed25519_keypair_t *signing_keypair)
+/** Add header strings to chunks, based on the extrainfo object extrainfo,
+ * and ed25519 keypair signing_keypair, if emit_ed_sigs is true.
+ * Helper for extrainfo_dump_to_string().
+ * Returns 0 on success, negative on failure. */
+static int
+extrainfo_dump_to_string_header_helper(
+ smartlist_t *chunks,
+ const extrainfo_t *extrainfo,
+ const ed25519_keypair_t *signing_keypair,
+ int emit_ed_sigs)
{
- const or_options_t *options = get_options();
char identity[HEX_DIGEST_LEN+1];
char published[ISO_TIME_LEN+1];
- char digest[DIGEST_LEN];
- int result;
- static int write_stats_to_extrainfo = 1;
- char sig[DIROBJ_MAX_SIG_LEN+1];
- char *s = NULL, *pre, *contents, *cp, *s_dup = NULL;
- time_t now = time(NULL);
- smartlist_t *chunks = smartlist_new();
- extrainfo_t *ei_tmp = NULL;
- const int emit_ed_sigs = signing_keypair &&
- extrainfo->cache_info.signing_key_cert;
char *ed_cert_line = NULL;
+ char *pre = NULL;
+ int rv = -1;
base16_encode(identity, sizeof(identity),
extrainfo->cache_info.identity_digest, DIGEST_LEN);
@@ -3169,12 +3156,41 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
ed_cert_line = tor_strdup("");
}
+ /* This is the first chunk in the file. If the file is too big, other chunks
+ * are removed. So we must only add one chunk here. */
tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n",
extrainfo->nickname, identity,
ed_cert_line,
published);
smartlist_add(chunks, pre);
+ rv = 0;
+ goto done;
+
+ err:
+ rv = -1;
+
+ done:
+ tor_free(ed_cert_line);
+ return rv;
+}
+
+/** Add pluggable transport and statistics strings to chunks, skipping
+ * statistics if write_stats_to_extrainfo is false.
+ * Helper for extrainfo_dump_to_string().
+ * Can not fail. */
+static void
+extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
+ int write_stats_to_extrainfo)
+{
+ const or_options_t *options = get_options();
+ char *contents = NULL;
+ time_t now = time(NULL);
+
+ /* If the file is too big, these chunks are removed, starting with the last
+ * chunk. So each chunk must be a complete line, and the file must be valid
+ * after each chunk. */
+
/* Add information about the pluggable transports we support, even if we
* are not publishing statistics. This information is needed by BridgeDB
* to distribute bridges. */
@@ -3241,34 +3257,132 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
}
}
}
+}
+
+/** Add an ed25519 signature of chunks to chunks, using the ed25519 keypair
+ * signing_keypair.
+ * Helper for extrainfo_dump_to_string().
+ * Returns 0 on success, negative on failure. */
+static int
+extrainfo_dump_to_string_ed_sig_helper(
+ smartlist_t *chunks,
+ const ed25519_keypair_t *signing_keypair)
+{
+ char sha256_digest[DIGEST256_LEN];
+ ed25519_signature_t ed_sig;
+ char buf[ED25519_SIG_BASE64_LEN+1];
+ int rv = -1;
+
+ /* These are two of the three final chunks in the file. If the file is too
+ * big, other chunks are removed. So we must only add two chunks here. */
+ smartlist_add_strdup(chunks, "router-sig-ed25519 ");
+ crypto_digest_smartlist_prefix(sha256_digest, DIGEST256_LEN,
+ ED_DESC_SIGNATURE_PREFIX,
+ chunks, "", DIGEST_SHA256);
+ if (ed25519_sign(&ed_sig, (const uint8_t*)sha256_digest, DIGEST256_LEN,
+ signing_keypair) < 0)
+ goto err;
+ ed25519_signature_to_base64(buf, &ed_sig);
+
+ smartlist_add_asprintf(chunks, "%s\n", buf);
+
+ rv = 0;
+ goto done;
+
+ err:
+ rv = -1;
+
+ done:
+ return rv;
+}
+
+/** Add an RSA signature of extrainfo_string to chunks, using the RSA key
+ * ident_key.
+ * Helper for extrainfo_dump_to_string().
+ * Returns 0 on success, negative on failure. */
+static int
+extrainfo_dump_to_string_rsa_sig_helper(smartlist_t *chunks,
+ crypto_pk_t *ident_key,
+ const char *extrainfo_string)
+{
+ char sig[DIROBJ_MAX_SIG_LEN+1];
+ char digest[DIGEST_LEN];
+ int rv = -1;
+
+ memset(sig, 0, sizeof(sig));
+ if (router_get_extrainfo_hash(extrainfo_string, strlen(extrainfo_string),
+ digest) < 0 ||
+ router_append_dirobj_signature(sig, sizeof(sig), digest, DIGEST_LEN,
+ ident_key) < 0) {
+ log_warn(LD_BUG, "Could not append signature to extra-info "
+ "descriptor.");
+ goto err;
+ }
+ smartlist_add_strdup(chunks, sig);
+
+ rv = 0;
+ goto done;
+
+ err:
+ rv = -1;
+
+ done:
+ return rv;
+}
+
+/** Write the contents of <b>extrainfo</b>, to * *<b>s_out</b>, signing them
+ * with <b>ident_key</b>.
+ *
+ * If ExtraInfoStatistics is 1, also write aggregated statistics and related
+ * configuration data before signing. Most statistics also have an option that
+ * enables or disables that particular statistic.
+ *
+ * Always write pluggable transport lines.
+ *
+ * Return 0 on success, negative on failure. */
+int
+extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
+ crypto_pk_t *ident_key,
+ const ed25519_keypair_t *signing_keypair)
+{
+ int result;
+ static int write_stats_to_extrainfo = 1;
+ char *s = NULL, *cp, *s_dup = NULL;
+ smartlist_t *chunks = smartlist_new();
+ extrainfo_t *ei_tmp = NULL;
+ const int emit_ed_sigs = signing_keypair &&
+ extrainfo->cache_info.signing_key_cert;
+ int rv = 0;
+
+ rv = extrainfo_dump_to_string_header_helper(chunks, extrainfo,
+ signing_keypair,
+ emit_ed_sigs);
+ if (rv < 0)
+ goto err;
+
+ extrainfo_dump_to_string_stats_helper(chunks, write_stats_to_extrainfo);
if (emit_ed_sigs) {
- char sha256_digest[DIGEST256_LEN];
- smartlist_add_strdup(chunks, "router-sig-ed25519 ");
- crypto_digest_smartlist_prefix(sha256_digest, DIGEST256_LEN,
- ED_DESC_SIGNATURE_PREFIX,
- chunks, "", DIGEST_SHA256);
- ed25519_signature_t ed_sig;
- char buf[ED25519_SIG_BASE64_LEN+1];
- if (ed25519_sign(&ed_sig, (const uint8_t*)sha256_digest, DIGEST256_LEN,
- signing_keypair) < 0)
+ rv = extrainfo_dump_to_string_ed_sig_helper(chunks, signing_keypair);
+ if (rv < 0)
goto err;
- ed25519_signature_to_base64(buf, &ed_sig);
-
- smartlist_add_asprintf(chunks, "%s\n", buf);
}
+ /* This is one of the three final chunks in the file. If the file is too big,
+ * other chunks are removed. So we must only add one chunk here. */
smartlist_add_strdup(chunks, "router-signature\n");
s = smartlist_join_strings(chunks, "", 0, NULL);
while (strlen(s) > MAX_EXTRAINFO_UPLOAD_SIZE - DIROBJ_MAX_SIG_LEN) {
/* So long as there are at least two chunks (one for the initial
* extra-info line and one for the router-signature), we can keep removing
- * things. */
- if (smartlist_len(chunks) > 2) {
- /* We remove the next-to-last element (remember, len-1 is the last
- element), since we need to keep the router-signature element. */
- int idx = smartlist_len(chunks) - 2;
+ * things. If emit_ed_sigs is true, we also keep 2 additional chunks at the
+ * end for the ed25519 signature. */
+ const int required_chunks = emit_ed_sigs ? 4 : 2;
+ if (smartlist_len(chunks) > required_chunks) {
+ /* We remove the next-to-last or 4th-last element (remember, len-1 is the
+ * last element), since we need to keep the router-signature elements. */
+ int idx = smartlist_len(chunks) - required_chunks;
char *e = smartlist_get(chunks, idx);
smartlist_del_keeporder(chunks, idx);
log_warn(LD_GENERAL, "We just generated an extra-info descriptor "
@@ -3285,15 +3399,10 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
}
}
- memset(sig, 0, sizeof(sig));
- if (router_get_extrainfo_hash(s, strlen(s), digest) < 0 ||
- router_append_dirobj_signature(sig, sizeof(sig), digest, DIGEST_LEN,
- ident_key) < 0) {
- log_warn(LD_BUG, "Could not append signature to extra-info "
- "descriptor.");
+ rv = extrainfo_dump_to_string_rsa_sig_helper(chunks, ident_key, s);
+ if (rv < 0)
goto err;
- }
- smartlist_add_strdup(chunks, sig);
+
tor_free(s);
s = smartlist_join_strings(chunks, "", 0, NULL);
@@ -3329,7 +3438,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
SMARTLIST_FOREACH(chunks, char *, chunk, tor_free(chunk));
smartlist_free(chunks);
tor_free(s_dup);
- tor_free(ed_cert_line);
extrainfo_free(ei_tmp);
return result;
@@ -3355,6 +3463,10 @@ router_free_all(void)
crypto_pk_free(server_identitykey);
crypto_pk_free(client_identitykey);
+ /* Destroying a locked mutex is undefined behaviour. This mutex may be
+ * locked, because multiple threads can access it. But we need to destroy
+ * it, otherwise re-initialisation will trigger undefined behaviour.
+ * See #31735 for details. */
tor_mutex_free(key_lock);
routerinfo_free(desc_routerinfo);
extrainfo_free(desc_extrainfo);