|
@@ -19,6 +19,7 @@
|
|
|
#include "directory.h"
|
|
|
#include "dirserv.h"
|
|
|
#include "dirvote.h"
|
|
|
+#include "fp_pair.h"
|
|
|
#include "geoip.h"
|
|
|
#include "hibernate.h"
|
|
|
#include "main.h"
|
|
@@ -38,6 +39,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
+DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
|
|
|
+DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
|
|
|
+DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
|
|
|
+DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
|
|
|
+#define SDMAP_FOREACH(map, keyvar, valvar) \
|
|
|
+ DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
|
|
|
+ valvar)
|
|
|
+#define RIMAP_FOREACH(map, keyvar, valvar) \
|
|
|
+ DIGESTMAP_FOREACH(rimap_to_digestmap(map), keyvar, routerinfo_t *, valvar)
|
|
|
+#define EIMAP_FOREACH(map, keyvar, valvar) \
|
|
|
+ DIGESTMAP_FOREACH(eimap_to_digestmap(map), keyvar, extrainfo_t *, valvar)
|
|
|
+#define DSMAP_FOREACH(map, keyvar, valvar) \
|
|
|
+ DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
|
|
|
+ valvar)
|
|
|
+
|
|
|
+
|
|
|
+typedef struct cert_list_t cert_list_t;
|
|
|
+
|
|
|
|
|
|
static const routerstatus_t *router_pick_directory_server_impl(
|
|
|
dirinfo_type_t auth, int flags);
|
|
@@ -56,19 +75,14 @@ static const char *signed_descriptor_get_body_impl(
|
|
|
int with_annotations);
|
|
|
static void list_pending_downloads(digestmap_t *result,
|
|
|
int purpose, const char *prefix);
|
|
|
+static void list_pending_fpsk_downloads(fp_pair_map_t *result);
|
|
|
static void launch_dummy_descriptor_download_as_needed(time_t now,
|
|
|
const or_options_t *options);
|
|
|
-
|
|
|
-DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
|
|
|
-DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
|
|
|
-DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
|
|
|
-#define SDMAP_FOREACH(map, keyvar, valvar) \
|
|
|
- DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
|
|
|
- valvar)
|
|
|
-#define RIMAP_FOREACH(map, keyvar, valvar) \
|
|
|
- DIGESTMAP_FOREACH(rimap_to_digestmap(map), keyvar, routerinfo_t *, valvar)
|
|
|
-#define EIMAP_FOREACH(map, keyvar, valvar) \
|
|
|
- DIGESTMAP_FOREACH(eimap_to_digestmap(map), keyvar, extrainfo_t *, valvar)
|
|
|
+static void download_status_reset_by_sk_in_cl(cert_list_t *cl,
|
|
|
+ const char *digest);
|
|
|
+static int download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
|
|
|
+ const char *digest,
|
|
|
+ time_t now, int max_failures);
|
|
|
|
|
|
|
|
|
|
|
@@ -78,10 +92,17 @@ static smartlist_t *trusted_dir_servers = NULL;
|
|
|
|
|
|
|
|
|
*/
|
|
|
-typedef struct cert_list_t {
|
|
|
- download_status_t dl_status;
|
|
|
+struct cert_list_t {
|
|
|
+
|
|
|
+ * The keys of download status map are cert->signing_key_digest for pending
|
|
|
+ * downloads by (identity digest/signing key digest) pair; functions such
|
|
|
+ * as authority_cert_get_by_digest() already assume these are unique.
|
|
|
+ */
|
|
|
+ struct digest_ds_map_t *dl_status_map;
|
|
|
+
|
|
|
+ download_status_t dl_status_by_id;
|
|
|
smartlist_t *certs;
|
|
|
-} cert_list_t;
|
|
|
+};
|
|
|
|
|
|
static digestmap_t *trusted_dir_certs = NULL;
|
|
|
|
|
@@ -125,6 +146,72 @@ get_n_authorities(dirinfo_type_t type)
|
|
|
return n;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static void
|
|
|
+download_status_reset_by_sk_in_cl(cert_list_t *cl, const char *digest)
|
|
|
+{
|
|
|
+ download_status_t *dlstatus = NULL;
|
|
|
+
|
|
|
+ tor_assert(cl);
|
|
|
+ tor_assert(digest);
|
|
|
+
|
|
|
+
|
|
|
+ if (!(cl->dl_status_map)) {
|
|
|
+ cl->dl_status_map = dsmap_new();
|
|
|
+ }
|
|
|
+
|
|
|
+ dlstatus = dsmap_get(cl->dl_status_map, digest);
|
|
|
+
|
|
|
+ if (!dlstatus) {
|
|
|
+
|
|
|
+ dlstatus = tor_malloc_zero(sizeof(*dlstatus));
|
|
|
+ dsmap_set(cl->dl_status_map, digest, dlstatus);
|
|
|
+ }
|
|
|
+ tor_assert(dlstatus);
|
|
|
+
|
|
|
+ download_status_reset(dlstatus);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * Return true if the download for this signing key digest in cl is ready
|
|
|
+ * to be re-attempted.
|
|
|
+ */
|
|
|
+static int
|
|
|
+download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
|
|
|
+ const char *digest,
|
|
|
+ time_t now, int max_failures)
|
|
|
+{
|
|
|
+ int rv = 0;
|
|
|
+ download_status_t *dlstatus = NULL;
|
|
|
+
|
|
|
+ tor_assert(cl);
|
|
|
+ tor_assert(digest);
|
|
|
+
|
|
|
+
|
|
|
+ if (!(cl->dl_status_map)) {
|
|
|
+ cl->dl_status_map = dsmap_new();
|
|
|
+ }
|
|
|
+
|
|
|
+ dlstatus = dsmap_get(cl->dl_status_map, digest);
|
|
|
+
|
|
|
+ if (dlstatus) {
|
|
|
+
|
|
|
+ rv = download_status_is_ready(dlstatus, now, max_failures);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ * If we don't know anything about it, return 1, since we haven't
|
|
|
+ * tried this one before. We need to create a new entry here,
|
|
|
+ * too.
|
|
|
+ */
|
|
|
+ dlstatus = tor_malloc_zero(sizeof(*dlstatus));
|
|
|
+ download_status_reset(dlstatus);
|
|
|
+ dsmap_set(cl->dl_status_map, digest, dlstatus);
|
|
|
+ rv = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
#define get_n_v2_authorities() get_n_authorities(V2_DIRINFO)
|
|
|
|
|
|
|
|
@@ -138,8 +225,9 @@ get_cert_list(const char *id_digest)
|
|
|
cl = digestmap_get(trusted_dir_certs, id_digest);
|
|
|
if (!cl) {
|
|
|
cl = tor_malloc_zero(sizeof(cert_list_t));
|
|
|
- cl->dl_status.schedule = DL_SCHED_CONSENSUS;
|
|
|
+ cl->dl_status_by_id.schedule = DL_SCHED_CONSENSUS;
|
|
|
cl->certs = smartlist_new();
|
|
|
+ cl->dl_status_map = dsmap_new();
|
|
|
digestmap_set(trusted_dir_certs, id_digest, cl);
|
|
|
}
|
|
|
return cl;
|
|
@@ -159,7 +247,9 @@ trusted_dirs_reload_certs(void)
|
|
|
tor_free(filename);
|
|
|
if (!contents)
|
|
|
return 0;
|
|
|
- r = trusted_dirs_load_certs_from_string(contents, 1, 1);
|
|
|
+ r = trusted_dirs_load_certs_from_string(
|
|
|
+ contents,
|
|
|
+ TRUSTED_DIRS_CERTS_SRC_FROM_STORE, 1);
|
|
|
tor_free(contents);
|
|
|
return r;
|
|
|
}
|
|
@@ -182,17 +272,23 @@ already_have_cert(authority_cert_t *cert)
|
|
|
}
|
|
|
|
|
|
|
|
|
- * <b>from_store</b> is true, the certificates are from the cache, and we
|
|
|
- * don't need to flush them to disk. If <b>flush</b> is true, we need
|
|
|
- * to flush any changed certificates to disk now. Return 0 on success, -1
|
|
|
- * if any certs fail to parse. */
|
|
|
+ * <b>source</b> is TRUSTED_DIRS_CERTS_SRC_FROM_STORE, the certificates are
|
|
|
+ * from the cache, and we don't need to flush them to disk. If we are a
|
|
|
+ * dirauth loading our own cert, source is TRUSTED_DIRS_CERTS_SRC_SELF.
|
|
|
+ * Otherwise, source is download type: TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST
|
|
|
+ * or TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST. If <b>flush</b> is true, we
|
|
|
+ * need to flush any changed certificates to disk now. Return 0 on success,
|
|
|
+ * -1 if any certs fail to parse.
|
|
|
+ */
|
|
|
+
|
|
|
int
|
|
|
-trusted_dirs_load_certs_from_string(const char *contents, int from_store,
|
|
|
+trusted_dirs_load_certs_from_string(const char *contents, int source,
|
|
|
int flush)
|
|
|
{
|
|
|
trusted_dir_server_t *ds;
|
|
|
const char *s, *eos;
|
|
|
int failure_code = 0;
|
|
|
+ int from_store = (source == TRUSTED_DIRS_CERTS_SRC_FROM_STORE);
|
|
|
|
|
|
for (s = contents; *s; s = eos) {
|
|
|
authority_cert_t *cert = authority_cert_parse_from_string(s, &eos);
|
|
@@ -229,7 +325,18 @@ trusted_dirs_load_certs_from_string(const char *contents, int from_store,
|
|
|
ds ? ds->nickname : "an old or new authority");
|
|
|
}
|
|
|
|
|
|
- authority_cert_dl_failed(cert->cache_info.identity_digest, 404);
|
|
|
+
|
|
|
+ * This is where we care about the source; authority_cert_dl_failed()
|
|
|
+ * needs to know whether the download was by fp or (fp,sk) pair to
|
|
|
+ * twiddle the right bit in the download map.
|
|
|
+ */
|
|
|
+ if (source == TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST) {
|
|
|
+ authority_cert_dl_failed(cert->cache_info.identity_digest,
|
|
|
+ NULL, 404);
|
|
|
+ } else if (source == TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST) {
|
|
|
+ authority_cert_dl_failed(cert->cache_info.identity_digest,
|
|
|
+ cert->signing_key_digest, 404);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
authority_cert_free(cert);
|
|
@@ -445,17 +552,53 @@ authority_cert_get_all(smartlist_t *certs_out)
|
|
|
}
|
|
|
|
|
|
|
|
|
- * ID <b>id_digest</b> fails with HTTP response code <b>status</b>: remember
|
|
|
- * the failure, so we don't try again immediately. */
|
|
|
+ * ID <b>id_digest</b> and, if not NULL, signed with key signing_key_digest
|
|
|
+ * fails with HTTP response code <b>status</b>: remember the failure, so we
|
|
|
+ * don't try again immediately. */
|
|
|
void
|
|
|
-authority_cert_dl_failed(const char *id_digest, int status)
|
|
|
+authority_cert_dl_failed(const char *id_digest,
|
|
|
+ const char *signing_key_digest, int status)
|
|
|
{
|
|
|
cert_list_t *cl;
|
|
|
+ download_status_t *dlstatus = NULL;
|
|
|
+ char id_digest_str[2*DIGEST_LEN+1];
|
|
|
+ char sk_digest_str[2*DIGEST_LEN+1];
|
|
|
+
|
|
|
if (!trusted_dir_certs ||
|
|
|
!(cl = digestmap_get(trusted_dir_certs, id_digest)))
|
|
|
return;
|
|
|
|
|
|
- download_status_failed(&cl->dl_status, status);
|
|
|
+
|
|
|
+ * Are we noting a failed download of the latest cert for the id digest,
|
|
|
+ * or of a download by (id, signing key) digest pair?
|
|
|
+ */
|
|
|
+ if (!signing_key_digest) {
|
|
|
+
|
|
|
+ download_status_failed(&cl->dl_status_by_id, status);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ *
|
|
|
+ * Look for a download_status_t in the map with this digest
|
|
|
+ */
|
|
|
+ dlstatus = dsmap_get(cl->dl_status_map, signing_key_digest);
|
|
|
+
|
|
|
+ if (dlstatus) {
|
|
|
+ download_status_failed(dlstatus, status);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ * Do this rather than hex_str(), since hex_str clobbers
|
|
|
+ * old results and we call twice in the param list.
|
|
|
+ */
|
|
|
+ base16_encode(id_digest_str, sizeof(id_digest_str),
|
|
|
+ id_digest, DIGEST_LEN);
|
|
|
+ base16_encode(sk_digest_str, sizeof(sk_digest_str),
|
|
|
+ signing_key_digest, DIGEST_LEN);
|
|
|
+ log_warn(LD_DIR,
|
|
|
+ "Got failure for cert fetch with (fp,sk) = (%s,%s), with "
|
|
|
+ "status %d, but knew nothing about the download.",
|
|
|
+ id_digest_str, sk_digest_str, status);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
@@ -471,7 +614,7 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
|
|
|
!(cl = digestmap_get(trusted_dir_certs, id_digest)))
|
|
|
return 0;
|
|
|
|
|
|
- n_failures = download_status_get_n_failures(&cl->dl_status);
|
|
|
+ n_failures = download_status_get_n_failures(&cl->dl_status_by_id);
|
|
|
return n_failures >= N_AUTH_CERT_DL_FAILURES_TO_BUG_USER;
|
|
|
}
|
|
|
|
|
@@ -487,20 +630,38 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
|
|
|
void
|
|
|
authority_certs_fetch_missing(networkstatus_t *status, time_t now)
|
|
|
{
|
|
|
- digestmap_t *pending;
|
|
|
+
|
|
|
+ * The pending_id digestmap tracks pending certificate downloads by
|
|
|
+ * identity digest; the pending_cert digestmap tracks pending downloads
|
|
|
+ * by (identity digest, signing key digest) pairs.
|
|
|
+ */
|
|
|
+ digestmap_t *pending_id;
|
|
|
+ fp_pair_map_t *pending_cert;
|
|
|
authority_cert_t *cert;
|
|
|
- smartlist_t *missing_digests;
|
|
|
+
|
|
|
+ * The missing_id_digests smartlist will hold a list of id digests
|
|
|
+ * we want to fetch the newest cert for; the missing_cert_digests
|
|
|
+ * smartlist will hold a list of fp_pair_t with an identity and
|
|
|
+ * signing key digest.
|
|
|
+ */
|
|
|
+ smartlist_t *missing_cert_digests, *missing_id_digests;
|
|
|
char *resource = NULL;
|
|
|
cert_list_t *cl;
|
|
|
const int cache = directory_caches_unknown_auth_certs(get_options());
|
|
|
+ fp_pair_t *fp_tmp = NULL;
|
|
|
+ char id_digest_str[2*DIGEST_LEN+1];
|
|
|
+ char sk_digest_str[2*DIGEST_LEN+1];
|
|
|
|
|
|
if (should_delay_dir_fetches(get_options()))
|
|
|
return;
|
|
|
|
|
|
- pending = digestmap_new();
|
|
|
- missing_digests = smartlist_new();
|
|
|
+ pending_cert = fp_pair_map_new();
|
|
|
+ pending_id = digestmap_new();
|
|
|
+ missing_cert_digests = smartlist_new();
|
|
|
+ missing_id_digests = smartlist_new();
|
|
|
|
|
|
- list_pending_downloads(pending, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
|
|
|
+ list_pending_downloads(pending_id, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
|
|
|
+ list_pending_fpsk_downloads(pending_cert);
|
|
|
if (status) {
|
|
|
SMARTLIST_FOREACH_BEGIN(status->voters, networkstatus_voter_info_t *,
|
|
|
voter) {
|
|
@@ -516,16 +677,43 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
|
|
|
sig->signing_key_digest);
|
|
|
if (cert) {
|
|
|
if (now < cert->expires)
|
|
|
- download_status_reset(&cl->dl_status);
|
|
|
+ download_status_reset_by_sk_in_cl(cl, sig->signing_key_digest);
|
|
|
continue;
|
|
|
}
|
|
|
- if (download_status_is_ready(&cl->dl_status, now,
|
|
|
- MAX_CERT_DL_FAILURES) &&
|
|
|
- !digestmap_get(pending, voter->identity_digest)) {
|
|
|
- log_info(LD_DIR, "We're missing a certificate from authority "
|
|
|
- "with signing key %s: launching request.",
|
|
|
- hex_str(sig->signing_key_digest, DIGEST_LEN));
|
|
|
- smartlist_add(missing_digests, sig->identity_digest);
|
|
|
+ if (download_status_is_ready_by_sk_in_cl(
|
|
|
+ cl, sig->signing_key_digest,
|
|
|
+ now, MAX_CERT_DL_FAILURES) &&
|
|
|
+ !fp_pair_map_get_by_digests(pending_cert,
|
|
|
+ voter->identity_digest,
|
|
|
+ sig->signing_key_digest)) {
|
|
|
+
|
|
|
+ * Do this rather than hex_str(), since hex_str clobbers
|
|
|
+ * old results and we call twice in the param list.
|
|
|
+ */
|
|
|
+ base16_encode(id_digest_str, sizeof(id_digest_str),
|
|
|
+ voter->identity_digest, DIGEST_LEN);
|
|
|
+ base16_encode(sk_digest_str, sizeof(sk_digest_str),
|
|
|
+ sig->signing_key_digest, DIGEST_LEN);
|
|
|
+
|
|
|
+ if (voter->nickname) {
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "We're missing a certificate from authority %s "
|
|
|
+ "(ID digest %s) with signing key %s: "
|
|
|
+ "launching request.",
|
|
|
+ voter->nickname, id_digest_str, sk_digest_str);
|
|
|
+ } else {
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "We're missing a certificate from authority ID digest "
|
|
|
+ "%s with signing key %s: launching request.",
|
|
|
+ id_digest_str, sk_digest_str);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ fp_tmp = tor_malloc(sizeof(*fp_tmp));
|
|
|
+ memcpy(fp_tmp->first, voter->identity_digest, sizeof(fp_tmp->first));
|
|
|
+ memcpy(fp_tmp->second, sig->signing_key_digest,
|
|
|
+ sizeof(fp_tmp->second));
|
|
|
+ smartlist_add(missing_cert_digests, fp_tmp);
|
|
|
}
|
|
|
} SMARTLIST_FOREACH_END(sig);
|
|
|
} SMARTLIST_FOREACH_END(voter);
|
|
@@ -534,60 +722,118 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
|
|
|
int found = 0;
|
|
|
if (!(ds->type & V3_DIRINFO))
|
|
|
continue;
|
|
|
- if (smartlist_digest_isin(missing_digests, ds->v3_identity_digest))
|
|
|
+ if (smartlist_digest_isin(missing_id_digests, ds->v3_identity_digest))
|
|
|
continue;
|
|
|
cl = get_cert_list(ds->v3_identity_digest);
|
|
|
SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, {
|
|
|
if (now < cert->expires) {
|
|
|
|
|
|
* verify a consensus with. Call it done. */
|
|
|
- download_status_reset(&cl->dl_status);
|
|
|
+ download_status_reset(&(cl->dl_status_by_id));
|
|
|
+
|
|
|
+ download_status_reset_by_sk_in_cl(cl, cert->signing_key_digest);
|
|
|
found = 1;
|
|
|
break;
|
|
|
}
|
|
|
});
|
|
|
if (!found &&
|
|
|
- download_status_is_ready(&cl->dl_status, now,MAX_CERT_DL_FAILURES) &&
|
|
|
- !digestmap_get(pending, ds->v3_identity_digest)) {
|
|
|
- log_info(LD_DIR, "No current certificate known for authority %s; "
|
|
|
- "launching request.", ds->nickname);
|
|
|
- smartlist_add(missing_digests, ds->v3_identity_digest);
|
|
|
+ download_status_is_ready(&(cl->dl_status_by_id), now,
|
|
|
+ MAX_CERT_DL_FAILURES) &&
|
|
|
+ !digestmap_get(pending_id, ds->v3_identity_digest)) {
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "No current certificate known for authority %s "
|
|
|
+ "(ID digest %s); launching request.",
|
|
|
+ ds->nickname, hex_str(ds->v3_identity_digest, DIGEST_LEN));
|
|
|
+ smartlist_add(missing_id_digests, ds->v3_identity_digest);
|
|
|
}
|
|
|
} SMARTLIST_FOREACH_END(ds);
|
|
|
|
|
|
- if (!smartlist_len(missing_digests)) {
|
|
|
- goto done;
|
|
|
- } else {
|
|
|
+
|
|
|
+ if (smartlist_len(missing_id_digests) > 0) {
|
|
|
smartlist_t *fps = smartlist_new();
|
|
|
smartlist_add(fps, tor_strdup("fp/"));
|
|
|
- SMARTLIST_FOREACH(missing_digests, const char *, d, {
|
|
|
- char *fp;
|
|
|
- if (digestmap_get(pending, d))
|
|
|
- continue;
|
|
|
- fp = tor_malloc(HEX_DIGEST_LEN+2);
|
|
|
- base16_encode(fp, HEX_DIGEST_LEN+1, d, DIGEST_LEN);
|
|
|
- fp[HEX_DIGEST_LEN] = '+';
|
|
|
- fp[HEX_DIGEST_LEN+1] = '\0';
|
|
|
- smartlist_add(fps, fp);
|
|
|
- });
|
|
|
- if (smartlist_len(fps) == 1) {
|
|
|
-
|
|
|
- SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
|
|
|
- smartlist_free(fps);
|
|
|
- goto done;
|
|
|
+
|
|
|
+ SMARTLIST_FOREACH(missing_id_digests, const char *, d, {
|
|
|
+ char *fp;
|
|
|
+ if (digestmap_get(pending_id, d))
|
|
|
+ continue;
|
|
|
+ fp = tor_malloc(HEX_DIGEST_LEN+2);
|
|
|
+ base16_encode(fp, HEX_DIGEST_LEN+1, d, DIGEST_LEN);
|
|
|
+ fp[HEX_DIGEST_LEN] = '+';
|
|
|
+ fp[HEX_DIGEST_LEN+1] = '\0';
|
|
|
+ smartlist_add(fps, fp);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (smartlist_len(fps) > 1) {
|
|
|
+ resource = smartlist_join_strings(fps, "", 0, NULL);
|
|
|
+ resource[strlen(resource)-1] = '\0';
|
|
|
+ directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
|
|
|
+ resource, PDS_RETRY_IF_NO_SERVERS);
|
|
|
+ tor_free(resource);
|
|
|
}
|
|
|
- resource = smartlist_join_strings(fps, "", 0, NULL);
|
|
|
- resource[strlen(resource)-1] = '\0';
|
|
|
+
|
|
|
+
|
|
|
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
|
|
|
smartlist_free(fps);
|
|
|
}
|
|
|
- directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
|
|
|
- resource, PDS_RETRY_IF_NO_SERVERS);
|
|
|
|
|
|
- done:
|
|
|
- tor_free(resource);
|
|
|
- smartlist_free(missing_digests);
|
|
|
- digestmap_free(pending, NULL);
|
|
|
+
|
|
|
+ if (smartlist_len(missing_cert_digests) > 0) {
|
|
|
+ smartlist_t *fp_pairs = smartlist_new();
|
|
|
+ int need_plus = 0, offset = 0;
|
|
|
+
|
|
|
+ smartlist_add(fp_pairs, tor_strdup("fp-sk/"));
|
|
|
+
|
|
|
+ SMARTLIST_FOREACH_BEGIN(missing_cert_digests, const fp_pair_t *, d) {
|
|
|
+ char *fp_pair;
|
|
|
+
|
|
|
+ if (fp_pair_map_get(pending_cert, d))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ fp_pair = tor_malloc(2*HEX_DIGEST_LEN+3);
|
|
|
+ offset = 0;
|
|
|
+ if (need_plus) {
|
|
|
+ fp_pair[offset++] = '+';
|
|
|
+ } else {
|
|
|
+
|
|
|
+ need_plus = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ base16_encode(fp_pair + offset, HEX_DIGEST_LEN+1,
|
|
|
+ d->first, DIGEST_LEN);
|
|
|
+ offset += HEX_DIGEST_LEN;
|
|
|
+
|
|
|
+ fp_pair[offset++] = '-';
|
|
|
+
|
|
|
+ base16_encode(fp_pair + offset, HEX_DIGEST_LEN+1,
|
|
|
+ d->second, DIGEST_LEN);
|
|
|
+ offset += HEX_DIGEST_LEN;
|
|
|
+
|
|
|
+ fp_pair[offset++] = '\0';
|
|
|
+
|
|
|
+
|
|
|
+ smartlist_add(fp_pairs, fp_pair);
|
|
|
+ } SMARTLIST_FOREACH_END(d);
|
|
|
+
|
|
|
+ if (smartlist_len(fp_pairs) > 1) {
|
|
|
+ resource = smartlist_join_strings(fp_pairs, "", 0, NULL);
|
|
|
+ resource[strlen(resource)-1] = '\0';
|
|
|
+ directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
|
|
|
+ resource, PDS_RETRY_IF_NO_SERVERS);
|
|
|
+ tor_free(resource);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ SMARTLIST_FOREACH(fp_pairs, char *, p, tor_free(p));
|
|
|
+ smartlist_free(fp_pairs);
|
|
|
+ }
|
|
|
+
|
|
|
+ smartlist_free(missing_id_digests);
|
|
|
+ SMARTLIST_FOREACH(missing_cert_digests, fp_pair_t *, p, tor_free(p));
|
|
|
+ smartlist_free(missing_cert_digests);
|
|
|
+ digestmap_free(pending_id, NULL);
|
|
|
+ fp_pair_map_free(pending_cert, NULL);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -4283,6 +4529,41 @@ list_pending_microdesc_downloads(digestmap_t *result)
|
|
|
list_pending_downloads(result, DIR_PURPOSE_FETCH_MICRODESC, "d/");
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * signing key digest) pair, set result[fp_pair] to (void *1).
|
|
|
+ */
|
|
|
+static void
|
|
|
+list_pending_fpsk_downloads(fp_pair_map_t *result)
|
|
|
+{
|
|
|
+ const char *pfx = "fp-sk/";
|
|
|
+ smartlist_t *tmp;
|
|
|
+ smartlist_t *conns;
|
|
|
+ const char *resource;
|
|
|
+
|
|
|
+ tor_assert(result);
|
|
|
+
|
|
|
+ tmp = smartlist_new();
|
|
|
+ conns = get_connection_array();
|
|
|
+
|
|
|
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
|
|
|
+ if (conn->type == CONN_TYPE_DIR &&
|
|
|
+ conn->purpose == DIR_PURPOSE_FETCH_CERTIFICATE &&
|
|
|
+ !conn->marked_for_close) {
|
|
|
+ resource = TO_DIR_CONN(conn)->requested_resource;
|
|
|
+ if (!strcmpstart(resource, pfx))
|
|
|
+ dir_split_resource_into_fingerprint_pairs(resource + strlen(pfx),
|
|
|
+ tmp);
|
|
|
+ }
|
|
|
+ } SMARTLIST_FOREACH_END(conn);
|
|
|
+
|
|
|
+ SMARTLIST_FOREACH_BEGIN(tmp, fp_pair_t *, fp) {
|
|
|
+ fp_pair_map_set(result, fp, (void*)1);
|
|
|
+ tor_free(fp);
|
|
|
+ } SMARTLIST_FOREACH_END(fp);
|
|
|
+
|
|
|
+ smartlist_free(tmp);
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* are listed as digests[i] for lo <= i < hi. (Lo and hi may be out of
|
|
|
* range.) If <b>source</b> is given, download from <b>source</b>;
|