aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/address_set.c2
-rw-r--r--src/common/aes.c3
-rw-r--r--src/common/compat_libevent.c33
-rw-r--r--src/common/compat_libevent.h2
-rw-r--r--src/common/compat_openssl.h6
-rw-r--r--src/common/compat_time.c2
-rw-r--r--src/common/crypto.c624
-rw-r--r--src/common/crypto.h40
-rw-r--r--src/common/crypto_curve25519.c5
-rw-r--r--src/common/crypto_digest.c24
-rw-r--r--src/common/crypto_ed25519.c6
-rw-r--r--src/common/crypto_format.c4
-rw-r--r--src/common/crypto_pwbox.c6
-rw-r--r--src/common/crypto_rand.c615
-rw-r--r--src/common/crypto_rand.h52
-rw-r--r--src/common/crypto_rsa.c8
-rw-r--r--src/common/crypto_s2k.c8
-rw-r--r--src/common/crypto_util.c107
-rw-r--r--src/common/crypto_util.h27
-rw-r--r--src/common/include.am10
-rw-r--r--src/common/log.c25
-rw-r--r--src/common/torlog.h2
-rw-r--r--src/common/tortls.c6
-rw-r--r--src/common/workqueue.c2
-rw-r--r--src/config/torrc.minimal.in-staging2
-rw-r--r--src/config/torrc.sample.in1
-rw-r--r--src/ext/ed25519/donna/ed25519-randombytes-custom.h2
-rw-r--r--src/ext/ed25519/donna/ed25519_tor.c2
-rw-r--r--src/ext/ed25519/ref10/blinding.c2
-rw-r--r--src/ext/ed25519/ref10/keypair.c3
-rw-r--r--src/ext/ed25519/ref10/randombytes.h2
-rw-r--r--src/ext/keccak-tiny/keccak-tiny-unrolled.c2
m---------src/ext/rust0
-rw-r--r--src/or/addressmap.c7
-rw-r--r--src/or/channelpadding.c1
-rw-r--r--src/or/circpathbias.c1
-rw-r--r--src/or/circuitbuild.c141
-rw-r--r--src/or/circuitbuild.h9
-rw-r--r--src/or/circuitlist.c2
-rw-r--r--src/or/circuitmux_ewma.c1
-rw-r--r--src/or/circuitstats.c21
-rw-r--r--src/or/circuituse.c45
-rw-r--r--src/or/command.c1
-rw-r--r--src/or/config.c27
-rw-r--r--src/or/config.h3
-rw-r--r--src/or/connection.c16
-rw-r--r--src/or/connection_edge.c2
-rw-r--r--src/or/connection_or.c2
-rw-r--r--src/or/conscache.c1
-rw-r--r--src/or/control.c127
-rw-r--r--src/or/control.h4
-rw-r--r--src/or/cpuworker.c2
-rw-r--r--src/or/dirauth/dirvote.c8
-rw-r--r--src/or/dirauth/mode.h38
-rw-r--r--src/or/dirauth/shared_random.c7
-rw-r--r--src/or/dirauth/shared_random_state.c10
-rw-r--r--src/or/directory.c5
-rw-r--r--src/or/dirserv.c27
-rw-r--r--src/or/dns.c1
-rw-r--r--src/or/dos.c1
-rw-r--r--src/or/entrynodes.c12
-rw-r--r--src/or/entrynodes.h1
-rw-r--r--src/or/ext_orport.c4
-rw-r--r--src/or/hibernate.c91
-rw-r--r--src/or/hibernate.h2
-rw-r--r--src/or/hs_cache.c1
-rw-r--r--src/or/hs_cache.h1
-rw-r--r--src/or/hs_cell.c1
-rw-r--r--src/or/hs_circuit.c21
-rw-r--r--src/or/hs_circuit.h1
-rw-r--r--src/or/hs_client.c30
-rw-r--r--src/or/hs_common.c2
-rw-r--r--src/or/hs_control.c1
-rw-r--r--src/or/hs_descriptor.c4
-rw-r--r--src/or/hs_descriptor.h1
-rw-r--r--src/or/hs_ident.c1
-rw-r--r--src/or/hs_ident.h1
-rw-r--r--src/or/hs_ntor.c1
-rw-r--r--src/or/hs_service.c11
-rw-r--r--src/or/hs_service.h3
-rw-r--r--src/or/hs_stats.c6
-rw-r--r--src/or/include.am1
-rw-r--r--src/or/main.c326
-rw-r--r--src/or/main.h3
-rw-r--r--src/or/networkstatus.c39
-rw-r--r--src/or/networkstatus.h2
-rw-r--r--src/or/nodelist.c2
-rw-r--r--src/or/onion.c1
-rw-r--r--src/or/onion_fast.c2
-rw-r--r--src/or/onion_ntor.c1
-rw-r--r--src/or/onion_tap.c2
-rw-r--r--src/or/periodic.c2
-rw-r--r--src/or/proto_socks.c1
-rw-r--r--src/or/relay.c2
-rw-r--r--src/or/relay_crypto.c3
-rw-r--r--src/or/rendclient.c6
-rw-r--r--src/or/rendcommon.c8
-rw-r--r--src/or/rendservice.c7
-rw-r--r--src/or/rephist.c1
-rw-r--r--src/or/router.c30
-rw-r--r--src/or/router.h2
-rw-r--r--src/or/routerkeys.c1
-rw-r--r--src/or/routerlist.c2
-rw-r--r--src/or/routerparse.c19
-rw-r--r--src/or/status.c6
-rw-r--r--src/or/torcert.c2
-rw-r--r--src/or/voting_schedule.c2
-rw-r--r--src/rust/Cargo.lock63
-rw-r--r--src/rust/Cargo.toml13
-rw-r--r--src/rust/crypto/Cargo.toml21
-rw-r--r--src/rust/crypto/digests/mod.rs7
-rw-r--r--src/rust/crypto/digests/sha2.rs213
-rw-r--r--src/rust/crypto/lib.rs36
-rw-r--r--src/rust/external/Cargo.toml3
-rw-r--r--src/rust/external/crypto_digest.rs402
-rw-r--r--src/rust/external/crypto_rand.rs87
-rw-r--r--src/rust/external/lib.rs6
-rw-r--r--src/rust/include.am9
-rw-r--r--src/rust/rand/Cargo.toml27
-rw-r--r--src/rust/rand/lib.rs16
-rw-r--r--src/rust/rand/rng.rs140
-rw-r--r--src/test/bench.c1
-rw-r--r--src/test/include.am2
-rw-r--r--src/test/rend_test_helpers.c1
-rw-r--r--src/test/test-memwipe.c2
-rw-r--r--src/test/test-timers.c2
-rw-r--r--src/test/test.c22
-rw-r--r--src/test/test.h2
-rw-r--r--src/test/test_addr.c155
-rw-r--r--src/test/test_address_set.c1
-rw-r--r--src/test/test_buffers.c1
-rw-r--r--src/test/test_cell_formats.c1
-rw-r--r--src/test/test_channel.c1
-rw-r--r--src/test/test_consdiffmgr.c1
-rw-r--r--src/test/test_containers.c1
-rw-r--r--src/test/test_crypto.c3
-rw-r--r--src/test/test_crypto_openssl.c4
-rw-r--r--src/test/test_crypto_slow.c1
-rw-r--r--src/test/test_dir.c28
-rw-r--r--src/test/test_dir_common.c1
-rw-r--r--src/test/test_dos.c1
-rw-r--r--src/test/test_entrynodes.c202
-rw-r--r--src/test/test_extorport.c1
-rw-r--r--src/test/test_helpers.c1
-rw-r--r--src/test/test_hs_cell.c1
-rw-r--r--src/test/test_hs_client.c18
-rw-r--r--src/test/test_hs_common.c14
-rw-r--r--src/test/test_hs_descriptor.c1
-rw-r--r--src/test/test_hs_intropoint.c2
-rw-r--r--src/test/test_hs_service.c3
-rw-r--r--src/test/test_mainloop.c142
-rw-r--r--src/test/test_nodelist.c1
-rw-r--r--src/test/test_oom.c1
-rw-r--r--src/test/test_relaycrypt.c1
-rw-r--r--src/test/test_routerlist.c1
-rw-r--r--src/test/test_shared_random.c7
-rw-r--r--src/test/test_storagedir.c1
-rw-r--r--src/test/test_tortls.c58
-rw-r--r--src/test/test_util.c1
-rw-r--r--src/test/test_util_format.c1
-rw-r--r--src/test/test_voting_schedule.c64
-rw-r--r--src/test/test_workqueue.c14
-rw-r--r--src/test/testing_common.c1
-rw-r--r--src/test/testing_rsakeys.c1
-rw-r--r--src/tools/tor-gencert.c2
-rw-r--r--src/trunnel/trunnel-local.h2
166 files changed, 3542 insertions, 1087 deletions
diff --git a/src/common/address_set.c b/src/common/address_set.c
index f61fa294e0..b2f4bb4c95 100644
--- a/src/common/address_set.c
+++ b/src/common/address_set.c
@@ -15,7 +15,7 @@
#include "address.h"
#include "compat.h"
#include "container.h"
-#include "crypto.h"
+#include "crypto_rand.h"
#include "util.h"
#include "siphash.h"
diff --git a/src/common/aes.c b/src/common/aes.c
index 95737cffcc..f6b933374a 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -17,7 +17,6 @@
#endif
#include <openssl/opensslv.h>
-#include "crypto.h"
#include "crypto_openssl_mgt.h"
#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
@@ -116,7 +115,7 @@ aes_cipher_free_(aes_cnt_cipher_t *cipher_)
if (!cipher_)
return;
EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_;
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+#ifdef OPENSSL_1_1_API
EVP_CIPHER_CTX_reset(cipher);
#else
EVP_CIPHER_CTX_cleanup(cipher);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 707efe3892..e60eb148d8 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -11,7 +11,7 @@
#define COMPAT_LIBEVENT_PRIVATE
#include "compat_libevent.h"
-#include "crypto.h"
+#include "crypto_rand.h"
#include "util.h"
#include "torlog.h"
@@ -253,10 +253,39 @@ periodic_timer_new(struct event_base *base,
}
timer->cb = cb;
timer->data = data;
- event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/
+ periodic_timer_launch(timer, tv);
return timer;
}
+/**
+ * Launch the timer <b>timer</b> to run at <b>tv</b> from now, and every
+ * <b>tv</b> thereafter.
+ *
+ * If the timer is already enabled, this function does nothing.
+ */
+void
+periodic_timer_launch(periodic_timer_t *timer, const struct timeval *tv)
+{
+ tor_assert(timer);
+ if (event_pending(timer->ev, EV_TIMEOUT, NULL))
+ return;
+ event_add(timer->ev, tv);
+}
+
+/**
+ * Disable the provided <b>timer</b>, but do not free it.
+ *
+ * You can reenable the same timer later with periodic_timer_launch.
+ *
+ * If the timer is already disabled, this function does nothing.
+ */
+void
+periodic_timer_disable(periodic_timer_t *timer)
+{
+ tor_assert(timer);
+ (void) event_del(timer->ev);
+}
+
/** Stop and free a periodic timer */
void
periodic_timer_free_(periodic_timer_t *timer)
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index e2747860a9..286a268122 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -31,6 +31,8 @@ periodic_timer_t *periodic_timer_new(struct event_base *base,
void (*cb)(periodic_timer_t *timer, void *data),
void *data);
void periodic_timer_free_(periodic_timer_t *);
+void periodic_timer_launch(periodic_timer_t *, const struct timeval *tv);
+void periodic_timer_disable(periodic_timer_t *);
#define periodic_timer_free(t) \
FREE_AND_NULL(periodic_timer_t, periodic_timer_free_, (t))
diff --git a/src/common/compat_openssl.h b/src/common/compat_openssl.h
index 1299ac36bb..d1481fb46c 100644
--- a/src/common/compat_openssl.h
+++ b/src/common/compat_openssl.h
@@ -9,6 +9,7 @@
#include <openssl/opensslv.h>
#include "crypto_openssl_mgt.h"
+
/**
* \file compat_openssl.h
*
@@ -27,8 +28,11 @@
#define OPENSSL_1_1_API
#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && ... */
-#ifndef OPENSSL_1_1_API
+#ifndef OPENSSL_VERSION
#define OPENSSL_VERSION SSLEAY_VERSION
+#endif
+
+#ifndef OPENSSL_1_1_API
#define OpenSSL_version(v) SSLeay_version(v)
#define OpenSSL_version_num() SSLeay()
#define RAND_OpenSSL() RAND_SSLeay()
diff --git a/src/common/compat_time.c b/src/common/compat_time.c
index b3723f533c..40847a8442 100644
--- a/src/common/compat_time.c
+++ b/src/common/compat_time.c
@@ -630,7 +630,7 @@ int32_t
monotime_coarse_diff_msec32_(const monotime_coarse_t *start,
const monotime_coarse_t *end)
{
- return (int32_t)monotime_coarse_diff_msec(start, end)
+ return (int32_t)monotime_coarse_diff_msec(start, end);
}
int64_t
diff --git a/src/common/crypto.c b/src/common/crypto.c
index c98a968757..d5b7c96916 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -23,22 +23,21 @@
#endif /* defined(_WIN32) */
#define CRYPTO_PRIVATE
-#include "crypto.h"
#include "compat_openssl.h"
+#include "crypto.h"
#include "crypto_curve25519.h"
+#include "crypto_digest.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
+#include "crypto_rand.h"
#include "crypto_rsa.h"
-#include "crypto_digest.h"
+#include "crypto_util.h"
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
-#include <openssl/rand.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/conf.h>
@@ -61,18 +60,6 @@ ENABLE_GCC_WARNING(redundant-decls)
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_FCNTL_H
-#include <sys/fcntl.h>
-#endif
-#ifdef HAVE_SYS_SYSCALL_H
-#include <sys/syscall.h>
-#endif
-#ifdef HAVE_SYS_RANDOM_H
-#include <sys/random.h>
-#endif
#include "torlog.h"
#include "torint.h"
@@ -85,12 +72,6 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "keccak-tiny/keccak-tiny.h"
-/** Longest recognized */
-#define MAX_DNS_LABEL_SIZE 63
-
-/** Largest strong entropy request */
-#define MAX_STRONGEST_RAND_SIZE 256
-
/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake
* while we're waiting for the second.*/
struct crypto_dh_t {
@@ -163,23 +144,6 @@ try_load_engine(const char *path, const char *engine)
}
#endif /* !defined(DISABLE_ENGINES) */
-/** Make sure that openssl is using its default PRNG. Return 1 if we had to
- * adjust it; 0 otherwise. */
-STATIC int
-crypto_force_rand_ssleay(void)
-{
- RAND_METHOD *default_method;
- default_method = RAND_OpenSSL();
- if (RAND_get_rand_method() != default_method) {
- log_notice(LD_CRYPTO, "It appears that one of our engines has provided "
- "a replacement the OpenSSL RNG. Resetting it to the default "
- "implementation.");
- RAND_set_rand_method(default_method);
- return 1;
- }
- return 0;
-}
-
static int have_seeded_siphash = 0;
/** Set up the siphash key if we haven't already done so. */
@@ -205,7 +169,7 @@ crypto_early_init(void)
crypto_early_initialized_ = 1;
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+#ifdef OPENSSL_1_1_API
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
OPENSSL_INIT_ADD_ALL_CIPHERS |
@@ -1091,576 +1055,6 @@ crypto_dh_free_(crypto_dh_t *dh)
tor_free(dh);
}
-/* random numbers */
-
-/** How many bytes of entropy we add at once.
- *
- * This is how much entropy OpenSSL likes to add right now, so maybe it will
- * work for us too. */
-#define ADD_ENTROPY 32
-
-/** Set the seed of the weak RNG to a random value. */
-void
-crypto_seed_weak_rng(tor_weak_rng_t *rng)
-{
- unsigned seed;
- crypto_rand((void*)&seed, sizeof(seed));
- tor_init_weak_random(rng, seed);
-}
-
-#ifdef TOR_UNIT_TESTS
-int break_strongest_rng_syscall = 0;
-int break_strongest_rng_fallback = 0;
-#endif
-
-/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
- * via system calls, storing it into <b>out</b>. Return 0 on success, -1 on
- * failure. A maximum request size of 256 bytes is imposed.
- */
-static int
-crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
-{
- tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE);
-
- /* We only log at notice-level here because in the case that this function
- * fails the crypto_strongest_rand_raw() caller will log with a warning-level
- * message and let crypto_strongest_rand() error out and finally terminating
- * Tor with an assertion error.
- */
-
-#ifdef TOR_UNIT_TESTS
- if (break_strongest_rng_syscall)
- return -1;
-#endif
-
-#if defined(_WIN32)
- static int provider_set = 0;
- static HCRYPTPROV provider;
-
- if (!provider_set) {
- if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- log_notice(LD_CRYPTO, "Unable to set Windows CryptoAPI provider [1].");
- return -1;
- }
- provider_set = 1;
- }
- if (!CryptGenRandom(provider, out_len, out)) {
- log_notice(LD_CRYPTO, "Unable get entropy from the Windows CryptoAPI.");
- return -1;
- }
-
- return 0;
-#elif defined(__linux__) && defined(SYS_getrandom)
- static int getrandom_works = 1; /* Be optimistic about our chances... */
-
- /* getrandom() isn't as straightforward as getentropy(), and has
- * no glibc wrapper.
- *
- * As far as I can tell from getrandom(2) and the source code, the
- * requests we issue will always succeed (though it will block on the
- * call if /dev/urandom isn't seeded yet), since we are NOT specifying
- * GRND_NONBLOCK and the request is <= 256 bytes.
- *
- * The manpage is unclear on what happens if a signal interrupts the call
- * while the request is blocked due to lack of entropy....
- *
- * We optimistically assume that getrandom() is available and functional
- * because it is the way of the future, and 2 branch mispredicts pale in
- * comparison to the overheads involved with failing to open
- * /dev/srandom followed by opening and reading from /dev/urandom.
- */
- if (PREDICT_LIKELY(getrandom_works)) {
- long ret;
- /* A flag of '0' here means to read from '/dev/urandom', and to
- * block if insufficient entropy is available to service the
- * request.
- */
- const unsigned int flags = 0;
- do {
- ret = syscall(SYS_getrandom, out, out_len, flags);
- } while (ret == -1 && ((errno == EINTR) ||(errno == EAGAIN)));
-
- if (PREDICT_UNLIKELY(ret == -1)) {
- /* LCOV_EXCL_START we can't actually make the syscall fail in testing. */
- tor_assert(errno != EAGAIN);
- tor_assert(errno != EINTR);
-
- /* Useful log message for errno. */
- if (errno == ENOSYS) {
- log_notice(LD_CRYPTO, "Can't get entropy from getrandom()."
- " You are running a version of Tor built to support"
- " getrandom(), but the kernel doesn't implement this"
- " function--probably because it is too old?"
- " Trying fallback method instead.");
- } else {
- log_notice(LD_CRYPTO, "Can't get entropy from getrandom(): %s."
- " Trying fallback method instead.",
- strerror(errno));
- }
-
- getrandom_works = 0; /* Don't bother trying again. */
- return -1;
- /* LCOV_EXCL_STOP */
- }
-
- tor_assert(ret == (long)out_len);
- return 0;
- }
-
- return -1; /* getrandom() previously failed unexpectedly. */
-#elif defined(HAVE_GETENTROPY)
- /* getentropy() is what Linux's getrandom() wants to be when it grows up.
- * the only gotcha is that requests are limited to 256 bytes.
- */
- return getentropy(out, out_len);
-#else
- (void) out;
-#endif /* defined(_WIN32) || ... */
-
- /* This platform doesn't have a supported syscall based random. */
- return -1;
-}
-
-/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
- * via the per-platform fallback mechanism, storing it into <b>out</b>.
- * Return 0 on success, -1 on failure. A maximum request size of 256 bytes
- * is imposed.
- */
-static int
-crypto_strongest_rand_fallback(uint8_t *out, size_t out_len)
-{
-#ifdef TOR_UNIT_TESTS
- if (break_strongest_rng_fallback)
- return -1;
-#endif
-
-#ifdef _WIN32
- /* Windows exclusively uses crypto_strongest_rand_syscall(). */
- (void)out;
- (void)out_len;
- return -1;
-#else /* !(defined(_WIN32)) */
- static const char *filenames[] = {
- "/dev/srandom", "/dev/urandom", "/dev/random", NULL
- };
- int fd, i;
- size_t n;
-
- for (i = 0; filenames[i]; ++i) {
- log_debug(LD_FS, "Considering %s as entropy source", filenames[i]);
- fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0);
- if (fd<0) continue;
- log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
- n = read_all(fd, (char*)out, out_len, 0);
- close(fd);
- if (n != out_len) {
- /* LCOV_EXCL_START
- * We can't make /dev/foorandom actually fail. */
- log_notice(LD_CRYPTO,
- "Error reading from entropy source %s (read only %lu bytes).",
- filenames[i],
- (unsigned long)n);
- return -1;
- /* LCOV_EXCL_STOP */
- }
-
- return 0;
- }
-
- return -1;
-#endif /* defined(_WIN32) */
-}
-
-/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
- * storing it into <b>out</b>. Return 0 on success, -1 on failure. A maximum
- * request size of 256 bytes is imposed.
- */
-STATIC int
-crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
-{
- static const size_t sanity_min_size = 16;
- static const int max_attempts = 3;
- tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE);
-
- /* For buffers >= 16 bytes (128 bits), we sanity check the output by
- * zero filling the buffer and ensuring that it actually was at least
- * partially modified.
- *
- * Checking that any individual byte is non-zero seems like it would
- * fail too often (p = out_len * 1/256) for comfort, but this is an
- * "adjust according to taste" sort of check.
- */
- memwipe(out, 0, out_len);
- for (int i = 0; i < max_attempts; i++) {
- /* Try to use the syscall/OS favored mechanism to get strong entropy. */
- if (crypto_strongest_rand_syscall(out, out_len) != 0) {
- /* Try to use the less-favored mechanism to get strong entropy. */
- if (crypto_strongest_rand_fallback(out, out_len) != 0) {
- /* Welp, we tried. Hopefully the calling code terminates the process
- * since we're basically boned without good entropy.
- */
- log_warn(LD_CRYPTO,
- "Cannot get strong entropy: no entropy source found.");
- return -1;
- }
- }
-
- if ((out_len < sanity_min_size) || !tor_mem_is_zero((char*)out, out_len))
- return 0;
- }
-
- /* LCOV_EXCL_START
- *
- * We tried max_attempts times to fill a buffer >= 128 bits long,
- * and each time it returned all '0's. Either the system entropy
- * source is busted, or the user should go out and buy a ticket to
- * every lottery on the planet.
- */
- log_warn(LD_CRYPTO, "Strong OS entropy returned all zero buffer.");
-
- return -1;
- /* LCOV_EXCL_STOP */
-}
-
-/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
- * storing it into <b>out</b>.
- */
-void
-crypto_strongest_rand(uint8_t *out, size_t out_len)
-{
-#define DLEN SHA512_DIGEST_LENGTH
- /* We're going to hash DLEN bytes from the system RNG together with some
- * bytes from the openssl PRNG, in order to yield DLEN bytes.
- */
- uint8_t inp[DLEN*2];
- uint8_t tmp[DLEN];
- tor_assert(out);
- while (out_len) {
- crypto_rand((char*) inp, DLEN);
- if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) {
- // LCOV_EXCL_START
- log_err(LD_CRYPTO, "Failed to load strong entropy when generating an "
- "important key. Exiting.");
- /* Die with an assertion so we get a stack trace. */
- tor_assert(0);
- // LCOV_EXCL_STOP
- }
- if (out_len >= DLEN) {
- SHA512(inp, sizeof(inp), out);
- out += DLEN;
- out_len -= DLEN;
- } else {
- SHA512(inp, sizeof(inp), tmp);
- memcpy(out, tmp, out_len);
- break;
- }
- }
- memwipe(tmp, 0, sizeof(tmp));
- memwipe(inp, 0, sizeof(inp));
-#undef DLEN
-}
-
-/** Seed OpenSSL's random number generator with bytes from the operating
- * system. Return 0 on success, -1 on failure.
- */
-int
-crypto_seed_rng(void)
-{
- int rand_poll_ok = 0, load_entropy_ok = 0;
- uint8_t buf[ADD_ENTROPY];
-
- /* OpenSSL has a RAND_poll function that knows about more kinds of
- * entropy than we do. We'll try calling that, *and* calling our own entropy
- * functions. If one succeeds, we'll accept the RNG as seeded. */
- rand_poll_ok = RAND_poll();
- if (rand_poll_ok == 0)
- log_warn(LD_CRYPTO, "RAND_poll() failed."); // LCOV_EXCL_LINE
-
- load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf));
- if (load_entropy_ok) {
- RAND_seed(buf, sizeof(buf));
- }
-
- memwipe(buf, 0, sizeof(buf));
-
- if ((rand_poll_ok || load_entropy_ok) && RAND_status() == 1)
- return 0;
- else
- return -1;
-}
-
-/** Write <b>n</b> bytes of strong random data to <b>to</b>. Supports mocking
- * for unit tests.
- *
- * This function is not allowed to fail; if it would fail to generate strong
- * entropy, it must terminate the process instead.
- */
-MOCK_IMPL(void,
-crypto_rand, (char *to, size_t n))
-{
- crypto_rand_unmocked(to, n);
-}
-
-/** Write <b>n</b> bytes of strong random data to <b>to</b>. Most callers
- * will want crypto_rand instead.
- *
- * This function is not allowed to fail; if it would fail to generate strong
- * entropy, it must terminate the process instead.
- */
-void
-crypto_rand_unmocked(char *to, size_t n)
-{
- int r;
- if (n == 0)
- return;
-
- tor_assert(n < INT_MAX);
- tor_assert(to);
- r = RAND_bytes((unsigned char*)to, (int)n);
- /* We consider a PRNG failure non-survivable. Let's assert so that we get a
- * stack trace about where it happened.
- */
- tor_assert(r >= 0);
-}
-
-/** Return a pseudorandom integer, chosen uniformly from the values
- * between 0 and <b>max</b>-1 inclusive. <b>max</b> must be between 1 and
- * INT_MAX+1, inclusive. */
-int
-crypto_rand_int(unsigned int max)
-{
- unsigned int val;
- unsigned int cutoff;
- tor_assert(max <= ((unsigned int)INT_MAX)+1);
- tor_assert(max > 0); /* don't div by 0 */
-
- /* We ignore any values that are >= 'cutoff,' to avoid biasing the
- * distribution with clipping at the upper end of unsigned int's
- * range.
- */
- cutoff = UINT_MAX - (UINT_MAX%max);
- while (1) {
- crypto_rand((char*)&val, sizeof(val));
- if (val < cutoff)
- return val % max;
- }
-}
-
-/** Return a pseudorandom integer, chosen uniformly from the values i such
- * that min <= i < max.
- *
- * <b>min</b> MUST be in range [0, <b>max</b>).
- * <b>max</b> MUST be in range (min, INT_MAX].
- */
-int
-crypto_rand_int_range(unsigned int min, unsigned int max)
-{
- tor_assert(min < max);
- tor_assert(max <= INT_MAX);
-
- /* The overflow is avoided here because crypto_rand_int() returns a value
- * between 0 and (max - min) inclusive. */
- return min + crypto_rand_int(max - min);
-}
-
-/** As crypto_rand_int_range, but supports uint64_t. */
-uint64_t
-crypto_rand_uint64_range(uint64_t min, uint64_t max)
-{
- tor_assert(min < max);
- return min + crypto_rand_uint64(max - min);
-}
-
-/** As crypto_rand_int_range, but supports time_t. */
-time_t
-crypto_rand_time_range(time_t min, time_t max)
-{
- tor_assert(min < max);
- return min + (time_t)crypto_rand_uint64(max - min);
-}
-
-/** Return a pseudorandom 64-bit integer, chosen uniformly from the values
- * between 0 and <b>max</b>-1 inclusive. */
-uint64_t
-crypto_rand_uint64(uint64_t max)
-{
- uint64_t val;
- uint64_t cutoff;
- tor_assert(max < UINT64_MAX);
- tor_assert(max > 0); /* don't div by 0 */
-
- /* We ignore any values that are >= 'cutoff,' to avoid biasing the
- * distribution with clipping at the upper end of unsigned int's
- * range.
- */
- cutoff = UINT64_MAX - (UINT64_MAX%max);
- while (1) {
- crypto_rand((char*)&val, sizeof(val));
- if (val < cutoff)
- return val % max;
- }
-}
-
-/** Return a pseudorandom double d, chosen uniformly from the range
- * 0.0 <= d < 1.0.
- */
-double
-crypto_rand_double(void)
-{
- /* We just use an unsigned int here; we don't really care about getting
- * more than 32 bits of resolution */
- unsigned int u;
- crypto_rand((char*)&u, sizeof(u));
-#if SIZEOF_INT == 4
-#define UINT_MAX_AS_DOUBLE 4294967296.0
-#elif SIZEOF_INT == 8
-#define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19
-#else
-#error SIZEOF_INT is neither 4 nor 8
-#endif /* SIZEOF_INT == 4 || ... */
- return ((double)u) / UINT_MAX_AS_DOUBLE;
-}
-
-/** Generate and return a new random hostname starting with <b>prefix</b>,
- * ending with <b>suffix</b>, and containing no fewer than
- * <b>min_rand_len</b> and no more than <b>max_rand_len</b> random base32
- * characters. Does not check for failure.
- *
- * Clip <b>max_rand_len</b> to MAX_DNS_LABEL_SIZE.
- **/
-char *
-crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix,
- const char *suffix)
-{
- char *result, *rand_bytes;
- int randlen, rand_bytes_len;
- size_t resultlen, prefixlen;
-
- if (max_rand_len > MAX_DNS_LABEL_SIZE)
- max_rand_len = MAX_DNS_LABEL_SIZE;
- if (min_rand_len > max_rand_len)
- min_rand_len = max_rand_len;
-
- randlen = crypto_rand_int_range(min_rand_len, max_rand_len+1);
-
- prefixlen = strlen(prefix);
- resultlen = prefixlen + strlen(suffix) + randlen + 16;
-
- rand_bytes_len = ((randlen*5)+7)/8;
- if (rand_bytes_len % 5)
- rand_bytes_len += 5 - (rand_bytes_len%5);
- rand_bytes = tor_malloc(rand_bytes_len);
- crypto_rand(rand_bytes, rand_bytes_len);
-
- result = tor_malloc(resultlen);
- memcpy(result, prefix, prefixlen);
- base32_encode(result+prefixlen, resultlen-prefixlen,
- rand_bytes, rand_bytes_len);
- tor_free(rand_bytes);
- strlcpy(result+prefixlen+randlen, suffix, resultlen-(prefixlen+randlen));
-
- return result;
-}
-
-/** Return a randomly chosen element of <b>sl</b>; or NULL if <b>sl</b>
- * is empty. */
-void *
-smartlist_choose(const smartlist_t *sl)
-{
- int len = smartlist_len(sl);
- if (len)
- return smartlist_get(sl,crypto_rand_int(len));
- return NULL; /* no elements to choose from */
-}
-
-/** Scramble the elements of <b>sl</b> into a random order. */
-void
-smartlist_shuffle(smartlist_t *sl)
-{
- int i;
- /* From the end of the list to the front, choose at random from the
- positions we haven't looked at yet, and swap that position into the
- current position. Remember to give "no swap" the same probability as
- any other swap. */
- for (i = smartlist_len(sl)-1; i > 0; --i) {
- int j = crypto_rand_int(i+1);
- smartlist_swap(sl, i, j);
- }
-}
-
-/**
- * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
- * the value <b>byte</b>.
- * If <b>mem</b> is NULL or <b>sz</b> is zero, nothing happens.
- *
- * This function is preferable to memset, since many compilers will happily
- * optimize out memset() when they can convince themselves that the data being
- * cleared will never be read.
- *
- * Right now, our convention is to use this function when we are wiping data
- * that's about to become inaccessible, such as stack buffers that are about
- * to go out of scope or structures that are about to get freed. (In
- * practice, it appears that the compilers we're currently using will optimize
- * out the memset()s for stack-allocated buffers, but not those for
- * about-to-be-freed structures. That could change, though, so we're being
- * wary.) If there are live reads for the data, then you can just use
- * memset().
- */
-void
-memwipe(void *mem, uint8_t byte, size_t sz)
-{
- if (sz == 0) {
- return;
- }
- /* If sz is nonzero, then mem must not be NULL. */
- tor_assert(mem != NULL);
-
- /* Data this large is likely to be an underflow. */
- tor_assert(sz < SIZE_T_CEILING);
-
- /* Because whole-program-optimization exists, we may not be able to just
- * have this function call "memset". A smart compiler could inline it, then
- * eliminate dead memsets, and declare itself to be clever. */
-
-#if defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY)
- /* Here's what you do on windows. */
- SecureZeroMemory(mem,sz);
-#elif defined(HAVE_RTLSECUREZEROMEMORY)
- RtlSecureZeroMemory(mem,sz);
-#elif defined(HAVE_EXPLICIT_BZERO)
- /* The BSDs provide this. */
- explicit_bzero(mem, sz);
-#elif defined(HAVE_MEMSET_S)
- /* This is in the C99 standard. */
- memset_s(mem, sz, 0, sz);
-#else
- /* This is a slow and ugly function from OpenSSL that fills 'mem' with junk
- * based on the pointer value, then uses that junk to update a global
- * variable. It's an elaborate ruse to trick the compiler into not
- * optimizing out the "wipe this memory" code. Read it if you like zany
- * programming tricks! In later versions of Tor, we should look for better
- * not-optimized-out memory wiping stuff...
- *
- * ...or maybe not. In practice, there are pure-asm implementations of
- * OPENSSL_cleanse() on most platforms, which ought to do the job.
- **/
-
- OPENSSL_cleanse(mem, sz);
-#endif /* defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY) || ... */
-
- /* Just in case some caller of memwipe() is relying on getting a buffer
- * filled with a particular value, fill the buffer.
- *
- * If this function gets inlined, this memset might get eliminated, but
- * that's okay: We only care about this particular memset in the case where
- * the caller should have been using memset(), and the memset() wouldn't get
- * eliminated. In other words, this is here so that we won't break anything
- * if somebody accidentally calls memwipe() instead of memset().
- **/
- memset(mem, byte, sz);
-}
-
/** @{ */
/** Uninitialize the crypto library. Return 0 on success. Does not detect
* failure.
@@ -1668,13 +1062,13 @@ memwipe(void *mem, uint8_t byte, size_t sz)
int
crypto_global_cleanup(void)
{
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+#ifndef OPENSSL_1_1_API
EVP_cleanup();
#endif
#ifndef NEW_THREAD_API
ERR_remove_thread_state(NULL);
#endif
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+#ifndef OPENSSL_1_1_API
ERR_free_strings();
#endif
@@ -1688,13 +1082,13 @@ crypto_global_cleanup(void)
dh_param_p = dh_param_p_tls = dh_param_g = NULL;
#ifndef DISABLE_ENGINES
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+#ifndef OPENSSL_1_1_API
ENGINE_cleanup();
#endif
#endif
CONF_modules_unload(1);
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+#ifndef OPENSSL_1_1_API
CRYPTO_cleanup_all_ex_data();
#endif
diff --git a/src/common/crypto.h b/src/common/crypto.h
index b586790329..c773557310 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -17,13 +17,10 @@
#include <stdio.h>
#include "torint.h"
-#include "testsupport.h"
#include "compat.h"
#include "util.h"
#include "crypto_rsa.h"
-#include "keccak-tiny/keccak-tiny.h"
-
/** Length of our symmetric cipher's keys of 128-bit. */
#define CIPHER_KEY_LEN 16
/** Length of our symmetric cipher's IV of 128-bit. */
@@ -41,6 +38,7 @@ typedef struct aes_cnt_cipher crypto_cipher_t;
typedef struct crypto_dh_t crypto_dh_t;
/* global state */
+int crypto_init_siphash_key(void);
int crypto_early_init(void) ATTR_WUR;
int crypto_global_init(int hardwareAccel,
const char *accelName,
@@ -105,31 +103,6 @@ int crypto_expand_key_material_rfc5869_sha256(
const uint8_t *info_in, size_t info_in_len,
uint8_t *key_out, size_t key_out_len);
-/* random numbers */
-int crypto_seed_rng(void) ATTR_WUR;
-MOCK_DECL(void,crypto_rand,(char *to, size_t n));
-void crypto_rand_unmocked(char *to, size_t n);
-void crypto_strongest_rand(uint8_t *out, size_t out_len);
-int crypto_rand_int(unsigned int max);
-int crypto_rand_int_range(unsigned int min, unsigned int max);
-uint64_t crypto_rand_uint64_range(uint64_t min, uint64_t max);
-time_t crypto_rand_time_range(time_t min, time_t max);
-uint64_t crypto_rand_uint64(uint64_t max);
-double crypto_rand_double(void);
-struct tor_weak_rng_t;
-void crypto_seed_weak_rng(struct tor_weak_rng_t *rng);
-int crypto_init_siphash_key(void);
-
-char *crypto_random_hostname(int min_rand_len, int max_rand_len,
- const char *prefix, const char *suffix);
-
-struct smartlist_t;
-void *smartlist_choose(const struct smartlist_t *sl);
-void smartlist_shuffle(struct smartlist_t *sl);
-
-/** OpenSSL-based utility functions. */
-void memwipe(void *mem, uint8_t byte, size_t sz);
-
/* Prototypes for private functions only used by tortls.c, crypto.c, and the
* unit tests. */
struct dh_st;
@@ -137,16 +110,5 @@ struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in);
-#ifdef CRYPTO_PRIVATE
-
-STATIC int crypto_force_rand_ssleay(void);
-STATIC int crypto_strongest_rand_raw(uint8_t *out, size_t out_len);
-
-#ifdef TOR_UNIT_TESTS
-extern int break_strongest_rng_syscall;
-extern int break_strongest_rng_fallback;
-#endif
-#endif /* defined(CRYPTO_PRIVATE) */
-
#endif /* !defined(TOR_CRYPTO_H) */
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
index ccf12d00f9..996d94c6e2 100644
--- a/src/common/crypto_curve25519.c
+++ b/src/common/crypto_curve25519.c
@@ -21,10 +21,11 @@
#include <sys/stat.h>
#endif
#include "container.h"
-#include "crypto.h"
#include "crypto_curve25519.h"
-#include "crypto_format.h"
#include "crypto_digest.h"
+#include "crypto_format.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "util.h"
#include "torlog.h"
diff --git a/src/common/crypto_digest.c b/src/common/crypto_digest.c
index cdcc1828c8..9f9a1a1e2c 100644
--- a/src/common/crypto_digest.c
+++ b/src/common/crypto_digest.c
@@ -10,10 +10,13 @@
* operations.
**/
+#include "container.h"
#include "crypto_digest.h"
-
-#include "crypto.h" /* common functions */
#include "crypto_openssl_mgt.h"
+#include "crypto_util.h"
+#include "torlog.h"
+
+#include "keccak-tiny/keccak-tiny.h"
DISABLE_GCC_WARNING(redundant-decls)
@@ -22,8 +25,6 @@ DISABLE_GCC_WARNING(redundant-decls)
ENABLE_GCC_WARNING(redundant-decls)
-#include "container.h"
-
/* Crypto digest functions */
/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
@@ -267,7 +268,11 @@ crypto_digest_new(void)
}
/** Allocate and return a new digest object to compute 256-bit digests
- * using <b>algorithm</b>. */
+ * using <b>algorithm</b>.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new`
+ * C_RUST_COUPLED: `crypto::digest::Sha256::default`
+ */
crypto_digest_t *
crypto_digest256_new(digest_algorithm_t algorithm)
{
@@ -297,6 +302,9 @@ crypto_digest_free_(crypto_digest_t *digest)
}
/** Add <b>len</b> bytes from <b>data</b> to the digest object.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess`
+ * C_RUST_COUPLED: `crypto::digest::Sha256::process`
*/
void
crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
@@ -334,6 +342,9 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
/** Compute the hash of the data that has been passed to the digest
* object; write the first out_len bytes of the result to <b>out</b>.
* <b>out_len</b> must be \<= DIGEST512_LEN.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest`
+ * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256`
*/
void
crypto_digest_get_digest(crypto_digest_t *digest,
@@ -382,6 +393,9 @@ crypto_digest_get_digest(crypto_digest_t *digest,
/** Allocate and return a new digest object with the same state as
* <b>digest</b>
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup`
+ * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256`
*/
crypto_digest_t *
crypto_digest_dup(const crypto_digest_t *digest)
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index f1cc0cb188..9c13e3bdf0 100644
--- a/src/common/crypto_ed25519.c
+++ b/src/common/crypto_ed25519.c
@@ -21,12 +21,12 @@
#include <sys/stat.h>
#endif
-#include "crypto.h"
-
-#include "crypto_digest.h"
#include "crypto_curve25519.h"
+#include "crypto_digest.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "torlog.h"
#include "util.h"
#include "util_format.h"
diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c
index 3f6fb9f54c..460e85bac1 100644
--- a/src/common/crypto_format.c
+++ b/src/common/crypto_format.c
@@ -15,11 +15,11 @@
#include <sys/stat.h>
#endif
#include "container.h"
-#include "crypto.h"
#include "crypto_curve25519.h"
+#include "crypto_digest.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
-#include "crypto_digest.h"
+#include "crypto_util.h"
#include "util.h"
#include "util_format.h"
#include "torlog.h"
diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c
index 604fc68e97..c2bd1d26cb 100644
--- a/src/common/crypto_pwbox.c
+++ b/src/common/crypto_pwbox.c
@@ -9,9 +9,11 @@
*/
#include "crypto.h"
-#include "crypto_s2k.h"
-#include "crypto_pwbox.h"
#include "crypto_digest.h"
+#include "crypto_pwbox.h"
+#include "crypto_rand.h"
+#include "crypto_s2k.h"
+#include "crypto_util.h"
#include "di_ops.h"
#include "util.h"
#include "pwbox.h"
diff --git a/src/common/crypto_rand.c b/src/common/crypto_rand.c
new file mode 100644
index 0000000000..df2e2f65d3
--- /dev/null
+++ b/src/common/crypto_rand.c
@@ -0,0 +1,615 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_rand.c
+ *
+ * \brief Functions for initialising and seeding (pseudo-)random
+ * number generators, and working with randomness.
+ **/
+
+#ifndef CRYPTO_RAND_PRIVATE
+#define CRYPTO_RAND_PRIVATE
+
+#include "crypto_rand.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <wincrypt.h>
+#endif /* defined(_WIN32) */
+
+#include "container.h"
+#include "compat.h"
+#include "compat_openssl.h"
+#include "crypto_util.h"
+#include "sandbox.h"
+#include "testsupport.h"
+#include "torlog.h"
+#include "util.h"
+#include "util_format.h"
+
+DISABLE_GCC_WARNING(redundant-decls)
+#include <openssl/rand.h>
+ENABLE_GCC_WARNING(redundant-decls)
+
+#if __GNUC__ && GCC_VERSION >= 402
+#if GCC_VERSION >= 406
+#pragma GCC diagnostic pop
+#else
+#pragma GCC diagnostic warning "-Wredundant-decls"
+#endif
+#endif /* __GNUC__ && GCC_VERSION >= 402 */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
+#ifdef HAVE_SYS_RANDOM_H
+#include <sys/random.h>
+#endif
+
+/**
+ * How many bytes of entropy we add at once.
+ *
+ * This is how much entropy OpenSSL likes to add right now, so maybe it will
+ * work for us too.
+ **/
+#define ADD_ENTROPY 32
+
+/**
+ * Longest recognized DNS query.
+ **/
+#define MAX_DNS_LABEL_SIZE 63
+
+/**
+ * Largest strong entropy request permitted.
+ **/
+#define MAX_STRONGEST_RAND_SIZE 256
+
+/**
+ * Set the seed of the weak RNG to a random value.
+ **/
+void
+crypto_seed_weak_rng(tor_weak_rng_t *rng)
+{
+ unsigned seed;
+ crypto_rand((void*)&seed, sizeof(seed));
+ tor_init_weak_random(rng, seed);
+}
+
+#ifdef TOR_UNIT_TESTS
+int break_strongest_rng_syscall = 0;
+int break_strongest_rng_fallback = 0;
+#endif
+
+/**
+ * Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
+ * via system calls, storing it into <b>out</b>. Return 0 on success, -1 on
+ * failure. A maximum request size of 256 bytes is imposed.
+ **/
+static int
+crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
+{
+ tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE);
+
+ /* We only log at notice-level here because in the case that this function
+ * fails the crypto_strongest_rand_raw() caller will log with a warning-level
+ * message and let crypto_strongest_rand() error out and finally terminating
+ * Tor with an assertion error.
+ */
+
+#ifdef TOR_UNIT_TESTS
+ if (break_strongest_rng_syscall)
+ return -1;
+#endif
+
+#if defined(_WIN32)
+ static int provider_set = 0;
+ static HCRYPTPROV provider;
+
+ if (!provider_set) {
+ if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ log_notice(LD_CRYPTO, "Unable to set Windows CryptoAPI provider [1].");
+ return -1;
+ }
+ provider_set = 1;
+ }
+ if (!CryptGenRandom(provider, out_len, out)) {
+ log_notice(LD_CRYPTO, "Unable get entropy from the Windows CryptoAPI.");
+ return -1;
+ }
+
+ return 0;
+#elif defined(__linux__) && defined(SYS_getrandom)
+ static int getrandom_works = 1; /* Be optimistic about our chances... */
+
+ /* getrandom() isn't as straightforward as getentropy(), and has
+ * no glibc wrapper.
+ *
+ * As far as I can tell from getrandom(2) and the source code, the
+ * requests we issue will always succeed (though it will block on the
+ * call if /dev/urandom isn't seeded yet), since we are NOT specifying
+ * GRND_NONBLOCK and the request is <= 256 bytes.
+ *
+ * The manpage is unclear on what happens if a signal interrupts the call
+ * while the request is blocked due to lack of entropy....
+ *
+ * We optimistically assume that getrandom() is available and functional
+ * because it is the way of the future, and 2 branch mispredicts pale in
+ * comparison to the overheads involved with failing to open
+ * /dev/srandom followed by opening and reading from /dev/urandom.
+ */
+ if (PREDICT_LIKELY(getrandom_works)) {
+ long ret;
+ /* A flag of '0' here means to read from '/dev/urandom', and to
+ * block if insufficient entropy is available to service the
+ * request.
+ */
+ const unsigned int flags = 0;
+ do {
+ ret = syscall(SYS_getrandom, out, out_len, flags);
+ } while (ret == -1 && ((errno == EINTR) ||(errno == EAGAIN)));
+
+ if (PREDICT_UNLIKELY(ret == -1)) {
+ /* LCOV_EXCL_START we can't actually make the syscall fail in testing. */
+ tor_assert(errno != EAGAIN);
+ tor_assert(errno != EINTR);
+
+ /* Useful log message for errno. */
+ if (errno == ENOSYS) {
+ log_notice(LD_CRYPTO, "Can't get entropy from getrandom()."
+ " You are running a version of Tor built to support"
+ " getrandom(), but the kernel doesn't implement this"
+ " function--probably because it is too old?"
+ " Trying fallback method instead.");
+ } else {
+ log_notice(LD_CRYPTO, "Can't get entropy from getrandom(): %s."
+ " Trying fallback method instead.",
+ strerror(errno));
+ }
+
+ getrandom_works = 0; /* Don't bother trying again. */
+ return -1;
+ /* LCOV_EXCL_STOP */
+ }
+
+ tor_assert(ret == (long)out_len);
+ return 0;
+ }
+
+ return -1; /* getrandom() previously failed unexpectedly. */
+#elif defined(HAVE_GETENTROPY)
+ /* getentropy() is what Linux's getrandom() wants to be when it grows up.
+ * the only gotcha is that requests are limited to 256 bytes.
+ */
+ return getentropy(out, out_len);
+#else
+ (void) out;
+#endif /* defined(_WIN32) || ... */
+
+ /* This platform doesn't have a supported syscall based random. */
+ return -1;
+}
+
+/**
+ * Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
+ * via the per-platform fallback mechanism, storing it into <b>out</b>.
+ * Return 0 on success, -1 on failure. A maximum request size of 256 bytes
+ * is imposed.
+ **/
+static int
+crypto_strongest_rand_fallback(uint8_t *out, size_t out_len)
+{
+#ifdef TOR_UNIT_TESTS
+ if (break_strongest_rng_fallback)
+ return -1;
+#endif
+
+#ifdef _WIN32
+ /* Windows exclusively uses crypto_strongest_rand_syscall(). */
+ (void)out;
+ (void)out_len;
+ return -1;
+#else /* !(defined(_WIN32)) */
+ static const char *filenames[] = {
+ "/dev/srandom", "/dev/urandom", "/dev/random", NULL
+ };
+ int fd, i;
+ size_t n;
+
+ for (i = 0; filenames[i]; ++i) {
+ log_debug(LD_FS, "Considering %s as entropy source", filenames[i]);
+ fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0);
+ if (fd<0) continue;
+ log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
+ n = read_all(fd, (char*)out, out_len, 0);
+ close(fd);
+ if (n != out_len) {
+ /* LCOV_EXCL_START
+ * We can't make /dev/foorandom actually fail. */
+ log_notice(LD_CRYPTO,
+ "Error reading from entropy source %s (read only %lu bytes).",
+ filenames[i],
+ (unsigned long)n);
+ return -1;
+ /* LCOV_EXCL_STOP */
+ }
+
+ return 0;
+ }
+
+ return -1;
+#endif /* defined(_WIN32) */
+}
+
+/**
+ * Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
+ * storing it into <b>out</b>. Return 0 on success, -1 on failure. A maximum
+ * request size of 256 bytes is imposed.
+ **/
+STATIC int
+crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
+{
+ static const size_t sanity_min_size = 16;
+ static const int max_attempts = 3;
+ tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE);
+
+ /* For buffers >= 16 bytes (128 bits), we sanity check the output by
+ * zero filling the buffer and ensuring that it actually was at least
+ * partially modified.
+ *
+ * Checking that any individual byte is non-zero seems like it would
+ * fail too often (p = out_len * 1/256) for comfort, but this is an
+ * "adjust according to taste" sort of check.
+ */
+ memwipe(out, 0, out_len);
+ for (int i = 0; i < max_attempts; i++) {
+ /* Try to use the syscall/OS favored mechanism to get strong entropy. */
+ if (crypto_strongest_rand_syscall(out, out_len) != 0) {
+ /* Try to use the less-favored mechanism to get strong entropy. */
+ if (crypto_strongest_rand_fallback(out, out_len) != 0) {
+ /* Welp, we tried. Hopefully the calling code terminates the process
+ * since we're basically boned without good entropy.
+ */
+ log_warn(LD_CRYPTO,
+ "Cannot get strong entropy: no entropy source found.");
+ return -1;
+ }
+ }
+
+ if ((out_len < sanity_min_size) || !tor_mem_is_zero((char*)out, out_len))
+ return 0;
+ }
+
+ /* LCOV_EXCL_START
+ *
+ * We tried max_attempts times to fill a buffer >= 128 bits long,
+ * and each time it returned all '0's. Either the system entropy
+ * source is busted, or the user should go out and buy a ticket to
+ * every lottery on the planet.
+ */
+ log_warn(LD_CRYPTO, "Strong OS entropy returned all zero buffer.");
+
+ return -1;
+ /* LCOV_EXCL_STOP */
+}
+
+/**
+ * Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
+ * storing it into <b>out</b>.
+ **/
+void
+crypto_strongest_rand(uint8_t *out, size_t out_len)
+{
+#define DLEN SHA512_DIGEST_LENGTH
+ /* We're going to hash DLEN bytes from the system RNG together with some
+ * bytes from the openssl PRNG, in order to yield DLEN bytes.
+ */
+ uint8_t inp[DLEN*2];
+ uint8_t tmp[DLEN];
+ tor_assert(out);
+ while (out_len) {
+ crypto_rand((char*) inp, DLEN);
+ if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) {
+ // LCOV_EXCL_START
+ log_err(LD_CRYPTO, "Failed to load strong entropy when generating an "
+ "important key. Exiting.");
+ /* Die with an assertion so we get a stack trace. */
+ tor_assert(0);
+ // LCOV_EXCL_STOP
+ }
+ if (out_len >= DLEN) {
+ SHA512(inp, sizeof(inp), out);
+ out += DLEN;
+ out_len -= DLEN;
+ } else {
+ SHA512(inp, sizeof(inp), tmp);
+ memcpy(out, tmp, out_len);
+ break;
+ }
+ }
+ memwipe(tmp, 0, sizeof(tmp));
+ memwipe(inp, 0, sizeof(inp));
+#undef DLEN
+}
+
+/**
+ * Seed OpenSSL's random number generator with bytes from the operating
+ * system. Return 0 on success, -1 on failure.
+ **/
+int
+crypto_seed_rng(void)
+{
+ int rand_poll_ok = 0, load_entropy_ok = 0;
+ uint8_t buf[ADD_ENTROPY];
+
+ /* OpenSSL has a RAND_poll function that knows about more kinds of
+ * entropy than we do. We'll try calling that, *and* calling our own entropy
+ * functions. If one succeeds, we'll accept the RNG as seeded. */
+ rand_poll_ok = RAND_poll();
+ if (rand_poll_ok == 0)
+ log_warn(LD_CRYPTO, "RAND_poll() failed."); // LCOV_EXCL_LINE
+
+ load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf));
+ if (load_entropy_ok) {
+ RAND_seed(buf, sizeof(buf));
+ }
+
+ memwipe(buf, 0, sizeof(buf));
+
+ if ((rand_poll_ok || load_entropy_ok) && RAND_status() == 1)
+ return 0;
+ else
+ return -1;
+}
+
+/**
+ * Write <b>n</b> bytes of strong random data to <b>to</b>. Supports mocking
+ * for unit tests.
+ *
+ * This function is not allowed to fail; if it would fail to generate strong
+ * entropy, it must terminate the process instead.
+ **/
+MOCK_IMPL(void,
+crypto_rand, (char *to, size_t n))
+{
+ crypto_rand_unmocked(to, n);
+}
+
+/**
+ * Write <b>n</b> bytes of strong random data to <b>to</b>. Most callers
+ * will want crypto_rand instead.
+ *
+ * This function is not allowed to fail; if it would fail to generate strong
+ * entropy, it must terminate the process instead.
+ **/
+void
+crypto_rand_unmocked(char *to, size_t n)
+{
+ int r;
+ if (n == 0)
+ return;
+
+ tor_assert(n < INT_MAX);
+ tor_assert(to);
+ r = RAND_bytes((unsigned char*)to, (int)n);
+ /* We consider a PRNG failure non-survivable. Let's assert so that we get a
+ * stack trace about where it happened.
+ */
+ tor_assert(r >= 0);
+}
+
+/**
+ * Return a pseudorandom integer, chosen uniformly from the values
+ * between 0 and <b>max</b>-1 inclusive. <b>max</b> must be between 1 and
+ * INT_MAX+1, inclusive.
+ */
+int
+crypto_rand_int(unsigned int max)
+{
+ unsigned int val;
+ unsigned int cutoff;
+ tor_assert(max <= ((unsigned int)INT_MAX)+1);
+ tor_assert(max > 0); /* don't div by 0 */
+
+ /* We ignore any values that are >= 'cutoff,' to avoid biasing the
+ * distribution with clipping at the upper end of unsigned int's
+ * range.
+ */
+ cutoff = UINT_MAX - (UINT_MAX%max);
+ while (1) {
+ crypto_rand((char*)&val, sizeof(val));
+ if (val < cutoff)
+ return val % max;
+ }
+}
+
+/**
+ * Return a pseudorandom integer, chosen uniformly from the values i such
+ * that min <= i < max.
+ *
+ * <b>min</b> MUST be in range [0, <b>max</b>).
+ * <b>max</b> MUST be in range (min, INT_MAX].
+ **/
+int
+crypto_rand_int_range(unsigned int min, unsigned int max)
+{
+ tor_assert(min < max);
+ tor_assert(max <= INT_MAX);
+
+ /* The overflow is avoided here because crypto_rand_int() returns a value
+ * between 0 and (max - min) inclusive. */
+ return min + crypto_rand_int(max - min);
+}
+
+/**
+ * As crypto_rand_int_range, but supports uint64_t.
+ **/
+uint64_t
+crypto_rand_uint64_range(uint64_t min, uint64_t max)
+{
+ tor_assert(min < max);
+ return min + crypto_rand_uint64(max - min);
+}
+
+/**
+ * As crypto_rand_int_range, but supports time_t.
+ **/
+time_t
+crypto_rand_time_range(time_t min, time_t max)
+{
+ tor_assert(min < max);
+ return min + (time_t)crypto_rand_uint64(max - min);
+}
+
+/**
+ * Return a pseudorandom 64-bit integer, chosen uniformly from the values
+ * between 0 and <b>max</b>-1 inclusive.
+ **/
+uint64_t
+crypto_rand_uint64(uint64_t max)
+{
+ uint64_t val;
+ uint64_t cutoff;
+ tor_assert(max < UINT64_MAX);
+ tor_assert(max > 0); /* don't div by 0 */
+
+ /* We ignore any values that are >= 'cutoff,' to avoid biasing the
+ * distribution with clipping at the upper end of unsigned int's
+ * range.
+ */
+ cutoff = UINT64_MAX - (UINT64_MAX%max);
+ while (1) {
+ crypto_rand((char*)&val, sizeof(val));
+ if (val < cutoff)
+ return val % max;
+ }
+}
+
+/**
+ * Return a pseudorandom double d, chosen uniformly from the range
+ * 0.0 <= d < 1.0.
+ **/
+double
+crypto_rand_double(void)
+{
+ /* We just use an unsigned int here; we don't really care about getting
+ * more than 32 bits of resolution */
+ unsigned int u;
+ crypto_rand((char*)&u, sizeof(u));
+#if SIZEOF_INT == 4
+#define UINT_MAX_AS_DOUBLE 4294967296.0
+#elif SIZEOF_INT == 8
+#define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19
+#else
+#error SIZEOF_INT is neither 4 nor 8
+#endif /* SIZEOF_INT == 4 || ... */
+ return ((double)u) / UINT_MAX_AS_DOUBLE;
+}
+
+/**
+ * Generate and return a new random hostname starting with <b>prefix</b>,
+ * ending with <b>suffix</b>, and containing no fewer than
+ * <b>min_rand_len</b> and no more than <b>max_rand_len</b> random base32
+ * characters. Does not check for failure.
+ *
+ * Clip <b>max_rand_len</b> to MAX_DNS_LABEL_SIZE.
+ **/
+char *
+crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix,
+ const char *suffix)
+{
+ char *result, *rand_bytes;
+ int randlen, rand_bytes_len;
+ size_t resultlen, prefixlen;
+
+ if (max_rand_len > MAX_DNS_LABEL_SIZE)
+ max_rand_len = MAX_DNS_LABEL_SIZE;
+ if (min_rand_len > max_rand_len)
+ min_rand_len = max_rand_len;
+
+ randlen = crypto_rand_int_range(min_rand_len, max_rand_len+1);
+
+ prefixlen = strlen(prefix);
+ resultlen = prefixlen + strlen(suffix) + randlen + 16;
+
+ rand_bytes_len = ((randlen*5)+7)/8;
+ if (rand_bytes_len % 5)
+ rand_bytes_len += 5 - (rand_bytes_len%5);
+ rand_bytes = tor_malloc(rand_bytes_len);
+ crypto_rand(rand_bytes, rand_bytes_len);
+
+ result = tor_malloc(resultlen);
+ memcpy(result, prefix, prefixlen);
+ base32_encode(result+prefixlen, resultlen-prefixlen,
+ rand_bytes, rand_bytes_len);
+ tor_free(rand_bytes);
+ strlcpy(result+prefixlen+randlen, suffix, resultlen-(prefixlen+randlen));
+
+ return result;
+}
+
+/**
+ * Return a randomly chosen element of <b>sl</b>; or NULL if <b>sl</b>
+ * is empty.
+ **/
+void *
+smartlist_choose(const smartlist_t *sl)
+{
+ int len = smartlist_len(sl);
+ if (len)
+ return smartlist_get(sl,crypto_rand_int(len));
+ return NULL; /* no elements to choose from */
+}
+
+/**
+ * Scramble the elements of <b>sl</b> into a random order.
+ **/
+void
+smartlist_shuffle(smartlist_t *sl)
+{
+ int i;
+ /* From the end of the list to the front, choose at random from the
+ positions we haven't looked at yet, and swap that position into the
+ current position. Remember to give "no swap" the same probability as
+ any other swap. */
+ for (i = smartlist_len(sl)-1; i > 0; --i) {
+ int j = crypto_rand_int(i+1);
+ smartlist_swap(sl, i, j);
+ }
+}
+
+/** Make sure that openssl is using its default PRNG. Return 1 if we had to
+ * adjust it; 0 otherwise. */
+int
+crypto_force_rand_ssleay(void)
+{
+ RAND_METHOD *default_method;
+ default_method = RAND_OpenSSL();
+ if (RAND_get_rand_method() != default_method) {
+ log_notice(LD_CRYPTO, "It appears that one of our engines has provided "
+ "a replacement the OpenSSL RNG. Resetting it to the default "
+ "implementation.");
+ RAND_set_rand_method(default_method);
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* !defined(CRYPTO_RAND_PRIVATE) */
+
diff --git a/src/common/crypto_rand.h b/src/common/crypto_rand.h
new file mode 100644
index 0000000000..4eac94f57b
--- /dev/null
+++ b/src/common/crypto_rand.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_rand.h
+ *
+ * \brief Common functions for using (psuedo-)random number generators.
+ **/
+
+#ifndef TOR_CRYPTO_RAND_H
+#define TOR_CRYPTO_RAND_H
+
+#include "torint.h"
+#include "util.h"
+
+/* random numbers */
+int crypto_seed_rng(void) ATTR_WUR;
+MOCK_DECL(void,crypto_rand,(char *to, size_t n));
+void crypto_rand_unmocked(char *to, size_t n);
+void crypto_strongest_rand(uint8_t *out, size_t out_len);
+int crypto_rand_int(unsigned int max);
+int crypto_rand_int_range(unsigned int min, unsigned int max);
+uint64_t crypto_rand_uint64_range(uint64_t min, uint64_t max);
+time_t crypto_rand_time_range(time_t min, time_t max);
+uint64_t crypto_rand_uint64(uint64_t max);
+double crypto_rand_double(void);
+struct tor_weak_rng_t;
+void crypto_seed_weak_rng(struct tor_weak_rng_t *rng);
+
+char *crypto_random_hostname(int min_rand_len, int max_rand_len,
+ const char *prefix, const char *suffix);
+
+struct smartlist_t;
+void *smartlist_choose(const struct smartlist_t *sl);
+void smartlist_shuffle(struct smartlist_t *sl);
+int crypto_force_rand_ssleay(void);
+
+#ifdef CRYPTO_RAND_PRIVATE
+
+STATIC int crypto_strongest_rand_raw(uint8_t *out, size_t out_len);
+
+#ifdef TOR_UNIT_TESTS
+extern int break_strongest_rng_syscall;
+extern int break_strongest_rng_fallback;
+#endif
+#endif /* defined(CRYPTO_RAND_PRIVATE) */
+
+#endif /* !defined(TOR_CRYPTO_RAND_H) */
+
diff --git a/src/common/crypto_rsa.c b/src/common/crypto_rsa.c
index 986ccb0ee2..0a88b0e772 100644
--- a/src/common/crypto_rsa.c
+++ b/src/common/crypto_rsa.c
@@ -9,12 +9,14 @@
* \brief Block of functions related with RSA utilities and operations.
**/
-#include "crypto_rsa.h"
#include "crypto.h"
-#include "compat_openssl.h"
#include "crypto_curve25519.h"
-#include "crypto_format.h"
#include "crypto_digest.h"
+#include "crypto_format.h"
+#include "compat_openssl.h"
+#include "crypto_rand.h"
+#include "crypto_rsa.h"
+#include "crypto_util.h"
DISABLE_GCC_WARNING(redundant-decls)
diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c
index 316445e40f..8543760ec5 100644
--- a/src/common/crypto_s2k.c
+++ b/src/common/crypto_s2k.c
@@ -12,11 +12,13 @@
#define CRYPTO_S2K_PRIVATE
-#include "crypto.h"
-#include "util.h"
#include "compat.h"
-#include "crypto_s2k.h"
+#include "crypto.h"
#include "crypto_digest.h"
+#include "crypto_rand.h"
+#include "crypto_s2k.h"
+#include "crypto_util.h"
+#include "util.h"
#include <openssl/evp.h>
diff --git a/src/common/crypto_util.c b/src/common/crypto_util.c
new file mode 100644
index 0000000000..b0d5b6b2f7
--- /dev/null
+++ b/src/common/crypto_util.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_util.c
+ *
+ * \brief Common cryptographic utilities.
+ **/
+
+#ifndef CRYPTO_UTIL_PRIVATE
+#define CRYPTO_UTIL_PRIVATE
+
+#include "crypto_util.h"
+
+#include <string.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#endif /* defined(_WIN32) */
+
+#include "util.h"
+
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/crypto.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+/**
+ * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
+ * the value <b>byte</b>.
+ * If <b>mem</b> is NULL or <b>sz</b> is zero, nothing happens.
+ *
+ * This function is preferable to memset, since many compilers will happily
+ * optimize out memset() when they can convince themselves that the data being
+ * cleared will never be read.
+ *
+ * Right now, our convention is to use this function when we are wiping data
+ * that's about to become inaccessible, such as stack buffers that are about
+ * to go out of scope or structures that are about to get freed. (In
+ * practice, it appears that the compilers we're currently using will optimize
+ * out the memset()s for stack-allocated buffers, but not those for
+ * about-to-be-freed structures. That could change, though, so we're being
+ * wary.) If there are live reads for the data, then you can just use
+ * memset().
+ */
+void
+memwipe(void *mem, uint8_t byte, size_t sz)
+{
+ if (sz == 0) {
+ return;
+ }
+ /* If sz is nonzero, then mem must not be NULL. */
+ tor_assert(mem != NULL);
+
+ /* Data this large is likely to be an underflow. */
+ tor_assert(sz < SIZE_T_CEILING);
+
+ /* Because whole-program-optimization exists, we may not be able to just
+ * have this function call "memset". A smart compiler could inline it, then
+ * eliminate dead memsets, and declare itself to be clever. */
+
+#if defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY)
+ /* Here's what you do on windows. */
+ SecureZeroMemory(mem,sz);
+#elif defined(HAVE_RTLSECUREZEROMEMORY)
+ RtlSecureZeroMemory(mem,sz);
+#elif defined(HAVE_EXPLICIT_BZERO)
+ /* The BSDs provide this. */
+ explicit_bzero(mem, sz);
+#elif defined(HAVE_MEMSET_S)
+ /* This is in the C99 standard. */
+ memset_s(mem, sz, 0, sz);
+#else
+ /* This is a slow and ugly function from OpenSSL that fills 'mem' with junk
+ * based on the pointer value, then uses that junk to update a global
+ * variable. It's an elaborate ruse to trick the compiler into not
+ * optimizing out the "wipe this memory" code. Read it if you like zany
+ * programming tricks! In later versions of Tor, we should look for better
+ * not-optimized-out memory wiping stuff...
+ *
+ * ...or maybe not. In practice, there are pure-asm implementations of
+ * OPENSSL_cleanse() on most platforms, which ought to do the job.
+ **/
+
+ OPENSSL_cleanse(mem, sz);
+#endif /* defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY) || ... */
+
+ /* Just in case some caller of memwipe() is relying on getting a buffer
+ * filled with a particular value, fill the buffer.
+ *
+ * If this function gets inlined, this memset might get eliminated, but
+ * that's okay: We only care about this particular memset in the case where
+ * the caller should have been using memset(), and the memset() wouldn't get
+ * eliminated. In other words, this is here so that we won't break anything
+ * if somebody accidentally calls memwipe() instead of memset().
+ **/
+ memset(mem, byte, sz);
+}
+
+#endif /* !defined(CRYPTO_UTIL_PRIVATE) */
+
diff --git a/src/common/crypto_util.h b/src/common/crypto_util.h
new file mode 100644
index 0000000000..922942b371
--- /dev/null
+++ b/src/common/crypto_util.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_util.h
+ *
+ * \brief Common functions for cryptographic routines.
+ **/
+
+#ifndef TOR_CRYPTO_UTIL_H
+#define TOR_CRYPTO_UTIL_H
+
+#include "torint.h"
+
+/** OpenSSL-based utility functions. */
+void memwipe(void *mem, uint8_t byte, size_t sz);
+
+#ifdef CRYPTO_UTIL_PRIVATE
+#ifdef TOR_UNIT_TESTS
+#endif /* defined(TOR_UNIT_TESTS) */
+#endif /* defined(CRYPTO_UTIL_PRIVATE) */
+
+#endif /* !defined(TOR_CRYPTO_UTIL_H) */
+
diff --git a/src/common/include.am b/src/common/include.am
index 87ab9d79e9..bce3fa20f6 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -116,11 +116,13 @@ LIBOR_CRYPTO_A_SRC = \
src/common/compress_zstd.c \
src/common/crypto.c \
src/common/crypto_digest.c \
- src/common/crypto_rsa.c \
+ src/common/crypto_format.c \
src/common/crypto_openssl_mgt.c \
src/common/crypto_pwbox.c \
+ src/common/crypto_rand.c \
+ src/common/crypto_rsa.c \
src/common/crypto_s2k.c \
- src/common/crypto_format.c \
+ src/common/crypto_util.c \
src/common/tortls.c \
src/common/crypto_curve25519.c \
src/common/crypto_ed25519.c
@@ -172,9 +174,11 @@ COMMONHEADERS = \
src/common/crypto_ed25519.h \
src/common/crypto_format.h \
src/common/crypto_openssl_mgt.h \
- src/common/crypto_rsa.h \
src/common/crypto_pwbox.h \
+ src/common/crypto_rand.h \
+ src/common/crypto_rsa.h \
src/common/crypto_s2k.h \
+ src/common/crypto_util.h \
src/common/di_ops.h \
src/common/handles.h \
src/common/memarea.h \
diff --git a/src/common/log.c b/src/common/log.c
index 922e9dd38f..ebd50f62d3 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -170,6 +170,9 @@ typedef struct pending_log_message_t {
/** Log messages waiting to be replayed onto callback-based logs */
static smartlist_t *pending_cb_messages = NULL;
+/** Callback to invoke when pending_cb_messages becomes nonempty. */
+static pending_callback_callback pending_cb_cb = NULL;
+
/** Log messages waiting to be replayed once the logging system is initialized.
*/
static smartlist_t *pending_startup_messages = NULL;
@@ -538,6 +541,9 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
smartlist_add(pending_cb_messages,
pending_log_message_new(severity,domain,NULL,msg_after_prefix));
*callbacks_deferred = 1;
+ if (smartlist_len(pending_cb_messages) == 1 && pending_cb_cb) {
+ pending_cb_cb();
+ }
}
} else {
lf->callback(severity, domain, msg_after_prefix);
@@ -825,6 +831,7 @@ logs_free_all(void)
logfiles = NULL;
messages = pending_cb_messages;
pending_cb_messages = NULL;
+ pending_cb_cb = NULL;
messages2 = pending_startup_messages;
pending_startup_messages = NULL;
UNLOCK_LOGS();
@@ -988,6 +995,24 @@ add_temp_log(int min_severity)
}
/**
+ * Register "cb" as the callback to call when there are new pending log
+ * callbacks to be flushed with flush_pending_log_callbacks().
+ *
+ * Note that this callback, if present, can be invoked from any thread.
+ *
+ * This callback must not log.
+ *
+ * It is intentional that this function contains the name "callback" twice: it
+ * sets a "callback" to be called on the condition that there is a "pending
+ * callback".
+ **/
+void
+logs_set_pending_callback_callback(pending_callback_callback cb)
+{
+ pending_cb_cb = cb;
+}
+
+/**
* Add a log handler to send messages in <b>severity</b>
* to the function <b>cb</b>.
*/
diff --git a/src/common/torlog.h b/src/common/torlog.h
index ac632ff521..de389883c0 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -154,6 +154,8 @@ int add_android_log(const log_severity_list_t *severity,
const char *android_identity_tag);
#endif // HAVE_ANDROID_LOG_H.
int add_callback_log(const log_severity_list_t *severity, log_callback cb);
+typedef void (*pending_callback_callback)(void);
+void logs_set_pending_callback_callback(pending_callback_callback cb);
void logs_set_domain_logging(int enabled);
int get_min_log_level(void);
void switch_logs_debug(void);
diff --git a/src/common/tortls.c b/src/common/tortls.c
index cd236363f8..669742c9dd 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -26,6 +26,8 @@
#endif
#include "crypto.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "compat.h"
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
@@ -56,7 +58,7 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "container.h"
#include <string.h>
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+#ifdef OPENSSL_1_1_API
#define X509_get_notBefore_const(cert) \
X509_get0_notBefore(cert)
#define X509_get_notAfter_const(cert) \
@@ -370,7 +372,7 @@ tor_tls_init(void)
check_no_tls_errors();
if (!tls_library_is_initialized) {
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+#ifdef OPENSSL_1_1_API
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#else
SSL_library_init();
diff --git a/src/common/workqueue.c b/src/common/workqueue.c
index 12e31414e7..563a98af96 100644
--- a/src/common/workqueue.c
+++ b/src/common/workqueue.c
@@ -27,7 +27,7 @@
#include "compat.h"
#include "compat_libevent.h"
#include "compat_threads.h"
-#include "crypto.h"
+#include "crypto_rand.h"
#include "util.h"
#include "workqueue.h"
#include "tor_queue.h"
diff --git a/src/config/torrc.minimal.in-staging b/src/config/torrc.minimal.in-staging
index 90f91e5cb9..86429f1176 100644
--- a/src/config/torrc.minimal.in-staging
+++ b/src/config/torrc.minimal.in-staging
@@ -100,7 +100,7 @@
## A handle for your relay, so people don't have to refer to it by key.
## Nicknames must be between 1 and 19 characters inclusive, and must
## contain only the alphanumeric characters (a-z, A-Z, 0-9). No unicode,
-## no emoji.
+## no emoji. If not set, "Unnamed" will be used.
#Nickname ididnteditheconfig
## Define these to limit how much relayed traffic you will allow. Your
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index 4e183478eb..72cca0be31 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -106,6 +106,7 @@
## A handle for your relay, so people don't have to refer to it by key.
## Nicknames must be between 1 and 19 characters inclusive, and must
## contain only the characters [a-zA-Z0-9].
+## If not set, "Unnamed" will be used.
#Nickname ididnteditheconfig
## Define these to limit how much relayed traffic you will allow. Your
diff --git a/src/ext/ed25519/donna/ed25519-randombytes-custom.h b/src/ext/ed25519/donna/ed25519-randombytes-custom.h
index 3fb0959fc4..27eade4f95 100644
--- a/src/ext/ed25519/donna/ed25519-randombytes-custom.h
+++ b/src/ext/ed25519/donna/ed25519-randombytes-custom.h
@@ -8,7 +8,7 @@
*/
/* Tor: Instead of calling OpenSSL's CSPRNG directly, call the wrapper. */
-#include "crypto.h"
+#include "crypto_rand.h"
static void
ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len)
diff --git a/src/ext/ed25519/donna/ed25519_tor.c b/src/ext/ed25519/donna/ed25519_tor.c
index 84fc3850a2..43de9faaea 100644
--- a/src/ext/ed25519/donna/ed25519_tor.c
+++ b/src/ext/ed25519/donna/ed25519_tor.c
@@ -40,6 +40,8 @@
#include "ed25519-randombytes.h"
#include "ed25519-hash.h"
+#include "crypto_util.h"
+
typedef unsigned char ed25519_signature[64];
typedef unsigned char ed25519_public_key[32];
typedef unsigned char ed25519_secret_key[32];
diff --git a/src/ext/ed25519/ref10/blinding.c b/src/ext/ed25519/ref10/blinding.c
index a3b32fa80c..88e84cac20 100644
--- a/src/ext/ed25519/ref10/blinding.c
+++ b/src/ext/ed25519/ref10/blinding.c
@@ -7,7 +7,7 @@
#include "ed25519_ref10.h"
#include <string.h>
-#include "crypto.h"
+#include "crypto_util.h"
static void
ed25519_ref10_gettweak(unsigned char *out, const unsigned char *param)
diff --git a/src/ext/ed25519/ref10/keypair.c b/src/ext/ed25519/ref10/keypair.c
index 68a88f9adc..c437f0a4f2 100644
--- a/src/ext/ed25519/ref10/keypair.c
+++ b/src/ext/ed25519/ref10/keypair.c
@@ -6,6 +6,9 @@
#include "crypto_hash_sha512.h"
#include "ge.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
+
int
crypto_sign_seckey(unsigned char *sk)
{
diff --git a/src/ext/ed25519/ref10/randombytes.h b/src/ext/ed25519/ref10/randombytes.h
index 8bf31631f0..a21dde8540 100644
--- a/src/ext/ed25519/ref10/randombytes.h
+++ b/src/ext/ed25519/ref10/randombytes.h
@@ -1,4 +1,4 @@
/* Added for Tor. */
-#include "crypto.h"
+#include "crypto_rand.h"
#define randombytes(b, n) \
(crypto_strongest_rand((b), (n)), 0)
diff --git a/src/ext/keccak-tiny/keccak-tiny-unrolled.c b/src/ext/keccak-tiny/keccak-tiny-unrolled.c
index d8d7fe335a..07e8c95bcf 100644
--- a/src/ext/keccak-tiny/keccak-tiny-unrolled.c
+++ b/src/ext/keccak-tiny/keccak-tiny-unrolled.c
@@ -9,7 +9,7 @@
#include "keccak-tiny.h"
#include <string.h>
-#include "crypto.h"
+#include "crypto_util.h"
#include "byteorder.h"
/******** Endianness conversion helpers ********/
diff --git a/src/ext/rust b/src/ext/rust
-Subproject fbc0c25785696a25b9cbc09ed645cc8d404ee0f
+Subproject e92c124a41535bd2131b9506a7d95c68c9d8fed
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index 96ce275578..7f861e4d24 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -21,9 +21,10 @@
#include "config.h"
#include "connection_edge.h"
#include "control.h"
+#include "crypto_rand.h"
#include "dns.h"
-#include "routerset.h"
#include "nodelist.h"
+#include "routerset.h"
/** A client-side struct to remember requests to rewrite addresses
* to new addresses. These structs are stored in the hash table
@@ -959,9 +960,11 @@ addressmap_get_virtual_address(int type)
char tmp[TOR_ADDR_BUF_LEN];
tor_addr_to_str(tmp, &addr, sizeof(tmp), 0);
if (strmap_get(addressmap, tmp)) {
+ // LCOV_EXCL_START
log_warn(LD_BUG, "%s wasn't in the addressmap, but %s was.",
buf, tmp);
continue;
+ // LCOV_EXCL_STOP
}
return tor_strdup(buf);
@@ -970,8 +973,10 @@ addressmap_get_virtual_address(int type)
log_warn(LD_CONFIG, "Ran out of virtual addresses!");
return NULL;
} else {
+ // LCOV_EXCL_START
log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
return NULL;
+ // LCOV_EXCL_STOP
}
}
diff --git a/src/or/channelpadding.c b/src/or/channelpadding.c
index 33b1cba355..a8b9a2b47b 100644
--- a/src/or/channelpadding.c
+++ b/src/or/channelpadding.c
@@ -16,6 +16,7 @@
#include "networkstatus.h"
#include "connection.h"
#include "connection_or.h"
+#include "crypto_rand.h"
#include "main.h"
#include "rephist.h"
#include "router.h"
diff --git a/src/or/circpathbias.c b/src/or/circpathbias.c
index c1c1ca31be..ff42bf91e4 100644
--- a/src/or/circpathbias.c
+++ b/src/or/circpathbias.c
@@ -30,6 +30,7 @@
#include "circuitstats.h"
#include "connection_edge.h"
#include "config.h"
+#include "crypto_rand.h"
#include "entrynodes.h"
#include "networkstatus.h"
#include "relay.h"
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 24c32b710c..09102d0c4c 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -43,7 +43,7 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
-#include "crypto.h"
+#include "crypto_rand.h"
#include "directory.h"
#include "entrynodes.h"
#include "hs_ntor.h"
@@ -72,10 +72,7 @@ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
static int circuit_deliver_create_cell(circuit_t *circ,
const create_cell_t *create_cell,
int relayed);
-static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit,
- int is_hs_v3_rp_circuit);
static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
-static int onion_extend_cpath(origin_circuit_t *circ);
STATIC int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static int circuit_send_first_onion_skin(origin_circuit_t *circ);
static int circuit_build_no_more_hops(origin_circuit_t *circ);
@@ -1133,19 +1130,29 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
return 0;
}
-/** Our clock just jumped by <b>seconds_elapsed</b>. Assume
- * something has also gone wrong with our network: notify the user,
- * and abandon all not-yet-used circuits. */
+/** Our clock just jumped by <b>seconds_elapsed</b>. If <b>was_idle</b> is
+ * true, then the monotonic time matches; otherwise it doesn't. Assume
+ * something has also gone wrong with our network: notify the user, and
+ * abandon all not-yet-used circuits. */
void
-circuit_note_clock_jumped(int seconds_elapsed)
+circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle)
{
int severity = server_mode(get_options()) ? LOG_WARN : LOG_NOTICE;
- tor_log(severity, LD_GENERAL, "Your system clock just jumped %d seconds %s; "
- "assuming established circuits no longer work.",
- seconds_elapsed >=0 ? seconds_elapsed : -seconds_elapsed,
- seconds_elapsed >=0 ? "forward" : "backward");
- control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME=%d",
- seconds_elapsed);
+ if (was_idle) {
+ tor_log(severity, LD_GENERAL, "Tor has been idle for "I64_FORMAT
+ " seconds; assuming established circuits no longer work.",
+ I64_PRINTF_ARG(seconds_elapsed));
+ } else {
+ tor_log(severity, LD_GENERAL,
+ "Your system clock just jumped "I64_FORMAT" seconds %s; "
+ "assuming established circuits no longer work.",
+ I64_PRINTF_ARG(
+ seconds_elapsed >=0 ? seconds_elapsed : -seconds_elapsed),
+ seconds_elapsed >=0 ? "forward" : "backward");
+ }
+ control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME="I64_FORMAT
+ " IDLE=%d",
+ I64_PRINTF_ARG(seconds_elapsed), was_idle?1:0);
/* so we log when it works again */
note_that_we_maybe_cant_complete_circuits();
control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s",
@@ -2283,7 +2290,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
* be used as an HS v3 rendezvous point.
*
* Return 0 if ok, -1 if circuit should be closed. */
-static int
+STATIC int
onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
int is_hs_v3_rp_circuit)
{
@@ -2454,12 +2461,71 @@ cpath_get_n_hops(crypt_path_t **head_ptr)
#endif /* defined(TOR_UNIT_TESTS) */
/**
+ * Build the exclude list for vanguard circuits.
+ *
+ * For vanguard circuits we exclude all the already chosen nodes (including the
+ * exit) from being middle hops to prevent the creation of A - B - A subpaths.
+ * We also allow the 4th hop to be the same as the guard node so as to not leak
+ * guard information to RP/IP/HSDirs.
+ *
+ * For vanguard circuits, we don't apply any subnet or family restrictions.
+ * This is to avoid impossible-to-build circuit paths, or just situations where
+ * our earlier guards prevent us from using most of our later ones.
+ *
+ * The alternative is building the circuit in reverse. Reverse calls to
+ * onion_extend_cpath() (ie: select outer hops first) would then have the
+ * property that you don't gain information about inner hops by observing
+ * outer ones. See https://trac.torproject.org/projects/tor/ticket/24487
+ * for this.
+ *
+ * (Note further that we still exclude the exit to prevent A - B - A
+ * at the end of the path. */
+static smartlist_t *
+build_vanguard_middle_exclude_list(uint8_t purpose,
+ cpath_build_state_t *state,
+ crypt_path_t *head,
+ int cur_len)
+{
+ smartlist_t *excluded;
+ const node_t *r;
+ crypt_path_t *cpath;
+ int i;
+
+ (void) purpose;
+
+ excluded = smartlist_new();
+
+ /* Add the exit to the exclude list (note that the exit/last hop is always
+ * chosen first in circuit_establish_circuit()). */
+ if ((r = build_state_get_exit_node(state))) {
+ smartlist_add(excluded, (node_t*)r);
+ }
+
+ /* If we are picking the 4th hop, allow that node to be the guard too.
+ * This prevents us from avoiding the Guard for those hops, which
+ * gives the adversary information about our guard if they control
+ * the RP, IP, or HSDIR. We don't do this check based on purpose
+ * because we also want to allow HS_VANGUARDS pre-build circuits
+ * to use the guard for that last hop.
+ */
+ if (cur_len == DEFAULT_ROUTE_LEN+1) {
+ /* Skip the first hop for the exclude list below */
+ head = head->next;
+ cur_len--;
+ }
+
+ for (i = 0, cpath = head; cpath && i < cur_len; ++i, cpath=cpath->next) {
+ if ((r = node_get_by_id(cpath->extend_info->identity_digest))) {
+ smartlist_add(excluded, (node_t*)r);
+ }
+ }
+
+ return excluded;
+}
+
+/**
* Build a list of nodes to exclude from the choice of this middle
* hop, based on already chosen nodes.
- *
- * XXX: At present, this function does not exclude any nodes from
- * the vanguard circuits. See
- * https://trac.torproject.org/projects/tor/ticket/24487
*/
static smartlist_t *
build_middle_exclude_list(uint8_t purpose,
@@ -2472,32 +2538,21 @@ build_middle_exclude_list(uint8_t purpose,
crypt_path_t *cpath;
int i;
+ /** Vanguard circuits have their own path selection rules */
+ if (circuit_should_use_vanguards(purpose)) {
+ return build_vanguard_middle_exclude_list(purpose, state, head, cur_len);
+ }
+
excluded = smartlist_new();
- /* Add the exit to the exclude list (note that the exit/last hop is always
- * chosen first in circuit_establish_circuit()). */
+ /* For non-vanguard circuits, add the exit and its family to the exclude list
+ * (note that the exit/last hop is always chosen first in
+ * circuit_establish_circuit()). */
if ((r = build_state_get_exit_node(state))) {
nodelist_add_node_and_family(excluded, r);
}
- /* XXX: We don't apply any other previously selected node restrictions for
- * vanguards, and allow nodes to be reused for those hop positions in the
- * same circuit. This is because after many rotations, you get to learn
- * inner guard nodes through the nodes that are not selected for outer
- * hops.
- *
- * The alternative is building the circuit in reverse. Reverse calls to
- * onion_extend_cpath() (ie: select outer hops first) would then have the
- * property that you don't gain information about inner hops by observing
- * outer ones. See https://trac.torproject.org/projects/tor/ticket/24487
- * for this.
- *
- * (Note further that we can and do still exclude the exit in the block
- * above, because it is chosen first in circuit_establish_circuit()..) */
- if (circuit_should_use_vanguards(purpose)) {
- return excluded;
- }
-
+ /* also exclude all other already chosen nodes and their family */
for (i = 0, cpath = head; cpath && i < cur_len; ++i, cpath=cpath->next) {
if ((r = node_get_by_id(cpath->extend_info->identity_digest))) {
nodelist_add_node_and_family(excluded, r);
@@ -2597,7 +2652,9 @@ choose_good_middle_server(uint8_t purpose,
/** If a hidden service circuit wants a specific middle node, pin it. */
if (middle_node_must_be_vanguard(options, purpose, cur_len)) {
log_debug(LD_GENERAL, "Picking a sticky node (cur_len = %d)", cur_len);
- return pick_vanguard_middle_node(options, flags, cur_len, excluded);
+ choice = pick_vanguard_middle_node(options, flags, cur_len, excluded);
+ smartlist_free(excluded);
+ return choice;
}
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
@@ -2637,7 +2694,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state,
/* This request is for an entry server to use for a regular circuit,
* and we use entry guard nodes. Just return one of the guard nodes. */
tor_assert(guard_state_out);
- return guards_choose_guard(state, guard_state_out);
+ return guards_choose_guard(state, purpose, guard_state_out);
}
excluded = smartlist_new();
@@ -2680,7 +2737,7 @@ onion_next_hop_in_cpath(crypt_path_t *cpath)
* Return 1 if the path is complete, 0 if we successfully added a hop,
* and -1 on error.
*/
-static int
+STATIC int
onion_extend_cpath(origin_circuit_t *circ)
{
uint8_t purpose = circ->base_.purpose;
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index bea31ad0dd..0184898e29 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -29,7 +29,7 @@ void circuit_n_chan_done(channel_t *chan, int status,
int inform_testing_reachability(void);
int circuit_timeout_want_to_count_circ(const origin_circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
-void circuit_note_clock_jumped(int seconds_elapsed);
+void circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle);
int circuit_extend(cell_t *cell, circuit_t *circ);
int circuit_init_cpath_crypto(crypt_path_t *cpath,
const char *key_data, size_t key_data_len,
@@ -83,6 +83,13 @@ STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei,
smartlist_t *nodes);
MOCK_DECL(STATIC int, count_acceptable_nodes, (smartlist_t *nodes));
+
+STATIC int onion_extend_cpath(origin_circuit_t *circ);
+
+STATIC int
+onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
+ int is_hs_v3_rp_circuit);
+
#if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS)
STATIC const node_t *pick_tor2web_rendezvous_node(router_crn_flags_t flags,
const or_options_t *options);
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index ea2f2c15c5..45fff7cc17 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -65,6 +65,8 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "entrynodes.h"
#include "main.h"
#include "hs_circuit.h"
diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c
index e85301b26d..e5d5a14581 100644
--- a/src/or/circuitmux_ewma.c
+++ b/src/or/circuitmux_ewma.c
@@ -37,6 +37,7 @@
#include "or.h"
#include "circuitmux.h"
#include "circuitmux_ewma.h"
+#include "crypto_rand.h"
#include "networkstatus.h"
/*** EWMA parameter #defines ***/
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index 6015bcf851..d8dc085c84 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -31,6 +31,7 @@
#include "config.h"
#include "confparse.h"
#include "control.h"
+#include "crypto_rand.h"
#include "main.h"
#include "networkstatus.h"
#include "rendclient.h"
@@ -893,11 +894,23 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt)
histogram[nth_max_bin[n]]);
}
- /* The following assert is safe, because we don't get called when we
- * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */
+ /* bin_counts can become zero if all of our last CBT_NCIRCUITS_TO_OBSERVE
+ * circuits were abandoned before they completed. This shouldn't happen,
+ * though. We should have reset/re-learned a lower timeout first. */
+ if (bin_counts == 0) {
+ ret = 0;
+ log_warn(LD_CIRC,
+ "No valid circuit build time data out of %d times, %u modes, "
+ "have_timeout=%d, %lfms", cbt->total_build_times, num_modes,
+ cbt->have_computed_timeout, cbt->timeout_ms);
+ goto done;
+ }
+
tor_assert(bin_counts > 0);
ret /= bin_counts;
+
+ done:
tor_free(histogram);
tor_free(nth_max_bin);
@@ -1183,6 +1196,10 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
* and less frechet-like. */
cbt->Xm = circuit_build_times_get_xm(cbt);
+ /* If Xm came back 0, then too many circuits were abandoned. */
+ if (cbt->Xm == 0)
+ return 0;
+
tor_assert(cbt->Xm > 0);
for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) {
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 47e29c28dd..ec09658282 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1756,6 +1756,39 @@ circuit_build_failed(origin_circuit_t *circ)
* the last hop or an earlier hop. then use this info below.
*/
int failed_at_last_hop = 0;
+
+ /* First, check to see if this was a path failure, rather than build
+ * failure.
+ *
+ * Note that we deliberately use circuit_get_cpath_len() (and not
+ * circuit_get_cpath_opened_len()) because we only want to ensure
+ * that a full path is *chosen*. This is different than a full path
+ * being *built*. We only want to count *build* failures below.
+ *
+ * Path selection failures can happen spuriously for a number
+ * of reasons (such as aggressive/invalid user-specified path
+ * restrictions in the torrc, insufficient microdescriptors, and
+ * non-user reasons like exitpolicy issues), and so should not be
+ * counted as failures below.
+ */
+ if (circuit_get_cpath_len(circ) < circ->build_state->desired_path_len) {
+ static ratelim_t pathfail_limit = RATELIM_INIT(3600);
+ log_fn_ratelim(&pathfail_limit, LOG_NOTICE, LD_CIRC,
+ "Our circuit %u (id: %" PRIu32 ") died due to an invalid "
+ "selected path, purpose %s. This may be a torrc "
+ "configuration issue, or a bug.",
+ TO_CIRCUIT(circ)->n_circ_id, circ->global_identifier,
+ circuit_purpose_to_string(TO_CIRCUIT(circ)->purpose));
+
+ /* If the path failed on an RP, retry it. */
+ if (TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND)
+ hs_circ_retry_service_rendezvous_point(circ);
+
+ /* In all other cases, just bail. The rest is just failure accounting
+ * that we don't want to do */
+ return;
+ }
+
/* If the last hop isn't open, and the second-to-last is, we failed
* at the last hop. */
if (circ->cpath &&
@@ -1805,18 +1838,8 @@ circuit_build_failed(origin_circuit_t *circ)
* If we have guard state (new guard API) and our path selection
* code actually chose a full path, then blame the failure of this
* circuit on the guard.
- *
- * Note that we deliberately use circuit_get_cpath_len() (and not
- * circuit_get_cpath_opened_len()) because we only want to ensure
- * that a full path is *chosen*. This is different than a full path
- * being *built*. We only want to blame *build* failures on this
- * guard. Path selection failures can happen spuriously for a number
- * of reasons (such as aggressive/invalid user-specified path
- * restrictions in the torrc, as well as non-user reasons like
- * exitpolicy issues), and so should not be counted here.
*/
- if (circ->guard_state &&
- circuit_get_cpath_len(circ) >= circ->build_state->desired_path_len)
+ if (circ->guard_state)
entry_guard_failed(&circ->guard_state);
/* if there are any one-hop streams waiting on this circuit, fail
* them now so they can retry elsewhere. */
diff --git a/src/or/command.c b/src/or/command.c
index 4fa05a18b4..39950f41bf 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -46,6 +46,7 @@
#include "config.h"
#include "control.h"
#include "cpuworker.h"
+#include "crypto_util.h"
#include "dos.h"
#include "hibernate.h"
#include "nodelist.h"
diff --git a/src/or/config.c b/src/or/config.c
index a2b84991a0..94a58f3488 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -79,6 +79,8 @@
#include "control.h"
#include "confparse.h"
#include "cpuworker.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "dirserv.h"
#include "dns.h"
#include "dos.h"
@@ -112,6 +114,7 @@
#include "procmon.h"
#include "dirauth/dirvote.h"
+#include "dirauth/mode.h"
#ifdef HAVE_SYSTEMD
# if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__)
@@ -1446,9 +1449,9 @@ options_act_reversible(const or_options_t *old_options, char **msg)
consider_hibernation(time(NULL));
/* Launch the listeners. (We do this before we setuid, so we can bind to
- * ports under 1024.) We don't want to rebind if we're hibernating. If
- * networking is disabled, this will close all but the control listeners,
- * but disable those. */
+ * ports under 1024.) We don't want to rebind if we're hibernating or
+ * shutting down. If networking is disabled, this will close all but the
+ * control listeners, but disable those. */
if (!we_are_hibernating()) {
if (retry_all_listeners(replaced_listeners, new_listeners,
options->DisableNetwork) < 0) {
@@ -1552,6 +1555,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
tor_malloc_zero(sizeof(log_severity_list_t));
close_temp_logs();
add_callback_log(severity, control_event_logmsg);
+ logs_set_pending_callback_callback(control_event_logmsg_pending);
control_adjust_event_log_severity();
tor_free(severity);
tor_log_update_sigsafe_err_fds();
@@ -1997,6 +2001,9 @@ options_act(const or_options_t *old_options)
finish_daemon(options->DataDirectory);
}
+ /* See whether we need to enable/disable our once-a-second timer. */
+ reschedule_per_second_timer();
+
/* We want to reinit keys as needed before we do much of anything else:
keys are important, and other things can depend on them. */
if (transition_affects_workers ||
@@ -8429,3 +8436,17 @@ init_cookie_authentication(const char *fname, const char *header,
return retval;
}
+/**
+ * Return true if any option is set in <b>options</b> to make us behave
+ * as a client.
+ */
+int
+options_any_client_port_set(const or_options_t *options)
+{
+ return (options->SocksPort_set ||
+ options->TransPort_set ||
+ options->NATDPort_set ||
+ options->DNSPort_set ||
+ options->HTTPTunnelPort_set);
+}
+
diff --git a/src/or/config.h b/src/or/config.h
index 1d3c27217e..4b41274434 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -214,6 +214,9 @@ smartlist_t *get_options_from_transport_options_line(const char *line,
const char *transport);
smartlist_t *get_options_for_server_transport(const char *transport);
+/* Port helper functions. */
+int options_any_client_port_set(const or_options_t *options);
+
#ifdef CONFIG_PRIVATE
#define CL_PORT_NO_STREAM_OPTIONS (1u<<0)
diff --git a/src/or/connection.c b/src/or/connection.c
index c2673ade16..3462dbeac2 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -76,6 +76,7 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "crypto_util.h"
#include "directory.h"
#include "dirserv.h"
#include "dns.h"
@@ -1761,13 +1762,13 @@ connection_connect_sockaddr,(connection_t *conn,
tor_assert(sa);
tor_assert(socket_error);
- if (get_options()->DisableNetwork) {
- /* We should never even try to connect anyplace if DisableNetwork is set.
- * Warn if we do, and refuse to make the connection.
+ if (net_is_completely_disabled()) {
+ /* We should never even try to connect anyplace if the network is
+ * completely shut off.
*
- * We only check DisableNetwork here, not we_are_hibernating(), since
- * we'll still try to fulfill client requests sometimes in the latter case
- * (if it is soft hibernation) */
+ * (We don't check net_is_disabled() here, since we still sometimes
+ * want to open connections when we're in soft hibernation.)
+ */
static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
*socket_error = SOCK_ERRNO(ENETUNREACH);
log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG,
@@ -3439,7 +3440,7 @@ int
connection_handle_read(connection_t *conn)
{
int res;
-
+ update_current_time(time(NULL));
res = connection_handle_read_impl(conn);
return res;
}
@@ -3982,6 +3983,7 @@ int
connection_handle_write(connection_t *conn, int force)
{
int res;
+ update_current_time(time(NULL));
conn->in_connection_handle_write = 1;
res = connection_handle_write_impl(conn, force);
conn->in_connection_handle_write = 0;
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 955f942c50..28e18aa853 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -70,6 +70,7 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "crypto_util.h"
#include "dns.h"
#include "dnsserv.h"
#include "directory.h"
@@ -3536,6 +3537,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
/* default to failed, change in dns_resolve if it turns out not to fail */
+ /* If we're hibernating or shutting down, we refuse to open new streams. */
if (we_are_hibernating()) {
relay_send_end_cell_from_edge(rh.stream_id, circ,
END_STREAM_REASON_HIBERNATING, NULL);
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 7723d9d2bd..7898fbd42e 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -39,6 +39,8 @@
#include "connection.h"
#include "connection_or.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "dirserv.h"
#include "entrynodes.h"
#include "geoip.h"
diff --git a/src/or/conscache.c b/src/or/conscache.c
index e25ac5f40b..51dc9d621f 100644
--- a/src/or/conscache.c
+++ b/src/or/conscache.c
@@ -5,6 +5,7 @@
#include "config.h"
#include "conscache.h"
+#include "crypto_util.h"
#include "storagedir.h"
#define CCE_MAGIC 0x17162253
diff --git a/src/or/control.c b/src/or/control.c
index bc7597707f..9323173f5d 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1,3 +1,4 @@
+
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
@@ -52,6 +53,8 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "directory.h"
#include "dirserv.h"
#include "dnsserv.h"
@@ -110,6 +113,10 @@ static int disable_log_messages = 0;
#define EVENT_IS_INTERESTING(e) \
(!! (global_event_mask & EVENT_MASK_(e)))
+/** Macro: true if any event from the bitfield 'e' is interesting. */
+#define ANY_EVENT_IS_INTERESTING(e) \
+ (!! (global_event_mask & (e)))
+
/** If we're using cookie-type authentication, how long should our cookies be?
*/
#define AUTHENTICATION_COOKIE_LEN 32
@@ -217,6 +224,7 @@ static void set_cached_network_liveness(int liveness);
static void flush_queued_events_cb(mainloop_event_t *event, void *arg);
static char * download_status_to_string(const download_status_t *dl);
+static void control_get_bytes_rw_last_sec(uint64_t *r, uint64_t *w);
/** Given a control event code for a message event, return the corresponding
* log severity. */
@@ -269,6 +277,7 @@ control_update_global_event_mask(void)
smartlist_t *conns = get_connection_array();
event_mask_t old_mask, new_mask;
old_mask = global_event_mask;
+ int any_old_per_sec_events = control_any_per_second_event_enabled();
global_event_mask = 0;
SMARTLIST_FOREACH(conns, connection_t *, _conn,
@@ -286,10 +295,13 @@ control_update_global_event_mask(void)
* we want to hear...*/
control_adjust_event_log_severity();
+ /* Macro: true if ev was false before and is true now. */
+#define NEWLY_ENABLED(ev) \
+ (! (old_mask & (ev)) && (new_mask & (ev)))
+
/* ...then, if we've started logging stream or circ bw, clear the
* appropriate fields. */
- if (! (old_mask & EVENT_STREAM_BANDWIDTH_USED) &&
- (new_mask & EVENT_STREAM_BANDWIDTH_USED)) {
+ if (NEWLY_ENABLED(EVENT_STREAM_BANDWIDTH_USED)) {
SMARTLIST_FOREACH(conns, connection_t *, conn,
{
if (conn->type == CONN_TYPE_AP) {
@@ -298,10 +310,18 @@ control_update_global_event_mask(void)
}
});
}
- if (! (old_mask & EVENT_CIRC_BANDWIDTH_USED) &&
- (new_mask & EVENT_CIRC_BANDWIDTH_USED)) {
+ if (NEWLY_ENABLED(EVENT_CIRC_BANDWIDTH_USED)) {
clear_circ_bw_fields();
}
+ if (NEWLY_ENABLED(EVENT_BANDWIDTH_USED)) {
+ uint64_t r, w;
+ control_get_bytes_rw_last_sec(&r, &w);
+ }
+ if (any_old_per_sec_events != control_any_per_second_event_enabled()) {
+ reschedule_per_second_timer();
+ }
+
+#undef NEWLY_ENABLED
}
/** Adjust the log severities that result in control_event_logmsg being called
@@ -350,6 +370,65 @@ control_event_is_interesting(int event)
return EVENT_IS_INTERESTING(event);
}
+/** Return true if any event that needs to fire once a second is enabled. */
+int
+control_any_per_second_event_enabled(void)
+{
+ return ANY_EVENT_IS_INTERESTING(
+ EVENT_MASK_(EVENT_BANDWIDTH_USED) |
+ EVENT_MASK_(EVENT_CELL_STATS) |
+ EVENT_MASK_(EVENT_CIRC_BANDWIDTH_USED) |
+ EVENT_MASK_(EVENT_CONN_BW) |
+ EVENT_MASK_(EVENT_STREAM_BANDWIDTH_USED)
+ );
+}
+
+/* The value of 'get_bytes_read()' the previous time that
+ * control_get_bytes_rw_last_sec() as called. */
+static uint64_t stats_prev_n_read = 0;
+/* The value of 'get_bytes_written()' the previous time that
+ * control_get_bytes_rw_last_sec() as called. */
+static uint64_t stats_prev_n_written = 0;
+
+/**
+ * Set <b>n_read</b> and <b>n_written</b> to the total number of bytes read
+ * and written by Tor since the last call to this function.
+ *
+ * Call this only from the main thread.
+ */
+static void
+control_get_bytes_rw_last_sec(uint64_t *n_read,
+ uint64_t *n_written)
+{
+ const uint64_t stats_n_bytes_read = get_bytes_read();
+ const uint64_t stats_n_bytes_written = get_bytes_written();
+
+ *n_read = stats_n_bytes_read - stats_prev_n_read;
+ *n_written = stats_n_bytes_written - stats_prev_n_written;
+ stats_prev_n_read = stats_n_bytes_read;
+ stats_prev_n_written = stats_n_bytes_written;
+}
+
+/**
+ * Run all the controller events (if any) that are scheduled to trigger once
+ * per second.
+ */
+void
+control_per_second_events(void)
+{
+ if (!control_any_per_second_event_enabled())
+ return;
+
+ uint64_t bytes_read, bytes_written;
+ control_get_bytes_rw_last_sec(&bytes_read, &bytes_written);
+ control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written);
+
+ control_event_stream_bandwidth_used();
+ control_event_conn_bandwidth_used();
+ control_event_circ_bandwidth_used();
+ control_event_circuit_cell_stats();
+}
+
/** Append a NUL-terminated string <b>s</b> to the end of
* <b>conn</b>-\>outbuf.
*/
@@ -803,6 +882,9 @@ queued_event_free_(queued_event_t *ev)
static void
queued_events_flush_all(int force)
{
+ /* Make sure that we get all the pending log events, if there are any. */
+ flush_pending_log_callbacks();
+
if (PREDICT_UNLIKELY(queued_control_events == NULL)) {
return;
}
@@ -1779,24 +1861,24 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
} else if (!strcmp(question, "process/pid")) {
int myPid = -1;
- #ifdef _WIN32
+#ifdef _WIN32
myPid = _getpid();
- #else
+#else
myPid = getpid();
- #endif
+#endif
tor_asprintf(answer, "%d", myPid);
} else if (!strcmp(question, "process/uid")) {
- #ifdef _WIN32
+#ifdef _WIN32
*answer = tor_strdup("-1");
- #else
+#else
int myUid = geteuid();
tor_asprintf(answer, "%d", myUid);
#endif /* defined(_WIN32) */
} else if (!strcmp(question, "process/user")) {
- #ifdef _WIN32
+#ifdef _WIN32
*answer = tor_strdup("");
- #else
+#else
int myUid = geteuid();
const struct passwd *myPwEntry = tor_getpwuid(myUid);
@@ -6186,7 +6268,7 @@ control_event_logmsg(int severity, uint32_t domain, const char *msg)
int event;
/* Don't even think of trying to add stuff to a buffer from a cpuworker
- * thread. */
+ * thread. (See #25987 for plan to fix.) */
if (! in_main_thread())
return;
@@ -6232,6 +6314,23 @@ control_event_logmsg(int severity, uint32_t domain, const char *msg)
}
}
+/**
+ * Logging callback: called when there is a queued pending log callback.
+ */
+void
+control_event_logmsg_pending(void)
+{
+ if (! in_main_thread()) {
+ /* We can't handle this case yet, since we're using a
+ * mainloop_event_t to invoke queued_events_flush_all. We ought to
+ * use a different mechanism instead: see #25987.
+ **/
+ return;
+ }
+ tor_assert(flush_queued_events_event);
+ mainloop_event_activate(flush_queued_events_event);
+}
+
/** Called whenever we receive new router descriptors: tell any
* interested control connections. <b>routers</b> is a list of
* routerinfo_t's.
@@ -7013,6 +7112,8 @@ control_event_bootstrap_problem(const char *warn, const char *reason,
if (bootstrap_problems >= BOOTSTRAP_PROBLEM_THRESHOLD)
dowarn = 1;
+ /* Don't warn about our bootstrapping status if we are hibernating or
+ * shutting down. */
if (we_are_hibernating())
dowarn = 0;
@@ -7584,6 +7685,8 @@ control_free_all(void)
{
smartlist_t *queued_events = NULL;
+ stats_prev_n_read = stats_prev_n_written = 0;
+
if (authentication_cookie) /* Free the auth cookie */
tor_free(authentication_cookie);
if (detached_onion_services) { /* Free the detached onion services */
diff --git a/src/or/control.h b/src/or/control.h
index 2f312a6638..92cbf866dd 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -40,6 +40,9 @@ int connection_control_process_inbuf(control_connection_t *conn);
#define EVENT_NS 0x000F
int control_event_is_interesting(int event);
+void control_per_second_events(void);
+int control_any_per_second_event_enabled(void);
+
int control_event_circuit_status(origin_circuit_t *circ,
circuit_status_event_t e, int reason);
int control_event_circuit_purpose_changed(origin_circuit_t *circ,
@@ -60,6 +63,7 @@ int control_event_conn_bandwidth(connection_t *conn);
int control_event_conn_bandwidth_used(void);
int control_event_circuit_cell_stats(void);
void control_event_logmsg(int severity, uint32_t domain, const char *msg);
+void control_event_logmsg_pending(void);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
time_t expires, const char *error,
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 083691c4f6..15ef6869cf 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -24,6 +24,8 @@
#include "connection_or.h"
#include "config.h"
#include "cpuworker.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "main.h"
#include "onion.h"
#include "rephist.h"
diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c
index fd629ca6ff..cbc3ff7829 100644
--- a/src/or/dirauth/dirvote.c
+++ b/src/or/dirauth/dirvote.c
@@ -9,7 +9,6 @@
#include "dircollate.h"
#include "directory.h"
#include "dirserv.h"
-#include "dirvote.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
@@ -23,9 +22,12 @@
#include "routerparse.h"
#include "entrynodes.h" /* needed for guardfraction methods */
#include "torcert.h"
-#include "shared_random_state.h"
#include "voting_schedule.h"
+#include "dirauth/dirvote.h"
+#include "dirauth/mode.h"
+#include "dirauth/shared_random_state.h"
+
/**
* \file dirvote.c
* \brief Functions to compute directory consensus, and schedule voting.
@@ -3972,7 +3974,7 @@ dirvote_clear_commits(networkstatus_t *ns)
}
}
-/* The given url is the /tor/status-gove GET directory request. Populates the
+/* The given url is the /tor/status-vote GET directory request. Populates the
* items list with strings that we can compress on the fly and dir_items with
* cached_dir_t objects that have a precompressed deflated version. */
void
diff --git a/src/or/dirauth/mode.h b/src/or/dirauth/mode.h
new file mode 100644
index 0000000000..8a0d3142f1
--- /dev/null
+++ b/src/or/dirauth/mode.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file mode.h
+ * \brief Standalone header file for directory authority mode.
+ **/
+
+#ifndef TOR_DIRAUTH_MODE_H
+#define TOR_DIRAUTH_MODE_H
+
+#ifdef HAVE_MODULE_DIRAUTH
+
+#include "router.h"
+
+/* Return true iff we believe ourselves to be a v3 authoritative directory
+ * server. */
+static inline int
+authdir_mode_v3(const or_options_t *options)
+{
+ return authdir_mode(options) && options->V3AuthoritativeDir != 0;
+}
+
+#else /* HAVE_MODULE_DIRAUTH */
+
+/* Without the dirauth module, we can't be a v3 directory authority, ever. */
+
+static inline int
+authdir_mode_v3(const or_options_t *options)
+{
+ (void) options;
+ return 0;
+}
+
+#endif /* HAVE_MODULE_DIRAUTH */
+
+#endif /* TOR_MODE_H */
+
diff --git a/src/or/dirauth/shared_random.c b/src/or/dirauth/shared_random.c
index f7ff5c58bb..6dd1f330e0 100644
--- a/src/or/dirauth/shared_random.c
+++ b/src/or/dirauth/shared_random.c
@@ -91,16 +91,19 @@
#include "shared_random.h"
#include "config.h"
#include "confparse.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "networkstatus.h"
-#include "routerkeys.h"
#include "router.h"
+#include "routerkeys.h"
#include "routerlist.h"
-#include "shared_random_state.h"
#include "shared_random_client.h"
+#include "shared_random_state.h"
#include "util.h"
#include "voting_schedule.h"
#include "dirauth/dirvote.h"
+#include "dirauth/mode.h"
/* String prefix of shared random values in votes/consensuses. */
static const char previous_srv_str[] = "shared-rand-previous-value";
diff --git a/src/or/dirauth/shared_random_state.c b/src/or/dirauth/shared_random_state.c
index 56c12c8c72..245fb99ce7 100644
--- a/src/or/dirauth/shared_random_state.c
+++ b/src/or/dirauth/shared_random_state.c
@@ -11,16 +11,16 @@
#define SHARED_RANDOM_STATE_PRIVATE
#include "or.h"
-#include "shared_random.h"
#include "config.h"
#include "confparse.h"
-#include "voting_schedule.h"
+#include "crypto_util.h"
+#include "dirauth/dirvote.h"
#include "networkstatus.h"
#include "router.h"
-#include "shared_random_state.h"
+#include "shared_random.h"
#include "shared_random_client.h"
-
-#include "dirauth/dirvote.h"
+#include "shared_random_state.h"
+#include "voting_schedule.h"
/* Default filename of the shared random state on disk. */
static const char default_fname[] = "sr-state";
diff --git a/src/or/directory.c b/src/or/directory.c
index 2c5ee23f3a..3e8d5ae9cf 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -18,6 +18,8 @@
#include "consdiffmgr.h"
#include "control.h"
#include "compat.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "directory.h"
#include "dirserv.h"
#include "entrynodes.h"
@@ -40,7 +42,6 @@
#include "routerlist.h"
#include "routerparse.h"
#include "routerset.h"
-#include "dirauth/shared_random.h"
#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
#if !defined(OpenBSD)
@@ -49,6 +50,8 @@
#endif
#include "dirauth/dirvote.h"
+#include "dirauth/mode.h"
+#include "dirauth/shared_random.h"
/**
* \file directory.c
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 61383aa861..c01234e0b9 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -955,7 +955,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
tor_assert(node);
if (router_is_me(router)) {
- /* We always know if we are down ourselves. */
+ /* We always know if we are shutting down or hibernating ourselves. */
answer = ! we_are_hibernating();
} else if (router->is_hibernating &&
(router->cache_info.published_on +
@@ -2459,6 +2459,18 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
int got_bw = 0;
int got_node_id = 0;
char *strtok_state; /* lame sauce d'jour */
+
+ if (strlen(line) == 0) {
+ log_warn(LD_DIRSERV, "Empty line in bandwidth file");
+ tor_free(line);
+ return -1;
+ }
+
+ /* Remove end of line character, so that is not part of the token */
+ if (line[strlen(line) - 1] == '\n') {
+ line[strlen(line) - 1] = '\0';
+ }
+
cp = tor_strtok_r(cp, " \t", &strtok_state);
if (!cp) {
@@ -2569,14 +2581,23 @@ dirserv_read_measured_bandwidths(const char *from_file,
time_t file_time, now;
int ok;
+ /* Initialise line, so that we can't possibly run off the end. */
+ memset(line, 0, sizeof(line));
+
if (fp == NULL) {
log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
from_file);
return -1;
}
- if (!fgets(line, sizeof(line), fp)
- || !strlen(line) || line[strlen(line)-1] != '\n') {
+ /* If fgets fails, line is either unmodified, or indeterminate. */
+ if (!fgets(line, sizeof(line), fp)) {
+ log_warn(LD_DIRSERV, "Empty bandwidth file");
+ fclose(fp);
+ return -1;
+ }
+
+ if (!strlen(line) || line[strlen(line)-1] != '\n') {
log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s",
escaped(line));
fclose(fp);
diff --git a/src/or/dns.c b/src/or/dns.c
index 411e2d5aa6..ba734ed900 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -56,6 +56,7 @@
#include "connection.h"
#include "connection_edge.h"
#include "control.h"
+#include "crypto_rand.h"
#include "dns.h"
#include "main.h"
#include "policies.h"
diff --git a/src/or/dos.c b/src/or/dos.c
index 2cb3470582..ee731accea 100644
--- a/src/or/dos.c
+++ b/src/or/dos.c
@@ -11,6 +11,7 @@
#include "or.h"
#include "channel.h"
#include "config.h"
+#include "crypto_rand.h"
#include "geoip.h"
#include "main.h"
#include "networkstatus.h"
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 2c2bf99925..27d760f1a8 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -118,11 +118,13 @@
#include "circpathbias.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuituse.h"
#include "circuitstats.h"
#include "config.h"
#include "confparse.h"
#include "connection.h"
#include "control.h"
+#include "crypto_rand.h"
#include "directory.h"
#include "entrynodes.h"
#include "main.h"
@@ -3478,12 +3480,18 @@ guards_update_all(void)
used. */
const node_t *
guards_choose_guard(cpath_build_state_t *state,
- circuit_guard_state_t **guard_state_out)
+ uint8_t purpose,
+ circuit_guard_state_t **guard_state_out)
{
const node_t *r = NULL;
const uint8_t *exit_id = NULL;
entry_guard_restriction_t *rst = NULL;
- if (state && (exit_id = build_state_get_exit_rsa_id(state))) {
+
+ /* Only apply restrictions if we have a specific exit node in mind, and only
+ * if we are not doing vanguard circuits: we don't want to apply guard
+ * restrictions to vanguard circuits. */
+ if (state && !circuit_should_use_vanguards(purpose) &&
+ (exit_id = build_state_get_exit_rsa_id(state))) {
/* We're building to a targeted exit node, so that node can't be
* chosen as our guard for this circuit. Remember that fact in a
* restriction. */
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index d562498313..e8c91da41b 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -322,6 +322,7 @@ struct circuit_guard_state_t {
/* Common entry points for old and new guard code */
int guards_update_all(void);
const node_t *guards_choose_guard(cpath_build_state_t *state,
+ uint8_t purpose,
circuit_guard_state_t **guard_state_out);
const node_t *guards_choose_dirguard(uint8_t dir_purpose,
circuit_guard_state_t **guard_state_out);
diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c
index 16a250fa58..b842442caf 100644
--- a/src/or/ext_orport.c
+++ b/src/or/ext_orport.c
@@ -20,9 +20,11 @@
#include "or.h"
#include "connection.h"
#include "connection_or.h"
-#include "ext_orport.h"
#include "control.h"
#include "config.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
+#include "ext_orport.h"
#include "main.h"
#include "proto_ext_or.h"
#include "util.h"
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index c4ae63acc4..d7d259470f 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -36,6 +36,7 @@ hibernating, phase 2:
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "crypto_rand.h"
#include "hibernate.h"
#include "main.h"
#include "router.h"
@@ -51,6 +52,10 @@ static time_t hibernate_end_time = 0;
* we aren't shutting down. */
static time_t shutdown_time = 0;
+/** A timed event that we'll use when it's time to wake up from
+ * hibernation. */
+static mainloop_event_t *wakeup_event = NULL;
+
/** Possible accounting periods. */
typedef enum {
UNIT_MONTH=1, UNIT_WEEK=2, UNIT_DAY=3,
@@ -130,6 +135,8 @@ static time_t start_of_accounting_period_after(time_t now);
static time_t start_of_accounting_period_containing(time_t now);
static void accounting_set_wakeup_time(void);
static void on_hibernate_state_change(hibernate_state_t prev_state);
+static void hibernate_schedule_wakeup_event(time_t now, time_t end_time);
+static void wakeup_event_callback(mainloop_event_t *ev, void *data);
/**
* Return the human-readable name for the hibernation state <b>state</b>
@@ -876,13 +883,26 @@ hibernate_begin_shutdown(void)
hibernate_begin(HIBERNATE_STATE_EXITING, time(NULL));
}
-/** Return true iff we are currently hibernating. */
+/**
+ * Return true iff we are currently hibernating -- that is, if we are in
+ * any non-live state.
+ */
MOCK_IMPL(int,
we_are_hibernating,(void))
{
return hibernate_state != HIBERNATE_STATE_LIVE;
}
+/**
+ * Return true iff we are currently _fully_ hibernating -- that is, if we are
+ * in a state where we expect to handle no network activity at all.
+ */
+MOCK_IMPL(int,
+we_are_fully_hibernating,(void))
+{
+ return hibernate_state == HIBERNATE_STATE_DORMANT;
+}
+
/** If we aren't currently dormant, close all connections and become
* dormant. */
static void
@@ -935,6 +955,63 @@ hibernate_go_dormant(time_t now)
or_state_mark_dirty(get_or_state(),
get_options()->AvoidDiskWrites ? now+600 : 0);
+
+ hibernate_schedule_wakeup_event(now, hibernate_end_time);
+}
+
+/**
+ * Schedule a mainloop event at <b>end_time</b> to wake up from a dormant
+ * state. We can't rely on this happening from second_elapsed_callback,
+ * since second_elapsed_callback will be shut down when we're dormant.
+ *
+ * (Note that We might immediately go back to sleep after we set the next
+ * wakeup time.)
+ */
+static void
+hibernate_schedule_wakeup_event(time_t now, time_t end_time)
+{
+ struct timeval delay = { 0, 0 };
+
+ if (now >= end_time) {
+ // In these cases we always wait at least a second, to avoid running
+ // the callback in a tight loop.
+ delay.tv_sec = 1;
+ } else {
+ delay.tv_sec = (end_time - now);
+ }
+
+ if (!wakeup_event) {
+ wakeup_event = mainloop_event_postloop_new(wakeup_event_callback, NULL);
+ }
+
+ mainloop_event_schedule(wakeup_event, &delay);
+}
+
+/**
+ * Called at the end of the interval, or at the wakeup time of the current
+ * interval, to exit the dormant state.
+ **/
+static void
+wakeup_event_callback(mainloop_event_t *ev, void *data)
+{
+ (void) ev;
+ (void) data;
+
+ const time_t now = time(NULL);
+ accounting_run_housekeeping(now);
+ consider_hibernation(now);
+ if (hibernate_state != HIBERNATE_STATE_DORMANT) {
+ /* We woke up, so everything's great here */
+ return;
+ }
+
+ /* We're still dormant. */
+ if (now < interval_wakeup_time)
+ hibernate_end_time = interval_wakeup_time;
+ else
+ hibernate_end_time = interval_end_time;
+
+ hibernate_schedule_wakeup_event(now, hibernate_end_time);
}
/** Called when hibernate_end_time has arrived. */
@@ -1123,6 +1200,18 @@ on_hibernate_state_change(hibernate_state_t prev_state)
if (prev_state != HIBERNATE_STATE_INITIAL) {
rescan_periodic_events(get_options());
}
+
+ reschedule_per_second_timer();
+}
+
+/** Free all resources held by the accounting module */
+void
+accounting_free_all(void)
+{
+ mainloop_event_free(wakeup_event);
+ hibernate_state = HIBERNATE_STATE_INITIAL;
+ hibernate_end_time = 0;
+ shutdown_time = 0;
}
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/hibernate.h b/src/or/hibernate.h
index 85fb42864b..453969d052 100644
--- a/src/or/hibernate.h
+++ b/src/or/hibernate.h
@@ -25,11 +25,13 @@ void accounting_add_bytes(size_t n_read, size_t n_written, int seconds);
int accounting_record_bandwidth_usage(time_t now, or_state_t *state);
void hibernate_begin_shutdown(void);
MOCK_DECL(int, we_are_hibernating, (void));
+MOCK_DECL(int, we_are_fully_hibernating,(void));
void consider_hibernation(time_t now);
int getinfo_helper_accounting(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
uint64_t get_accounting_max_total(void);
+void accounting_free_all(void);
#ifdef HIBERNATE_PRIVATE
/** Possible values of hibernate_state */
diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c
index df53efd32d..ecc845d17f 100644
--- a/src/or/hs_cache.c
+++ b/src/or/hs_cache.c
@@ -11,6 +11,7 @@
#include "or.h"
#include "config.h"
+#include "crypto_util.h"
#include "hs_ident.h"
#include "hs_common.h"
#include "hs_client.h"
diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h
index a141634cc4..0d0085ffdc 100644
--- a/src/or/hs_cache.h
+++ b/src/or/hs_cache.h
@@ -11,7 +11,6 @@
#include <stdint.h>
-#include "crypto.h"
#include "crypto_ed25519.h"
#include "hs_common.h"
#include "hs_descriptor.h"
diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c
index ad92521d34..03273a44f9 100644
--- a/src/or/hs_cell.c
+++ b/src/or/hs_cell.c
@@ -8,6 +8,7 @@
#include "or.h"
#include "config.h"
+#include "crypto_util.h"
#include "rendservice.h"
#include "replaycache.h"
#include "util.h"
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index 3a674f6223..a35d2af8ba 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -13,6 +13,8 @@
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "nodelist.h"
#include "policies.h"
#include "relay.h"
@@ -193,11 +195,8 @@ register_intro_circ(const hs_service_intro_point_t *ip,
tor_assert(circ);
if (ip->base.is_only_legacy) {
- uint8_t digest[DIGEST_LEN];
- if (BUG(crypto_pk_get_digest(ip->legacy_key, (char *) digest) < 0)) {
- return;
- }
- hs_circuitmap_register_intro_circ_v2_service_side(circ, digest);
+ hs_circuitmap_register_intro_circ_v2_service_side(circ,
+ ip->legacy_key_digest);
} else {
hs_circuitmap_register_intro_circ_v3_service_side(circ,
&ip->auth_key_kp.pubkey);
@@ -675,22 +674,14 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
origin_circuit_t *
hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
{
- origin_circuit_t *circ = NULL;
-
tor_assert(ip);
if (ip->base.is_only_legacy) {
- uint8_t digest[DIGEST_LEN];
- if (BUG(crypto_pk_get_digest(ip->legacy_key, (char *) digest) < 0)) {
- goto end;
- }
- circ = hs_circuitmap_get_intro_circ_v2_service_side(digest);
+ return hs_circuitmap_get_intro_circ_v2_service_side(ip->legacy_key_digest);
} else {
- circ = hs_circuitmap_get_intro_circ_v3_service_side(
+ return hs_circuitmap_get_intro_circ_v3_service_side(
&ip->auth_key_kp.pubkey);
}
- end:
- return circ;
}
/* Called when we fail building a rendezvous circuit at some point other than
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
index 2f5beaa168..f69137e1d5 100644
--- a/src/or/hs_circuit.h
+++ b/src/or/hs_circuit.h
@@ -10,7 +10,6 @@
#define TOR_HS_CIRCUIT_H
#include "or.h"
-#include "crypto.h"
#include "crypto_ed25519.h"
#include "hs_service.h"
diff --git a/src/or/hs_client.c b/src/or/hs_client.c
index 20963cd453..26e8785d9f 100644
--- a/src/or/hs_client.c
+++ b/src/or/hs_client.c
@@ -9,29 +9,31 @@
#define HS_CLIENT_PRIVATE
#include "or.h"
-#include "hs_circuit.h"
-#include "hs_ident.h"
+#include "circpathbias.h"
+#include "circuitbuild.h"
+#include "circuitlist.h"
+#include "circuituse.h"
+#include "config.h"
+#include "connection.h"
#include "connection_edge.h"
#include "container.h"
-#include "rendclient.h"
-#include "hs_descriptor.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
+#include "directory.h"
#include "hs_cache.h"
#include "hs_cell.h"
-#include "config.h"
-#include "directory.h"
+#include "hs_circuit.h"
#include "hs_client.h"
#include "hs_control.h"
-#include "router.h"
-#include "routerset.h"
-#include "circuitlist.h"
-#include "circuituse.h"
-#include "connection.h"
-#include "nodelist.h"
-#include "circpathbias.h"
+#include "hs_descriptor.h"
+#include "hs_ident.h"
#include "hs_ntor.h"
-#include "circuitbuild.h"
#include "networkstatus.h"
+#include "nodelist.h"
#include "reasons.h"
+#include "rendclient.h"
+#include "router.h"
+#include "routerset.h"
/* Return a human-readable string for the client fetch status code. */
static const char *
diff --git a/src/or/hs_common.c b/src/or/hs_common.c
index 5edddd8940..3081ad216c 100644
--- a/src/or/hs_common.c
+++ b/src/or/hs_common.c
@@ -15,6 +15,8 @@
#include "config.h"
#include "circuitbuild.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "hs_cache.h"
diff --git a/src/or/hs_control.c b/src/or/hs_control.c
index eca9ed1dd5..6b9b95c6d8 100644
--- a/src/or/hs_control.c
+++ b/src/or/hs_control.c
@@ -8,6 +8,7 @@
#include "or.h"
#include "control.h"
+#include "crypto_util.h"
#include "hs_common.h"
#include "hs_control.h"
#include "hs_descriptor.h"
diff --git a/src/or/hs_descriptor.c b/src/or/hs_descriptor.c
index 7388807bc5..096122392d 100644
--- a/src/or/hs_descriptor.c
+++ b/src/or/hs_descriptor.c
@@ -59,6 +59,8 @@
#include "ed25519_cert.h" /* Trunnel interface. */
#include "hs_descriptor.h"
#include "circuitbuild.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "parsecommon.h"
#include "rendcache.h"
#include "hs_cache.h"
@@ -1895,7 +1897,7 @@ desc_sig_is_valid(const char *b64_sig,
}
/* Find the start of signature. */
- sig_start = tor_memstr(encoded_desc, encoded_len, "\n" str_signature);
+ sig_start = tor_memstr(encoded_desc, encoded_len, "\n" str_signature " ");
/* Getting here means the token parsing worked for the signature so if we
* can't find the start of the signature, we have a code flow issue. */
if (!sig_start) {
diff --git a/src/or/hs_descriptor.h b/src/or/hs_descriptor.h
index 09979410e1..8195c6efbc 100644
--- a/src/or/hs_descriptor.h
+++ b/src/or/hs_descriptor.h
@@ -16,6 +16,7 @@
#include "container.h"
#include "crypto.h"
#include "crypto_ed25519.h"
+#include "ed25519_cert.h" /* needed for trunnel */
#include "torcert.h"
/* Trunnel */
diff --git a/src/or/hs_ident.c b/src/or/hs_ident.c
index 0bce2f625b..3603e329d4 100644
--- a/src/or/hs_ident.c
+++ b/src/or/hs_ident.c
@@ -7,6 +7,7 @@
* subsytem.
**/
+#include "crypto_util.h"
#include "hs_ident.h"
/* Return a newly allocated circuit identifier. The given public key is copied
diff --git a/src/or/hs_ident.h b/src/or/hs_ident.h
index 91ec389aa4..8f9da30c35 100644
--- a/src/or/hs_ident.h
+++ b/src/or/hs_ident.h
@@ -21,7 +21,6 @@
#ifndef TOR_HS_IDENT_H
#define TOR_HS_IDENT_H
-#include "crypto.h"
#include "crypto_ed25519.h"
#include "hs_common.h"
diff --git a/src/or/hs_ntor.c b/src/or/hs_ntor.c
index a416bc46c3..809fa83bb8 100644
--- a/src/or/hs_ntor.c
+++ b/src/or/hs_ntor.c
@@ -25,6 +25,7 @@
*/
#include "or.h"
+#include "crypto_util.h"
#include "hs_ntor.h"
/* String constants used by the ntor HS protocol */
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index e40e9203e7..9001a521ab 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -15,6 +15,8 @@
#include "circuituse.h"
#include "config.h"
#include "connection.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "directory.h"
#include "main.h"
#include "networkstatus.h"
@@ -441,6 +443,10 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy)
if (crypto_pk_generate_key(ip->legacy_key) < 0) {
goto err;
}
+ if (crypto_pk_get_digest(ip->legacy_key,
+ (char *) ip->legacy_key_digest) < 0) {
+ goto err;
+ }
}
if (ei == NULL) {
@@ -872,11 +878,6 @@ register_all_services(void)
tor_assert(hs_service_staging_list);
- /* We'll save us some allocation and computing time. */
- if (smartlist_len(hs_service_staging_list) == 0) {
- return;
- }
-
/* Allocate a new map that will replace the current one. */
new_service_map = tor_malloc_zero(sizeof(*new_service_map));
HT_INIT(hs_service_ht, new_service_map);
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index 2e27d8a899..5494b6f5fa 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -50,6 +50,9 @@ typedef struct hs_service_intro_point_t {
/* Legacy key if that intro point doesn't support v3. This should be used if
* the base object legacy flag is set. */
crypto_pk_t *legacy_key;
+ /* Legacy key SHA1 public key digest. This should be used only if the base
+ * object legacy flag is set. */
+ uint8_t legacy_key_digest[DIGEST_LEN];
/* Amount of INTRODUCE2 cell accepted from this intro point. */
uint64_t introduce2_count;
diff --git a/src/or/hs_stats.c b/src/or/hs_stats.c
index 3e183a5bfc..1e2a96945b 100644
--- a/src/or/hs_stats.c
+++ b/src/or/hs_stats.c
@@ -3,7 +3,7 @@
/**
* \file hs_stats.c
- * \brief Keeps stats about the activity of our hidden service.
+ * \brief Keeps stats about the activity of our onion service(s).
**/
#include "or.h"
@@ -42,14 +42,14 @@ hs_stats_get_n_introduce2_v2_cells(void)
return n_introduce2_v2;
}
-/** Note that we attempted to launch another circuit to a rendezvous point */
+/** Note that we attempted to launch another circuit to a rendezvous point. */
void
hs_stats_note_service_rendezvous_launch(void)
{
n_rendezvous_launches++;
}
-/** Return the number of rendezvous circuits we have attempted to launch */
+/** Return the number of rendezvous circuits we have attempted to launch. */
uint32_t
hs_stats_get_n_rendezvous_launches(void)
{
diff --git a/src/or/include.am b/src/or/include.am
index 9cae7d0039..bc0b9d2bfb 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -279,6 +279,7 @@ ORHEADERS = \
ORHEADERS += \
src/or/dirauth/dircollate.h \
src/or/dirauth/dirvote.h \
+ src/or/dirauth/mode.h \
src/or/dirauth/shared_random.h \
src/or/dirauth/shared_random_state.h
diff --git a/src/or/main.c b/src/or/main.c
index cf0df9ba79..9dce158b33 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -71,6 +71,7 @@
#include "control.h"
#include "cpuworker.h"
#include "crypto_s2k.h"
+#include "crypto_rand.h"
#include "directory.h"
#include "dirserv.h"
#include "dns.h"
@@ -103,7 +104,6 @@
#include "routerlist.h"
#include "routerparse.h"
#include "scheduler.h"
-#include "dirauth/shared_random.h"
#include "statefile.h"
#include "status.h"
#include "tor_api.h"
@@ -119,6 +119,8 @@
#include <event2/event.h>
#include "dirauth/dirvote.h"
+#include "dirauth/mode.h"
+#include "dirauth/shared_random.h"
#ifdef HAVE_SYSTEMD
# if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__)
@@ -161,11 +163,6 @@ token_bucket_rw_t global_bucket;
/* Token bucket for relayed traffic. */
token_bucket_rw_t global_relayed_bucket;
-/* DOCDOC stats_prev_n_read */
-static uint64_t stats_prev_n_read = 0;
-/* DOCDOC stats_prev_n_written */
-static uint64_t stats_prev_n_written = 0;
-
/* XXX we might want to keep stats about global_relayed_*_bucket too. Or not.*/
/** How many bytes have we read since we started the process? */
static uint64_t stats_n_bytes_read = 0;
@@ -188,6 +185,8 @@ static uint64_t stats_n_main_loop_idle = 0;
static time_t time_of_last_signewnym = 0;
/** Is there a signewnym request we're currently waiting to handle? */
static int signewnym_is_pending = 0;
+/** Mainloop event for the deferred signewnym call. */
+static mainloop_event_t *handle_deferred_signewnym_ev = NULL;
/** How many times have we called newnym? */
static unsigned newnym_epoch = 0;
@@ -1254,7 +1253,8 @@ run_connection_housekeeping(int i, time_t now)
} else if (we_are_hibernating() &&
! have_any_circuits &&
!connection_get_outbuf_len(conn)) {
- /* We're hibernating, there's no circuits, and nothing to flush.*/
+ /* We're hibernating or shutting down, there's no circuits, and nothing to
+ * flush.*/
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[Hibernating or exiting].",
(int)conn->s,conn->address, conn->port);
@@ -1316,6 +1316,16 @@ signewnym_impl(time_t now)
control_event_signal(SIGNEWNYM);
}
+/** Callback: run a deferred signewnym. */
+static void
+handle_deferred_signewnym_cb(mainloop_event_t *event, void *arg)
+{
+ (void)event;
+ (void)arg;
+ log_info(LD_CONTROL, "Honoring delayed NEWNYM request");
+ signewnym_impl(time(NULL));
+}
+
/** Return the number of times that signewnym has been called. */
unsigned
get_signewnym_epoch(void)
@@ -1350,6 +1360,7 @@ CALLBACK(heartbeat);
CALLBACK(hs_service);
CALLBACK(launch_descriptor_fetches);
CALLBACK(launch_reachability_tests);
+CALLBACK(reachability_warnings);
CALLBACK(record_bridge_stats);
CALLBACK(rend_cache_failure_clean);
CALLBACK(reset_padding_counts);
@@ -1393,6 +1404,8 @@ STATIC periodic_event_item_t periodic_events[] = {
CALLBACK(check_onion_keys_expiry_time, PERIODIC_EVENT_ROLE_ROUTER, 0),
CALLBACK(expire_old_ciruits_serverside, PERIODIC_EVENT_ROLE_ROUTER,
PERIODIC_EVENT_FLAG_NEED_NET),
+ CALLBACK(reachability_warnings, PERIODIC_EVENT_ROLE_ROUTER,
+ PERIODIC_EVENT_FLAG_NEED_NET),
CALLBACK(retry_dns, PERIODIC_EVENT_ROLE_ROUTER, 0),
CALLBACK(rotate_onion_key, PERIODIC_EVENT_ROLE_ROUTER, 0),
@@ -1480,7 +1493,7 @@ get_my_roles(const or_options_t *options)
int roles = 0;
int is_bridge = options->BridgeRelay;
- int is_client = any_client_port_set(options);
+ int is_client = options_any_client_port_set(options);
int is_relay = server_mode(options);
int is_dirauth = authdir_mode_v3(options);
int is_bridgeauth = authdir_mode_bridge(options);
@@ -1659,6 +1672,11 @@ static mainloop_event_t *postloop_cleanup_ev=NULL;
void
mainloop_schedule_postloop_cleanup(void)
{
+ if (PREDICT_UNLIKELY(postloop_cleanup_ev == NULL)) {
+ // (It's possible that we can get here if we decide to close a connection
+ // in the earliest stages of our configuration, before we create events.)
+ return;
+ }
mainloop_event_activate(postloop_cleanup_ev);
}
@@ -1699,17 +1717,6 @@ run_scheduled_events(time_t now)
*/
consider_hibernation(now);
- /* 0b. If we've deferred a signewnym, make sure it gets handled
- * eventually. */
- if (signewnym_is_pending &&
- time_of_last_signewnym + MAX_SIGNEWNYM_RATE <= now) {
- log_info(LD_CONTROL, "Honoring delayed NEWNYM request");
- signewnym_impl(now);
- }
-
- /* 0c. If we've deferred log messages for the controller, handle them now */
- flush_pending_log_callbacks();
-
/* Maybe enough time elapsed for us to reconsider a circuit. */
circuit_upgrade_circuits_from_guard_wait();
@@ -2330,6 +2337,54 @@ expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options)
return 11;
}
+/**
+ * Callback: Send warnings if Tor doesn't find its ports reachable.
+ */
+static int
+reachability_warnings_callback(time_t now, const or_options_t *options)
+{
+ (void) now;
+
+ if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
+ return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime());
+ }
+
+ if (server_mode(options) &&
+ !net_is_disabled() &&
+ have_completed_a_circuit()) {
+ /* every 20 minutes, check and complain if necessary */
+ const routerinfo_t *me = router_get_my_routerinfo();
+ if (me && !check_whether_orport_reachable(options)) {
+ char *address = tor_dup_ip(me->addr);
+ log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that "
+ "its ORPort is reachable. Relays do not publish descriptors "
+ "until their ORPort and DirPort are reachable. Please check "
+ "your firewalls, ports, address, /etc/hosts file, etc.",
+ address, me->or_port);
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED ORADDRESS=%s:%d",
+ address, me->or_port);
+ tor_free(address);
+ }
+
+ if (me && !check_whether_dirport_reachable(options)) {
+ char *address = tor_dup_ip(me->addr);
+ log_warn(LD_CONFIG,
+ "Your server (%s:%d) has not managed to confirm that its "
+ "DirPort is reachable. Relays do not publish descriptors "
+ "until their ORPort and DirPort are reachable. Please check "
+ "your firewalls, ports, address, /etc/hosts file, etc.",
+ address, me->dir_port);
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED DIRADDRESS=%s:%d",
+ address, me->dir_port);
+ tor_free(address);
+ }
+ }
+
+ return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT;
+}
+
static int dns_honesty_first_time = 1;
/**
@@ -2441,10 +2496,100 @@ hs_service_callback(time_t now, const or_options_t *options)
/** Timer: used to invoke second_elapsed_callback() once per second. */
static periodic_timer_t *second_timer = NULL;
-/** Number of libevent errors in the last second: we die if we get too many. */
-static int n_libevent_errors = 0;
-/** Last time that second_elapsed_callback was called. */
+
+/**
+ * Enable or disable the per-second timer as appropriate, creating it if
+ * necessary.
+ */
+void
+reschedule_per_second_timer(void)
+{
+ struct timeval one_second;
+ one_second.tv_sec = 1;
+ one_second.tv_usec = 0;
+
+ if (! second_timer) {
+ second_timer = periodic_timer_new(tor_libevent_get_base(),
+ &one_second,
+ second_elapsed_callback,
+ NULL);
+ tor_assert(second_timer);
+ }
+
+ const bool run_per_second_events =
+ control_any_per_second_event_enabled() || ! net_is_completely_disabled();
+
+ if (run_per_second_events) {
+ periodic_timer_launch(second_timer, &one_second);
+ } else {
+ periodic_timer_disable(second_timer);
+ }
+}
+
+/** Last time that update_current_time was called. */
static time_t current_second = 0;
+/** Last time that update_current_time updated current_second. */
+static monotime_coarse_t current_second_last_changed;
+
+/**
+ * Set the current time to "now", which should be the value returned by
+ * time(). Check for clock jumps and track the total number of seconds we
+ * have been running.
+ */
+void
+update_current_time(time_t now)
+{
+ if (PREDICT_LIKELY(now == current_second)) {
+ /* We call this function a lot. Most frequently, the current second
+ * will not have changed, so we just return. */
+ return;
+ }
+
+ const time_t seconds_elapsed = current_second ? (now - current_second) : 0;
+
+ /* Check the wall clock against the monotonic clock, so we can
+ * better tell idleness from clock jumps and/or other shenanigans. */
+ monotime_coarse_t last_updated;
+ memcpy(&last_updated, &current_second_last_changed, sizeof(last_updated));
+ monotime_coarse_get(&current_second_last_changed);
+
+ /** How much clock jumping do we tolerate? */
+#define NUM_JUMPED_SECONDS_BEFORE_WARN 100
+
+ /** How much idleness do we tolerate? */
+#define NUM_IDLE_SECONDS_BEFORE_WARN 3600
+
+ if (seconds_elapsed < -NUM_JUMPED_SECONDS_BEFORE_WARN) {
+ // moving back in time is always a bad sign.
+ circuit_note_clock_jumped(seconds_elapsed, false);
+ } else if (seconds_elapsed >= NUM_JUMPED_SECONDS_BEFORE_WARN) {
+ /* Compare the monotonic clock to the result of time(). */
+ const int32_t monotime_msec_passed =
+ monotime_coarse_diff_msec32(&last_updated,
+ &current_second_last_changed);
+ const int monotime_sec_passed = monotime_msec_passed / 1000;
+ const int discrepancy = monotime_sec_passed - (int)seconds_elapsed;
+ /* If the monotonic clock deviates from time(NULL), we have a couple of
+ * possibilities. On some systems, this means we have been suspended or
+ * sleeping. Everywhere, it can mean that the wall-clock time has
+ * been changed -- for example, with settimeofday().
+ *
+ * On the other hand, if the monotonic time matches with the wall-clock
+ * time, we've probably just been idle for a while, with no events firing.
+ * we tolerate much more of that.
+ */
+ const bool clock_jumped = abs(discrepancy) > 2;
+
+ if (clock_jumped || seconds_elapsed >= NUM_IDLE_SECONDS_BEFORE_WARN) {
+ circuit_note_clock_jumped(seconds_elapsed, ! clock_jumped);
+ }
+ } else if (seconds_elapsed > 0) {
+ stats_n_seconds_working += seconds_elapsed;
+ }
+
+ update_approx_time(now);
+ current_second = now;
+}
/** Libevent callback: invoked once every second. */
static void
@@ -2454,81 +2599,21 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
* could use Libevent's timers for this rather than checking the current
* time against a bunch of timeouts every second. */
time_t now;
- size_t bytes_written;
- size_t bytes_read;
- int seconds_elapsed;
- const or_options_t *options = get_options();
(void)timer;
(void)arg;
- n_libevent_errors = 0;
-
- /* log_notice(LD_GENERAL, "Tick."); */
now = time(NULL);
- update_approx_time(now);
-
- /* the second has rolled over. check more stuff. */
- seconds_elapsed = current_second ? (int)(now - current_second) : 0;
- bytes_read = (size_t)(stats_n_bytes_read - stats_prev_n_read);
- bytes_written = (size_t)(stats_n_bytes_written - stats_prev_n_written);
- stats_prev_n_read = stats_n_bytes_read;
- stats_prev_n_written = stats_n_bytes_written;
-
- control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written);
- control_event_stream_bandwidth_used();
- control_event_conn_bandwidth_used();
- control_event_circ_bandwidth_used();
- control_event_circuit_cell_stats();
- if (server_mode(options) &&
- !net_is_disabled() &&
- seconds_elapsed > 0 &&
- have_completed_a_circuit() &&
- get_uptime() / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT !=
- (get_uptime()+seconds_elapsed) /
- TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
- /* every 20 minutes, check and complain if necessary */
- const routerinfo_t *me = router_get_my_routerinfo();
- if (me && !check_whether_orport_reachable(options)) {
- char *address = tor_dup_ip(me->addr);
- log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that "
- "its ORPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address, me->or_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED ORADDRESS=%s:%d",
- address, me->or_port);
- tor_free(address);
- }
-
- if (me && !check_whether_dirport_reachable(options)) {
- char *address = tor_dup_ip(me->addr);
- log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that its "
- "DirPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address, me->dir_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED DIRADDRESS=%s:%d",
- address, me->dir_port);
- tor_free(address);
- }
- }
+ /* We don't need to do this once-per-second any more: time-updating is
+ * only in this callback _because it is a callback_. It should be fine
+ * to disable this callback, and the time will still get updated.
+ */
+ update_current_time(now);
-/** If more than this many seconds have elapsed, probably the clock
- * jumped: doesn't count. */
-#define NUM_JUMPED_SECONDS_BEFORE_WARN 100
- if (seconds_elapsed < -NUM_JUMPED_SECONDS_BEFORE_WARN ||
- seconds_elapsed >= NUM_JUMPED_SECONDS_BEFORE_WARN) {
- circuit_note_clock_jumped(seconds_elapsed);
- } else if (seconds_elapsed > 0)
- stats_n_seconds_working += seconds_elapsed;
+ /* Maybe some controller events are ready to fire */
+ control_per_second_events();
run_scheduled_events(now);
-
- current_second = now; /* remember which second it is, for next time */
}
#ifdef HAVE_SYSTEMD_209
@@ -2544,21 +2629,6 @@ systemd_watchdog_callback(periodic_timer_t *timer, void *arg)
}
#endif /* defined(HAVE_SYSTEMD_209) */
-#ifndef _WIN32
-/** Called when a possibly ignorable libevent error occurs; ensures that we
- * don't get into an infinite loop by ignoring too many errors from
- * libevent. */
-static int
-got_libevent_error(void)
-{
- if (++n_libevent_errors > 8) {
- log_err(LD_NET, "Too many libevent errors in one second; dying");
- return -1;
- }
- return 0;
-}
-#endif /* !defined(_WIN32) */
-
#define UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST (6*60*60)
/** Called when our IP address seems to have changed. <b>at_interface</b>
@@ -2821,17 +2891,7 @@ do_main_loop(void)
}
/* set up once-a-second callback. */
- if (! second_timer) {
- struct timeval one_second;
- one_second.tv_sec = 1;
- one_second.tv_usec = 0;
-
- second_timer = periodic_timer_new(tor_libevent_get_base(),
- &one_second,
- second_elapsed_callback,
- NULL);
- tor_assert(second_timer);
- }
+ reschedule_per_second_timer();
#ifdef HAVE_SYSTEMD_209
uint64_t watchdog_delay;
@@ -2900,6 +2960,11 @@ do_main_loop(void)
return run_main_loop_until_done();
}
+#ifndef _WIN32
+/** Rate-limiter for EINVAL-type libevent warnings. */
+static ratelim_t libevent_error_ratelim = RATELIM_INIT(10);
+#endif
+
/**
* Run the main loop a single time. Return 0 for "exit"; -1 for "exit with
* error", and 1 for "run this again."
@@ -2965,9 +3030,12 @@ run_main_loop_once(void)
return -1;
#ifndef _WIN32
} else if (e == EINVAL) {
- log_warn(LD_NET, "EINVAL from libevent: should you upgrade libevent?");
- if (got_libevent_error())
+ log_fn_ratelim(&libevent_error_ratelim, LOG_WARN, LD_NET,
+ "EINVAL from libevent: should you upgrade libevent?");
+ if (libevent_error_ratelim.n_calls_since_last_time > 8) {
+ log_err(LD_NET, "Too many libevent errors, too fast: dying");
return -1;
+ }
#endif /* !defined(_WIN32) */
} else {
tor_assert_nonfatal_once(! ERRNO_IS_EINPROGRESS(e));
@@ -3013,6 +3081,7 @@ signal_callback(evutil_socket_t fd, short events, void *arg)
(void)fd;
(void)events;
+ update_current_time(time(NULL));
process_signal(sig);
}
@@ -3075,10 +3144,20 @@ process_signal(int sig)
case SIGNEWNYM: {
time_t now = time(NULL);
if (time_of_last_signewnym + MAX_SIGNEWNYM_RATE > now) {
- signewnym_is_pending = 1;
+ const time_t delay_sec =
+ time_of_last_signewnym + MAX_SIGNEWNYM_RATE - now;
+ if (! signewnym_is_pending) {
+ signewnym_is_pending = 1;
+ if (!handle_deferred_signewnym_ev) {
+ handle_deferred_signewnym_ev =
+ mainloop_event_postloop_new(handle_deferred_signewnym_cb, NULL);
+ }
+ const struct timeval delay_tv = { delay_sec, 0 };
+ mainloop_event_schedule(handle_deferred_signewnym_ev, &delay_tv);
+ }
log_notice(LD_CONTROL,
- "Rate limiting NEWNYM request: delaying by %d second(s)",
- (int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now));
+ "Rate limiting NEWNYM request: delaying by %d second(s)",
+ (int)(delay_sec));
} else {
signewnym_impl(now);
}
@@ -3592,6 +3671,8 @@ tor_free_all(int postfork)
hs_free_all();
dos_free_all();
circuitmux_ewma_free_all();
+ accounting_free_all();
+
if (!postfork) {
config_free_all();
or_state_free_all();
@@ -3617,6 +3698,7 @@ tor_free_all(int postfork)
mainloop_event_free(directory_all_unreachable_cb_event);
mainloop_event_free(schedule_active_linked_connections_event);
mainloop_event_free(postloop_cleanup_ev);
+ mainloop_event_free(handle_deferred_signewnym_ev);
#ifdef HAVE_SYSTEMD_209
periodic_timer_free(systemd_watchdog_timer);
@@ -3624,7 +3706,6 @@ tor_free_all(int postfork)
memset(&global_bucket, 0, sizeof(global_bucket));
memset(&global_relayed_bucket, 0, sizeof(global_relayed_bucket));
- stats_prev_n_read = stats_prev_n_written = 0;
stats_n_bytes_read = stats_n_bytes_written = 0;
time_of_process_start = 0;
time_of_last_signewnym = 0;
@@ -3638,8 +3719,9 @@ tor_free_all(int postfork)
should_init_bridge_stats = 1;
dns_honesty_first_time = 1;
heartbeat_callback_first_time = 1;
- n_libevent_errors = 0;
current_second = 0;
+ memset(&current_second_last_changed, 0,
+ sizeof(current_second_last_changed));
if (!postfork) {
release_lockfile();
diff --git a/src/or/main.h b/src/or/main.h
index a312b51e05..9dbbc6e5ee 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -66,6 +66,8 @@ void reschedule_dirvote(const or_options_t *options);
void mainloop_schedule_postloop_cleanup(void);
void rescan_periodic_events(const or_options_t *options);
+void update_current_time(time_t now);
+
MOCK_DECL(long,get_uptime,(void));
MOCK_DECL(void,reset_uptime,(void));
@@ -92,6 +94,7 @@ uint64_t get_main_loop_error_count(void);
uint64_t get_main_loop_idle_count(void);
void periodic_events_on_new_options(const or_options_t *options);
+void reschedule_per_second_timer(void);
extern time_t time_of_process_start;
extern int quiet_level;
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index ac3e94e884..b7443b4c7a 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -48,6 +48,8 @@
#include "connection_or.h"
#include "consdiffmgr.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "directory.h"
#include "dirserv.h"
#include "dos.h"
@@ -63,13 +65,14 @@
#include "routerlist.h"
#include "routerparse.h"
#include "scheduler.h"
-#include "dirauth/shared_random.h"
#include "transports.h"
#include "torcert.h"
#include "channelpadding.h"
#include "voting_schedule.h"
#include "dirauth/dirvote.h"
+#include "dirauth/mode.h"
+#include "dirauth/shared_random.h"
/** Most recently received and validated v3 "ns"-flavored consensus network
* status. */
@@ -1688,24 +1691,6 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c,
#endif /* defined(TOR_UNIT_TESTS) */
/**
- * Return true if any option is set in <b>options</b> to make us behave
- * as a client.
- *
- * XXXX If we need this elsewhere at any point, we should make it nonstatic
- * XXXX and move it into another file.
- */
-int
-any_client_port_set(const or_options_t *options)
-{
- return (options->SocksPort_set ||
- options->TransPort_set ||
- options->NATDPort_set ||
- options->ControlPort_set ||
- options->DNSPort_set ||
- options->HTTPTunnelPort_set);
-}
-
-/**
* Helper for handle_missing_protocol_warning: handles either the
* client case (if <b>is_client</b> is set) or the server case otherwise.
*/
@@ -1740,7 +1725,7 @@ handle_missing_protocol_warning(const networkstatus_t *c,
const or_options_t *options)
{
const int is_server = server_mode(options);
- const int is_client = any_client_port_set(options) || !is_server;
+ const int is_client = options_any_client_port_set(options) || !is_server;
if (is_server)
handle_missing_protocol_warning_impl(c, 0);
@@ -1855,17 +1840,9 @@ networkstatus_set_current_consensus(const char *consensus,
current_valid_after = current_md_consensus->valid_after;
}
} else {
- cached_dir_t *cur;
- char buf[128];
- tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor);
- consensus_fname = get_cachedir_fname(buf);
- tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor);
- unverified_fname = get_cachedir_fname(buf);
- cur = dirserv_get_consensus(flavor);
- if (cur) {
- current_digests = &cur->digests;
- current_valid_after = cur->published;
- }
+ tor_assert_nonfatal_unreached();
+ result = -2;
+ goto done;
}
if (current_digests &&
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 0c325959d7..6a7a42f911 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -147,8 +147,6 @@ void vote_routerstatus_free_(vote_routerstatus_t *rs);
#define vote_routerstatus_free(rs) \
FREE_AND_NULL(vote_routerstatus_t, vote_routerstatus_free_, (rs))
-int any_client_port_set(const or_options_t *options);
-
#ifdef NETWORKSTATUS_PRIVATE
#ifdef TOR_UNIT_TESTS
STATIC int networkstatus_set_current_consensus_from_ns(networkstatus_t *c,
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 675cbb0056..bc9a79940b 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -66,6 +66,8 @@
#include <string.h>
+#include "dirauth/mode.h"
+
static void nodelist_drop_node(node_t *node, int remove_from_ht);
#define node_free(val) \
FREE_AND_NULL(node_t, node_free_, (val))
diff --git a/src/or/onion.c b/src/or/onion.c
index 0c88c4d7ee..829be12bae 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -67,6 +67,7 @@
#include "circuitlist.h"
#include "config.h"
#include "cpuworker.h"
+#include "crypto_util.h"
#include "networkstatus.h"
#include "onion.h"
#include "onion_fast.h"
diff --git a/src/or/onion_fast.c b/src/or/onion_fast.c
index de9103b1f5..9f9b2199d4 100644
--- a/src/or/onion_fast.c
+++ b/src/or/onion_fast.c
@@ -29,6 +29,8 @@
#include "or.h"
#include "onion_fast.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
/** Release all state held in <b>victim</b>. */
void
diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c
index 8ad876a587..02d43cb722 100644
--- a/src/or/onion_ntor.c
+++ b/src/or/onion_ntor.c
@@ -23,6 +23,7 @@
#define ONION_NTOR_PRIVATE
#include "crypto.h"
#include "crypto_digest.h"
+#include "crypto_util.h"
#include "onion_ntor.h"
#include "torlog.h"
#include "util.h"
diff --git a/src/or/onion_tap.c b/src/or/onion_tap.c
index c71fa236ed..44737034f4 100644
--- a/src/or/onion_tap.c
+++ b/src/or/onion_tap.c
@@ -29,6 +29,8 @@
#include "or.h"
#include "config.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "onion_tap.h"
#include "rephist.h"
diff --git a/src/or/periodic.c b/src/or/periodic.c
index 76aa418b35..92fa677f8f 100644
--- a/src/or/periodic.c
+++ b/src/or/periodic.c
@@ -14,6 +14,7 @@
#include "or.h"
#include "compat_libevent.h"
#include "config.h"
+#include "main.h"
#include "periodic.h"
/** We disable any interval greater than this number of seconds, on the
@@ -48,6 +49,7 @@ periodic_event_dispatch(mainloop_event_t *ev, void *data)
}
time_t now = time(NULL);
+ update_current_time(now);
const or_options_t *options = get_options();
// log_debug(LD_GENERAL, "Dispatching %s", event->name);
int r = event->fn(now, options);
diff --git a/src/or/proto_socks.c b/src/or/proto_socks.c
index 8700fe1269..57a7d1cd64 100644
--- a/src/or/proto_socks.c
+++ b/src/or/proto_socks.c
@@ -9,6 +9,7 @@
#include "buffers.h"
#include "control.h"
#include "config.h"
+#include "crypto_util.h"
#include "ext_orport.h"
#include "proto_socks.h"
#include "reasons.h"
diff --git a/src/or/relay.c b/src/or/relay.c
index 8c248e6d98..b0b1af4454 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -61,6 +61,8 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "geoip.h"
#include "hs_cache.h"
#include "main.h"
diff --git a/src/or/relay_crypto.c b/src/or/relay_crypto.c
index c42a4f9cca..530c8e5828 100644
--- a/src/or/relay_crypto.c
+++ b/src/or/relay_crypto.c
@@ -6,9 +6,10 @@
#include "or.h"
#include "config.h"
+#include "crypto_util.h"
#include "hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
-#include "relay_crypto.h"
#include "relay.h"
+#include "relay_crypto.h"
/** Update digest from the payload of cell. Assign integrity part to
* cell.
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 9a1b97c6d6..7ef12a4faf 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -15,10 +15,13 @@
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
+#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "directory.h"
-#include "hs_common.h"
#include "hs_circuit.h"
#include "hs_client.h"
+#include "hs_common.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
@@ -29,7 +32,6 @@
#include "router.h"
#include "routerlist.h"
#include "routerset.h"
-#include "control.h"
static extend_info_t *rend_client_get_random_intro_impl(
const rend_cache_entry_t *rend_query,
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 230da4be5c..3a7dfe28f8 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -14,18 +14,20 @@
#include "circuitbuild.h"
#include "config.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
+#include "hs_client.h"
#include "hs_common.h"
+#include "hs_intropoint.h"
+#include "networkstatus.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rendmid.h"
-#include "hs_intropoint.h"
-#include "hs_client.h"
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
-#include "networkstatus.h"
/** Return 0 if one and two are the same service ids, else -1 or 1 */
int
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index afaeabe5dc..92c323b10d 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -16,6 +16,8 @@
#include "circuituse.h"
#include "config.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "directory.h"
#include "hs_common.h"
#include "hs_config.h"
@@ -627,10 +629,11 @@ void
rend_service_prune_list(void)
{
smartlist_t *old_service_list = rend_service_list;
- /* Don't try to prune anything if we have no staging list. */
+
if (!rend_service_staging_list) {
- return;
+ rend_service_staging_list = smartlist_new();
}
+
rend_service_prune_list_impl_();
if (old_service_list) {
/* Every remaining service in the old list have been removed from the
diff --git a/src/or/rephist.c b/src/or/rephist.c
index bac2efb1f4..c7117bad63 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -78,6 +78,7 @@
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
+#include "crypto_rand.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "rephist.h"
diff --git a/src/or/router.c b/src/or/router.c
index 93b61b69ef..07abf1f8d5 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -13,6 +13,8 @@
#include "config.h"
#include "connection.h"
#include "control.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "crypto_curve25519.h"
#include "directory.h"
#include "dirserv.h"
@@ -35,6 +37,8 @@
#include "transports.h"
#include "routerset.h"
+#include "dirauth/mode.h"
+
/**
* \file router.c
* \brief Miscellaneous relay functionality, including RSA key maintenance,
@@ -1595,30 +1599,31 @@ router_perform_bandwidth_test(int num_circs, time_t now)
}
}
-/** Return true iff our network is in some sense disabled: either we're
- * hibernating, entering hibernation, or the network is turned off with
- * DisableNetwork. */
+/** Return true iff our network is in some sense disabled or shutting down:
+ * either we're hibernating, entering hibernation, or the network is turned
+ * off with DisableNetwork. */
int
net_is_disabled(void)
{
return get_options()->DisableNetwork || we_are_hibernating();
}
-/** Return true iff we believe ourselves to be an authoritative
- * directory server.
- */
+/** Return true iff our network is in some sense "completely disabled" either
+ * we're fully hibernating or the network is turned off with
+ * DisableNetwork. */
int
-authdir_mode(const or_options_t *options)
+net_is_completely_disabled(void)
{
- return options->AuthoritativeDir != 0;
+ return get_options()->DisableNetwork || we_are_fully_hibernating();
}
-/** Return true iff we believe ourselves to be a v3 authoritative
+
+/** Return true iff we believe ourselves to be an authoritative
* directory server.
*/
int
-authdir_mode_v3(const or_options_t *options)
+authdir_mode(const or_options_t *options)
{
- return authdir_mode(options) && options->V3AuthoritativeDir != 0;
+ return options->AuthoritativeDir != 0;
}
/** Return true iff we are an authoritative directory server that is
* authoritative about receiving and serving descriptors of type
@@ -2272,6 +2277,7 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
/* and compute ri->bandwidthburst similarly */
ri->bandwidthburst = get_effective_bwburst(options);
+ /* Report bandwidth, unless we're hibernating or shutting down */
ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
if (dns_seems_to_be_broken() || has_dns_init_failed()) {
@@ -2542,6 +2548,8 @@ check_descriptor_bandwidth_changed(time_t now)
return;
prev = router_get_my_routerinfo()->bandwidthcapacity;
+ /* Consider ourselves to have zero bandwidth if we're hibernating or
+ * shutting down. */
cur = we_are_hibernating() ? 0 : rep_hist_bandwidth_assess();
if ((prev != cur && (!prev || !cur)) ||
cur > prev*2 ||
diff --git a/src/or/router.h b/src/or/router.h
index e5efe577e3..0db2c1cfb2 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -53,9 +53,9 @@ void router_dirport_found_reachable(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
int net_is_disabled(void);
+int net_is_completely_disabled(void);
int authdir_mode(const or_options_t *options);
-int authdir_mode_v3(const or_options_t *options);
int authdir_mode_handles_descs(const or_options_t *options, int purpose);
int authdir_mode_publishes_statuses(const or_options_t *options);
int authdir_mode_tests_reachability(const or_options_t *options);
diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c
index 1933aaf4b6..43460da8cc 100644
--- a/src/or/routerkeys.c
+++ b/src/or/routerkeys.c
@@ -16,6 +16,7 @@
#include "or.h"
#include "config.h"
+#include "crypto_util.h"
#include "router.h"
#include "crypto_pwbox.h"
#include "routerkeys.h"
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 7eb9ec7990..7603eb3ecf 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -99,6 +99,7 @@
#include "config.h"
#include "connection.h"
#include "control.h"
+#include "crypto_rand.h"
#include "directory.h"
#include "dirserv.h"
#include "entrynodes.h"
@@ -122,6 +123,7 @@
#include "torcert.h"
#include "dirauth/dirvote.h"
+#include "dirauth/mode.h"
// #define DEBUG_ROUTERLIST
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index a729aa4b11..7af41c3baf 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -56,27 +56,28 @@
#define ROUTERPARSE_PRIVATE
#include "or.h"
-#include "config.h"
#include "circuitstats.h"
+#include "config.h"
+#include "crypto_util.h"
+#include "dirauth/shared_random.h"
#include "dirserv.h"
+#include "entrynodes.h"
+#include "memarea.h"
+#include "microdesc.h"
+#include "networkstatus.h"
#include "parsecommon.h"
#include "policies.h"
#include "protover.h"
#include "rendcommon.h"
-#include "router.h"
-#include "routerlist.h"
-#include "memarea.h"
-#include "microdesc.h"
-#include "networkstatus.h"
#include "rephist.h"
+#include "router.h"
#include "routerkeys.h"
+#include "routerlist.h"
#include "routerparse.h"
-#include "entrynodes.h"
-#include "torcert.h"
#include "sandbox.h"
#include "shared_random_client.h"
+#include "torcert.h"
#include "voting_schedule.h"
-#include "dirauth/shared_random.h"
#undef log
#include <math.h>
diff --git a/src/or/status.c b/src/or/status.c
index 4c497739e8..4b8033d114 100644
--- a/src/or/status.c
+++ b/src/or/status.c
@@ -87,19 +87,19 @@ bytes_to_usage(uint64_t bytes)
return bw_string;
}
-/** Log some usage info about our hidden service */
+/** Log some usage info about our onion service(s). */
static void
log_onion_service_stats(void)
{
unsigned int num_services = hs_service_get_num_services();
- /* If there are no active hidden services, no need to print logs */
+ /* If there are no active onion services, no need to print logs */
if (num_services == 0) {
return;
}
log_notice(LD_HEARTBEAT,
- "Our hidden service%s received %u v2 and %u v3 INTRODUCE2 cells "
+ "Our onion service%s received %u v2 and %u v3 INTRODUCE2 cells "
"and attempted to launch %d rendezvous circuits.",
num_services == 1 ? "" : "s",
hs_stats_get_n_introduce2_v2_cells(),
diff --git a/src/or/torcert.c b/src/or/torcert.c
index 51935ddf72..1c5afd965a 100644
--- a/src/or/torcert.c
+++ b/src/or/torcert.c
@@ -27,7 +27,7 @@
#include "or.h"
#include "config.h"
-#include "crypto.h"
+#include "crypto_util.h"
#include "torcert.h"
#include "ed25519_cert.h"
#include "torlog.h"
diff --git a/src/or/voting_schedule.c b/src/or/voting_schedule.c
index b7676d5e79..1d66b5e225 100644
--- a/src/or/voting_schedule.c
+++ b/src/or/voting_schedule.c
@@ -39,7 +39,9 @@ voting_schedule_get_start_of_next_interval(time_t now, int interval,
tm.tm_sec = 0;
if (tor_timegm(&tm, &midnight_today) < 0) {
+ // LCOV_EXCL_START
log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight.");
+ // LCOV_EXCL_STOP
}
midnight_tomorrow = midnight_today + (24*60*60);
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 91c0502c60..ddbc0ac2b7 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -1,8 +1,35 @@
[[package]]
+name = "crypto"
+version = "0.0.1"
+dependencies = [
+ "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "external 0.0.1",
+ "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smartlist 0.0.1",
+]
+
+[[package]]
+name = "digest"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "external"
version = "0.0.1"
dependencies = [
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smartlist 0.0.1",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -23,6 +50,32 @@ dependencies = [
]
[[package]]
+name = "rand"
+version = "0.0.1"
+dependencies = [
+ "external 0.0.1",
+ "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tor_allocate 0.0.1",
+ "tor_log 0.1.0",
+ "tor_util 0.0.1",
+]
+
+[[package]]
+name = "rand"
+version = "0.5.0-pre.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "smartlist"
version = "0.0.1"
dependencies = [
@@ -61,5 +114,15 @@ dependencies = [
"tor_log 0.1.0",
]
+[[package]]
+name = "typenum"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[metadata]
+"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
+"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
+"checksum rand 0.5.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7d7a7728c20bfd9fcc6e713e748e787c3d00e5ffd139b3ad1b5be92c5dfbaad5"
+"checksum rand_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0224284424a4b818387b58d59336c288f99b48f69681aa60cc681fe038bbca5d"
+"checksum typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a99dc6780ef33c78780b826cf9d2a78840b72cae9474de4bcaf9051e60ebbd"
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index 4ae8033eb3..1aaab0c4f8 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -1,6 +1,15 @@
[workspace]
-members = ["tor_util", "protover", "smartlist", "external", "tor_allocate",
-"tor_rust", "tor_log"]
+members = [
+ "crypto",
+ "external",
+ "protover",
+ "rand",
+ "smartlist",
+ "tor_allocate",
+ "tor_log",
+ "tor_rust",
+ "tor_util",
+]
[profile.release]
debug = true
diff --git a/src/rust/crypto/Cargo.toml b/src/rust/crypto/Cargo.toml
new file mode 100644
index 0000000000..e6a8bffa27
--- /dev/null
+++ b/src/rust/crypto/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+authors = ["The Tor Project",
+ "Isis Lovecruft <isis@torproject.org>"]
+name = "crypto"
+version = "0.0.1"
+publish = false
+
+[lib]
+name = "crypto"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
+[dependencies]
+libc = "=0.2.39"
+digest = "=0.7.2"
+
+[dependencies.external]
+path = "../external"
+
+[dependencies.smartlist]
+path = "../smartlist"
diff --git a/src/rust/crypto/digests/mod.rs b/src/rust/crypto/digests/mod.rs
new file mode 100644
index 0000000000..a2463b89eb
--- /dev/null
+++ b/src/rust/crypto/digests/mod.rs
@@ -0,0 +1,7 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Hash Digests and eXtendible Output Functions (XOFs)
+
+pub mod sha2;
diff --git a/src/rust/crypto/digests/sha2.rs b/src/rust/crypto/digests/sha2.rs
new file mode 100644
index 0000000000..1cbb6c581e
--- /dev/null
+++ b/src/rust/crypto/digests/sha2.rs
@@ -0,0 +1,213 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Hash Digests and eXtendible Output Functions (XOFs)
+
+pub use digest::Digest;
+
+use digest::BlockInput;
+use digest::FixedOutput;
+use digest::Input;
+use digest::generic_array::GenericArray;
+use digest::generic_array::typenum::U32;
+use digest::generic_array::typenum::U64;
+
+use external::crypto_digest::CryptoDigest;
+use external::crypto_digest::DigestAlgorithm;
+use external::crypto_digest::get_256_bit_digest;
+use external::crypto_digest::get_512_bit_digest;
+
+pub use external::crypto_digest::DIGEST256_LEN;
+pub use external::crypto_digest::DIGEST512_LEN;
+
+/// The block size for both SHA-256 and SHA-512 digests is 512 bits/64 bytes.
+///
+/// Unfortunately, we have to use the generic_array crate currently to express
+/// this at compile time. Later, in the future, when Rust implements const
+/// generics, we'll be able to remove this dependency (actually, it will get
+/// removed from the digest crate, which is currently `pub use`ing it).
+type BlockSize = U64;
+
+/// A SHA2-256 digest.
+///
+/// # C_RUST_COUPLED
+///
+/// * `crypto_digest_dup`
+#[derive(Clone)]
+pub struct Sha256 {
+ engine: CryptoDigest,
+}
+
+/// Construct a new, default instance of a `Sha256` hash digest function.
+///
+/// # Examples
+///
+/// ```
+/// use crypto::digest::Sha256;
+///
+/// let hasher: Sha256 = Sha256::default();
+/// ```
+///
+/// # Returns
+///
+/// A new `Sha256` digest.
+impl Default for Sha256 {
+ fn default() -> Sha256 {
+ Sha256{ engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_256)) }
+ }
+}
+
+impl BlockInput for Sha256 {
+ type BlockSize = BlockSize;
+}
+
+/// Input `msg` into the digest.
+///
+/// # Examples
+///
+/// ```
+/// use crypto::digest::Sha256;
+///
+/// let hasher: Sha256 = Sha256::default();
+///
+/// hasher.process(b"foo");
+/// hasher.process(b"bar");
+/// ```
+impl Input for Sha256 {
+ fn process(&mut self, msg: &[u8]) {
+ self.engine.add_bytes(&msg);
+ }
+}
+
+/// Retrieve the output hash from everything which has been fed into this
+/// `Sha256` digest thus far.
+///
+//
+// FIXME: Once const generics land in Rust, we should genericise calling
+// crypto_digest_get_digest in external::crypto_digest.
+impl FixedOutput for Sha256 {
+ type OutputSize = U32;
+
+ fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> {
+ let buffer: [u8; DIGEST256_LEN] = get_256_bit_digest(self.engine);
+
+ GenericArray::from(buffer)
+ }
+}
+
+/// A SHA2-512 digest.
+///
+/// # C_RUST_COUPLED
+///
+/// * `crypto_digest_dup`
+#[derive(Clone)]
+pub struct Sha512 {
+ engine: CryptoDigest,
+}
+
+/// Construct a new, default instance of a `Sha512` hash digest function.
+///
+/// # Examples
+///
+/// ```
+/// use crypto::digest::Sha512;
+///
+/// let hasher: Sha256 = Sha512::default();
+/// ```
+///
+/// # Returns
+///
+/// A new `Sha512` digest.
+impl Default for Sha512 {
+ fn default() -> Sha512 {
+ Sha512{ engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_512)) }
+ }
+}
+
+impl BlockInput for Sha512 {
+ type BlockSize = BlockSize;
+}
+
+/// Input `msg` into the digest.
+///
+/// # Examples
+///
+/// ```
+/// use crypto::digest::Sha512;
+///
+/// let hasher: Sha512 = Sha512::default();
+///
+/// hasher.process(b"foo");
+/// hasher.process(b"bar");
+/// ```
+impl Input for Sha512 {
+ fn process(&mut self, msg: &[u8]) {
+ self.engine.add_bytes(&msg);
+ }
+}
+
+/// Retrieve the output hash from everything which has been fed into this
+/// `Sha512` digest thus far.
+///
+//
+// FIXME: Once const generics land in Rust, we should genericise calling
+// crypto_digest_get_digest in external::crypto_digest.
+impl FixedOutput for Sha512 {
+ type OutputSize = U32;
+
+ fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> {
+ let buffer: [u8; DIGEST512_LEN] = get_512_bit_digest(self.engine);
+
+ GenericArray::clone_from_slice(&buffer)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use digest::Digest;
+
+ use super::*;
+
+ #[test]
+ fn sha256_default() {
+ let _: Sha256 = Sha256::default();
+ }
+
+ #[test]
+ fn sha256_digest() {
+ let mut h: Sha256 = Sha256::new();
+ let mut result: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
+
+ h.input(b"foo");
+ h.input(b"bar");
+ h.input(b"baz");
+
+ result.copy_from_slice(h.fixed_result().as_slice());
+
+ println!("{:?}", &result[..]);
+
+ assert_eq!(&result[..], &b"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"[..]);
+ }
+
+ #[test]
+ fn sha512_default() {
+ let _: Sha512 = Sha512::default();
+ }
+
+ #[test]
+ fn sha512_digest() {
+ let mut h: Sha512 = Sha512::new();
+ let mut result: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
+
+ h.input(b"foo");
+ h.input(b"bar");
+ h.input(b"baz");
+
+ result.copy_from_slice(h.fixed_result().as_slice());
+
+ println!("{:?}", &result[..]);
+
+ assert_eq!(&result[..], &b"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"[..]);
+ }
+}
diff --git a/src/rust/crypto/lib.rs b/src/rust/crypto/lib.rs
new file mode 100644
index 0000000000..d0793a8575
--- /dev/null
+++ b/src/rust/crypto/lib.rs
@@ -0,0 +1,36 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Common cryptographic functions and utilities.
+//!
+//! # Hash Digests and eXtendable Output Functions (XOFs)
+//!
+//! The `digests` module contains submodules for specific hash digests
+//! and extendable output functions.
+//!
+//! ```
+//! use crypto::digests::sha256::Sha256;
+//!
+//! let hasher: Sha256 = Sha256::default();
+//! let mut result: [u8; 32] = [0u8; 32];
+//!
+//! hasher.input("foo");
+//! hasher.input("bar");
+//! hasher.input("baz");
+//!
+//! result.copy_from_slice(hasher.result().as_bytes());
+//!
+//! assert!(result == "XXX");
+//! ```
+
+#[deny(missing_docs)]
+
+// External crates from cargo or TOR_RUST_DEPENDENCIES.
+extern crate digest;
+extern crate libc;
+
+// Our local crates.
+extern crate external;
+
+mod digests; // Unfortunately named "digests" plural to avoid name conflict with the digest crate
diff --git a/src/rust/external/Cargo.toml b/src/rust/external/Cargo.toml
index b5957b1079..60ec03be40 100644
--- a/src/rust/external/Cargo.toml
+++ b/src/rust/external/Cargo.toml
@@ -6,6 +6,9 @@ name = "external"
[dependencies]
libc = "=0.2.39"
+[dependencies.smartlist]
+path = "../smartlist"
+
[lib]
name = "external"
path = "lib.rs"
diff --git a/src/rust/external/crypto_digest.rs b/src/rust/external/crypto_digest.rs
new file mode 100644
index 0000000000..bc49e6124c
--- /dev/null
+++ b/src/rust/external/crypto_digest.rs
@@ -0,0 +1,402 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Bindings to external digest and XOF functions which live within
+//! src/common/crypto_digest.[ch].
+//!
+//! We wrap our C implementations in src/common/crypto_digest.[ch] with more
+//! Rusty types and interfaces in src/rust/crypto/digest/.
+
+use std::process::abort;
+
+use libc::c_char;
+use libc::c_int;
+use libc::size_t;
+use libc::uint8_t;
+
+use smartlist::Stringlist;
+
+/// Length of the output of our message digest.
+pub const DIGEST_LEN: usize = 20;
+
+/// Length of the output of our second (improved) message digests. (For now
+/// this is just sha256, but it could be any other 256-bit digest.)
+pub const DIGEST256_LEN: usize = 32;
+
+/// Length of the output of our 64-bit optimized message digests (SHA512).
+pub const DIGEST512_LEN: usize = 64;
+
+/// Length of a sha1 message digest when encoded in base32 with trailing = signs
+/// removed.
+pub const BASE32_DIGEST_LEN: usize = 32;
+
+/// Length of a sha1 message digest when encoded in base64 with trailing = signs
+/// removed.
+pub const BASE64_DIGEST_LEN: usize = 27;
+
+/// Length of a sha256 message digest when encoded in base64 with trailing =
+/// signs removed.
+pub const BASE64_DIGEST256_LEN: usize = 43;
+
+/// Length of a sha512 message digest when encoded in base64 with trailing =
+/// signs removed.
+pub const BASE64_DIGEST512_LEN: usize = 86;
+
+/// Length of hex encoding of SHA1 digest, not including final NUL.
+pub const HEX_DIGEST_LEN: usize = 40;
+
+/// Length of hex encoding of SHA256 digest, not including final NUL.
+pub const HEX_DIGEST256_LEN: usize = 64;
+
+/// Length of hex encoding of SHA512 digest, not including final NUL.
+pub const HEX_DIGEST512_LEN: usize = 128;
+
+/// Our C code uses an enum to declare the digest algorithm types which we know
+/// about. However, because enums are implementation-defined in C, we can
+/// neither work with them directly nor translate them into Rust enums.
+/// Instead, we represent them as a u8 (under the assumption that we'll never
+/// support more than 256 hash functions).
+#[allow(non_camel_case_types)]
+type digest_algorithm_t = u8;
+
+const DIGEST_SHA1: digest_algorithm_t = 0;
+const DIGEST_SHA256: digest_algorithm_t = 1;
+const DIGEST_SHA512: digest_algorithm_t = 2;
+const DIGEST_SHA3_256: digest_algorithm_t = 3;
+const DIGEST_SHA3_512: digest_algorithm_t = 4;
+
+/// The total number of digest algorithms we currently support.
+///
+/// We can't access these from Rust, because their definitions in C require
+/// introspecting the `digest_algorithm_t` typedef, which is an enum, so we have
+/// to redefine them here.
+const N_DIGEST_ALGORITHMS: usize = DIGEST_SHA3_512 as usize + 1;
+
+/// The number of hash digests we produce for a `common_digests_t`.
+///
+/// We can't access these from Rust, because their definitions in C require
+/// introspecting the `digest_algorithm_t` typedef, which is an enum, so we have
+/// to redefine them here.
+const N_COMMON_DIGEST_ALGORITHMS: usize = DIGEST_SHA256 as usize + 1;
+
+/// A digest function.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(non_camel_case_types)]
+struct crypto_digest_t {
+ // This private, zero-length field forces the struct to be treated the same
+ // as its opaque C couterpart.
+ _unused: [u8; 0],
+}
+
+/// An eXtendible Output Function (XOF).
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(non_camel_case_types)]
+struct crypto_xof_t {
+ // This private, zero-length field forces the struct to be treated the same
+ // as its opaque C couterpart.
+ _unused: [u8; 0],
+}
+
+/// A set of all the digests we commonly compute, taken on a single
+/// string. Any digests that are shorter than 512 bits are right-padded
+/// with 0 bits.
+///
+/// Note that this representation wastes 44 bytes for the SHA1 case, so
+/// don't use it for anything where we need to allocate a whole bunch at
+/// once.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(non_camel_case_types)]
+struct common_digests_t {
+ pub d: [[c_char; N_COMMON_DIGEST_ALGORITHMS]; DIGEST256_LEN],
+}
+
+/// A `smartlist_t` is just an alias for the `#[repr(C)]` type `Stringlist`, to
+/// make it more clear that we're working with a smartlist which is owned by C.
+#[allow(non_camel_case_types)]
+type smartlist_t = Stringlist;
+
+/// All of the external functions from `src/common/crypto_digest.h`.
+///
+/// These are kept private because they should be wrapped with Rust to make their usage safer.
+//
+// BINDGEN_GENERATED: These definitions were generated with bindgen and cleaned
+// up manually. As such, there are more bindings than are likely necessary or
+// which are in use.
+#[allow(dead_code)]
+extern "C" {
+ fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int;
+ fn crypto_digest256(digest: *mut c_char, m: *const c_char, len: size_t,
+ algorithm: digest_algorithm_t) -> c_int;
+ fn crypto_digest512(digest: *mut c_char, m: *const c_char, len: size_t,
+ algorithm: digest_algorithm_t) -> c_int;
+ fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t) -> c_int;
+ fn crypto_digest_smartlist_prefix(digest_out: *mut c_char, len_out: size_t, prepend: *const c_char,
+ lst: *const smartlist_t, append: *const c_char, alg: digest_algorithm_t);
+ fn crypto_digest_smartlist(digest_out: *mut c_char, len_out: size_t,
+ lst: *const smartlist_t, append: *const c_char, alg: digest_algorithm_t);
+ fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char;
+ fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t;
+ fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int;
+ fn crypto_digest_new() -> *mut crypto_digest_t;
+ fn crypto_digest256_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
+ fn crypto_digest512_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
+ fn crypto_digest_free(digest: *mut crypto_digest_t);
+ fn crypto_digest_add_bytes(digest: *mut crypto_digest_t, data: *const c_char, len: size_t);
+ fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t);
+ fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t;
+ fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t);
+ fn crypto_hmac_sha256(hmac_out: *mut c_char, key: *const c_char, key_len: size_t,
+ msg: *const c_char, msg_len: size_t);
+ fn crypto_mac_sha3_256(mac_out: *mut uint8_t, len_out: size_t,
+ key: *const uint8_t, key_len: size_t,
+ msg: *const uint8_t, msg_len: size_t);
+ fn crypto_xof_new() -> *mut crypto_xof_t;
+ fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t);
+ fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t);
+ fn crypto_xof_free(xof: *mut crypto_xof_t);
+}
+
+/// A wrapper around a `digest_algorithm_t`.
+pub enum DigestAlgorithm {
+ SHA2_256,
+ SHA2_512,
+ SHA3_256,
+ SHA3_512,
+}
+
+impl From<DigestAlgorithm> for digest_algorithm_t {
+ fn from(digest: DigestAlgorithm) -> digest_algorithm_t {
+ match digest {
+ DigestAlgorithm::SHA2_256 => DIGEST_SHA256,
+ DigestAlgorithm::SHA2_512 => DIGEST_SHA512,
+ DigestAlgorithm::SHA3_256 => DIGEST_SHA3_256,
+ DigestAlgorithm::SHA3_512 => DIGEST_SHA3_512,
+ }
+ }
+}
+
+/// A wrapper around a mutable pointer to a `crypto_digest_t`.
+pub struct CryptoDigest(*mut crypto_digest_t);
+
+/// Explicitly copy the state of a `CryptoDigest` hash digest context.
+///
+/// # C_RUST_COUPLED
+///
+/// * `crypto_digest_dup`
+impl Clone for CryptoDigest {
+ fn clone(&self) -> CryptoDigest {
+ let digest: *mut crypto_digest_t;
+
+ unsafe {
+ digest = crypto_digest_dup(self.0 as *const crypto_digest_t);
+ }
+
+ // See the note in the implementation of CryptoDigest for the
+ // reasoning for `abort()` here.
+ if digest.is_null() {
+ abort();
+ }
+
+ CryptoDigest(digest)
+ }
+}
+
+impl CryptoDigest {
+ /// A wrapper to call one of the C functions `crypto_digest_new`,
+ /// `crypto_digest256_new`, or `crypto_digest512_new`.
+ ///
+ /// # Warnings
+ ///
+ /// This function will `abort()` the entire process in an "abnormal" fashion,
+ /// i.e. not unwinding this or any other thread's stack, running any
+ /// destructors, or calling any panic/exit hooks) if `tor_malloc()` (called in
+ /// `crypto_digest256_new()`) is unable to allocate memory.
+ ///
+ /// # Returns
+ ///
+ /// A new `CryptoDigest`, which is a wrapper around a opaque representation
+ /// of a `crypto_digest_t`. The underlying `crypto_digest_t` _MUST_ only
+ /// ever be handled via a raw pointer, and never introspected.
+ ///
+ /// # C_RUST_COUPLED
+ ///
+ /// * `crypto_digest_new`
+ /// * `crypto_digest256_new`
+ /// * `crypto_digest512_new`
+ /// * `tor_malloc` (called by `crypto_digest256_new`, but we make
+ /// assumptions about its behvaiour and return values here)
+ pub fn new(algorithm: Option<DigestAlgorithm>) -> CryptoDigest {
+ let digest: *mut crypto_digest_t;
+
+ if algorithm.is_none() {
+ unsafe {
+ digest = crypto_digest_new();
+ }
+ } else {
+ let algo: digest_algorithm_t = algorithm.unwrap().into(); // can't fail because it's Some
+
+ unsafe {
+ // XXX This is a pretty awkward API to use from Rust...
+ digest = match algo {
+ DIGEST_SHA1 => crypto_digest_new(),
+ DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256),
+ DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256),
+ DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512),
+ DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512),
+ _ => abort(),
+ }
+ }
+ }
+
+ // In our C code, `crypto_digest*_new()` allocates memory with
+ // `tor_malloc()`. In `tor_malloc()`, if the underlying malloc
+ // implementation fails to allocate the requested memory and returns a
+ // NULL pointer, we call `exit(1)`. In the case that this `exit(1)` is
+ // called within a worker, be that a process or a thread, the inline
+ // comments within `tor_malloc()` mention "that's ok, since the parent
+ // will run out of memory soon anyway". However, if it takes long
+ // enough for the worker to die, and it manages to return a NULL pointer
+ // to our Rust code, our Rust is now in an irreparably broken state and
+ // may exhibit undefined behaviour. An even worse scenario, if/when we
+ // have parent/child processes/threads controlled by Rust, would be that
+ // the UB contagion in Rust manages to spread to other children before
+ // the entire process (hopefully terminates).
+ //
+ // However, following the assumptions made in `tor_malloc()` that
+ // calling `exit(1)` in a child is okay because the parent will
+ // eventually run into the same errors, and also to stymie any UB
+ // contagion in the meantime, we call abort!() here to terminate the
+ // entire program immediately.
+ if digest.is_null() {
+ abort();
+ }
+
+ CryptoDigest(digest)
+ }
+
+ /// A wrapper to call the C function `crypto_digest_add_bytes`.
+ ///
+ /// # Inputs
+ ///
+ /// * `bytes`: a byte slice of bytes to be added into this digest.
+ ///
+ /// # C_RUST_COUPLED
+ ///
+ /// * `crypto_digest_add_bytes`
+ pub fn add_bytes(&self, bytes: &[u8]) {
+ unsafe {
+ crypto_digest_add_bytes(self.0 as *mut crypto_digest_t,
+ bytes.as_ptr() as *const c_char,
+ bytes.len() as size_t)
+ }
+ }
+}
+
+/// Get the 256-bit digest output of a `crypto_digest_t`.
+///
+/// # Inputs
+///
+/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA256` or a
+/// `DIGEST_SHA3_256`.
+///
+/// # Warning
+///
+/// Calling this function with a `CryptoDigest` which is neither SHA2-256 or
+/// SHA3-256 is a programming error. Since we cannot introspect the opaque
+/// struct from Rust, however, there is no way for us to check that the correct
+/// one is being passed in. That is up to you, dear programmer. If you mess
+/// up, you will get a incorrectly-sized hash digest in return, and it will be
+/// your fault. Don't do that.
+///
+/// # Returns
+///
+/// A 256-bit hash digest, as a `[u8; 32]`.
+///
+/// # C_RUST_COUPLED
+///
+/// * `crypto_digest_get_digest`
+/// * `DIGEST256_LEN`
+//
+// FIXME: Once const generics land in Rust, we should genericise calling
+// crypto_digest_get_digest w.r.t. output array size.
+pub fn get_256_bit_digest(digest: CryptoDigest) -> [u8; DIGEST256_LEN] {
+ let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
+
+ unsafe {
+ crypto_digest_get_digest(digest.0,
+ buffer.as_mut_ptr() as *mut c_char,
+ DIGEST256_LEN as size_t);
+
+ if buffer.as_ptr().is_null() {
+ abort();
+ }
+ }
+ buffer
+}
+
+/// Get the 512-bit digest output of a `crypto_digest_t`.
+///
+/// # Inputs
+///
+/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA512` or a
+/// `DIGEST_SHA3_512`.
+///
+/// # Warning
+///
+/// Calling this function with a `CryptoDigest` which is neither SHA2-512 or
+/// SHA3-512 is a programming error. Since we cannot introspect the opaque
+/// struct from Rust, however, there is no way for us to check that the correct
+/// one is being passed in. That is up to you, dear programmer. If you mess
+/// up, you will get a incorrectly-sized hash digest in return, and it will be
+/// your fault. Don't do that.
+///
+/// # Returns
+///
+/// A 512-bit hash digest, as a `[u8; 64]`.
+///
+/// # C_RUST_COUPLED
+///
+/// * `crypto_digest_get_digest`
+/// * `DIGEST512_LEN`
+//
+// FIXME: Once const generics land in Rust, we should genericise calling
+// crypto_digest_get_digest w.r.t. output array size.
+pub fn get_512_bit_digest(digest: CryptoDigest) -> [u8; DIGEST512_LEN] {
+ let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
+
+ unsafe {
+ crypto_digest_get_digest(digest.0,
+ buffer.as_mut_ptr() as *mut c_char,
+ DIGEST512_LEN as size_t);
+
+ if buffer.as_ptr().is_null() {
+ abort();
+ }
+ }
+ buffer
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_layout_common_digests_t() {
+ assert_eq!(::std::mem::size_of::<common_digests_t>(), 64usize,
+ concat!("Size of: ", stringify!(common_digests_t)));
+ assert_eq!(::std::mem::align_of::<common_digests_t>(), 1usize,
+ concat!("Alignment of ", stringify!(common_digests_t)));
+ }
+
+ #[test]
+ fn test_layout_crypto_digest_t() {
+ assert_eq!(::std::mem::size_of::<crypto_digest_t>(), 0usize,
+ concat!("Size of: ", stringify!(crypto_digest_t)));
+ assert_eq!(::std::mem::align_of::<crypto_digest_t>(), 1usize,
+ concat!("Alignment of ", stringify!(crypto_digest_t)));
+ }
+}
diff --git a/src/rust/external/crypto_rand.rs b/src/rust/external/crypto_rand.rs
new file mode 100644
index 0000000000..af1ade0161
--- /dev/null
+++ b/src/rust/external/crypto_rand.rs
@@ -0,0 +1,87 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Bindings to external (P)RNG interfaces and utilities in
+//! src/common/crypto_rand.[ch].
+//!
+//! We wrap our C implementations in src/common/crypto_rand.[ch] here in order
+//! to provide wrappers with native Rust types, and then provide more Rusty
+//! types and and trait implementations in src/rust/crypto/rand/.
+
+use std::time::Duration;
+
+use libc::c_double;
+use libc::c_int;
+use libc::size_t;
+use libc::time_t;
+use libc::uint8_t;
+
+extern "C" {
+ fn crypto_seed_rng() -> c_int;
+ fn crypto_rand(out: *mut uint8_t, out_len: size_t);
+ fn crypto_strongest_rand(out: *mut uint8_t, out_len: size_t);
+ fn crypto_rand_time_range(min: time_t, max: time_t) -> time_t;
+ fn crypto_rand_double() -> c_double;
+}
+
+/// Seed OpenSSL's random number generator with bytes from the operating
+/// system.
+///
+/// # Returns
+///
+/// `true` on success; `false` on failure.
+pub fn c_tor_crypto_seed_rng() -> bool {
+ let ret: c_int;
+
+ unsafe {
+ ret = crypto_seed_rng();
+ }
+ match ret {
+ 0 => return true,
+ _ => return false,
+ }
+}
+
+/// Fill the bytes of `dest` with random data.
+pub fn c_tor_crypto_rand(dest: &mut [u8]) {
+ unsafe {
+ crypto_rand(dest.as_mut_ptr(), dest.len() as size_t);
+ }
+}
+
+/// Fill the bytes of `dest` with "strong" random data by hashing
+/// together randomness obtained from OpenSSL's RNG and the operating
+/// system.
+pub fn c_tor_crypto_strongest_rand(dest: &mut [u8]) {
+ // We'll let the C side panic if the len is larger than
+ // MAX_STRONGEST_RAND_SIZE, rather than potentially panicking here. A
+ // paranoid caller should assert on the length of dest *before* calling this
+ // function.
+ unsafe {
+ crypto_strongest_rand(dest.as_mut_ptr(), dest.len() as size_t);
+ }
+}
+
+/// Get a random time, in seconds since the Unix Epoch.
+///
+/// # Returns
+///
+/// A `std::time::Duration` of seconds since the Unix Epoch.
+pub fn c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration {
+ let ret: time_t;
+
+ unsafe {
+ ret = crypto_rand_time_range(min.as_secs() as time_t, max.as_secs() as time_t);
+ }
+
+ Duration::from_secs(ret as u64)
+}
+
+/// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0).
+pub fn c_tor_crypto_rand_double() -> f64 {
+ unsafe {
+ crypto_rand_double()
+ }
+}
+
diff --git a/src/rust/external/lib.rs b/src/rust/external/lib.rs
index 0af0d6452d..ffd38ac5da 100644
--- a/src/rust/external/lib.rs
+++ b/src/rust/external/lib.rs
@@ -1,4 +1,4 @@
-//! Copyright (c) 2016-2017, The Tor Project, Inc. */
+//! Copyright (c) 2016-2018, The Tor Project, Inc. */
//! See LICENSE for licensing information */
//! Interface for external calls to tor C ABI
@@ -9,6 +9,10 @@
extern crate libc;
+extern crate smartlist;
+
+pub mod crypto_digest;
+mod crypto_rand;
mod external;
pub use external::*;
diff --git a/src/rust/include.am b/src/rust/include.am
index f1aa0bd5ac..ba652bda0c 100644
--- a/src/rust/include.am
+++ b/src/rust/include.am
@@ -4,7 +4,13 @@ EXTRA_DIST +=\
src/rust/Cargo.toml \
src/rust/Cargo.lock \
src/rust/.cargo/config.in \
+ src/rust/crypto/Cargo.toml \
+ src/rust/crypto/lib.rs \
+ src/rust/crypto/digests/mod.rs \
+ src/rust/crypto/digests/sha2.rs \
src/rust/external/Cargo.toml \
+ src/rust/external/crypto_digest.rs \
+ src/rust/external/crypto_rand.rs \
src/rust/external/external.rs \
src/rust/external/lib.rs \
src/rust/protover/Cargo.toml \
@@ -14,6 +20,9 @@ EXTRA_DIST +=\
src/rust/protover/lib.rs \
src/rust/protover/protover.rs \
src/rust/protover/tests/protover.rs \
+ src/rust/rand/Cargo.toml \
+ src/rust/rand/lib.rs \
+ src/rust/rand/rng.rs \
src/rust/smartlist/Cargo.toml \
src/rust/smartlist/lib.rs \
src/rust/smartlist/smartlist.rs \
diff --git a/src/rust/rand/Cargo.toml b/src/rust/rand/Cargo.toml
new file mode 100644
index 0000000000..b5bbf5c1b6
--- /dev/null
+++ b/src/rust/rand/Cargo.toml
@@ -0,0 +1,27 @@
+# TODO: Note that this package should be merged into the "crypto" crate after #24659 is merged.
+
+[package]
+authors = ["The Tor Project"]
+version = "0.0.1"
+name = "rand"
+publish = false
+
+[features]
+testing = ["tor_log/testing"]
+
+[dependencies]
+libc = "=0.2.39"
+rand_core = "=0.1.0"
+
+external = { path = "../external" }
+tor_allocate = { path = "../tor_allocate" }
+tor_log = { path = "../tor_log" }
+tor_util = { path = "../tor_util" }
+
+[dev-dependencies]
+rand = { version = "=0.5.0-pre.1", default-features = false }
+
+[lib]
+name = "rand"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
diff --git a/src/rust/rand/lib.rs b/src/rust/rand/lib.rs
new file mode 100644
index 0000000000..6b3058ad58
--- /dev/null
+++ b/src/rust/rand/lib.rs
@@ -0,0 +1,16 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+// External dependencies
+#[cfg(test)]
+extern crate rand;
+extern crate rand_core;
+
+// Internal dependencies
+extern crate external;
+#[cfg(not(test))]
+#[macro_use]
+extern crate tor_log;
+
+pub mod rng;
diff --git a/src/rust/rand/rng.rs b/src/rust/rand/rng.rs
new file mode 100644
index 0000000000..cfd96c9617
--- /dev/null
+++ b/src/rust/rand/rng.rs
@@ -0,0 +1,140 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Wrappers for Tor's random number generators to provide implementations of
+//! `rand_core` traits.
+
+// This is the real implementation, in use in production, which calls into our C
+// wrappers in /src/common/crypto_rand.c, which call into OpenSSL, system
+// libraries, and make syscalls.
+#[cfg(not(test))]
+mod internal {
+ use std::u64;
+
+ use rand_core::CryptoRng;
+ use rand_core::Error;
+ use rand_core::RngCore;
+ use rand_core::impls::next_u32_via_fill;
+ use rand_core::impls::next_u64_via_fill;
+
+ use external::c_tor_crypto_rand;
+ use external::c_tor_crypto_strongest_rand;
+ use external::c_tor_crypto_seed_rng;
+
+ use tor_log::LogDomain;
+ use tor_log::LogSeverity;
+
+ /// Largest strong entropy request permitted.
+ //
+ // C_RUST_COUPLED: `MAX_STRONGEST_RAND_SIZE` /src/common/crypto_rand.c
+ const MAX_STRONGEST_RAND_SIZE: usize = 256;
+
+ /// A wrapper around OpenSSL's RNG.
+ pub struct TorRng {
+ // This private, zero-length field forces the struct to be treated the
+ // same as its opaque C couterpart.
+ _unused: [u8; 0],
+ }
+
+ /// Mark `TorRng` as being suitable for cryptographic purposes.
+ impl CryptoRng for TorRng {}
+
+ impl TorRng {
+ // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c
+ #[allow(dead_code)]
+ fn new() -> Self {
+ if !c_tor_crypto_seed_rng() {
+ tor_log_msg!(LogSeverity::Warn, LogDomain::General,
+ "TorRng::from_seed()",
+ "The RNG could not be seeded!");
+ }
+ // XXX also log success at info level —isis
+ TorRng{ _unused: [0u8; 0] }
+ }
+ }
+
+ impl RngCore for TorRng {
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u32(&mut self) -> u32 {
+ next_u32_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ c_tor_crypto_rand(dest);
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+ }
+
+ /// A CSPRNG which hashes together randomness from OpenSSL's RNG and entropy
+ /// obtained from the operating system.
+ pub struct TorStrongestRng {
+ // This private, zero-length field forces the struct to be treated the
+ // same as its opaque C couterpart.
+ _unused: [u8; 0],
+ }
+
+ /// Mark `TorRng` as being suitable for cryptographic purposes.
+ impl CryptoRng for TorStrongestRng {}
+
+ impl TorStrongestRng {
+ // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c
+ #[allow(dead_code)]
+ fn new() -> Self {
+ if !c_tor_crypto_seed_rng() {
+ tor_log_msg!(LogSeverity::Warn, LogDomain::General,
+ "TorStrongestRng::from_seed()",
+ "The RNG could not be seeded!");
+ }
+ // XXX also log success at info level —isis
+ TorStrongestRng{ _unused: [0u8; 0] }
+ }
+ }
+
+ impl RngCore for TorStrongestRng {
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u32(&mut self) -> u32 {
+ next_u32_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ debug_assert!(dest.len() <= MAX_STRONGEST_RAND_SIZE);
+
+ c_tor_crypto_strongest_rand(dest);
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+ }
+}
+
+// For testing, we expose a pure-Rust implementation.
+#[cfg(test)]
+mod internal {
+ // It doesn't matter if we pretend ChaCha is a CSPRNG in tests.
+ pub use rand::ChaChaRng as TorRng;
+ pub use rand::ChaChaRng as TorStrongestRng;
+}
+
+// Finally, expose the public functionality of whichever appropriate internal
+// module.
+pub use self::internal::*;
+
diff --git a/src/test/bench.c b/src/test/bench.c
index be04c5209a..9ab23c9921 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -23,6 +23,7 @@
#include "crypto_curve25519.h"
#include "onion_ntor.h"
#include "crypto_ed25519.h"
+#include "crypto_rand.h"
#include "consdiff.h"
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
diff --git a/src/test/include.am b/src/test/include.am
index eb61d74893..9543635c84 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -139,6 +139,7 @@ src_test_test_SOURCES = \
src/test/test_keypin.c \
src/test/test_link_handshake.c \
src/test/test_logging.c \
+ src/test/test_mainloop.c \
src/test/test_microdesc.c \
src/test/test_nodelist.c \
src/test/test_oom.c \
@@ -171,6 +172,7 @@ src_test_test_SOURCES = \
src/test/test_util.c \
src/test/test_util_format.c \
src/test/test_util_process.c \
+ src/test/test_voting_schedule.c \
src/test/test_helpers.c \
src/test/test_dns.c \
src/test/testing_common.c \
diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c
index 095bfecf21..9ac3894b0b 100644
--- a/src/test/rend_test_helpers.c
+++ b/src/test/rend_test_helpers.c
@@ -2,6 +2,7 @@
/* See LICENSE for licensing information */
#include "or.h"
+#include "crypto_rand.h"
#include "test.h"
#include "rendcommon.h"
#include "rend_test_helpers.h"
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index 89d946d506..aaaf2e7f68 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -7,7 +7,7 @@
#include <sys/types.h>
#include <stdlib.h>
-#include "crypto.h"
+#include "crypto_util.h"
#include "compat.h"
#include "util.h"
diff --git a/src/test/test-timers.c b/src/test/test-timers.c
index 5efd99cacf..f20f29578b 100644
--- a/src/test/test-timers.c
+++ b/src/test/test-timers.c
@@ -9,7 +9,7 @@
#include "compat.h"
#include "compat_libevent.h"
-#include "crypto.h"
+#include "crypto_rand.h"
#include "timers.h"
#include "util.h"
diff --git a/src/test/test.c b/src/test/test.c
index 2963f169cf..f0e8b9b728 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -9,6 +9,7 @@
**/
#include "orconfig.h"
+#include "crypto_rand.h"
#include <stdio.h>
#ifdef HAVE_FCNTL_H
@@ -349,6 +350,18 @@ test_onion_queues(void *arg)
tor_free(onionskin);
}
+static crypto_cipher_t *crypto_rand_aes_cipher = NULL;
+
+// Mock replacement for crypto_rand: Generates bytes from a provided AES_CTR
+// cipher in <b>crypto_rand_aes_cipher</b>.
+static void
+crypto_rand_deterministic_aes(char *out, size_t n)
+{
+ tor_assert(crypto_rand_aes_cipher);
+ memset(out, 0, n);
+ crypto_cipher_crypt_inplace(crypto_rand_aes_cipher, out, n);
+}
+
static void
test_circuit_timeout(void *arg)
{
@@ -378,6 +391,11 @@ test_circuit_timeout(void *arg)
state = or_state_new();
+ // Use a deterministic RNG here, or else we'll get nondeterministic
+ // coverage in some of the circuitstats functions.
+ MOCK(crypto_rand, crypto_rand_deterministic_aes);
+ crypto_rand_aes_cipher = crypto_cipher_new("xyzzyplughplover");
+
circuitbuild_running_unit_tests();
#define timeout0 (build_time_t)(30*1000.0)
initial.Xm = 3000;
@@ -512,6 +530,8 @@ test_circuit_timeout(void *arg)
circuit_build_times_free_timeouts(&final);
or_state_free(state);
teardown_periodic_events();
+ UNMOCK(crypto_rand);
+ crypto_cipher_free(crypto_rand_aes_cipher);
}
/** Test encoding and parsing of rendezvous service descriptors. */
@@ -839,6 +859,7 @@ struct testgroup_t testgroups[] = {
{ "dir/", dir_tests },
{ "dir_handle_get/", dir_handle_get_tests },
{ "dir/md/", microdesc_tests },
+ { "dir/voting-schedule/", voting_schedule_tests },
{ "dos/", dos_tests },
{ "entryconn/", entryconn_tests },
{ "entrynodes/", entrynodes_tests },
@@ -859,6 +880,7 @@ struct testgroup_t testgroups[] = {
{ "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
{ "link-handshake/", link_handshake_tests },
+ { "mainloop/", mainloop_tests },
{ "nodelist/", nodelist_tests },
{ "oom/", oom_tests },
{ "oos/", oos_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 15965ccaf4..3095d54e33 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -234,6 +234,7 @@ extern struct testcase_t introduce_tests[];
extern struct testcase_t keypin_tests[];
extern struct testcase_t link_handshake_tests[];
extern struct testcase_t logging_tests[];
+extern struct testcase_t mainloop_tests[];
extern struct testcase_t microdesc_tests[];
extern struct testcase_t nodelist_tests[];
extern struct testcase_t oom_tests[];
@@ -265,6 +266,7 @@ extern struct testcase_t tortls_tests[];
extern struct testcase_t util_tests[];
extern struct testcase_t util_format_tests[];
extern struct testcase_t util_process_tests[];
+extern struct testcase_t voting_schedule_tests[];
extern struct testcase_t dns_tests[];
extern struct testcase_t handle_tests[];
extern struct testcase_t sr_tests[];
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index e1a40b7e60..40db31320f 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -6,8 +6,10 @@
#define ADDRESSMAP_PRIVATE
#include "orconfig.h"
#include "or.h"
+#include "crypto_rand.h"
#include "test.h"
#include "addressmap.h"
+#include "log_test_helpers.h"
/** Mocking replacement: only handles localhost. */
static int
@@ -941,6 +943,158 @@ test_virtaddrmap(void *data)
;
}
+static const char *canned_data = NULL;
+static size_t canned_data_len = 0;
+
+/* Mock replacement for crypto_rand() that returns canned data from
+ * canned_data above. */
+static void
+crypto_canned(char *ptr, size_t n)
+{
+ if (canned_data_len) {
+ size_t to_copy = MIN(n, canned_data_len);
+ memcpy(ptr, canned_data, to_copy);
+ canned_data += to_copy;
+ canned_data_len -= to_copy;
+ n -= to_copy;
+ ptr += to_copy;
+ }
+ if (n) {
+ crypto_rand_unmocked(ptr, n);
+ }
+}
+
+static void
+test_virtaddrmap_persist(void *data)
+{
+ (void)data;
+ const char *a, *b, *c;
+ tor_addr_t addr;
+ char *ones = NULL;
+
+ addressmap_init();
+
+ // Try a hostname.
+ a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
+ tor_strdup("foobar.baz"));
+ tt_assert(a);
+ tt_assert(!strcmpend(a, ".virtual"));
+
+ // mock crypto_rand to repeat the same result twice; make sure we get
+ // different outcomes. (Because even though the odds for receiving the
+ // same 80-bit address twice is only 1/2^40, it could still happen for
+ // some user -- but running our test through 2^40 iterations isn't
+ // reasonable.)
+ canned_data = "1234567890" // the first call returns this.
+ "1234567890" // the second call returns this.
+ "abcdefghij"; // the third call returns this.
+ canned_data_len = 30;
+ MOCK(crypto_rand, crypto_canned);
+
+ a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
+ tor_strdup("quuxit.baz"));
+ b = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
+ tor_strdup("nescio.baz"));
+ tt_assert(a);
+ tt_assert(b);
+ tt_str_op(a, OP_EQ, "gezdgnbvgy3tqojq.virtual");
+ tt_str_op(b, OP_EQ, "mfrggzdfmztwq2lk.virtual");
+
+ // Now try something to get us an ipv4 address
+ UNMOCK(crypto_rand);
+ tt_int_op(0,OP_EQ, parse_virtual_addr_network("192.168.0.0/16",
+ AF_INET, 0, NULL));
+ a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
+ tor_strdup("foobar.baz"));
+ tt_assert(a);
+ tt_assert(!strcmpstart(a, "192.168."));
+ tor_addr_parse(&addr, a);
+ tt_int_op(AF_INET, OP_EQ, tor_addr_family(&addr));
+
+ b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
+ tor_strdup("quuxit.baz"));
+ tt_str_op(b, OP_NE, a);
+ tt_assert(!strcmpstart(b, "192.168."));
+
+ // Try some canned entropy and verify all the we discard duplicates,
+ // addresses that end with 0, and addresses that end with 255.
+ MOCK(crypto_rand, crypto_canned);
+ canned_data = "\x01\x02\x03\x04" // okay
+ "\x01\x02\x03\x04" // duplicate
+ "\x03\x04\x00\x00" // bad ending 1
+ "\x05\x05\x00\xff" // bad ending 2
+ "\x05\x06\x07\xf0"; // okay
+ canned_data_len = 20;
+ a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
+ tor_strdup("wumble.onion"));
+ b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
+ tor_strdup("wumpus.onion"));
+ tt_str_op(a, OP_EQ, "192.168.3.4");
+ tt_str_op(b, OP_EQ, "192.168.7.240");
+
+ // Now try IPv6!
+ UNMOCK(crypto_rand);
+ tt_int_op(0,OP_EQ, parse_virtual_addr_network("1010:F000::/20",
+ AF_INET6, 0, NULL));
+ a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
+ tor_strdup("foobar.baz"));
+ tt_assert(a);
+ tt_assert(!strcmpstart(a, "[1010:f"));
+ tor_addr_parse(&addr, a);
+ tt_int_op(AF_INET6, OP_EQ, tor_addr_family(&addr));
+
+ b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
+ tor_strdup("quuxit.baz"));
+ tt_str_op(b, OP_NE, a);
+ tt_assert(!strcmpstart(b, "[1010:f"));
+
+ // Try IPv6 with canned entropy, to make sure we detect duplicates.
+ MOCK(crypto_rand, crypto_canned);
+ canned_data = "acanthopterygian" // okay
+ "cinematographist" // okay
+ "acanthopterygian" // duplicate
+ "acanthopterygian" // duplicate
+ "acanthopterygian" // duplicate
+ "cinematographist" // duplicate
+ "coadministration"; // okay
+ canned_data_len = 16 * 7;
+ a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
+ tor_strdup("wuffle.baz"));
+ b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
+ tor_strdup("gribble.baz"));
+ c = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
+ tor_strdup("surprisingly-legible.baz"));
+ tt_str_op(a, OP_EQ, "[1010:f16e:7468:6f70:7465:7279:6769:616e]");
+ tt_str_op(b, OP_EQ, "[1010:fe65:6d61:746f:6772:6170:6869:7374]");
+ tt_str_op(c, OP_EQ, "[1010:f164:6d69:6e69:7374:7261:7469:6f6e]");
+
+ // Try address exhaustion: make sure we can actually fail if we
+ // get too many already-existing addresses.
+ canned_data_len = 128*1024;
+ canned_data = ones = tor_malloc(canned_data_len);
+ memset(ones, 1, canned_data_len);
+ // There is some chance this one will fail if a previous random
+ // allocation gave out the address already.
+ a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
+ tor_strdup("might-work.onion"));
+ if (a) {
+ tt_str_op(a, OP_EQ, "192.168.1.1");
+ }
+ setup_capture_of_logs(LOG_WARN);
+ // This one will definitely fail, since we've set up the RNG to hand
+ // out "1" forever.
+ b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
+ tor_strdup("wont-work.onion"));
+ tt_assert(b == NULL);
+ expect_single_log_msg_containing("Ran out of virtual addresses!");
+
+ done:
+ UNMOCK(crypto_rand);
+ tor_free(ones);
+ addressmap_free_all();
+ teardown_capture_of_logs();
+}
+
static void
test_addr_localname(void *arg)
{
@@ -1095,6 +1249,7 @@ struct testcase_t addr_tests[] = {
ADDR_LEGACY(ip6_helpers),
ADDR_LEGACY(parse),
{ "virtaddr", test_virtaddrmap, 0, NULL, NULL },
+ { "virtaddr_persist", test_virtaddrmap_persist, TT_FORK, NULL, NULL },
{ "localname", test_addr_localname, 0, NULL, NULL },
{ "dup_ip", test_addr_dup_ip, 0, NULL, NULL },
{ "sockaddr_to_str", test_addr_sockaddr_to_str, 0, NULL, NULL },
diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c
index df022f539a..f7441a6491 100644
--- a/src/test/test_address_set.c
+++ b/src/test/test_address_set.c
@@ -2,6 +2,7 @@
/* See LICENSE for licensing information */
#include "or.h"
+#include "crypto_rand.h"
#include "address_set.h"
#include "microdesc.h"
#include "networkstatus.h"
diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
index 057d9fa2dc..868f6a8ba4 100644
--- a/src/test/test_buffers.c
+++ b/src/test/test_buffers.c
@@ -8,6 +8,7 @@
#include "or.h"
#include "buffers.h"
#include "buffers_tls.h"
+#include "crypto_rand.h"
#include "proto_http.h"
#include "proto_socks.h"
#include "test.h"
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 88cdef383f..54d9716780 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -12,6 +12,7 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "config.h"
+#include "crypto_rand.h"
#include "onion.h"
#include "onion_tap.h"
#include "onion_fast.h"
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index b20063c85e..76124a6e75 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -12,6 +12,7 @@
#include "circuitmux_ewma.h"
/* For var_cell_free */
#include "connection_or.h"
+#include "crypto_rand.h"
/* For packed_cell stuff */
#define RELAY_PRIVATE
#include "relay.h"
diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c
index a9a4b6a98e..3b91baca39 100644
--- a/src/test/test_consdiffmgr.c
+++ b/src/test/test_consdiffmgr.c
@@ -9,6 +9,7 @@
#include "consdiff.h"
#include "consdiffmgr.h"
#include "cpuworker.h"
+#include "crypto_rand.h"
#include "networkstatus.h"
#include "routerparse.h"
#include "workqueue.h"
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index c4dba73750..3fc3523af4 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -5,6 +5,7 @@
#include "orconfig.h"
#include "or.h"
+#include "crypto_rand.h"
#include "fp_pair.h"
#include "test.h"
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index c8443fd3bb..24eef156b0 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -5,7 +5,7 @@
#include "orconfig.h"
#define CRYPTO_CURVE25519_PRIVATE
-#define CRYPTO_PRIVATE
+#define CRYPTO_RAND_PRIVATE
#include "or.h"
#include "test.h"
#include "aes.h"
@@ -13,6 +13,7 @@
#include "siphash.h"
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
+#include "crypto_rand.h"
#include "ed25519_vectors.inc"
/** Run unit tests for Diffie-Hellman functionality. */
diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c
index 090cb4242b..a016277508 100644
--- a/src/test/test_crypto_openssl.c
+++ b/src/test/test_crypto_openssl.c
@@ -5,9 +5,9 @@
#include "orconfig.h"
-#define CRYPTO_PRIVATE
+#define CRYPTO_RAND_PRIVATE
-#include "crypto.h"
+#include "crypto_rand.h"
#include "util.h"
#include "util_format.h"
#include "compat.h"
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
index 2afb71ff5a..0e1f5bd227 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -9,6 +9,7 @@
#include "test.h"
#include "crypto_s2k.h"
#include "crypto_pwbox.h"
+#include "crypto_rand.h"
#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT)
#define HAVE_LIBSCRYPT
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 4927530296..0106e40d97 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -23,6 +23,7 @@
#include "config.h"
#include "control.h"
#include "crypto_ed25519.h"
+#include "crypto_rand.h"
#include "directory.h"
#include "dirserv.h"
#include "dirauth/dirvote.h"
@@ -1500,6 +1501,13 @@ test_dir_measured_bw_kb(void *arg)
"bw=1024 junk=007\n",
"misc=junk node_id=$557365204145532d32353620696e73746561642e "
"bw=1024 junk=007\n",
+ /* check whether node_id can be at the end */
+ "bw=1024 node_id=$557365204145532d32353620696e73746561642e\n",
+ /* check whether node_id can be at the end and bw has something in front*/
+ "foo=bar bw=1024 node_id=$557365204145532d32353620696e73746561642e\n",
+ /* check whether node_id can be at the end and something in the
+ * in the middle of bw and node_id */
+ "bw=1024 foo=bar node_id=$557365204145532d32353620696e73746561642e\n",
"end"
};
const char *lines_fail[] = {
@@ -1554,6 +1562,25 @@ test_dir_measured_bw_kb(void *arg)
return;
}
+/* Test dirserv_read_measured_bandwidths */
+static void
+test_dir_dirserv_read_measured_bandwidths(void *arg)
+{
+ char *fname=NULL;
+ (void)arg;
+
+ fname = tor_strdup(get_fname("V3BandwidthsFile"));
+ /* Test an empty file */
+ write_str_to_file(fname, "", 0);
+ setup_capture_of_logs(LOG_WARN);
+ tt_int_op(-1, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL));
+ expect_log_msg("Empty bandwidth file\n");
+
+ done:
+ tor_free(fname);
+ teardown_capture_of_logs();
+}
+
#define MBWC_INIT_TIME 1000
/** Do the measured bandwidth cache unit test */
@@ -5822,6 +5849,7 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(versions),
DIR_LEGACY(fp_pairs),
DIR(split_fps, 0),
+ DIR_LEGACY(dirserv_read_measured_bandwidths),
DIR_LEGACY(measured_bw_kb),
DIR_LEGACY(measured_bw_kb_cache),
DIR_LEGACY(param_voting),
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index 5f92154ea9..230410f7fa 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -5,7 +5,6 @@
#include "orconfig.h"
#define DIRVOTE_PRIVATE
-#include "crypto.h"
#include "test.h"
#include "container.h"
#include "or.h"
diff --git a/src/test/test_dos.c b/src/test/test_dos.c
index cb9d9e559c..8ae967f3ae 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -8,6 +8,7 @@
#include "or.h"
#include "dos.h"
#include "circuitlist.h"
+#include "crypto_rand.h"
#include "geoip.h"
#include "channel.h"
#include "microdesc.h"
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index f55e9f0173..cfcb88a66e 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -4,6 +4,7 @@
#include "orconfig.h"
#define CIRCUITLIST_PRIVATE
+#define CIRCUITBUILD_PRIVATE
#define STATEFILE_PRIVATE
#define ENTRYNODES_PRIVATE
#define ROUTERLIST_PRIVATE
@@ -14,8 +15,10 @@
#include "bridges.h"
#include "circuitlist.h"
+#include "circuitbuild.h"
#include "config.h"
#include "confparse.h"
+#include "crypto_rand.h"
#include "directory.h"
#include "entrynodes.h"
#include "nodelist.h"
@@ -74,6 +77,17 @@ bfn_mock_node_get_by_id(const char *id)
return NULL;
}
+/* Helper function to free a test node. */
+static void
+test_node_free(node_t *n)
+{
+ tor_free(n->rs);
+ tor_free(n->md->onion_curve25519_pkey);
+ short_policy_free(n->md->exit_policy);
+ tor_free(n->md);
+ tor_free(n);
+}
+
/* Unittest cleanup function: Cleanup the fake network. */
static int
big_fake_network_cleanup(const struct testcase_t *testcase, void *ptr)
@@ -83,9 +97,7 @@ big_fake_network_cleanup(const struct testcase_t *testcase, void *ptr)
if (big_fake_net_nodes) {
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
- tor_free(n->rs);
- tor_free(n->md);
- tor_free(n);
+ test_node_free(n);
});
smartlist_free(big_fake_net_nodes);
}
@@ -113,9 +125,18 @@ big_fake_network_setup(const struct testcase_t *testcase)
big_fake_net_nodes = smartlist_new();
for (i = 0; i < N_NODES; ++i) {
+ curve25519_secret_key_t curve25519_secret_key;
+
node_t *n = tor_malloc_zero(sizeof(node_t));
n->md = tor_malloc_zero(sizeof(microdesc_t));
+ /* Generate curve25519 key for this node */
+ n->md->onion_curve25519_pkey =
+ tor_malloc_zero(sizeof(curve25519_public_key_t));
+ curve25519_secret_key_generate(&curve25519_secret_key, 0);
+ curve25519_public_key_generate(n->md->onion_curve25519_pkey,
+ &curve25519_secret_key);
+
crypto_rand(n->identity, sizeof(n->identity));
n->rs = tor_malloc_zero(sizeof(routerstatus_t));
@@ -135,8 +156,8 @@ big_fake_network_setup(const struct testcase_t *testcase)
{
char nickname_binary[8];
crypto_rand(nickname_binary, sizeof(nickname_binary));
- base64_encode(n->rs->nickname, sizeof(n->rs->nickname),
- nickname_binary, sizeof(nickname_binary), 0);
+ base32_encode(n->rs->nickname, sizeof(n->rs->nickname),
+ nickname_binary, sizeof(nickname_binary));
}
/* Call half of the nodes a possible guard. */
@@ -144,6 +165,12 @@ big_fake_network_setup(const struct testcase_t *testcase)
n->is_possible_guard = 1;
n->rs->guardfraction_percentage = 100;
n->rs->has_guardfraction = 1;
+ n->rs->is_possible_guard = 1;
+ }
+
+ /* Make some of these nodes a possible exit */
+ if (i % 7 == 0) {
+ n->md->exit_policy = parse_short_policy("accept 443");
}
smartlist_add(big_fake_net_nodes, n);
@@ -1075,9 +1102,7 @@ test_entry_guard_expand_sample_small_net(void *arg)
/* Fun corner case: not enough guards to make up our whole sample size. */
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
if (n_sl_idx >= 15) {
- tor_free(n->rs);
- tor_free(n->md);
- tor_free(n);
+ test_node_free(n);
SMARTLIST_DEL_CURRENT(big_fake_net_nodes, n);
} else {
n->rs->addr = 0; // make the filter reject this.
@@ -1171,9 +1196,7 @@ test_entry_guard_update_from_consensus_status(void *arg)
entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 5);
node_t *n = (node_t*) bfn_mock_node_get_by_id(g->identity);
smartlist_remove(big_fake_net_nodes, n);
- tor_free(n->rs);
- tor_free(n->md);
- tor_free(n);
+ test_node_free(n);
}
update_approx_time(start + 300);
sampled_guards_update_from_consensus(gs);
@@ -2804,6 +2827,161 @@ test_entry_guard_outdated_dirserver_exclusion(void *arg)
}
}
+/** Test helper to extend the <b>oc</b> circuit path <b>n</b> times and then
+ * ensure that the circuit is now complete. */
+static void
+helper_extend_circuit_path_n_times(origin_circuit_t *oc, int n)
+{
+ int retval;
+ int i;
+
+ /* Extend path n times */
+ for (i = 0 ; i < n ; i++) {
+ retval = onion_extend_cpath(oc);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_int_op(circuit_get_cpath_len(oc), OP_EQ, i+1);
+ }
+
+ /* Now do it one last time and see that circ is complete */
+ retval = onion_extend_cpath(oc);
+ tt_int_op(retval, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+/** Test for basic Tor path selection. Makes sure we build 3-hop circuits. */
+static void
+test_entry_guard_basic_path_selection(void *arg)
+{
+ (void) arg;
+
+ int retval;
+
+ /* Enable entry guards */
+ or_options_t *options = get_options_mutable();
+ options->UseEntryGuards = 1;
+
+ /* disables /16 check since all nodes have the same addr... */
+ options->EnforceDistinctSubnets = 0;
+
+ /* Create our circuit */
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
+ oc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+
+ /* First pick the exit and pin it on the build_state */
+ retval = onion_pick_cpath_exit(oc, NULL, 0);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Extend path 3 times. First we pick guard, then middle, then exit. */
+ helper_extend_circuit_path_n_times(oc, 3);
+
+ done:
+ circuit_free_(circ);
+}
+
+/** Test helper to build an L2 and L3 vanguard list. The vanguard lists
+ * produced should be completely disjoint. */
+static void
+helper_setup_vanguard_list(or_options_t *options)
+{
+ int i = 0;
+
+ /* Add some nodes to the vanguard L2 list */
+ options->HSLayer2Nodes = routerset_new();
+ for (i = 0; i < 10 ; i += 2) {
+ node_t *vanguard_node = smartlist_get(big_fake_net_nodes, i);
+ tt_assert(vanguard_node->is_possible_guard);
+ routerset_parse(options->HSLayer2Nodes, vanguard_node->rs->nickname, "l2");
+ }
+ /* also add some nodes to vanguard L3 list
+ * (L2 list and L3 list should be disjoint for this test to work) */
+ options->HSLayer3Nodes = routerset_new();
+ for (i = 10; i < 20 ; i += 2) {
+ node_t *vanguard_node = smartlist_get(big_fake_net_nodes, i);
+ tt_assert(vanguard_node->is_possible_guard);
+ routerset_parse(options->HSLayer3Nodes, vanguard_node->rs->nickname, "l3");
+ }
+
+ done:
+ ;
+}
+
+/** Test to ensure that vanguard path selection works properly. Ensures that
+ * default vanguard circuits are 4 hops, and that path selection works
+ * correctly given the vanguard settings. */
+static void
+test_entry_guard_vanguard_path_selection(void *arg)
+{
+ (void) arg;
+
+ int retval;
+
+ /* Enable entry guards */
+ or_options_t *options = get_options_mutable();
+ options->UseEntryGuards = 1;
+
+ /* XXX disables /16 check */
+ options->EnforceDistinctSubnets = 0;
+
+ /* Setup our vanguard list */
+ helper_setup_vanguard_list(options);
+
+ /* Create our circuit */
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
+ oc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ oc->build_state->is_internal = 1;
+
+ /* Switch circuit purpose to vanguards */
+ circ->purpose = CIRCUIT_PURPOSE_HS_VANGUARDS;
+
+ /* First pick the exit and pin it on the build_state */
+ tt_int_op(oc->build_state->desired_path_len, OP_EQ, 0);
+ retval = onion_pick_cpath_exit(oc, NULL, 0);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Ensure that vanguards make 4-hop circuits by default */
+ tt_int_op(oc->build_state->desired_path_len, OP_EQ, 4);
+
+ /* Extend path as many times as needed to have complete circ. */
+ helper_extend_circuit_path_n_times(oc, oc->build_state->desired_path_len);
+
+ /* Test that the cpath linked list is set correctly. */
+ crypt_path_t *l1_node = oc->cpath;
+ crypt_path_t *l2_node = l1_node->next;
+ crypt_path_t *l3_node = l2_node->next;
+ crypt_path_t *l4_node = l3_node->next;
+ crypt_path_t *l1_node_again = l4_node->next;
+ tt_ptr_op(l1_node, OP_EQ, l1_node_again);
+
+ /* Test that L2 is indeed HSLayer2Node */
+ retval = routerset_contains_extendinfo(options->HSLayer2Nodes,
+ l2_node->extend_info);
+ tt_int_op(retval, OP_EQ, 4);
+ /* test that L3 node is _not_ contained in HSLayer2Node */
+ retval = routerset_contains_extendinfo(options->HSLayer2Nodes,
+ l3_node->extend_info);
+ tt_int_op(retval, OP_LT, 4);
+
+ /* Test that L3 is indeed HSLayer3Node */
+ retval = routerset_contains_extendinfo(options->HSLayer3Nodes,
+ l3_node->extend_info);
+ tt_int_op(retval, OP_EQ, 4);
+ /* test that L2 node is _not_ contained in HSLayer3Node */
+ retval = routerset_contains_extendinfo(options->HSLayer3Nodes,
+ l2_node->extend_info);
+ tt_int_op(retval, OP_LT, 4);
+
+ /* TODO: Test that L1 can be the same as exit. To test this we need start
+ enforcing EnforceDistinctSubnets again, which means that we need to give
+ each test node a different address which currently breaks some tests. */
+
+ done:
+ circuit_free_(circ);
+}
+
static const struct testcase_setup_t big_fake_network = {
big_fake_network_setup, big_fake_network_cleanup
};
@@ -2867,6 +3045,8 @@ struct testcase_t entrynodes_tests[] = {
BFN_TEST(select_and_cancel),
BFN_TEST(drop_guards),
BFN_TEST(outdated_dirserver_exclusion),
+ BFN_TEST(basic_path_selection),
+ BFN_TEST(vanguard_path_selection),
UPGRADE_TEST(upgrade_a_circuit, "c1-done c2-done"),
UPGRADE_TEST(upgrade_blocked_by_live_primary_guards, "c1-done c2-done"),
diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c
index cadef257f1..e05342cb8a 100644
--- a/src/test/test_extorport.c
+++ b/src/test/test_extorport.c
@@ -10,6 +10,7 @@
#include "connection_or.h"
#include "config.h"
#include "control.h"
+#include "crypto_rand.h"
#include "ext_orport.h"
#include "main.h"
#include "test.h"
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index 6ada64dcff..1db5e9064f 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -18,6 +18,7 @@
#include "config.h"
#include "confparse.h"
#include "connection.h"
+#include "crypto_rand.h"
#include "main.h"
#include "nodelist.h"
#include "relay.h"
diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c
index 1b3c788a67..5c5236b391 100644
--- a/src/test/test_hs_cell.c
+++ b/src/test/test_hs_cell.c
@@ -14,6 +14,7 @@
#include "log_test_helpers.h"
#include "crypto_ed25519.h"
+#include "crypto_rand.h"
#include "hs_cell.h"
#include "hs_intropoint.h"
#include "hs_service.h"
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 58e12abca0..50dca588ed 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -397,21 +397,25 @@ test_client_pick_intro(void *arg)
} SMARTLIST_FOREACH_END(ip);
/* Try to get a random intro: Should return the chosen one! */
- extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
- tor_assert(ip);
- tt_assert(!tor_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN));
- tt_mem_op(ip->identity_digest, OP_EQ, chosen_intro_ei->identity_digest,
- DIGEST_LEN);
+ /* (We try several times, to make sure this behavior is consistent, and to
+ * cover the different cases of client_get_random_intro().) */
+ for (int i = 0; i < 64; ++i) {
+ extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
+ tor_assert(ip);
+ tt_assert(!tor_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN));
+ tt_mem_op(ip->identity_digest, OP_EQ, chosen_intro_ei->identity_digest,
+ DIGEST_LEN);
+ extend_info_free(ip);
+ }
extend_info_free(chosen_intro_ei);
- extend_info_free(ip);
/* Now also mark the chosen one as failed: See that we can't get any intro
points anymore. */
hs_cache_client_intro_state_note(&service_kp.pubkey,
&chosen_intro_point->auth_key_cert->signed_key,
INTRO_POINT_FAILURE_TIMEOUT);
- ip = client_get_random_intro(&service_kp.pubkey);
+ extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
tor_assert(!ip);
}
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index dcca5713eb..8bcb2c7e46 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -17,6 +17,7 @@
#include "hs_test_helpers.h"
#include "connection_edge.h"
+#include "crypto_rand.h"
#include "hs_common.h"
#include "hs_client.h"
#include "hs_service.h"
@@ -360,11 +361,8 @@ mock_networkstatus_get_live_consensus(time_t now)
static void
test_responsible_hsdirs(void *arg)
{
- time_t now = approx_time();
smartlist_t *responsible_dirs = smartlist_new();
networkstatus_t *ns = NULL;
- int retval;
-
(void) arg;
hs_init();
@@ -386,12 +384,12 @@ test_responsible_hsdirs(void *arg)
helper_add_hsdir_to_networkstatus(ns, 3, "spyro", 0);
}
- ed25519_keypair_t kp;
- retval = ed25519_keypair_generate(&kp, 0);
- tt_int_op(retval, OP_EQ , 0);
+ /* Use a fixed time period and pub key so we always take the same path */
+ ed25519_public_key_t pubkey;
+ uint64_t time_period_num = 17653; // 2 May, 2018, 14:00.
+ memset(&pubkey, 42, sizeof(pubkey));
- uint64_t time_period_num = hs_get_time_period_num(now);
- hs_get_responsible_hsdirs(&kp.pubkey, time_period_num,
+ hs_get_responsible_hsdirs(&pubkey, time_period_num,
0, 0, responsible_dirs);
/* Make sure that we only found 2 responsible HSDirs.
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 388b85f975..988f77f2fa 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -10,6 +10,7 @@
#include "crypto_ed25519.h"
#include "crypto_digest.h"
+#include "crypto_rand.h"
#include "ed25519_cert.h"
#include "or.h"
#include "hs_descriptor.h"
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index fe3236c331..4253c9a388 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -13,7 +13,7 @@
#include "test.h"
#include "log_test_helpers.h"
-#include "crypto.h"
+#include "crypto_rand.h"
#include "or.h"
#include "circuitlist.h"
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index d2198c621b..33b5e96070 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -33,13 +33,12 @@
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
-#include "crypto.h"
+#include "crypto_rand.h"
#include "dirauth/dirvote.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "relay.h"
#include "routerparse.h"
-
#include "hs_common.h"
#include "hs_config.h"
#include "hs_ident.h"
diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c
new file mode 100644
index 0000000000..9da8a039dd
--- /dev/null
+++ b/src/test/test_mainloop.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_mainloop.c
+ * \brief Tests for functions closely related to the Tor main loop
+ */
+
+#include "test.h"
+#include "log_test_helpers.h"
+
+#include "or.h"
+#include "main.h"
+
+static const uint64_t BILLION = 1000000000;
+
+static void
+test_mainloop_update_time_normal(void *arg)
+{
+ (void)arg;
+
+ monotime_enable_test_mocking();
+ /* This is arbitrary */
+ uint64_t mt_now = U64_LITERAL(7493289274986);
+ /* This time is in the past as of when this test was written. */
+ time_t now = 1525272090;
+ monotime_coarse_set_mock_time_nsec(mt_now);
+ reset_uptime();
+ update_current_time(now);
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 0);
+
+ update_current_time(now); // Same time as before is a no-op.
+ tt_int_op(get_uptime(), OP_EQ, 0);
+
+ now += 1;
+ mt_now += BILLION;
+ monotime_coarse_set_mock_time_nsec(mt_now);
+ update_current_time(now);
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 1);
+
+ now += 2; // two-second jump is unremarkable.
+ mt_now += 2*BILLION;
+ update_current_time(now);
+ monotime_coarse_set_mock_time_nsec(mt_now);
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 3);
+
+ now -= 1; // a one-second hop backwards is also unremarkable.
+ update_current_time(now);
+ tt_int_op(approx_time(), OP_EQ, now); // it changes the approx time...
+ tt_int_op(get_uptime(), OP_EQ, 3); // but it doesn't roll back our uptime
+
+ done:
+ monotime_disable_test_mocking();
+}
+
+static void
+test_mainloop_update_time_jumps(void *arg)
+{
+ (void)arg;
+
+ monotime_enable_test_mocking();
+ /* This is arbitrary */
+ uint64_t mt_now = U64_LITERAL(7493289274986);
+ /* This time is in the past as of when this test was written. */
+ time_t now = 220897152;
+ monotime_coarse_set_mock_time_nsec(mt_now);
+ reset_uptime();
+ update_current_time(now);
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 0);
+
+ /* Put some uptime on the clock.. */
+ now += 3;
+ mt_now += 3*BILLION;
+ monotime_coarse_set_mock_time_nsec(mt_now);
+ update_current_time(now);
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 3);
+
+ /* Now try jumping forward and backward, without updating the monotonic
+ * clock. */
+ setup_capture_of_logs(LOG_NOTICE);
+ now += 1800;
+ update_current_time(now);
+ expect_single_log_msg_containing(
+ "Your system clock just jumped 1800 seconds forward");
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
+ mock_clean_saved_logs();
+
+ now -= 600;
+ update_current_time(now);
+ expect_single_log_msg_containing(
+ "Your system clock just jumped 600 seconds backward");
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
+ mock_clean_saved_logs();
+
+ /* uptime tracking should go normally now if the clock moves sensibly. */
+ now += 2;
+ mt_now += 2*BILLION;
+ update_current_time(now);
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 5);
+
+ /* If we skip forward by a few minutes but the monotonic clock agrees,
+ * we've just been idle: that counts as not worth warning about. */
+ now += 1800;
+ mt_now += 1800*BILLION;
+ monotime_coarse_set_mock_time_nsec(mt_now);
+ update_current_time(now);
+ expect_no_log_entry();
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 5); // this doesn't count to uptime, though.
+
+ /* If we skip forward by a long time, even if the clock agrees, it's
+ * idnless that counts. */
+ now += 4000;
+ mt_now += 4000*BILLION;
+ monotime_coarse_set_mock_time_nsec(mt_now);
+ update_current_time(now);
+ expect_single_log_msg_containing("Tor has been idle for 4000 seconds");
+ tt_int_op(approx_time(), OP_EQ, now);
+ tt_int_op(get_uptime(), OP_EQ, 5);
+
+ done:
+ teardown_capture_of_logs();
+ monotime_disable_test_mocking();
+}
+
+#define MAINLOOP_TEST(name) \
+ { #name, test_mainloop_## name , TT_FORK, NULL, NULL }
+
+struct testcase_t mainloop_tests[] = {
+ MAINLOOP_TEST(update_time_normal),
+ MAINLOOP_TEST(update_time_jumps),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index a873003d72..9499fd0380 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -7,6 +7,7 @@
**/
#include "or.h"
+#include "crypto_rand.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "torcert.h"
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
index c172fe60c7..abf8896452 100644
--- a/src/test/test_oom.c
+++ b/src/test/test_oom.c
@@ -13,6 +13,7 @@
#include "compat_libevent.h"
#include "connection.h"
#include "config.h"
+#include "crypto_rand.h"
#include "relay.h"
#include "test.h"
#include "test_helpers.h"
diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c
index eba9897184..60bd479719 100644
--- a/src/test/test_relaycrypt.c
+++ b/src/test/test_relaycrypt.c
@@ -7,6 +7,7 @@
#include "circuitbuild.h"
#define CIRCUITLIST_PRIVATE
#include "circuitlist.h"
+#include "crypto_rand.h"
#include "relay.h"
#include "relay_crypto.h"
#include "test.h"
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index 71b487f35b..7fed656282 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -18,6 +18,7 @@
#include "connection.h"
#include "container.h"
#include "control.h"
+#include "crypto_rand.h"
#include "directory.h"
#include "dirauth/dirvote.h"
#include "entrynodes.h"
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 775a1c1d23..f6ab0dfabd 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -9,16 +9,17 @@
#include "or.h"
#include "test.h"
#include "config.h"
+#include "crypto_rand.h"
#include "dirauth/dirvote.h"
#include "dirauth/shared_random.h"
#include "dirauth/shared_random_state.h"
+#include "log_test_helpers.h"
+#include "networkstatus.h"
+#include "router.h"
#include "routerkeys.h"
#include "routerlist.h"
-#include "router.h"
#include "routerparse.h"
#include "shared_random_client.h"
-#include "networkstatus.h"
-#include "log_test_helpers.h"
#include "voting_schedule.h"
static authority_cert_t *mock_cert;
diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c
index a27074c21f..26606f9b6e 100644
--- a/src/test/test_storagedir.c
+++ b/src/test/test_storagedir.c
@@ -2,6 +2,7 @@
/* See LICENSE for licensing information */
#include "or.h"
+#include "crypto_rand.h"
#include "storagedir.h"
#include "test.h"
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index ef1be139a6..388f6df325 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -205,7 +205,7 @@ test_tortls_tor_tls_get_error(void *data)
static void
library_init(void)
{
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+#ifdef OPENSSL_1_1_API
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#else
SSL_library_init();
@@ -522,7 +522,7 @@ test_tortls_x509_cert_free(void *ignored)
tor_x509_cert_free(cert);
cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
- cert->cert = tor_malloc_zero(sizeof(X509));
+ cert->cert = X509_new();
cert->encoded = tor_malloc_zero(1);
tor_x509_cert_free(cert);
}
@@ -560,6 +560,15 @@ fixed_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
return 1;
}
+/*
+ * Use only for the matching fake_x509_free() call
+ */
+static X509 *
+fake_x509_malloc(void)
+{
+ return tor_malloc_zero(sizeof(X509));
+}
+
static void
fake_x509_free(X509 *cert)
{
@@ -590,9 +599,9 @@ test_tortls_cert_matches_key(void *ignored)
tls = tor_malloc_zero(sizeof(tor_tls_t));
cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
- one = tor_malloc_zero(sizeof(X509));
+ one = fake_x509_malloc();
one->references = 1;
- two = tor_malloc_zero(sizeof(X509));
+ two = fake_x509_malloc();
two->references = 1;
res = tor_tls_cert_matches_key(tls, cert);
@@ -648,7 +657,7 @@ test_tortls_cert_get_key(void *ignored)
crypto_pk_t *res = NULL;
cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
X509 *key = NULL;
- key = tor_malloc_zero(sizeof(X509));
+ key = fake_x509_malloc();
key->references = 1;
res = tor_tls_cert_get_key(cert);
@@ -847,8 +856,10 @@ test_tortls_classify_client_ciphers(void *ignored)
sk_SSL_CIPHER_zero(ciphers);
one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
+ tt_assert(one);
one->id = 0x00ff;
two = get_cipher_by_name("ECDHE-RSA-AES128-GCM-SHA256");
+ tt_assert(two);
two->id = 0x0000;
sk_SSL_CIPHER_push(ciphers, one);
tls->client_cipher_list_type = 0;
@@ -918,6 +929,7 @@ test_tortls_client_is_using_v2_ciphers(void *ignored)
ciphers = sk_SSL_CIPHER_new_null();
SSL_CIPHER *one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
+ tt_assert(one);
one->id = 0x00ff;
sk_SSL_CIPHER_push(ciphers, one);
sess->ciphers = ciphers;
@@ -2472,8 +2484,8 @@ test_tortls_context_new(void *ignored)
fixed_crypto_pk_generate_key_with_bits_result[1] = 0;
fixed_tor_tls_create_certificate_result_index = 0;
fixed_tor_tls_create_certificate_result[0] = NULL;
- fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[1] = X509_new();
+ fixed_tor_tls_create_certificate_result[2] = X509_new();
ret = tor_tls_context_new(NULL, 0, 0, 0);
tt_assert(!ret);
@@ -2483,9 +2495,9 @@ test_tortls_context_new(void *ignored)
fixed_crypto_pk_new_result[2] = NULL;
fixed_crypto_pk_generate_key_with_bits_result_index = 0;
fixed_tor_tls_create_certificate_result_index = 0;
- fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[0] = X509_new();
fixed_tor_tls_create_certificate_result[1] = NULL;
- fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[2] = X509_new();
ret = tor_tls_context_new(NULL, 0, 0, 0);
tt_assert(!ret);
@@ -2495,8 +2507,8 @@ test_tortls_context_new(void *ignored)
fixed_crypto_pk_new_result[2] = NULL;
fixed_crypto_pk_generate_key_with_bits_result_index = 0;
fixed_tor_tls_create_certificate_result_index = 0;
- fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[0] = X509_new();
+ fixed_tor_tls_create_certificate_result[1] = X509_new();
fixed_tor_tls_create_certificate_result[2] = NULL;
ret = tor_tls_context_new(NULL, 0, 0, 0);
tt_assert(!ret);
@@ -2508,9 +2520,9 @@ test_tortls_context_new(void *ignored)
fixed_crypto_pk_new_result[2] = NULL;
fixed_crypto_pk_generate_key_with_bits_result_index = 0;
fixed_tor_tls_create_certificate_result_index = 0;
- fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[0] = X509_new();
+ fixed_tor_tls_create_certificate_result[1] = X509_new();
+ fixed_tor_tls_create_certificate_result[2] = X509_new();
fixed_tor_x509_cert_new_result_index = 0;
fixed_tor_x509_cert_new_result[0] = NULL;
fixed_tor_x509_cert_new_result[1] = NULL;
@@ -2524,9 +2536,9 @@ test_tortls_context_new(void *ignored)
fixed_crypto_pk_new_result[2] = NULL;
fixed_crypto_pk_generate_key_with_bits_result_index = 0;
fixed_tor_tls_create_certificate_result_index = 0;
- fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[0] = X509_new();
+ fixed_tor_tls_create_certificate_result[1] = X509_new();
+ fixed_tor_tls_create_certificate_result[2] = X509_new();
fixed_tor_x509_cert_new_result_index = 0;
fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
fixed_tor_x509_cert_new_result[1] = NULL;
@@ -2540,9 +2552,9 @@ test_tortls_context_new(void *ignored)
fixed_crypto_pk_new_result[2] = NULL;
fixed_crypto_pk_generate_key_with_bits_result_index = 0;
fixed_tor_tls_create_certificate_result_index = 0;
- fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[0] = X509_new();
+ fixed_tor_tls_create_certificate_result[1] = X509_new();
+ fixed_tor_tls_create_certificate_result[2] = X509_new();
fixed_tor_x509_cert_new_result_index = 0;
fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t));
@@ -2556,9 +2568,9 @@ test_tortls_context_new(void *ignored)
fixed_crypto_pk_new_result[2] = NULL;
fixed_crypto_pk_generate_key_with_bits_result_index = 0;
fixed_tor_tls_create_certificate_result_index = 0;
- fixed_tor_tls_create_certificate_result[0] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
- fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+ fixed_tor_tls_create_certificate_result[0] = X509_new();
+ fixed_tor_tls_create_certificate_result[1] = X509_new();
+ fixed_tor_tls_create_certificate_result[2] = X509_new();
fixed_tor_x509_cert_new_result_index = 0;
fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t));
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 9c028fd47d..ec11bfd5f5 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -12,6 +12,7 @@
#include "buffers.h"
#include "config.h"
#include "control.h"
+#include "crypto_rand.h"
#include "test.h"
#include "memarea.h"
#include "util_process.h"
diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c
index 683d5fdac1..10645fe117 100644
--- a/src/test/test_util_format.c
+++ b/src/test/test_util_format.c
@@ -6,6 +6,7 @@
#include "test.h"
+#include "crypto_rand.h"
#define UTIL_FORMAT_PRIVATE
#include "util_format.h"
diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c
new file mode 100644
index 0000000000..df6058b74f
--- /dev/null
+++ b/src/test/test_voting_schedule.c
@@ -0,0 +1,64 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#include "or.h"
+#include "voting_schedule.h"
+
+#include "test.h"
+
+static void
+test_voting_schedule_interval_start(void *arg)
+{
+#define next_interval voting_schedule_get_start_of_next_interval
+ (void)arg;
+ char buf[ISO_TIME_LEN+1];
+
+ // Midnight UTC tonight (as I am writing this test)
+ const time_t midnight = 1525651200;
+ format_iso_time(buf, midnight);
+ tt_str_op(buf, OP_EQ, "2018-05-07 00:00:00");
+
+ /* Some simple tests with a 50-minute voting interval */
+
+ tt_i64_op(next_interval(midnight, 3000, 0), OP_EQ,
+ midnight+3000);
+
+ tt_i64_op(next_interval(midnight+100, 3000, 0), OP_EQ,
+ midnight+3000);
+
+ tt_i64_op(next_interval(midnight+3000, 3000, 0), OP_EQ,
+ midnight+6000);
+
+ tt_i64_op(next_interval(midnight+3001, 3000, 0), OP_EQ,
+ midnight+6000);
+
+ /* Make sure that we roll around properly at midnight */
+ tt_i64_op(next_interval(midnight+83000, 3000, 0), OP_EQ,
+ midnight+84000);
+
+ /* We start fresh at midnight UTC, even if there are leftover seconds. */
+ tt_i64_op(next_interval(midnight+84005, 3000, 0), OP_EQ,
+ midnight+86400);
+
+ /* Now try with offsets. (These are only used for test networks.) */
+ tt_i64_op(next_interval(midnight, 3000, 99), OP_EQ,
+ midnight+99);
+
+ tt_i64_op(next_interval(midnight+100, 3000, 99), OP_EQ,
+ midnight+3099);
+
+ done:
+ ;
+#undef next_interval
+}
+
+#define VS(name,flags) \
+ { #name, test_voting_schedule_##name, (flags), NULL, NULL }
+
+struct testcase_t voting_schedule_tests[] = {
+ VS(interval_start, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c
index 940973cda5..cc7073850c 100644
--- a/src/test/test_workqueue.c
+++ b/src/test/test_workqueue.c
@@ -7,8 +7,8 @@
#include "compat_threads.h"
#include "onion.h"
#include "workqueue.h"
-#include "crypto.h"
#include "crypto_curve25519.h"
+#include "crypto_rand.h"
#include "compat_libevent.h"
#include <stdio.h>
@@ -224,7 +224,8 @@ add_n_work_items(threadpool_t *tp, int n)
workqueue_entry_t **to_cancel;
workqueue_entry_t *ent;
- to_cancel = tor_malloc(sizeof(workqueue_entry_t*) * opt_n_cancel);
+ // We'll choose randomly which entries to cancel.
+ to_cancel = tor_calloc(opt_n_cancel, sizeof(workqueue_entry_t*));
while (n_queued++ < n) {
ent = add_work(tp);
@@ -233,9 +234,14 @@ add_n_work_items(threadpool_t *tp, int n)
tor_libevent_exit_loop_after_delay(tor_libevent_get_base(), NULL);
return -1;
}
- if (n_try_cancel < opt_n_cancel &&
- tor_weak_random_range(&weak_rng, n) < opt_n_cancel) {
+
+ if (n_try_cancel < opt_n_cancel) {
to_cancel[n_try_cancel++] = ent;
+ } else {
+ int p = tor_weak_random_range(&weak_rng, n_queued);
+ if (p < n_try_cancel) {
+ to_cancel[p] = ent;
+ }
}
}
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 312c07471d..4c3fe15960 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -13,6 +13,7 @@
#include "or.h"
#include "control.h"
#include "config.h"
+#include "crypto_rand.h"
#include "rephist.h"
#include "backtrace.h"
#include "test.h"
diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c
index 7a24c0ed14..94d3db328a 100644
--- a/src/test/testing_rsakeys.c
+++ b/src/test/testing_rsakeys.c
@@ -3,6 +3,7 @@
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#include "crypto_rand.h"
#include "orconfig.h"
#include "or.h"
#include "test.h"
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index 639a6fbc23..aafefdad74 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -40,6 +40,8 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "torlog.h"
#include "crypto.h"
#include "crypto_digest.h"
+#include "crypto_rand.h"
+#include "crypto_util.h"
#include "address.h"
#include "util_format.h"
diff --git a/src/trunnel/trunnel-local.h b/src/trunnel/trunnel-local.h
index b7c2ab98ef..8aa6d0ddaa 100644
--- a/src/trunnel/trunnel-local.h
+++ b/src/trunnel/trunnel-local.h
@@ -4,7 +4,7 @@
#include "util.h"
#include "compat.h"
-#include "crypto.h"
+#include "crypto_util.h"
#define trunnel_malloc tor_malloc
#define trunnel_calloc tor_calloc