diff options
167 files changed, 2974 insertions, 848 deletions
diff --git a/.travis.yml b/.travis.yml index 6ea11ce9d8..aab6f6b3d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -160,7 +160,9 @@ script: after_failure: ## `make check` will leave a log file with more details of test failures. - - cat test-suite.log + - if [[ "$DISTCHECK" == "" ]]; then cat test-suite.log; fi + ## `make distcheck` puts it somewhere different. + - if [[ "$DISTCHECK" != "" ]]; then make show-distdir-testlog; fi after_success: ## If this build was one that produced coverage, upload it. diff --git a/Makefile.am b/Makefile.am index 163b650bb0..97a39031a9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -274,3 +274,11 @@ if USE_RUST distclean-local: distclean-rust endif +# This relies on some internal details of how automake implements +# distcheck. We check two directories because automake-1.15 changed +# from $(distdir)/_build to $(distdir)/_build/sub. +show-distdir-testlog: + @if test -d "$(distdir)/_build/sub"; then \ + cat $(distdir)/_build/sub/$(TEST_SUITE_LOG); \ + else \ + cat $(distdir)/_build/$(TEST_SUITE_LOG); fi diff --git a/changes/bug25705 b/changes/bug25705 new file mode 100644 index 0000000000..360d96d4c6 --- /dev/null +++ b/changes/bug25705 @@ -0,0 +1,5 @@ + o Minor bugfixes (circuit path selection): + - Don't count path selection failures as circuit build failures. This + should eliminate cases where Tor blames its guard or the network + for situations like insufficient microdescriptors and/or overly + restrictive torrc settings. Fixes bug 25705; bugfix on 0.3.3.1-alpha. diff --git a/changes/bug25733 b/changes/bug25733 new file mode 100644 index 0000000000..775c1ae00e --- /dev/null +++ b/changes/bug25733 @@ -0,0 +1,4 @@ + o Minor bugfixes (Assert crash): + - Avoid an assert in the circuit build timeout code if we fail to + allow any circuits to actually complete. Fixes bug 25733; + bugfix on 0.2.2.2-alpha. diff --git a/changes/bug25870 b/changes/bug25870 new file mode 100644 index 0000000000..aea5a1e303 --- /dev/null +++ b/changes/bug25870 @@ -0,0 +1,6 @@ + o Minor bugfixes (vanguards): + - Allow the last hop in a vanguard circuit to be the same as our first, + to prevent the adversary from influencing guard node choice by choice + of last hop. Also prevent the creation of A - B - A paths, or A - A + paths, which are forbidden by relays. Fixes bug 25870; bugfix on + 0.3.3.1-alpha. diff --git a/changes/bug26052 b/changes/bug26052 new file mode 100644 index 0000000000..4721933fa5 --- /dev/null +++ b/changes/bug26052 @@ -0,0 +1,6 @@ + o Minor bugfixes (documentation): + - Stop saying in the manual that clients cache ipv4 dns answers + from exit relays. We haven't used them since 0.2.6.3-alpha, and + in ticket 24050 we stopped even caching them as of 0.3.2.6-alpha, + but we forgot to say so in the man page. Fixes bug 26052; bugfix + on 0.3.2.6-alpha. diff --git a/changes/ticket25993 b/changes/ticket25993 new file mode 100644 index 0000000000..8eafcd1812 --- /dev/null +++ b/changes/ticket25993 @@ -0,0 +1,4 @@ + o Minor features (testing): + - We now have improved testing for addressmap_get_virtual_address() + function. This should improve our test coverage, and make our test + coverage more deterministic. Closes ticket 25993. diff --git a/changes/ticket25995 b/changes/ticket25995 new file mode 100644 index 0000000000..855020bd39 --- /dev/null +++ b/changes/ticket25995 @@ -0,0 +1,5 @@ + o Minor bugfixes (tests): + - While running the circuit_timeout test, fix the PRNG to a deterministic + AES stream, so that the test coverage from this test will itself be + deterministic. Fixes bug 25995; bugfix on 0.2.2.2-alpha. + diff --git a/changes/ticket26004 b/changes/ticket26004 new file mode 100644 index 0000000000..6b082f1453 --- /dev/null +++ b/changes/ticket26004 @@ -0,0 +1,5 @@ + o Minor features (directory authority, forward compatibility): + - Make the lines of the measured bandwidth file able to contain their + entries in any order. Previously, the node_id entry needed to come + first. Closes ticket 26004. + diff --git a/changes/ticket26008 b/changes/ticket26008 new file mode 100644 index 0000000000..7550c959e2 --- /dev/null +++ b/changes/ticket26008 @@ -0,0 +1,7 @@ + o Minor bugfixes (test): + - When testing workqueue event-cancellation, make sure that we actually + cancel an event, and that cancel each event with equal probability. + (It was previously possible, though extremely unlikely, for our + event-canceling test not to cancel any events.) Fixes bug 26008; + bugfix on 0.2.6.3-alpha. + diff --git a/changes/ticket26014 b/changes/ticket26014 new file mode 100644 index 0000000000..9d62ddbba9 --- /dev/null +++ b/changes/ticket26014 @@ -0,0 +1,4 @@ + o Minor features (Testing): + - Add a unit test for voting_schedule_get_start_of_next_interval(). + Closes ticket 26014, and helps make unit test coverage more + deterministic. diff --git a/configure.ac b/configure.ac index 387fc6fbeb..3bf436203f 100644 --- a/configure.ac +++ b/configure.ac @@ -306,7 +306,10 @@ fi AM_CONDITIONAL(USEPYTHON, [test "x$PYTHON" != "x"]) dnl List all external rust crates we depend on here. Include the version -rust_crates="libc-0.2.39" +rust_crates=" \ + digest-0.7.2 \ + libc-0.2.39 \ +" AC_SUBST(rust_crates) ifdef([AC_C_FLEXIBLE_ARRAY_MEMBER], [ diff --git a/doc/HACKING/HelpfulTools.md b/doc/HACKING/HelpfulTools.md index f919d08ec1..a0795076e0 100644 --- a/doc/HACKING/HelpfulTools.md +++ b/doc/HACKING/HelpfulTools.md @@ -4,6 +4,22 @@ Useful tools These aren't strictly necessary for hacking on Tor, but they can help track down bugs. +Travis CI +--------- +It's CI. Looks like this: https://travis-ci.org/torproject/tor. + +Runs automatically on Pull Requests sent to torproject/tor. You can set it up +for your fork to build commits outside of PRs too: + +1. sign up for GitHub: https://github.com/join +2. fork https://github.com/torproject/tor: + https://help.github.com/articles/fork-a-repo/ +3. follow https://docs.travis-ci.com/user/getting-started/#To-get-started-with-Travis-CI. + skip steps involving `.travis.yml` (we already have one). + +Builds should show up on the web at travis-ci.com and on IRC at #tor-ci on +OFTC. If they don't, ask #tor-dev (also on OFTC). + Jenkins ------- diff --git a/doc/HACKING/Module.md b/doc/HACKING/Module.md new file mode 100644 index 0000000000..1028a029d9 --- /dev/null +++ b/doc/HACKING/Module.md @@ -0,0 +1,111 @@ +# Modules in Tor # + +This document describes the build system and coding standards when writing a +module in Tor. + +## What is a module? ## + +In the context of the tor code base, a module is a subsystem that we can +selectively enable or disable, at `configure` time. + +Currently, there is only one module: + + - Directory Authority subsystem (dirauth) + +It is located in its own directory in `src/or/dirauth/`. To disable it, one +need to pass `--disable-module-dirauth` at configure time. All modules are +currently enabled by default. + +## Build System ## + +The changes to the build system are pretty straightforward. + +1. Locate in the `configure.ac` file this define: `m4_define(MODULES`. It + contains a list (white-space separated) of the module in tor. Add yours to + the list. + +2. Use the `AC_ARG_ENABLE([module-dirauth]` template for your new module. We + use the "disable module" approach instead of enabling them one by one. So, + by default, tor will build all the modules. + + This will define the `HAVE_MODULE_<name>` statement which can be used in + the C code to conditionally compile things for your module. And the + `BUILD_MODULE_<name>` is also defined for automake files (e.g: include.am). + +3. In the `src/or/include.am` file, locate the `MODULE_DIRAUTH_SOURCES` value. + You need to create your own `_SOURCES` variable for your module and then + conditionally add the it to `LIBTOR_A_SOURCES` if you should build the + module. + + It is then **very** important to add your SOURCES variable to + `src_or_libtor_testing_a_SOURCES` so the tests can build it. + +4. Do the same for header files, locate `ORHEADERS +=` which always add all + headers of all modules so the symbol can be found for the module entry + points. + +Finally, your module will automatically be included in the +`TOR_MODULES_ALL_ENABLED` variable which is used to build the unit tests. They +always build everything in order to tests everything. + +## Coding ## + +As mentioned above, a module must be isolated in its own directory (name of +the module) in `src/or/`. + +There are couples of "rules" you want to follow: + +* Minimize as much as you can the number of entry points into your module. + Less is always better but of course that doesn't work out for every use + case. However, it is a good thing to always keep that in mind. + +* Do **not** use the `HAVE_MODULE_<name>` define outside of the module code + base. Every entry point should have a second definition if the module is + disabled. For instance: + + ``` + #ifdef HAVE_MODULE_DIRAUTH + + int sr_init(int save_to_disk); + + #else /* HAVE_MODULE_DIRAUTH */ + + static inline int + sr_init(int save_to_disk) + { + (void) save_to_disk; + return 0; + } + + #endif /* HAVE_MODULE_DIRAUTH */ + + ``` + + The main reason for this approach is to avoid having conditional code + everywhere in the code base. It should be centralized as much as possible + which helps maintainability but also avoids conditional spaghetti code + making the code much more difficult to follow/understand. + +* It is possible that you end up with code that needs to be used by the rest + of the code base but is still part of your module. As a good example, if you + look at `src/or/shared_random_client.c`: it contains code needed by the hidden + service subsystem but mainly related to the shared random subsystem very + specific to the dirauth module. + + This is fine but try to keep it as lean as possible and never use the same + filename as the one in the module. For example, this is a bad idea and + should never be done: + + - `src/or/shared_random.c` + - `src/or/dirauth/shared_random.c` + +* When you include headers from the module, **always** use the full module + path in your statement. Example: + + `#include "dirauth/dirvote.h"` + + The main reason is that we do **not** add the module include path by default + so it needs to be specified. But also, it helps our human brain understand + which part comes from a module or not. + + Even **in** the module itself, use the full include path like above. diff --git a/doc/include.am b/doc/include.am index 0e8de231e1..7942188eaf 100644 --- a/doc/include.am +++ b/doc/include.am @@ -35,10 +35,15 @@ EXTRA_DIST+= doc/asciidoc-helper.sh \ doc/TUNING \ doc/HACKING/README.1st.md \ doc/HACKING/CodingStandards.md \ + doc/HACKING/CodingStandardsRust.md \ + doc/HACKING/Fuzzing.md \ doc/HACKING/GettingStarted.md \ + doc/HACKING/GettingStartedRust.md \ doc/HACKING/HelpfulTools.md \ doc/HACKING/HowToReview.md \ + doc/HACKING/Module.md \ doc/HACKING/ReleasingTor.md \ + doc/HACKING/Tracing.md \ doc/HACKING/WritingTests.md docdir = @docdir@ diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 9471db9362..f42ad0dd3c 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -543,13 +543,21 @@ GENERAL OPTIONS (Default: 1) [[FetchUselessDescriptors]] **FetchUselessDescriptors** **0**|**1**:: - If set to 1, Tor will fetch every consensus flavor, descriptor, and - certificate that it hears about. Otherwise, it will avoid fetching useless - descriptors: flavors that it is not using to build circuits, and authority - certificates it does not trust. This option is useful if you're using a + If set to 1, Tor will fetch every consensus flavor, and all server + descriptors and authority certificates referenced by those consensuses, + except for extra info descriptors. When this option is 1, Tor will also + keep fetching descriptors, even when idle. + If set to 0, Tor will avoid fetching useless descriptors: flavors that it + is not using to build circuits, and authority certificates it does not + trust. When Tor hasn't built any application circuits, it will go idle, + and stop fetching descriptors. This option is useful if you're using a tor client with an external parser that uses a full consensus. - This option fetches all documents, **DirCache** fetches and serves - all documents. (Default: 0) + This option fetches all documents except extrainfo descriptors, + **DirCache** fetches and serves all documents except extrainfo + descriptors, **DownloadExtraInfo*** fetches extrainfo documents, and serves + them if **DirCache** is on, and **UseMicrodescriptors** changes the + flavour of consensues and descriptors that is fetched and used for + building circuits. (Default: 0) [[HTTPProxy]] **HTTPProxy** __host__[:__port__]:: Tor will make all its directory requests through this host:port (or host:80 @@ -1229,7 +1237,7 @@ The following options are useful only for clients (that is, if flag is not supported. **CacheIPv4DNS**;; Tells the client to remember IPv4 DNS answers we receive from exit - nodes via this connection. (On by default.) + nodes via this connection. **CacheIPv6DNS**;; Tells the client to remember IPv6 DNS answers we receive from exit nodes via this connection. @@ -1584,6 +1592,14 @@ The following options are useful only for clients (that is, if which means that nodes specified in ExcludeNodes will not be picked. + + When either this option or HSLayer3Nodes are set, the /16 subnet + and node family restrictions are removed for hidden service + circuits. Additionally, we allow the guard node to be present + as the Rend, HSDir, and IP node, and as the hop before it. This + is done to prevent the adversary from inferring information + about our guard, layer2, and layer3 node choices at later points + in the path. + + This option is meant to be managed by a Tor controller such as https://github.com/mikeperry-tor/vanguards that selects and updates this set of nodes for you. Hence it does not do load @@ -1629,6 +1645,14 @@ The following options are useful only for clients (that is, if ExcludeNodes have higher priority than HSLayer3Nodes, which means that nodes specified in ExcludeNodes will not be picked. + + + When either this option or HSLayer2Nodes are set, the /16 subnet + and node family restrictions are removed for hidden service + circuits. Additionally, we allow the guard node to be present + as the Rend, HSDir, and IP node, and as the hop before it. This + is done to prevent the adversary from inferring information + about our guard, layer2, and layer3 node choices at later points + in the path. + This option is meant to be managed by a Tor controller such as https://github.com/mikeperry-tor/vanguards that selects and @@ -1642,9 +1666,8 @@ The following options are useful only for clients (that is, if in order to build its circuits. Using microdescriptors makes Tor clients download less directory information, thus saving bandwidth. Directory caches need to fetch regular descriptors and microdescriptors, so this - option doesn't save any bandwidth for them. If this option is set to - "auto" (recommended) then it is on for all clients that do not set - FetchUselessDescriptors. (Default: auto) + option doesn't save any bandwidth for them. For legacy reasons, auto is + accepted, but it has the same effect as 1. (Default: auto) [[PathBiasCircThreshold]] **PathBiasCircThreshold** __NUM__ + @@ -2058,6 +2081,8 @@ is non-zero): [[Nickname]] **Nickname** __name__:: Set the server's nickname to \'name'. 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. Relays can always be uniquely identified + by their identity fingerprints. [[NumCPUs]] **NumCPUs** __num__:: How many processes to use at once for decrypting onionskins and other @@ -2390,10 +2415,12 @@ details.) some entry in the policy is accepted. [[DirCache]] **DirCache** **0**|**1**:: - When this option is set, Tor caches all current directory documents and - accepts client requests for them. Setting DirPort is not required for this, - because clients connect via the ORPort by default. Setting either DirPort - or BridgeRelay and setting DirCache to 0 is not supported. (Default: 1) + When this option is set, Tor caches all current directory documents except + extra info documents, and accepts client requests for them. If + **DownloadExtraInfo** is set, cached extra info documents are also cached. + Setting **DirPort** is not required for **DirCache**, because clients + connect via the ORPort by default. Setting either DirPort or BridgeRelay + and setting DirCache to 0 is not supported. (Default: 1) [[MaxConsensusAgeForDiffs]] **MaxConsensusAgeForDiffs** __N__ **minutes**|**hours**|**days**|**weeks**:: When this option is nonzero, Tor caches will not try to generate 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 efb4fe855c..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) diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c index 707efe3892..fa00fb836b 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" diff --git a/src/common/crypto.c b/src/common/crypto.c index 3943465020..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. */ @@ -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. 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/tortls.c b/src/common/tortls.c index 4044a0e708..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 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..6881e0ebb8 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); @@ -2283,7 +2280,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 +2451,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 +2528,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 +2642,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 +2684,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 +2727,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..ae4aef768a 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -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 a6bfab5b9b..9af613e931 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__) diff --git a/src/or/connection.c b/src/or/connection.c index c2673ade16..4361e1ca0c 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" diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 955f942c50..5ae1538bfe 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" 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 4557d467b9..93b204f9a3 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -52,6 +52,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" 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 66a530b6db..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. 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 e058e04f8b..bfcec6e105 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -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) { 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..98f32adb1c 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" 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 4174470636..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" 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..eb48cb0601 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" 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 cf2760760a..b7296ddcf9 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" 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 8cdf27ed4b..c3505a2d91 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__) diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index ac3e94e884..44c0638c2b 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. */ @@ -1855,17 +1858,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/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/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..43600cd913 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" 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..996a28a91f 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, @@ -1612,14 +1616,6 @@ authdir_mode(const or_options_t *options) { return options->AuthoritativeDir != 0; } -/** Return true iff we believe ourselves to be a v3 authoritative - * directory server. - */ -int -authdir_mode_v3(const or_options_t *options) -{ - return authdir_mode(options) && options->V3AuthoritativeDir != 0; -} /** Return true iff we are an authoritative directory server that is * authoritative about receiving and serving descriptors of type * <b>purpose</b> on its dirport. diff --git a/src/or/router.h b/src/or/router.h index e5efe577e3..03eca9c65d 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -55,7 +55,6 @@ void router_perform_bandwidth_test(int num_circs, time_t now); int net_is_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..43eaf1e239 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -171,6 +171,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..0ad33ec0c0 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 }, diff --git a/src/test/test.h b/src/test/test.h index 15965ccaf4..0cd0304629 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -265,6 +265,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 7d5018ef5b..8e5a5fa470 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..77ba6e3bb4 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[] = { 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_common.c b/src/test/test_hs_common.c index 94d3d52e98..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" 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_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_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 |