/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file authcert.c
* \brief Code to maintain directory authorities' certificates.
*
* Authority certificates are signed with authority identity keys; they
* are used to authenticate shorter-term authority signing keys. We
* fetch them when we find a consensus or a vote that has been signed
* with a signing key we don't recognize. We cache them on disk and
* load them on startup. Authority operators generate them with the
* "tor-gencert" utility.
*/
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/or/policies.h"
#include "feature/client/bridges.h"
#include "feature/dirauth/authmode.h"
#include "feature/dirclient/dirclient.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/dircommon/fp_pair.h"
#include "feature/dirparse/authcert_parse.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/node_select.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/relay/routermode.h"
#include "core/or/connection_st.h"
#include "feature/dirclient/dir_server_st.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/document_signature_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/networkstatus_voter_info_st.h"
#include "feature/nodelist/node_st.h"
DECLARE_TYPED_DIGESTMAP_FNS(dsmap, digest_ds_map_t, download_status_t)
#define DSMAP_FOREACH(map, keyvar, valvar) \
DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
valvar)
#define dsmap_free(map, fn) MAP_FREE_AND_NULL(dsmap, (map), (fn))
/* Forward declaration for cert_list_t */
typedef struct cert_list_t cert_list_t;
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);
static void list_pending_fpsk_downloads(fp_pair_map_t *result);
/** List of certificates for a single authority, and download status for
* latest certificate.
*/
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;
/* There is also a dlstatus for the download by identity key only */
download_status_t dl_status_by_id;
smartlist_t *certs;
};
/** Map from v3 identity key digest to cert_list_t. */
static digestmap_t *trusted_dir_certs = NULL;
/** True iff any key certificate in at least one member of
* <b>trusted_dir_certs</b> has changed since we last flushed the
* certificates to disk. */
static int trusted_dir_servers_certs_changed = 0;
/** Initialise schedule, want_authority, and increment_on in the download
* status dlstatus, then call download_status_reset() on it.
* It is safe to call this function or download_status_reset() multiple times
* on a new dlstatus. But it should *not* be called after a dlstatus has been
* used to count download attempts or failures. */
static void
download_status_cert_init(download_status_t *dlstatus)
{
dlstatus->schedule = DL_SCHED_CONSENSUS;
dlstatus->want_authority = DL_WANT_ANY_DIRSERVER;
dlstatus->increment_on = DL_SCHED_INCREMENT_FAILURE;
dlstatus->last_backoff_position = 0;
dlstatus->last_delay_used = 0;
/* Use the new schedule to set next_attempt_at */
download_status_reset(dlstatus);
}
/** Reset the download status of a specified element in a dsmap */
static void
download_status_reset_by_sk_in_cl(cert_list_t *cl, const char *digest)
{
download_status_t *dlstatus<