aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/address.c18
-rw-r--r--src/common/buffers.h1
-rw-r--r--src/common/compat.c82
-rw-r--r--src/common/compat.h6
-rw-r--r--src/common/compat_libevent.c147
-rw-r--r--src/common/compat_libevent.h22
-rw-r--r--src/common/compat_winthreads.c1
-rw-r--r--src/common/compress.c10
-rw-r--r--src/common/compress.h1
-rw-r--r--src/common/compress_zstd.c112
-rw-r--r--src/common/compress_zstd.h7
-rw-r--r--src/common/container.c2
-rw-r--r--src/common/crypto.c779
-rw-r--r--src/common/crypto.h118
-rw-r--r--src/common/crypto_curve25519.c1
-rw-r--r--src/common/crypto_curve25519.h1
-rw-r--r--src/common/crypto_digest.c569
-rw-r--r--src/common/crypto_digest.h136
-rw-r--r--src/common/crypto_ed25519.c1
-rw-r--r--src/common/crypto_format.c1
-rw-r--r--src/common/crypto_pwbox.c1
-rw-r--r--src/common/crypto_rsa.c260
-rw-r--r--src/common/crypto_rsa.h17
-rw-r--r--src/common/crypto_s2k.c1
-rw-r--r--src/common/include.am2
-rw-r--r--src/common/log.c31
-rw-r--r--src/common/procmon.c27
-rw-r--r--src/common/timers.c18
-rw-r--r--src/common/torlog.h14
-rw-r--r--src/common/tortls.c2
-rw-r--r--src/common/tortls.h2
-rw-r--r--src/common/util.c350
-rw-r--r--src/common/util.h27
-rw-r--r--src/common/workqueue.c47
-rw-r--r--src/common/workqueue.h5
35 files changed, 1428 insertions, 1391 deletions
diff --git a/src/common/address.c b/src/common/address.c
index a2f4c93b91..ca263425f0 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1697,7 +1697,7 @@ get_interface_address6_via_udp_socket_hack,(int severity,
sa_family_t family,
tor_addr_t *addr))
{
- struct sockaddr_storage my_addr, target_addr;
+ struct sockaddr_storage target_addr;
int sock=-1, r=-1;
socklen_t addr_len;
@@ -1740,21 +1740,19 @@ get_interface_address6_via_udp_socket_hack,(int severity,
goto err;
}
- if (tor_getsockname(sock,(struct sockaddr*)&my_addr, &addr_len)) {
+ if (tor_addr_from_getsockname(addr, sock) < 0) {
int e = tor_socket_errno(sock);
log_fn(severity, LD_NET, "getsockname() to determine interface failed: %s",
tor_socket_strerror(e));
goto err;
}
- if (tor_addr_from_sockaddr(addr, (struct sockaddr*)&my_addr, NULL) == 0) {
- if (tor_addr_is_loopback(addr) || tor_addr_is_multicast(addr)) {
- log_fn(severity, LD_NET, "Address that we determined via UDP socket"
- " magic is unsuitable for public comms.");
- } else {
- r=0;
- }
- }
+ if (tor_addr_is_loopback(addr) || tor_addr_is_multicast(addr)) {
+ log_fn(severity, LD_NET, "Address that we determined via UDP socket"
+ " magic is unsuitable for public comms.");
+ } else {
+ r=0;
+ }
err:
if (sock >= 0)
diff --git a/src/common/buffers.h b/src/common/buffers.h
index 22a5f7bfa3..4275152de2 100644
--- a/src/common/buffers.h
+++ b/src/common/buffers.h
@@ -13,7 +13,6 @@
#define TOR_BUFFERS_H
#include "compat.h"
-#include "compat.h"
#include "torint.h"
#include "testsupport.h"
diff --git a/src/common/compat.c b/src/common/compat.c
index 4cb346dfa5..693fca70ea 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -100,7 +100,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
/* Only use the linux prctl; the IRIX prctl is totally different */
#include <sys/prctl.h>
#elif defined(__APPLE__)
-#include <sys/types.h>
#include <sys/ptrace.h>
#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) || ... */
@@ -116,7 +115,7 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
-#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#ifdef HAVE_SYS_SYSLIMITS_H
@@ -204,25 +203,17 @@ tor_rename(const char *path_old, const char *path_new)
sandbox_intern_string(path_new));
}
-/* Some MinGW builds have sys/mman.h, but not the corresponding symbols.
- * Other configs rename the symbols using macros (including getpagesize).
- * So check for sys/mman.h and unistd.h, and a getpagesize declaration. */
-#if (defined(HAVE_SYS_MMAN_H) && defined(HAVE_UNISTD_H) && \
- defined(HAVE_DECL_GETPAGESIZE))
-#define COMPAT_HAS_MMAN_AND_PAGESIZE
-#endif
-
-#if defined(COMPAT_HAS_MMAN_AND_PAGESIZE) || \
- defined(RUNNING_DOXYGEN)
+#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN)
/** Try to create a memory mapping for <b>filename</b> and return it. On
- * failure, return NULL. Sets errno properly, using ERANGE to mean
- * "empty file". */
+ * failure, return NULL. Sets errno properly, using ERANGE to mean
+ * "empty file". Must only be called on trusted Tor-owned files, as changing
+ * the underlying file's size causes unspecified behavior. */
tor_mmap_t *
tor_mmap_file(const char *filename)
{
int fd; /* router file */
char *string;
- int page_size, result;
+ int result;
tor_mmap_t *res;
size_t size, filesize;
struct stat st;
@@ -251,13 +242,6 @@ tor_mmap_file(const char *filename)
return NULL;
}
size = filesize = (size_t)(st.st_size);
- /*
- * Should we check for weird crap like mmapping a named pipe here,
- * or just wait for if (!size) below to fail?
- */
- /* ensure page alignment */
- page_size = getpagesize();
- size += (size%page_size) ? page_size-(size%page_size) : 0;
if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) {
log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename);
@@ -418,40 +402,8 @@ tor_munmap_file(tor_mmap_t *handle)
return 0;
}
#else
-tor_mmap_t *
-tor_mmap_file(const char *filename)
-{
- struct stat st;
- char *res = read_file_to_str(filename, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
- tor_mmap_t *handle;
- if (! res)
- return NULL;
- handle = tor_malloc_zero(sizeof(tor_mmap_t));
- handle->data = res;
- handle->size = st.st_size;
- return handle;
-}
-
-/** Unmap the file mapped with tor_mmap_file(), and return 0 for success
- * or -1 for failure.
- */
-
-int
-tor_munmap_file(tor_mmap_t *handle)
-{
- char *d = NULL;
- if (handle == NULL)
- return 0;
-
- d = (char*)handle->data;
- tor_free(d);
- memwipe(handle, 0, sizeof(tor_mmap_t));
- tor_free(handle);
-
- /* Can't fail in this mmap()/munmap()-free case */
- return 0;
-}
-#endif /* defined(COMPAT_HAS_MMAN_AND_PAGESIZE) || ... || ... */
+#error "cannot implement tor_mmap_file"
+#endif /* defined(HAVE_MMAP) || ... || ... */
/** Replacement for snprintf. Differs from platform snprintf in two
* ways: First, always NUL-terminates its output. Second, always
@@ -1392,6 +1344,24 @@ tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
return getsockname(sock, address, address_len);
}
+/**
+ * Find the local address associated with the socket <b>sock</b>, and
+ * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure.
+ *
+ * (As tor_getsockname, but instead places the result in a tor_addr_t.) */
+int
+tor_addr_from_getsockname(tor_addr_t *addr_out, tor_socket_t sock)
+{
+ struct sockaddr_storage ss;
+ socklen_t ss_len = sizeof(ss);
+ memset(&ss, 0, sizeof(ss));
+
+ if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0)
+ return -1;
+
+ return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL);
+}
+
/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
* on failure.
*/
diff --git a/src/common/compat.h b/src/common/compat.h
index 93301feda0..1bdff8db3d 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -318,12 +318,12 @@ typedef struct tor_mmap_t {
size_t size; /**< Size of the file. */
/* None of the fields below should be accessed from outside compat.c */
-#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_MMAP
size_t mapping_size; /**< Size of the actual mapping. (This is this file
* size, rounded up to the nearest page.) */
#elif defined _WIN32
HANDLE mmap_handle;
-#endif /* defined(HAVE_SYS_MMAN_H) || ... */
+#endif /* defined(HAVE_MMAP) || ... */
} tor_mmap_t;
@@ -510,6 +510,8 @@ int get_n_open_sockets(void);
MOCK_DECL(int,
tor_getsockname,(tor_socket_t socket, struct sockaddr *address,
socklen_t *address_len));
+struct tor_addr_t;
+int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock);
#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags)
#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags)
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 735385557c..0d0e4337bb 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -221,6 +221,121 @@ periodic_timer_free_(periodic_timer_t *timer)
tor_free(timer);
}
+/**
+ * Type used to represent events that run directly from the main loop,
+ * either because they are activated from elsewhere in the code, or
+ * because they have a simple timeout.
+ *
+ * We use this type to avoid exposing Libevent's API throughout the rest
+ * of the codebase.
+ *
+ * This type can't be used for all events: it doesn't handle events that
+ * are triggered by signals or by sockets.
+ */
+struct mainloop_event_t {
+ struct event *ev;
+ void (*cb)(mainloop_event_t *, void *);
+ void *userdata;
+};
+
+/**
+ * Internal: Implements mainloop event using a libevent event.
+ */
+static void
+mainloop_event_cb(evutil_socket_t fd, short what, void *arg)
+{
+ (void)fd;
+ (void)what;
+ mainloop_event_t *mev = arg;
+ mev->cb(mev, mev->userdata);
+}
+
+/**
+ * Create and return a new mainloop_event_t to run the function <b>cb</b>.
+ *
+ * When run, the callback function will be passed the mainloop_event_t
+ * and <b>userdata</b> as its arguments. The <b>userdata</b> pointer
+ * must remain valid for as long as the mainloop_event_t event exists:
+ * it is your responsibility to free it.
+ *
+ * The event is not scheduled by default: Use mainloop_event_activate()
+ * or mainloop_event_schedule() to make it run.
+ */
+mainloop_event_t *
+mainloop_event_new(void (*cb)(mainloop_event_t *, void *),
+ void *userdata)
+{
+ tor_assert(cb);
+
+ struct event_base *base = tor_libevent_get_base();
+ mainloop_event_t *mev = tor_malloc_zero(sizeof(mainloop_event_t));
+ mev->ev = tor_event_new(base, -1, 0, mainloop_event_cb, mev);
+ tor_assert(mev->ev);
+ mev->cb = cb;
+ mev->userdata = userdata;
+ return mev;
+}
+
+/**
+ * Schedule <b>event</b> to run in the main loop, immediately. If it is
+ * not scheduled, it will run anyway. If it is already scheduled to run
+ * later, it will run now instead. This function will have no effect if
+ * the event is already scheduled to run.
+ *
+ * This function may only be called from the main thread.
+ */
+void
+mainloop_event_activate(mainloop_event_t *event)
+{
+ tor_assert(event);
+ event_active(event->ev, EV_READ, 1);
+}
+
+/** Schedule <b>event</b> to run in the main loop, after a delay of <b>tv</b>.
+ *
+ * If the event is scheduled for a different time, cancel it and run
+ * after this delay instead. If the event is currently pending to run
+ * <em>now</b>, has no effect.
+ *
+ * Do not call this function with <b>tv</b> == NULL -- use
+ * mainloop_event_activate() instead.
+ *
+ * This function may only be called from the main thread.
+ */
+int
+mainloop_event_schedule(mainloop_event_t *event, const struct timeval *tv)
+{
+ tor_assert(event);
+ if (BUG(tv == NULL)) {
+ // LCOV_EXCL_START
+ mainloop_event_activate(event);
+ return 0;
+ // LCOV_EXCL_STOP
+ }
+ return event_add(event->ev, tv);
+}
+
+/** Cancel <b>event</b> if it is currently active or pending. (Do nothing if
+ * the event is not currently active or pending.) */
+void
+mainloop_event_cancel(mainloop_event_t *event)
+{
+ if (!event)
+ return;
+ (void) event_del(event->ev);
+}
+
+/** Cancel <b>event</b> and release all storage associated with it. */
+void
+mainloop_event_free_(mainloop_event_t *event)
+{
+ if (!event)
+ return;
+ tor_event_free(event->ev);
+ memset(event, 0xb8, sizeof(*event));
+ tor_free(event);
+}
+
int
tor_init_libevent_rng(void)
{
@@ -248,6 +363,38 @@ tor_libevent_free_all(void)
the_event_base = NULL;
}
+/**
+ * Run the event loop for the provided event_base, handling events until
+ * something stops it. If <b>once</b> is set, then just poll-and-run
+ * once, then exit. Return 0 on success, -1 if an error occurred, or 1
+ * if we exited because no events were pending or active.
+ *
+ * This isn't reentrant or multithreaded.
+ */
+int
+tor_libevent_run_event_loop(struct event_base *base, int once)
+{
+ const int flags = once ? EVLOOP_ONCE : 0;
+ return event_base_loop(base, flags);
+}
+
+/** Tell the event loop to exit after <b>delay</b>. If <b>delay</b> is NULL,
+ * instead exit after we're done running the currently active events. */
+void
+tor_libevent_exit_loop_after_delay(struct event_base *base,
+ const struct timeval *delay)
+{
+ event_base_loopexit(base, delay);
+}
+
+/** Tell the event loop to exit after running whichever callback is currently
+ * active. */
+void
+tor_libevent_exit_loop_after_callback(struct event_base *base)
+{
+ event_base_loopbreak(base);
+}
+
#if defined(LIBEVENT_VERSION_NUMBER) && \
LIBEVENT_VERSION_NUMBER >= V(2,1,1) && \
!defined(TOR_UNIT_TESTS)
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 1853e50917..c8b0371564 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -7,8 +7,6 @@
#include "orconfig.h"
#include "testsupport.h"
-#include <event2/event.h>
-
void configure_libevent_logging(void);
void suppress_libevent_log_msg(const char *msg);
@@ -19,6 +17,9 @@ void suppress_libevent_log_msg(const char *msg);
evdns_add_server_port_with_base(tor_libevent_get_base(), \
(sock),(tcp),(cb),(data));
+struct event;
+struct event_base;
+
void tor_event_free_(struct event *ev);
#define tor_event_free(ev) \
FREE_AND_NULL(struct event, tor_event_free_, (ev))
@@ -33,8 +34,16 @@ void periodic_timer_free_(periodic_timer_t *);
#define periodic_timer_free(t) \
FREE_AND_NULL(periodic_timer_t, periodic_timer_free_, (t))
-#define tor_event_base_loopexit event_base_loopexit
-#define tor_event_base_loopbreak event_base_loopbreak
+typedef struct mainloop_event_t mainloop_event_t;
+mainloop_event_t *mainloop_event_new(void (*cb)(mainloop_event_t *, void *),
+ void *userdata);
+void mainloop_event_activate(mainloop_event_t *event);
+int mainloop_event_schedule(mainloop_event_t *event,
+ const struct timeval *delay);
+void mainloop_event_cancel(mainloop_event_t *event);
+void mainloop_event_free_(mainloop_event_t *event);
+#define mainloop_event_free(event) \
+ FREE_AND_NULL(mainloop_event_t, mainloop_event_free_, (event))
/** Defines a configuration for using libevent with Tor: passed as an argument
* to tor_libevent_initialize() to describe how we want to set up. */
@@ -63,6 +72,11 @@ void tor_gettimeofday_cache_set(const struct timeval *tv);
void tor_libevent_postfork(void);
#endif
+int tor_libevent_run_event_loop(struct event_base *base, int once);
+void tor_libevent_exit_loop_after_delay(struct event_base *base,
+ const struct timeval *delay);
+void tor_libevent_exit_loop_after_callback(struct event_base *base);
+
#ifdef COMPAT_LIBEVENT_PRIVATE
/** Macro: returns the number of a Libevent version as a 4-byte number,
diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c
index 5f7ec94c23..7021344f6e 100644
--- a/src/common/compat_winthreads.c
+++ b/src/common/compat_winthreads.c
@@ -18,7 +18,6 @@
#include "util.h"
#include "container.h"
#include "torlog.h"
-#include <process.h>
/* This value is more or less total cargo-cult */
#define SPIN_COUNT 2000
diff --git a/src/common/compress.c b/src/common/compress.c
index 47c93cf6a9..cb1549f1aa 100644
--- a/src/common/compress.c
+++ b/src/common/compress.c
@@ -663,3 +663,13 @@ tor_compress_init(void)
tor_zstd_init();
}
+/** Warn if we had any problems while setting up our compression libraries.
+ *
+ * (This isn't part of tor_compress_init, since the logs aren't set up yet.)
+ */
+void
+tor_compress_log_init_warnings(void)
+{
+ tor_zstd_warn_if_version_mismatched();
+}
+
diff --git a/src/common/compress.h b/src/common/compress.h
index 952102bf97..65d63a4386 100644
--- a/src/common/compress.h
+++ b/src/common/compress.h
@@ -87,6 +87,7 @@ void tor_compress_free_(tor_compress_state_t *state);
size_t tor_compress_state_size(const tor_compress_state_t *state);
void tor_compress_init(void);
+void tor_compress_log_init_warnings(void);
#endif /* !defined(TOR_COMPRESS_H) */
diff --git a/src/common/compress_zstd.c b/src/common/compress_zstd.c
index 0db87d61b7..4024f5594d 100644
--- a/src/common/compress_zstd.c
+++ b/src/common/compress_zstd.c
@@ -18,6 +18,13 @@
#include "compress.h"
#include "compress_zstd.h"
+#ifdef ENABLE_ZSTD_ADVANCED_APIS
+/* This is a lie, but we make sure it doesn't get us in trouble by wrapping
+ * all invocations of zstd's static-only functions in a check to make sure
+ * that the compile-time version matches the run-time version. */
+#define ZSTD_STATIC_LINKING_ONLY
+#endif
+
#ifdef HAVE_ZSTD
#include <zstd.h>
#endif
@@ -51,21 +58,31 @@ tor_zstd_method_supported(void)
#endif
}
+#ifdef HAVE_ZSTD
+/** Format a zstd version number as a string in <b>buf</b>. */
+static void
+tor_zstd_format_version(char *buf, size_t buflen, unsigned version_number)
+{
+ tor_snprintf(buf, buflen,
+ "%u.%u.%u",
+ version_number / 10000 % 100,
+ version_number / 100 % 100,
+ version_number % 100);
+}
+#endif
+
+#define VERSION_STR_MAX_LEN 16 /* more than enough space for 99.99.99 */
+
/** Return a string representation of the version of the currently running
* version of libzstd. Returns NULL if Zstandard is unsupported. */
const char *
tor_zstd_get_version_str(void)
{
#ifdef HAVE_ZSTD
- static char version_str[16];
- size_t version_number;
+ static char version_str[VERSION_STR_MAX_LEN];
- version_number = ZSTD_versionNumber();
- tor_snprintf(version_str, sizeof(version_str),
- "%d.%d.%d",
- (int) version_number / 10000 % 100,
- (int) version_number / 100 % 100,
- (int) version_number % 100);
+ tor_zstd_format_version(version_str, sizeof(version_str),
+ ZSTD_versionNumber());
return version_str;
#else /* !(defined(HAVE_ZSTD)) */
@@ -85,6 +102,26 @@ tor_zstd_get_header_version_str(void)
#endif
}
+#ifdef TOR_UNIT_TESTS
+static int static_apis_disable_for_testing = 0;
+#endif
+
+/** Return true iff we can use the "static-only" APIs. */
+int
+tor_zstd_can_use_static_apis(void)
+{
+#if defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD)
+#ifdef TOR_UNIT_TESTS
+ if (static_apis_disable_for_testing) {
+ return 0;
+ }
+#endif
+ return (ZSTD_VERSION_NUMBER == ZSTD_versionNumber());
+#else
+ return 0;
+#endif
+}
+
/** Internal Zstandard state for incremental compression/decompression.
* The body of this struct is not exposed. */
struct tor_zstd_compress_state_t {
@@ -112,9 +149,11 @@ struct tor_zstd_compress_state_t {
#ifdef HAVE_ZSTD
/** Return an approximate number of bytes stored in memory to hold the
- * Zstandard compression/decompression state. */
+ * Zstandard compression/decompression state. This is a fake estimate
+ * based on inspecting the zstd source: tor_zstd_state_size_precalc() is
+ * more accurate when it's allowed to use "static-only" functions */
static size_t
-tor_zstd_state_size_precalc(int compress, int preset)
+tor_zstd_state_size_precalc_fake(int compress, int preset)
{
tor_assert(preset > 0);
@@ -171,6 +210,28 @@ tor_zstd_state_size_precalc(int compress, int preset)
return memory_usage;
}
+
+/** Return an approximate number of bytes stored in memory to hold the
+ * Zstandard compression/decompression state. */
+static size_t
+tor_zstd_state_size_precalc(int compress, int preset)
+{
+#ifdef ZSTD_STATIC_LINKING_ONLY
+ if (tor_zstd_can_use_static_apis()) {
+ if (compress) {
+#ifdef HAVE_ZSTD_ESTIMATECSTREAMSIZE
+ return ZSTD_estimateCStreamSize(preset);
+#endif
+ } else {
+#ifdef HAVE_ZSTD_ESTIMATEDCTXSIZE
+ /* Could use DStream, but that takes a windowSize. */
+ return ZSTD_estimateDCtxSize();
+#endif
+ }
+ }
+#endif
+ return tor_zstd_state_size_precalc_fake(compress, preset);
+}
#endif /* defined(HAVE_ZSTD) */
/** Construct and return a tor_zstd_compress_state_t object using
@@ -440,3 +501,34 @@ tor_zstd_init(void)
atomic_counter_init(&total_zstd_allocation);
}
+/** Warn if the header and library versions don't match. */
+void
+tor_zstd_warn_if_version_mismatched(void)
+{
+#if defined(HAVE_ZSTD) && defined(ENABLE_ZSTD_ADVANCED_APIS)
+ if (! tor_zstd_can_use_static_apis()) {
+ char header_version[VERSION_STR_MAX_LEN];
+ char runtime_version[VERSION_STR_MAX_LEN];
+ tor_zstd_format_version(header_version, sizeof(header_version),
+ ZSTD_VERSION_NUMBER);
+ tor_zstd_format_version(runtime_version, sizeof(runtime_version),
+ ZSTD_versionNumber());
+
+ log_warn(LD_GENERAL,
+ "Tor was compiled with zstd %s, but is running with zstd %s. "
+ "For safety, we'll avoid using advanced zstd functionality.",
+ header_version, runtime_version);
+ }
+#endif
+}
+
+#ifdef TOR_UNIT_TESTS
+/** Testing only: disable usage of static-only APIs, so we can make sure that
+ * we still work without them. */
+void
+tor_zstd_set_static_apis_disabled_for_testing(int disabled)
+{
+ static_apis_disable_for_testing = disabled;
+}
+#endif
+
diff --git a/src/common/compress_zstd.h b/src/common/compress_zstd.h
index 9bca24ded7..bd42cf65ce 100644
--- a/src/common/compress_zstd.h
+++ b/src/common/compress_zstd.h
@@ -17,6 +17,8 @@ const char *tor_zstd_get_version_str(void);
const char *tor_zstd_get_header_version_str(void);
+int tor_zstd_can_use_static_apis(void);
+
/** Internal state for an incremental Zstandard compression/decompression. */
typedef struct tor_zstd_compress_state_t tor_zstd_compress_state_t;
@@ -41,6 +43,11 @@ size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state);
size_t tor_zstd_get_total_allocation(void);
void tor_zstd_init(void);
+void tor_zstd_warn_if_version_mismatched(void);
+
+#ifdef TOR_UNIT_TESTS
+void tor_zstd_set_static_apis_disabled_for_testing(int disabled);
+#endif
#endif /* !defined(TOR_COMPRESS_ZSTD_H) */
diff --git a/src/common/container.c b/src/common/container.c
index 54b0b2028f..5386e6458b 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -15,7 +15,7 @@
#include "util.h"
#include "torlog.h"
#include "container.h"
-#include "crypto.h"
+#include "crypto_digest.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/common/crypto.c b/src/common/crypto.c
index d85aca4004..9fcd17742c 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -29,6 +29,7 @@
#include "crypto_ed25519.h"
#include "crypto_format.h"
#include "crypto_rsa.h"
+#include "crypto_digest.h"
DISABLE_GCC_WARNING(redundant-decls)
@@ -397,266 +398,6 @@ crypto_cipher_free_(crypto_cipher_t *env)
aes_cipher_free(env);
}
-/* public key crypto */
-
-/** Check a siglen-byte long signature at <b>sig</b> against
- * <b>datalen</b> bytes of data at <b>data</b>, using the public key
- * in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for
- * SHA1(data). Else return -1.
- */
-MOCK_IMPL(int,
-crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data,
- size_t datalen, const char *sig,
- size_t siglen))
-{
- char digest[DIGEST_LEN];
- char *buf;
- size_t buflen;
- int r;
-
- tor_assert(env);
- tor_assert(data);
- tor_assert(sig);
- tor_assert(datalen < SIZE_T_CEILING);
- tor_assert(siglen < SIZE_T_CEILING);
-
- if (crypto_digest(digest,data,datalen)<0) {
- log_warn(LD_BUG, "couldn't compute digest");
- return -1;
- }
- buflen = crypto_pk_keysize(env);
- buf = tor_malloc(buflen);
- r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
- if (r != DIGEST_LEN) {
- log_warn(LD_CRYPTO, "Invalid signature");
- tor_free(buf);
- return -1;
- }
- if (tor_memneq(buf, digest, DIGEST_LEN)) {
- log_warn(LD_CRYPTO, "Signature mismatched with digest.");
- tor_free(buf);
- return -1;
- }
- tor_free(buf);
-
- return 0;
-}
-
-/** Compute a SHA1 digest of <b>fromlen</b> bytes of data stored at
- * <b>from</b>; sign the data with the private key in <b>env</b>, and
- * store it in <b>to</b>. Return the number of bytes written on
- * success, and -1 on failure.
- *
- * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
- * at least the length of the modulus of <b>env</b>.
- */
-int
-crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
- const char *from, size_t fromlen)
-{
- int r;
- char digest[DIGEST_LEN];
- if (crypto_digest(digest,from,fromlen)<0)
- return -1;
- r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN);
- memwipe(digest, 0, sizeof(digest));
- return r;
-}
-
-/** Perform a hybrid (public/secret) encryption on <b>fromlen</b>
- * bytes of data from <b>from</b>, with padding type 'padding',
- * storing the results on <b>to</b>.
- *
- * Returns the number of bytes written on success, -1 on failure.
- *
- * The encrypted data consists of:
- * - The source data, padded and encrypted with the public key, if the
- * padded source data is no longer than the public key, and <b>force</b>
- * is false, OR
- * - The beginning of the source data prefixed with a 16-byte symmetric key,
- * padded and encrypted with the public key; followed by the rest of
- * the source data encrypted in AES-CTR mode with the symmetric key.
- *
- * NOTE that this format does not authenticate the symmetrically encrypted
- * part of the data, and SHOULD NOT BE USED for new protocols.
- */
-int
-crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env,
- char *to, size_t tolen,
- const char *from,
- size_t fromlen,
- int padding, int force)
-{
- int overhead, outlen, r;
- size_t pkeylen, symlen;
- crypto_cipher_t *cipher = NULL;
- char *buf = NULL;
-
- tor_assert(env);
- tor_assert(from);
- tor_assert(to);
- tor_assert(fromlen < SIZE_T_CEILING);
-
- overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding));
- pkeylen = crypto_pk_keysize(env);
-
- if (!force && fromlen+overhead <= pkeylen) {
- /* It all fits in a single encrypt. */
- return crypto_pk_public_encrypt(env,to,
- tolen,
- from,fromlen,padding);
- }
- tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN);
- tor_assert(tolen >= pkeylen);
-
- char key[CIPHER_KEY_LEN];
- crypto_rand(key, sizeof(key)); /* generate a new key. */
- cipher = crypto_cipher_new(key);
-
- buf = tor_malloc(pkeylen+1);
- memcpy(buf, key, CIPHER_KEY_LEN);
- memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN);
-
- /* Length of symmetrically encrypted data. */
- symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN);
-
- outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding);
- if (outlen!=(int)pkeylen) {
- goto err;
- }
- r = crypto_cipher_encrypt(cipher, to+outlen,
- from+pkeylen-overhead-CIPHER_KEY_LEN, symlen);
-
- if (r<0) goto err;
- memwipe(buf, 0, pkeylen);
- memwipe(key, 0, sizeof(key));
- tor_free(buf);
- crypto_cipher_free(cipher);
- tor_assert(outlen+symlen < INT_MAX);
- return (int)(outlen + symlen);
- err:
-
- memwipe(buf, 0, pkeylen);
- memwipe(key, 0, sizeof(key));
- tor_free(buf);
- crypto_cipher_free(cipher);
- return -1;
-}
-
-/** Invert crypto_pk_obsolete_public_hybrid_encrypt. Returns the number of
- * bytes written on success, -1 on failure.
- *
- * NOTE that this format does not authenticate the symmetrically encrypted
- * part of the data, and SHOULD NOT BE USED for new protocols.
- */
-int
-crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env,
- char *to,
- size_t tolen,
- const char *from,
- size_t fromlen,
- int padding, int warnOnFailure)
-{
- int outlen, r;
- size_t pkeylen;
- crypto_cipher_t *cipher = NULL;
- char *buf = NULL;
-
- tor_assert(fromlen < SIZE_T_CEILING);
- pkeylen = crypto_pk_keysize(env);
-
- if (fromlen <= pkeylen) {
- return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding,
- warnOnFailure);
- }
-
- buf = tor_malloc(pkeylen);
- outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding,
- warnOnFailure);
- if (outlen<0) {
- log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
- "Error decrypting public-key data");
- goto err;
- }
- if (outlen < CIPHER_KEY_LEN) {
- log_fn(warnOnFailure?LOG_WARN:LOG_INFO, LD_CRYPTO,
- "No room for a symmetric key");
- goto err;
- }
- cipher = crypto_cipher_new(buf);
- if (!cipher) {
- goto err;
- }
- memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN);
- outlen -= CIPHER_KEY_LEN;
- tor_assert(tolen - outlen >= fromlen - pkeylen);
- r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen);
- if (r<0)
- goto err;
- memwipe(buf,0,pkeylen);
- tor_free(buf);
- crypto_cipher_free(cipher);
- tor_assert(outlen + fromlen < INT_MAX);
- return (int)(outlen + (fromlen-pkeylen));
- err:
- memwipe(buf,0,pkeylen);
- tor_free(buf);
- crypto_cipher_free(cipher);
- return -1;
-}
-
-/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
- * public key into <b>digest_out</b> (must have DIGEST_LEN bytes of space).
- * Return 0 on success, -1 on failure.
- */
-int
-crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
-{
- char *buf;
- size_t buflen;
- int len;
- int rv = -1;
-
- buflen = crypto_pk_keysize(pk)*2;
- buf = tor_malloc(buflen);
- len = crypto_pk_asn1_encode(pk, buf, buflen);
- if (len < 0)
- goto done;
-
- if (crypto_digest(digest_out, buf, len) < 0)
- goto done;
-
- rv = 0;
- done:
- tor_free(buf);
- return rv;
-}
-
-/** Compute all digests of the DER encoding of <b>pk</b>, and store them
- * in <b>digests_out</b>. Return 0 on success, -1 on failure. */
-int
-crypto_pk_get_common_digests(crypto_pk_t *pk, common_digests_t *digests_out)
-{
- char *buf;
- size_t buflen;
- int len;
- int rv = -1;
-
- buflen = crypto_pk_keysize(pk)*2;
- buf = tor_malloc(buflen);
- len = crypto_pk_asn1_encode(pk, buf, buflen);
- if (len < 0)
- goto done;
-
- if (crypto_common_digests(digests_out, (char*)buf, len) < 0)
- goto done;
-
- rv = 0;
- done:
- tor_free(buf);
- return rv;
-}
-
/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces
* every four characters. */
void
@@ -788,524 +529,6 @@ crypto_cipher_decrypt_with_iv(const char *key,
return (int)(fromlen - CIPHER_IV_LEN);
}
-/* SHA-1 */
-
-/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
- * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
- * Return 0 on success, -1 on failure.
- */
-int
-crypto_digest(char *digest, const char *m, size_t len)
-{
- tor_assert(m);
- tor_assert(digest);
- if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL)
- return -1;
- return 0;
-}
-
-/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
- * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
- * into <b>digest</b>. Return 0 on success, -1 on failure. */
-int
-crypto_digest256(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm)
-{
- tor_assert(m);
- tor_assert(digest);
- tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
-
- int ret = 0;
- if (algorithm == DIGEST_SHA256)
- ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
- else
- ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
- > -1);
-
- if (!ret)
- return -1;
- return 0;
-}
-
-/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
- * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
- * into <b>digest</b>. Return 0 on success, -1 on failure. */
-int
-crypto_digest512(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm)
-{
- tor_assert(m);
- tor_assert(digest);
- tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
-
- int ret = 0;
- if (algorithm == DIGEST_SHA512)
- ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
- != NULL);
- else
- ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
- > -1);
-
- if (!ret)
- return -1;
- return 0;
-}
-
-/** Set the common_digests_t in <b>ds_out</b> to contain every digest on the
- * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on
- * success, -1 on failure. */
-int
-crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len)
-{
- tor_assert(ds_out);
- memset(ds_out, 0, sizeof(*ds_out));
- if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
- return -1;
- if (crypto_digest256(ds_out->d[DIGEST_SHA256], m, len, DIGEST_SHA256) < 0)
- return -1;
-
- return 0;
-}
-
-/** Return the name of an algorithm, as used in directory documents. */
-const char *
-crypto_digest_algorithm_get_name(digest_algorithm_t alg)
-{
- switch (alg) {
- case DIGEST_SHA1:
- return "sha1";
- case DIGEST_SHA256:
- return "sha256";
- case DIGEST_SHA512:
- return "sha512";
- case DIGEST_SHA3_256:
- return "sha3-256";
- case DIGEST_SHA3_512:
- return "sha3-512";
- // LCOV_EXCL_START
- default:
- tor_fragile_assert();
- return "??unknown_digest??";
- // LCOV_EXCL_STOP
- }
-}
-
-/** Given the name of a digest algorithm, return its integer value, or -1 if
- * the name is not recognized. */
-int
-crypto_digest_algorithm_parse_name(const char *name)
-{
- if (!strcmp(name, "sha1"))
- return DIGEST_SHA1;
- else if (!strcmp(name, "sha256"))
- return DIGEST_SHA256;
- else if (!strcmp(name, "sha512"))
- return DIGEST_SHA512;
- else if (!strcmp(name, "sha3-256"))
- return DIGEST_SHA3_256;
- else if (!strcmp(name, "sha3-512"))
- return DIGEST_SHA3_512;
- else
- return -1;
-}
-
-/** Given an algorithm, return the digest length in bytes. */
-size_t
-crypto_digest_algorithm_get_length(digest_algorithm_t alg)
-{
- switch (alg) {
- case DIGEST_SHA1:
- return DIGEST_LEN;
- case DIGEST_SHA256:
- return DIGEST256_LEN;
- case DIGEST_SHA512:
- return DIGEST512_LEN;
- case DIGEST_SHA3_256:
- return DIGEST256_LEN;
- case DIGEST_SHA3_512:
- return DIGEST512_LEN;
- default:
- tor_assert(0); // LCOV_EXCL_LINE
- return 0; /* Unreachable */ // LCOV_EXCL_LINE
- }
-}
-
-/** Intermediate information about the digest of a stream of data. */
-struct crypto_digest_t {
- digest_algorithm_t algorithm; /**< Which algorithm is in use? */
- /** State for the digest we're using. Only one member of the
- * union is usable, depending on the value of <b>algorithm</b>. Note also
- * that space for other members might not even be allocated!
- */
- union {
- SHA_CTX sha1; /**< state for SHA1 */
- SHA256_CTX sha2; /**< state for SHA256 */
- SHA512_CTX sha512; /**< state for SHA512 */
- keccak_state sha3; /**< state for SHA3-[256,512] */
- } d;
-};
-
-#ifdef TOR_UNIT_TESTS
-
-digest_algorithm_t
-crypto_digest_get_algorithm(crypto_digest_t *digest)
-{
- tor_assert(digest);
-
- return digest->algorithm;
-}
-
-#endif /* defined(TOR_UNIT_TESTS) */
-
-/**
- * Return the number of bytes we need to malloc in order to get a
- * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
- * when we free one.
- */
-static size_t
-crypto_digest_alloc_bytes(digest_algorithm_t alg)
-{
- /* Helper: returns the number of bytes in the 'f' field of 'st' */
-#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
- /* Gives the length of crypto_digest_t through the end of the field 'd' */
-#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
- STRUCT_FIELD_SIZE(crypto_digest_t, f))
- switch (alg) {
- case DIGEST_SHA1:
- return END_OF_FIELD(d.sha1);
- case DIGEST_SHA256:
- return END_OF_FIELD(d.sha2);
- case DIGEST_SHA512:
- return END_OF_FIELD(d.sha512);
- case DIGEST_SHA3_256:
- case DIGEST_SHA3_512:
- return END_OF_FIELD(d.sha3);
- default:
- tor_assert(0); // LCOV_EXCL_LINE
- return 0; // LCOV_EXCL_LINE
- }
-#undef END_OF_FIELD
-#undef STRUCT_FIELD_SIZE
-}
-
-/**
- * Internal function: create and return a new digest object for 'algorithm'.
- * Does not typecheck the algorithm.
- */
-static crypto_digest_t *
-crypto_digest_new_internal(digest_algorithm_t algorithm)
-{
- crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
- r->algorithm = algorithm;
-
- switch (algorithm)
- {
- case DIGEST_SHA1:
- SHA1_Init(&r->d.sha1);
- break;
- case DIGEST_SHA256:
- SHA256_Init(&r->d.sha2);
- break;
- case DIGEST_SHA512:
- SHA512_Init(&r->d.sha512);
- break;
- case DIGEST_SHA3_256:
- keccak_digest_init(&r->d.sha3, 256);
- break;
- case DIGEST_SHA3_512:
- keccak_digest_init(&r->d.sha3, 512);
- break;
- default:
- tor_assert_unreached();
- }
-
- return r;
-}
-
-/** Allocate and return a new digest object to compute SHA1 digests.
- */
-crypto_digest_t *
-crypto_digest_new(void)
-{
- return crypto_digest_new_internal(DIGEST_SHA1);
-}
-
-/** Allocate and return a new digest object to compute 256-bit digests
- * using <b>algorithm</b>. */
-crypto_digest_t *
-crypto_digest256_new(digest_algorithm_t algorithm)
-{
- tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
- return crypto_digest_new_internal(algorithm);
-}
-
-/** Allocate and return a new digest object to compute 512-bit digests
- * using <b>algorithm</b>. */
-crypto_digest_t *
-crypto_digest512_new(digest_algorithm_t algorithm)
-{
- tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
- return crypto_digest_new_internal(algorithm);
-}
-
-/** Deallocate a digest object.
- */
-void
-crypto_digest_free_(crypto_digest_t *digest)
-{
- if (!digest)
- return;
- size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
- memwipe(digest, 0, bytes);
- tor_free(digest);
-}
-
-/** Add <b>len</b> bytes from <b>data</b> to the digest object.
- */
-void
-crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
- size_t len)
-{
- tor_assert(digest);
- tor_assert(data);
- /* Using the SHA*_*() calls directly means we don't support doing
- * SHA in hardware. But so far the delay of getting the question
- * to the hardware, and hearing the answer, is likely higher than
- * just doing it ourselves. Hashes are fast.
- */
- switch (digest->algorithm) {
- case DIGEST_SHA1:
- SHA1_Update(&digest->d.sha1, (void*)data, len);
- break;
- case DIGEST_SHA256:
- SHA256_Update(&digest->d.sha2, (void*)data, len);
- break;
- case DIGEST_SHA512:
- SHA512_Update(&digest->d.sha512, (void*)data, len);
- break;
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
- case DIGEST_SHA3_512:
- keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
- break;
- default:
- /* LCOV_EXCL_START */
- tor_fragile_assert();
- break;
- /* LCOV_EXCL_STOP */
- }
-}
-
-/** 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.
- */
-void
-crypto_digest_get_digest(crypto_digest_t *digest,
- char *out, size_t out_len)
-{
- unsigned char r[DIGEST512_LEN];
- crypto_digest_t tmpenv;
- tor_assert(digest);
- tor_assert(out);
- tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
-
- /* The SHA-3 code handles copying into a temporary ctx, and also can handle
- * short output buffers by truncating appropriately. */
- if (digest->algorithm == DIGEST_SHA3_256 ||
- digest->algorithm == DIGEST_SHA3_512) {
- keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
- return;
- }
-
- const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
- /* memcpy into a temporary ctx, since SHA*_Final clears the context */
- memcpy(&tmpenv, digest, alloc_bytes);
- switch (digest->algorithm) {
- case DIGEST_SHA1:
- SHA1_Final(r, &tmpenv.d.sha1);
- break;
- case DIGEST_SHA256:
- SHA256_Final(r, &tmpenv.d.sha2);
- break;
- case DIGEST_SHA512:
- SHA512_Final(r, &tmpenv.d.sha512);
- break;
-//LCOV_EXCL_START
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
- case DIGEST_SHA3_512:
- default:
- log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
- /* This is fatal, because it should never happen. */
- tor_assert_unreached();
- break;
-//LCOV_EXCL_STOP
- }
- memcpy(out, r, out_len);
- memwipe(r, 0, sizeof(r));
-}
-
-/** Allocate and return a new digest object with the same state as
- * <b>digest</b>
- */
-crypto_digest_t *
-crypto_digest_dup(const crypto_digest_t *digest)
-{
- tor_assert(digest);
- const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
- return tor_memdup(digest, alloc_bytes);
-}
-
-/** Replace the state of the digest object <b>into</b> with the state
- * of the digest object <b>from</b>. Requires that 'into' and 'from'
- * have the same digest type.
- */
-void
-crypto_digest_assign(crypto_digest_t *into,
- const crypto_digest_t *from)
-{
- tor_assert(into);
- tor_assert(from);
- tor_assert(into->algorithm == from->algorithm);
- const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
- memcpy(into,from,alloc_bytes);
-}
-
-/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
- * at <b>digest_out</b> to the hash of the concatenation of those strings,
- * plus the optional string <b>append</b>, computed with the algorithm
- * <b>alg</b>.
- * <b>out_len</b> must be \<= DIGEST512_LEN. */
-void
-crypto_digest_smartlist(char *digest_out, size_t len_out,
- const smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg)
-{
- crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
-}
-
-/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
- * at <b>digest_out</b> to the hash of the concatenation of: the
- * optional string <b>prepend</b>, those strings,
- * and the optional string <b>append</b>, computed with the algorithm
- * <b>alg</b>.
- * <b>len_out</b> must be \<= DIGEST512_LEN. */
-void
-crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
- const char *prepend,
- const smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg)
-{
- crypto_digest_t *d = crypto_digest_new_internal(alg);
- if (prepend)
- crypto_digest_add_bytes(d, prepend, strlen(prepend));
- SMARTLIST_FOREACH(lst, const char *, cp,
- crypto_digest_add_bytes(d, cp, strlen(cp)));
- if (append)
- crypto_digest_add_bytes(d, append, strlen(append));
- crypto_digest_get_digest(d, digest_out, len_out);
- crypto_digest_free(d);
-}
-
-/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
- * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
- * result in <b>hmac_out</b>. Asserts on failure.
- */
-void
-crypto_hmac_sha256(char *hmac_out,
- const char *key, size_t key_len,
- const char *msg, size_t msg_len)
-{
- unsigned char *rv = NULL;
- /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
- tor_assert(hmac_out);
- rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
- (unsigned char*)hmac_out, NULL);
- tor_assert(rv);
-}
-
-/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a
- * <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length
- * <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in
- * <b>mac_out</b>. This function can't fail. */
-void
-crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
- const uint8_t *key, size_t key_len,
- const uint8_t *msg, size_t msg_len)
-{
- crypto_digest_t *digest;
-
- const uint64_t key_len_netorder = tor_htonll(key_len);
-
- tor_assert(mac_out);
- tor_assert(key);
- tor_assert(msg);
-
- digest = crypto_digest256_new(DIGEST_SHA3_256);
-
- /* Order matters here that is any subsystem using this function should
- * expect this very precise ordering in the MAC construction. */
- crypto_digest_add_bytes(digest, (const char *) &key_len_netorder,
- sizeof(key_len_netorder));
- crypto_digest_add_bytes(digest, (const char *) key, key_len);
- crypto_digest_add_bytes(digest, (const char *) msg, msg_len);
- crypto_digest_get_digest(digest, (char *) mac_out, len_out);
- crypto_digest_free(digest);
-}
-
-/** Internal state for a eXtendable-Output Function (XOF). */
-struct crypto_xof_t {
- keccak_state s;
-};
-
-/** Allocate a new XOF object backed by SHAKE-256. The security level
- * provided is a function of the length of the output used. Read and
- * understand FIPS-202 A.2 "Additional Consideration for Extendable-Output
- * Functions" before using this construct.
- */
-crypto_xof_t *
-crypto_xof_new(void)
-{
- crypto_xof_t *xof;
- xof = tor_malloc(sizeof(crypto_xof_t));
- keccak_xof_init(&xof->s, 256);
- return xof;
-}
-
-/** Absorb bytes into a XOF object. Must not be called after a call to
- * crypto_xof_squeeze_bytes() for the same instance, and will assert
- * if attempted.
- */
-void
-crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len)
-{
- int i = keccak_xof_absorb(&xof->s, data, len);
- tor_assert(i == 0);
-}
-
-/** Squeeze bytes out of a XOF object. Calling this routine will render
- * the XOF instance ineligible to absorb further data.
- */
-void
-crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
-{
- int i = keccak_xof_squeeze(&xof->s, out, len);
- tor_assert(i == 0);
-}
-
-/** Cleanse and deallocate a XOF object. */
-void
-crypto_xof_free_(crypto_xof_t *xof)
-{
- if (!xof)
- return;
- memwipe(xof, 0, sizeof(crypto_xof_t));
- tor_free(xof);
-}
-
/* DH */
/** Our DH 'g' parameter */
diff --git a/src/common/crypto.h b/src/common/crypto.h
index a9c8837b9e..b586790329 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -24,13 +24,6 @@
#include "keccak-tiny/keccak-tiny.h"
-/** Length of the output of our message digest. */
-#define DIGEST_LEN 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.) */
-#define DIGEST256_LEN 32
-/** Length of the output of our 64-bit optimized message digests (SHA512). */
-#define DIGEST512_LEN 64
/** 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. */
@@ -40,54 +33,11 @@
/** Length of our DH keys. */
#define DH_BYTES (1024/8)
-/** Length of a sha1 message digest when encoded in base32 with trailing =
- * signs removed. */
-#define BASE32_DIGEST_LEN 32
-/** Length of a sha1 message digest when encoded in base64 with trailing =
- * signs removed. */
-#define BASE64_DIGEST_LEN 27
-/** Length of a sha256 message digest when encoded in base64 with trailing =
- * signs removed. */
-#define BASE64_DIGEST256_LEN 43
-/** Length of a sha512 message digest when encoded in base64 with trailing =
- * signs removed. */
-#define BASE64_DIGEST512_LEN 86
-
/** Length of encoded public key fingerprints, including space; but not
* including terminating NUL. */
#define FINGERPRINT_LEN 49
-/** Length of hex encoding of SHA1 digest, not including final NUL. */
-#define HEX_DIGEST_LEN 40
-/** Length of hex encoding of SHA256 digest, not including final NUL. */
-#define HEX_DIGEST256_LEN 64
-/** Length of hex encoding of SHA512 digest, not including final NUL. */
-#define HEX_DIGEST512_LEN 128
-
-typedef enum {
- DIGEST_SHA1 = 0,
- DIGEST_SHA256 = 1,
- DIGEST_SHA512 = 2,
- DIGEST_SHA3_256 = 3,
- DIGEST_SHA3_512 = 4,
-} digest_algorithm_t;
-#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1)
-#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
-
-/** 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.
- **/
-typedef struct {
- char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN];
-} common_digests_t;
typedef struct aes_cnt_cipher crypto_cipher_t;
-typedef struct crypto_digest_t crypto_digest_t;
-typedef struct crypto_xof_t crypto_xof_t;
typedef struct crypto_dh_t crypto_dh_t;
/* global state */
@@ -114,24 +64,6 @@ void crypto_cipher_free_(crypto_cipher_t *env);
#define crypto_cipher_free(c) \
FREE_AND_NULL(crypto_cipher_t, crypto_cipher_free_, (c))
-/* public key crypto */
-MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env,
- const char *data, size_t datalen,
- const char *sig, size_t siglen));
-int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
- const char *from, size_t fromlen);
-int crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to,
- size_t tolen,
- const char *from, size_t fromlen,
- int padding, int force);
-int crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to,
- size_t tolen,
- const char *from, size_t fromlen,
- int padding, int warnOnFailure);
-int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out);
-int crypto_pk_get_common_digests(crypto_pk_t *pk,
- common_digests_t *digests_out);
-
/* symmetric crypto */
const char *crypto_cipher_get_key(crypto_cipher_t *env);
@@ -148,52 +80,6 @@ int crypto_cipher_decrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen);
-/* SHA-1 and other digests. */
-int crypto_digest(char *digest, const char *m, size_t len);
-int crypto_digest256(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm);
-int crypto_digest512(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm);
-int crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len);
-struct smartlist_t;
-void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
- const char *prepend,
- const struct smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg);
-void crypto_digest_smartlist(char *digest_out, size_t len_out,
- const struct smartlist_t *lst, const char *append,
- digest_algorithm_t alg);
-const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
-size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg);
-int crypto_digest_algorithm_parse_name(const char *name);
-crypto_digest_t *crypto_digest_new(void);
-crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
-crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
-void crypto_digest_free_(crypto_digest_t *digest);
-#define crypto_digest_free(d) \
- FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d))
-void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
- size_t len);
-void crypto_digest_get_digest(crypto_digest_t *digest,
- char *out, size_t out_len);
-crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest);
-void crypto_digest_assign(crypto_digest_t *into,
- const crypto_digest_t *from);
-void crypto_hmac_sha256(char *hmac_out,
- const char *key, size_t key_len,
- const char *msg, size_t msg_len);
-void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
- const uint8_t *key, size_t key_len,
- const uint8_t *msg, size_t msg_len);
-
-crypto_xof_t *crypto_xof_new(void);
-void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len);
-void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
-void crypto_xof_free_(crypto_xof_t *xof);
-#define crypto_xof_free(xof) \
- FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof))
-
/* Key negotiation */
#define DH_TYPE_CIRCUIT 1
#define DH_TYPE_REND 2
@@ -262,9 +148,5 @@ extern int break_strongest_rng_fallback;
#endif
#endif /* defined(CRYPTO_PRIVATE) */
-#ifdef TOR_UNIT_TESTS
-digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest);
-#endif
-
#endif /* !defined(TOR_CRYPTO_H) */
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
index 8793fa6274..ccf12d00f9 100644
--- a/src/common/crypto_curve25519.c
+++ b/src/common/crypto_curve25519.c
@@ -24,6 +24,7 @@
#include "crypto.h"
#include "crypto_curve25519.h"
#include "crypto_format.h"
+#include "crypto_digest.h"
#include "util.h"
#include "torlog.h"
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
index 11f7423b07..4834fa0836 100644
--- a/src/common/crypto_curve25519.h
+++ b/src/common/crypto_curve25519.h
@@ -6,6 +6,7 @@
#include "testsupport.h"
#include "torint.h"
+#include "crypto_digest.h"
#include "crypto_openssl_mgt.h"
/** Length of a curve25519 public key when encoded. */
diff --git a/src/common/crypto_digest.c b/src/common/crypto_digest.c
new file mode 100644
index 0000000000..cdcc1828c8
--- /dev/null
+++ b/src/common/crypto_digest.c
@@ -0,0 +1,569 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_digest.c
+ * \brief Block of functions related with digest and xof utilities and
+ * operations.
+ **/
+
+#include "crypto_digest.h"
+
+#include "crypto.h" /* common functions */
+#include "crypto_openssl_mgt.h"
+
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+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
+ * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
+ * Return 0 on success, -1 on failure.
+ */
+int
+crypto_digest(char *digest, const char *m, size_t len)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL)
+ return -1;
+ return 0;
+}
+
+/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+int
+crypto_digest256(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA256)
+ ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
+ else
+ ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
+ > -1);
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+int
+crypto_digest512(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA512)
+ ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
+ != NULL);
+ else
+ ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
+ > -1);
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Set the common_digests_t in <b>ds_out</b> to contain every digest on the
+ * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on
+ * success, -1 on failure. */
+int
+crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len)
+{
+ tor_assert(ds_out);
+ memset(ds_out, 0, sizeof(*ds_out));
+ if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
+ return -1;
+ if (crypto_digest256(ds_out->d[DIGEST_SHA256], m, len, DIGEST_SHA256) < 0)
+ return -1;
+
+ return 0;
+}
+
+/** Return the name of an algorithm, as used in directory documents. */
+const char *
+crypto_digest_algorithm_get_name(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1:
+ return "sha1";
+ case DIGEST_SHA256:
+ return "sha256";
+ case DIGEST_SHA512:
+ return "sha512";
+ case DIGEST_SHA3_256:
+ return "sha3-256";
+ case DIGEST_SHA3_512:
+ return "sha3-512";
+ // LCOV_EXCL_START
+ default:
+ tor_fragile_assert();
+ return "??unknown_digest??";
+ // LCOV_EXCL_STOP
+ }
+}
+
+/** Given the name of a digest algorithm, return its integer value, or -1 if
+ * the name is not recognized. */
+int
+crypto_digest_algorithm_parse_name(const char *name)
+{
+ if (!strcmp(name, "sha1"))
+ return DIGEST_SHA1;
+ else if (!strcmp(name, "sha256"))
+ return DIGEST_SHA256;
+ else if (!strcmp(name, "sha512"))
+ return DIGEST_SHA512;
+ else if (!strcmp(name, "sha3-256"))
+ return DIGEST_SHA3_256;
+ else if (!strcmp(name, "sha3-512"))
+ return DIGEST_SHA3_512;
+ else
+ return -1;
+}
+
+/** Given an algorithm, return the digest length in bytes. */
+size_t
+crypto_digest_algorithm_get_length(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1:
+ return DIGEST_LEN;
+ case DIGEST_SHA256:
+ return DIGEST256_LEN;
+ case DIGEST_SHA512:
+ return DIGEST512_LEN;
+ case DIGEST_SHA3_256:
+ return DIGEST256_LEN;
+ case DIGEST_SHA3_512:
+ return DIGEST512_LEN;
+ default:
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; /* Unreachable */ // LCOV_EXCL_LINE
+ }
+}
+
+/** Intermediate information about the digest of a stream of data. */
+struct crypto_digest_t {
+ digest_algorithm_t algorithm; /**< Which algorithm is in use? */
+ /** State for the digest we're using. Only one member of the
+ * union is usable, depending on the value of <b>algorithm</b>. Note also
+ * that space for other members might not even be allocated!
+ */
+ union {
+ SHA_CTX sha1; /**< state for SHA1 */
+ SHA256_CTX sha2; /**< state for SHA256 */
+ SHA512_CTX sha512; /**< state for SHA512 */
+ keccak_state sha3; /**< state for SHA3-[256,512] */
+ } d;
+};
+
+#ifdef TOR_UNIT_TESTS
+
+digest_algorithm_t
+crypto_digest_get_algorithm(crypto_digest_t *digest)
+{
+ tor_assert(digest);
+
+ return digest->algorithm;
+}
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/**
+ * Return the number of bytes we need to malloc in order to get a
+ * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
+ * when we free one.
+ */
+static size_t
+crypto_digest_alloc_bytes(digest_algorithm_t alg)
+{
+ /* Helper: returns the number of bytes in the 'f' field of 'st' */
+#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
+ /* Gives the length of crypto_digest_t through the end of the field 'd' */
+#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
+ STRUCT_FIELD_SIZE(crypto_digest_t, f))
+ switch (alg) {
+ case DIGEST_SHA1:
+ return END_OF_FIELD(d.sha1);
+ case DIGEST_SHA256:
+ return END_OF_FIELD(d.sha2);
+ case DIGEST_SHA512:
+ return END_OF_FIELD(d.sha512);
+ case DIGEST_SHA3_256:
+ case DIGEST_SHA3_512:
+ return END_OF_FIELD(d.sha3);
+ default:
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; // LCOV_EXCL_LINE
+ }
+#undef END_OF_FIELD
+#undef STRUCT_FIELD_SIZE
+}
+
+/**
+ * Internal function: create and return a new digest object for 'algorithm'.
+ * Does not typecheck the algorithm.
+ */
+static crypto_digest_t *
+crypto_digest_new_internal(digest_algorithm_t algorithm)
+{
+ crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
+ r->algorithm = algorithm;
+
+ switch (algorithm)
+ {
+ case DIGEST_SHA1:
+ SHA1_Init(&r->d.sha1);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Init(&r->d.sha2);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Init(&r->d.sha512);
+ break;
+ case DIGEST_SHA3_256:
+ keccak_digest_init(&r->d.sha3, 256);
+ break;
+ case DIGEST_SHA3_512:
+ keccak_digest_init(&r->d.sha3, 512);
+ break;
+ default:
+ tor_assert_unreached();
+ }
+
+ return r;
+}
+
+/** Allocate and return a new digest object to compute SHA1 digests.
+ */
+crypto_digest_t *
+crypto_digest_new(void)
+{
+ return crypto_digest_new_internal(DIGEST_SHA1);
+}
+
+/** Allocate and return a new digest object to compute 256-bit digests
+ * using <b>algorithm</b>. */
+crypto_digest_t *
+crypto_digest256_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Allocate and return a new digest object to compute 512-bit digests
+ * using <b>algorithm</b>. */
+crypto_digest_t *
+crypto_digest512_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Deallocate a digest object.
+ */
+void
+crypto_digest_free_(crypto_digest_t *digest)
+{
+ if (!digest)
+ return;
+ size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memwipe(digest, 0, bytes);
+ tor_free(digest);
+}
+
+/** Add <b>len</b> bytes from <b>data</b> to the digest object.
+ */
+void
+crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
+ size_t len)
+{
+ tor_assert(digest);
+ tor_assert(data);
+ /* Using the SHA*_*() calls directly means we don't support doing
+ * SHA in hardware. But so far the delay of getting the question
+ * to the hardware, and hearing the answer, is likely higher than
+ * just doing it ourselves. Hashes are fast.
+ */
+ switch (digest->algorithm) {
+ case DIGEST_SHA1:
+ SHA1_Update(&digest->d.sha1, (void*)data, len);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Update(&digest->d.sha2, (void*)data, len);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Update(&digest->d.sha512, (void*)data, len);
+ break;
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
+ break;
+ default:
+ /* LCOV_EXCL_START */
+ tor_fragile_assert();
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+}
+
+/** 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.
+ */
+void
+crypto_digest_get_digest(crypto_digest_t *digest,
+ char *out, size_t out_len)
+{
+ unsigned char r[DIGEST512_LEN];
+ crypto_digest_t tmpenv;
+ tor_assert(digest);
+ tor_assert(out);
+ tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
+
+ /* The SHA-3 code handles copying into a temporary ctx, and also can handle
+ * short output buffers by truncating appropriately. */
+ if (digest->algorithm == DIGEST_SHA3_256 ||
+ digest->algorithm == DIGEST_SHA3_512) {
+ keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
+ return;
+ }
+
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ /* memcpy into a temporary ctx, since SHA*_Final clears the context */
+ memcpy(&tmpenv, digest, alloc_bytes);
+ switch (digest->algorithm) {
+ case DIGEST_SHA1:
+ SHA1_Final(r, &tmpenv.d.sha1);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Final(r, &tmpenv.d.sha2);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Final(r, &tmpenv.d.sha512);
+ break;
+//LCOV_EXCL_START
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ default:
+ log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
+ /* This is fatal, because it should never happen. */
+ tor_assert_unreached();
+ break;
+//LCOV_EXCL_STOP
+ }
+ memcpy(out, r, out_len);
+ memwipe(r, 0, sizeof(r));
+}
+
+/** Allocate and return a new digest object with the same state as
+ * <b>digest</b>
+ */
+crypto_digest_t *
+crypto_digest_dup(const crypto_digest_t *digest)
+{
+ tor_assert(digest);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ return tor_memdup(digest, alloc_bytes);
+}
+
+/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object.
+ */
+void
+crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
+ const crypto_digest_t *digest)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ tor_assert(bytes <= sizeof(checkpoint->mem));
+ memcpy(checkpoint->mem, digest, bytes);
+}
+
+/** Restore the state of <b>digest</b> from <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object. Requires that the
+ * state was previously stored with crypto_digest_checkpoint() */
+void
+crypto_digest_restore(crypto_digest_t *digest,
+ const crypto_digest_checkpoint_t *checkpoint)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memcpy(digest, checkpoint->mem, bytes);
+}
+
+/** Replace the state of the digest object <b>into</b> with the state
+ * of the digest object <b>from</b>. Requires that 'into' and 'from'
+ * have the same digest type.
+ */
+void
+crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from)
+{
+ tor_assert(into);
+ tor_assert(from);
+ tor_assert(into->algorithm == from->algorithm);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
+ memcpy(into,from,alloc_bytes);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of those strings,
+ * plus the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>out_len</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of: the
+ * optional string <b>prepend</b>, those strings,
+ * and the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>len_out</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
+ const char *prepend,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_t *d = crypto_digest_new_internal(alg);
+ if (prepend)
+ crypto_digest_add_bytes(d, prepend, strlen(prepend));
+ SMARTLIST_FOREACH(lst, const char *, cp,
+ crypto_digest_add_bytes(d, cp, strlen(cp)));
+ if (append)
+ crypto_digest_add_bytes(d, append, strlen(append));
+ crypto_digest_get_digest(d, digest_out, len_out);
+ crypto_digest_free(d);
+}
+
+/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
+ * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
+ * result in <b>hmac_out</b>. Asserts on failure.
+ */
+void
+crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len)
+{
+ unsigned char *rv = NULL;
+ /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
+ tor_assert(key_len < INT_MAX);
+ tor_assert(msg_len < INT_MAX);
+ tor_assert(hmac_out);
+ rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
+ (unsigned char*)hmac_out, NULL);
+ tor_assert(rv);
+}
+
+/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a
+ * <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length
+ * <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in
+ * <b>mac_out</b>. This function can't fail. */
+void
+crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *msg, size_t msg_len)
+{
+ crypto_digest_t *digest;
+
+ const uint64_t key_len_netorder = tor_htonll(key_len);
+
+ tor_assert(mac_out);
+ tor_assert(key);
+ tor_assert(msg);
+
+ digest = crypto_digest256_new(DIGEST_SHA3_256);
+
+ /* Order matters here that is any subsystem using this function should
+ * expect this very precise ordering in the MAC construction. */
+ crypto_digest_add_bytes(digest, (const char *) &key_len_netorder,
+ sizeof(key_len_netorder));
+ crypto_digest_add_bytes(digest, (const char *) key, key_len);
+ crypto_digest_add_bytes(digest, (const char *) msg, msg_len);
+ crypto_digest_get_digest(digest, (char *) mac_out, len_out);
+ crypto_digest_free(digest);
+}
+
+/* xof functions */
+
+/** Internal state for a eXtendable-Output Function (XOF). */
+struct crypto_xof_t {
+ keccak_state s;
+};
+
+/** Allocate a new XOF object backed by SHAKE-256. The security level
+ * provided is a function of the length of the output used. Read and
+ * understand FIPS-202 A.2 "Additional Consideration for Extendable-Output
+ * Functions" before using this construct.
+ */
+crypto_xof_t *
+crypto_xof_new(void)
+{
+ crypto_xof_t *xof;
+ xof = tor_malloc(sizeof(crypto_xof_t));
+ keccak_xof_init(&xof->s, 256);
+ return xof;
+}
+
+/** Absorb bytes into a XOF object. Must not be called after a call to
+ * crypto_xof_squeeze_bytes() for the same instance, and will assert
+ * if attempted.
+ */
+void
+crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len)
+{
+ int i = keccak_xof_absorb(&xof->s, data, len);
+ tor_assert(i == 0);
+}
+
+/** Squeeze bytes out of a XOF object. Calling this routine will render
+ * the XOF instance ineligible to absorb further data.
+ */
+void
+crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
+{
+ int i = keccak_xof_squeeze(&xof->s, out, len);
+ tor_assert(i == 0);
+}
+
+/** Cleanse and deallocate a XOF object. */
+void
+crypto_xof_free_(crypto_xof_t *xof)
+{
+ if (!xof)
+ return;
+ memwipe(xof, 0, sizeof(crypto_xof_t));
+ tor_free(xof);
+}
+
diff --git a/src/common/crypto_digest.h b/src/common/crypto_digest.h
new file mode 100644
index 0000000000..3bd74acdfa
--- /dev/null
+++ b/src/common/crypto_digest.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_digest.h
+ *
+ * \brief Headers for crypto_digest.c
+ **/
+
+#ifndef TOR_CRYPTO_DIGEST_H
+#define TOR_CRYPTO_DIGEST_H
+
+#include <stdio.h>
+
+#include "container.h"
+#include "torint.h"
+
+/** Length of the output of our message digest. */
+#define DIGEST_LEN 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.) */
+#define DIGEST256_LEN 32
+/** Length of the output of our 64-bit optimized message digests (SHA512). */
+#define DIGEST512_LEN 64
+
+/** Length of a sha1 message digest when encoded in base32 with trailing =
+ * signs removed. */
+#define BASE32_DIGEST_LEN 32
+/** Length of a sha1 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST_LEN 27
+/** Length of a sha256 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST256_LEN 43
+/** Length of a sha512 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST512_LEN 86
+
+/** Length of hex encoding of SHA1 digest, not including final NUL. */
+#define HEX_DIGEST_LEN 40
+/** Length of hex encoding of SHA256 digest, not including final NUL. */
+#define HEX_DIGEST256_LEN 64
+/** Length of hex encoding of SHA512 digest, not including final NUL. */
+#define HEX_DIGEST512_LEN 128
+
+typedef enum {
+ DIGEST_SHA1 = 0,
+ DIGEST_SHA256 = 1,
+ DIGEST_SHA512 = 2,
+ DIGEST_SHA3_256 = 3,
+ DIGEST_SHA3_512 = 4,
+} digest_algorithm_t;
+#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1)
+#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
+
+#define DIGEST_CHECKPOINT_BYTES (SIZEOF_VOID_P + 512)
+/** Structure used to temporarily save the a digest object. Only implemented
+ * for SHA1 digest for now. */
+typedef struct crypto_digest_checkpoint_t {
+ uint8_t mem[DIGEST_CHECKPOINT_BYTES];
+} crypto_digest_checkpoint_t;
+
+/** 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.
+ **/
+typedef struct {
+ char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN];
+} common_digests_t;
+
+typedef struct crypto_digest_t crypto_digest_t;
+typedef struct crypto_xof_t crypto_xof_t;
+
+/* SHA-1 and other digests */
+int crypto_digest(char *digest, const char *m, size_t len);
+int crypto_digest256(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm);
+int crypto_digest512(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm);
+int crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len);
+void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
+ const char *prepend,
+ const struct smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg);
+void crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const struct smartlist_t *lst, const char *append,
+ digest_algorithm_t alg);
+const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
+size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg);
+int crypto_digest_algorithm_parse_name(const char *name);
+crypto_digest_t *crypto_digest_new(void);
+crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
+crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
+void crypto_digest_free_(crypto_digest_t *digest);
+#define crypto_digest_free(d) \
+ FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d))
+void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
+ size_t len);
+void crypto_digest_get_digest(crypto_digest_t *digest,
+ char *out, size_t out_len);
+crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest);
+void crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
+ const crypto_digest_t *digest);
+void crypto_digest_restore(crypto_digest_t *digest,
+ const crypto_digest_checkpoint_t *checkpoint);
+void crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from);
+void crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len);
+void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *msg, size_t msg_len);
+
+/* xof functions*/
+crypto_xof_t *crypto_xof_new(void);
+void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len);
+void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
+void crypto_xof_free_(crypto_xof_t *xof);
+#define crypto_xof_free(xof) \
+ FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof))
+
+#ifdef TOR_UNIT_TESTS
+digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest);
+#endif
+
+#endif /* !defined(TOR_CRYPTO_DIGEST_H) */
+
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index b962a59de1..f1cc0cb188 100644
--- a/src/common/crypto_ed25519.c
+++ b/src/common/crypto_ed25519.c
@@ -23,6 +23,7 @@
#include "crypto.h"
+#include "crypto_digest.h"
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c
index 1d090a8770..3f6fb9f54c 100644
--- a/src/common/crypto_format.c
+++ b/src/common/crypto_format.c
@@ -19,6 +19,7 @@
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
+#include "crypto_digest.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 12acc9331c..604fc68e97 100644
--- a/src/common/crypto_pwbox.c
+++ b/src/common/crypto_pwbox.c
@@ -11,6 +11,7 @@
#include "crypto.h"
#include "crypto_s2k.h"
#include "crypto_pwbox.h"
+#include "crypto_digest.h"
#include "di_ops.h"
#include "util.h"
#include "pwbox.h"
diff --git a/src/common/crypto_rsa.c b/src/common/crypto_rsa.c
index fa572580a4..986ccb0ee2 100644
--- a/src/common/crypto_rsa.c
+++ b/src/common/crypto_rsa.c
@@ -13,8 +13,8 @@
#include "crypto.h"
#include "compat_openssl.h"
#include "crypto_curve25519.h"
-#include "crypto_ed25519.h"
#include "crypto_format.h"
+#include "crypto_digest.h"
DISABLE_GCC_WARNING(redundant-decls)
@@ -627,6 +627,148 @@ crypto_pk_copy_full(crypto_pk_t *env)
return crypto_new_pk_from_rsa_(new_key);
}
+/** Perform a hybrid (public/secret) encryption on <b>fromlen</b>
+ * bytes of data from <b>from</b>, with padding type 'padding',
+ * storing the results on <b>to</b>.
+ *
+ * Returns the number of bytes written on success, -1 on failure.
+ *
+ * The encrypted data consists of:
+ * - The source data, padded and encrypted with the public key, if the
+ * padded source data is no longer than the public key, and <b>force</b>
+ * is false, OR
+ * - The beginning of the source data prefixed with a 16-byte symmetric key,
+ * padded and encrypted with the public key; followed by the rest of
+ * the source data encrypted in AES-CTR mode with the symmetric key.
+ *
+ * NOTE that this format does not authenticate the symmetrically encrypted
+ * part of the data, and SHOULD NOT BE USED for new protocols.
+ */
+int
+crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env,
+ char *to, size_t tolen,
+ const char *from,
+ size_t fromlen,
+ int padding, int force)
+{
+ int overhead, outlen, r;
+ size_t pkeylen, symlen;
+ crypto_cipher_t *cipher = NULL;
+ char *buf = NULL;
+
+ tor_assert(env);
+ tor_assert(from);
+ tor_assert(to);
+ tor_assert(fromlen < SIZE_T_CEILING);
+
+ overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding));
+ pkeylen = crypto_pk_keysize(env);
+
+ if (!force && fromlen+overhead <= pkeylen) {
+ /* It all fits in a single encrypt. */
+ return crypto_pk_public_encrypt(env,to,
+ tolen,
+ from,fromlen,padding);
+ }
+ tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN);
+ tor_assert(tolen >= pkeylen);
+
+ char key[CIPHER_KEY_LEN];
+ crypto_rand(key, sizeof(key)); /* generate a new key. */
+ cipher = crypto_cipher_new(key);
+
+ buf = tor_malloc(pkeylen+1);
+ memcpy(buf, key, CIPHER_KEY_LEN);
+ memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN);
+
+ /* Length of symmetrically encrypted data. */
+ symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN);
+
+ outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding);
+ if (outlen!=(int)pkeylen) {
+ goto err;
+ }
+ r = crypto_cipher_encrypt(cipher, to+outlen,
+ from+pkeylen-overhead-CIPHER_KEY_LEN, symlen);
+
+ if (r<0) goto err;
+ memwipe(buf, 0, pkeylen);
+ memwipe(key, 0, sizeof(key));
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ tor_assert(outlen+symlen < INT_MAX);
+ return (int)(outlen + symlen);
+ err:
+
+ memwipe(buf, 0, pkeylen);
+ memwipe(key, 0, sizeof(key));
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ return -1;
+}
+
+/** Invert crypto_pk_obsolete_public_hybrid_encrypt. Returns the number of
+ * bytes written on success, -1 on failure.
+ *
+ * NOTE that this format does not authenticate the symmetrically encrypted
+ * part of the data, and SHOULD NOT BE USED for new protocols.
+ */
+int
+crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env,
+ char *to,
+ size_t tolen,
+ const char *from,
+ size_t fromlen,
+ int padding, int warnOnFailure)
+{
+ int outlen, r;
+ size_t pkeylen;
+ crypto_cipher_t *cipher = NULL;
+ char *buf = NULL;
+
+ tor_assert(fromlen < SIZE_T_CEILING);
+ pkeylen = crypto_pk_keysize(env);
+
+ if (fromlen <= pkeylen) {
+ return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding,
+ warnOnFailure);
+ }
+
+ buf = tor_malloc(pkeylen);
+ outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding,
+ warnOnFailure);
+ if (outlen<0) {
+ log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
+ "Error decrypting public-key data");
+ goto err;
+ }
+ if (outlen < CIPHER_KEY_LEN) {
+ log_fn(warnOnFailure?LOG_WARN:LOG_INFO, LD_CRYPTO,
+ "No room for a symmetric key");
+ goto err;
+ }
+ cipher = crypto_cipher_new(buf);
+ if (!cipher) {
+ goto err;
+ }
+ memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN);
+ outlen -= CIPHER_KEY_LEN;
+ tor_assert(tolen - outlen >= fromlen - pkeylen);
+ r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen);
+ if (r<0)
+ goto err;
+ memwipe(buf,0,pkeylen);
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ tor_assert(outlen + fromlen < INT_MAX);
+ return (int)(outlen + (fromlen-pkeylen));
+ err:
+ memwipe(buf,0,pkeylen);
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ return -1;
+}
+
/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
* in <b>env</b>, using the padding method <b>padding</b>. On success,
* write the result to <b>to</b>, and return the number of bytes
@@ -849,6 +991,122 @@ crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
return 0;
}
+/** Check a siglen-byte long signature at <b>sig</b> against
+ * <b>datalen</b> bytes of data at <b>data</b>, using the public key
+ * in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for
+ * SHA1(data). Else return -1.
+ */
+MOCK_IMPL(int,
+crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data,
+ size_t datalen, const char *sig,
+ size_t siglen))
+{
+ char digest[DIGEST_LEN];
+ char *buf;
+ size_t buflen;
+ int r;
+
+ tor_assert(env);
+ tor_assert(data);
+ tor_assert(sig);
+ tor_assert(datalen < SIZE_T_CEILING);
+ tor_assert(siglen < SIZE_T_CEILING);
+
+ if (crypto_digest(digest,data,datalen)<0) {
+ log_warn(LD_BUG, "couldn't compute digest");
+ return -1;
+ }
+ buflen = crypto_pk_keysize(env);
+ buf = tor_malloc(buflen);
+ r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
+ if (r != DIGEST_LEN) {
+ log_warn(LD_CRYPTO, "Invalid signature");
+ tor_free(buf);
+ return -1;
+ }
+ if (tor_memneq(buf, digest, DIGEST_LEN)) {
+ log_warn(LD_CRYPTO, "Signature mismatched with digest.");
+ tor_free(buf);
+ return -1;
+ }
+ tor_free(buf);
+
+ return 0;
+}
+
+/** Compute a SHA1 digest of <b>fromlen</b> bytes of data stored at
+ * <b>from</b>; sign the data with the private key in <b>env</b>, and
+ * store it in <b>to</b>. Return the number of bytes written on
+ * success, and -1 on failure.
+ *
+ * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
+ * at least the length of the modulus of <b>env</b>.
+ */
+int
+crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen)
+{
+ int r;
+ char digest[DIGEST_LEN];
+ if (crypto_digest(digest,from,fromlen)<0)
+ return -1;
+ r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN);
+ memwipe(digest, 0, sizeof(digest));
+ return r;
+}
+
+/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
+ * public key into <b>digest_out</b> (must have DIGEST_LEN bytes of space).
+ * Return 0 on success, -1 on failure.
+ */
+int
+crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
+{
+ char *buf;
+ size_t buflen;
+ int len;
+ int rv = -1;
+
+ buflen = crypto_pk_keysize(pk)*2;
+ buf = tor_malloc(buflen);
+ len = crypto_pk_asn1_encode(pk, buf, buflen);
+ if (len < 0)
+ goto done;
+
+ if (crypto_digest(digest_out, buf, len) < 0)
+ goto done;
+
+ rv = 0;
+ done:
+ tor_free(buf);
+ return rv;
+}
+
+/** Compute all digests of the DER encoding of <b>pk</b>, and store them
+ * in <b>digests_out</b>. Return 0 on success, -1 on failure. */
+int
+crypto_pk_get_common_digests(crypto_pk_t *pk, common_digests_t *digests_out)
+{
+ char *buf;
+ size_t buflen;
+ int len;
+ int rv = -1;
+
+ buflen = crypto_pk_keysize(pk)*2;
+ buf = tor_malloc(buflen);
+ len = crypto_pk_asn1_encode(pk, buf, buflen);
+ if (len < 0)
+ goto done;
+
+ if (crypto_common_digests(digests_out, (char*)buf, len) < 0)
+ goto done;
+
+ rv = 0;
+ done:
+ tor_free(buf);
+ return rv;
+}
+
/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the
* Base64 encoding of the DER representation of the private key as a NUL
* terminated string, and return it via <b>priv_out</b>. Return 0 on
diff --git a/src/common/crypto_rsa.h b/src/common/crypto_rsa.h
index 5b9025c629..2f5442a5d2 100644
--- a/src/common/crypto_rsa.h
+++ b/src/common/crypto_rsa.h
@@ -15,13 +15,13 @@
#include "orconfig.h"
+#include "crypto_digest.h"
#include <stdio.h>
#include "torint.h"
#include "testsupport.h"
#include "compat.h"
#include "util.h"
#include "torlog.h"
-#include "crypto_curve25519.h"
/** Length of our public keys. */
#define PK_BYTES (1024/8)
@@ -69,6 +69,14 @@ crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig);
crypto_pk_t *crypto_pk_copy_full(crypto_pk_t *orig);
int crypto_pk_key_is_private(const crypto_pk_t *key);
int crypto_pk_public_exponent_ok(crypto_pk_t *env);
+int crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen,
+ int padding, int force);
+int crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen,
+ int padding, int warnOnFailure);
int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen, int padding);
int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen,
@@ -84,6 +92,13 @@ crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out);
+MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env,
+ const char *data, size_t datalen, const char *sig, size_t siglen));
+int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen);
+int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out);
+int crypto_pk_get_common_digests(crypto_pk_t *pk,
+ common_digests_t *digests_out);
int crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out);
crypto_pk_t *crypto_pk_base64_decode(const char *str, size_t len);
diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c
index b2fcca54c4..316445e40f 100644
--- a/src/common/crypto_s2k.c
+++ b/src/common/crypto_s2k.c
@@ -16,6 +16,7 @@
#include "util.h"
#include "compat.h"
#include "crypto_s2k.h"
+#include "crypto_digest.h"
#include <openssl/evp.h>
diff --git a/src/common/include.am b/src/common/include.am
index 6945285108..73c51ff0b2 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -114,6 +114,7 @@ LIBOR_CRYPTO_A_SRC = \
src/common/compress_zlib.c \
src/common/compress_zstd.c \
src/common/crypto.c \
+ src/common/crypto_digest.c \
src/common/crypto_rsa.c \
src/common/crypto_openssl_mgt.c \
src/common/crypto_pwbox.c \
@@ -165,6 +166,7 @@ COMMONHEADERS = \
src/common/confline.h \
src/common/container.h \
src/common/crypto.h \
+ src/common/crypto_digest.h \
src/common/crypto_curve25519.h \
src/common/crypto_ed25519.h \
src/common/crypto_format.h \
diff --git a/src/common/log.c b/src/common/log.c
index 9f4a8b2bc2..922e9dd38f 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -52,6 +52,13 @@
#define raw_assert(x) assert(x) // assert OK
+/** Defining compile-time constants for Tor log levels (used by the Rust
+ * log wrapper at src/rust/tor_log) */
+const int LOG_WARN_ = LOG_WARN;
+const int LOG_NOTICE_ = LOG_NOTICE;
+const log_domain_mask_t LD_GENERAL_ = LD_GENERAL;
+const log_domain_mask_t LD_NET_ = LD_NET;
+
/** Information for a single logfile; only used in log.c */
typedef struct logfile_t {
struct logfile_t *next; /**< Next logfile_t in the linked list. */
@@ -225,6 +232,30 @@ log_set_application_name(const char *name)
appname = name ? tor_strdup(name) : NULL;
}
+/** Return true if some of the running logs might be interested in a log
+ * message of the given severity in the given domains. If this function
+ * returns true, the log message might be ignored anyway, but if it returns
+ * false, it is definitely_ safe not to log the message. */
+int
+log_message_is_interesting(int severity, log_domain_mask_t domain)
+{
+ (void) domain;
+ return (severity <= log_global_min_severity_);
+}
+
+/**
+ * As tor_log, but takes an optional function name, and does not treat its
+ * <b>string</b> as a printf format.
+ *
+ * For use by Rust integration.
+ */
+void
+tor_log_string(int severity, log_domain_mask_t domain,
+ const char *function, const char *string)
+{
+ log_fn_(severity, domain, function, "%s", string);
+}
+
/** Log time granularity in milliseconds. */
static int log_time_granularity = 1;
diff --git a/src/common/procmon.c b/src/common/procmon.c
index abcbbeaa21..73c14cd584 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -10,8 +10,6 @@
#include "util.h"
-#include <event2/event.h>
-
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
@@ -44,7 +42,7 @@ typedef int pid_t;
/* Currently we need to poll in some way on all systems. */
#ifdef PROCMON_POLLS
-static void tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
+static void tor_process_monitor_poll_cb(periodic_timer_t *ev,
void *procmon_);
#endif
@@ -136,7 +134,7 @@ struct tor_process_monitor_t {
/** A Libevent event structure, to either poll for the process's
* existence or receive a notification when the process ends. */
- struct event *e;
+ periodic_timer_t *e;
/** A callback to be called when the process ends. */
tor_procmon_callback_t cb;
@@ -159,9 +157,6 @@ tor_validate_process_specifier(const char *process_spec,
return parse_process_specifier(process_spec, &ppspec, msg);
}
-/* XXXX we should use periodic_timer_new() for this stuff */
-#define PERIODIC_TIMER_FLAGS EV_PERSIST
-
/* DOCDOC poll_interval_tv */
static const struct timeval poll_interval_tv = {15, 0};
@@ -225,13 +220,9 @@ tor_process_monitor_new(struct event_base *base,
procmon->cb_arg = cb_arg;
#ifdef PROCMON_POLLS
- procmon->e = tor_event_new(base, -1 /* no FD */, PERIODIC_TIMER_FLAGS,
- tor_process_monitor_poll_cb, procmon);
- /* Note: If you port this file to plain Libevent 2, check that
- * procmon->e is non-NULL. We don't need to here because
- * tor_evtimer_new never returns NULL. */
-
- evtimer_add(procmon->e, &poll_interval_tv);
+ procmon->e = periodic_timer_new(base,
+ &poll_interval_tv,
+ tor_process_monitor_poll_cb, procmon);
#else /* !(defined(PROCMON_POLLS)) */
#error OOPS?
#endif /* defined(PROCMON_POLLS) */
@@ -246,14 +237,12 @@ tor_process_monitor_new(struct event_base *base,
/** Libevent callback to poll for the existence of the process
* monitored by <b>procmon_</b>. */
static void
-tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
- void *procmon_)
+tor_process_monitor_poll_cb(periodic_timer_t *event, void *procmon_)
{
+ (void)event;
tor_process_monitor_t *procmon = (tor_process_monitor_t *)(procmon_);
int its_dead_jim;
- (void)unused1; (void)unused2;
-
tor_assert(procmon != NULL);
#ifdef _WIN32
@@ -336,7 +325,7 @@ tor_process_monitor_free_(tor_process_monitor_t *procmon)
#endif
if (procmon->e != NULL)
- tor_event_free(procmon->e);
+ periodic_timer_free(procmon->e);
tor_free(procmon);
}
diff --git a/src/common/timers.c b/src/common/timers.c
index 552080b11e..a90817da1c 100644
--- a/src/common/timers.c
+++ b/src/common/timers.c
@@ -37,8 +37,6 @@
#include "torlog.h"
#include "util.h"
-#include <event2/event.h>
-
struct timeout_cb {
timer_cb_fn_t cb;
void *arg;
@@ -69,7 +67,7 @@ struct timeout_cb {
#include "src/ext/timeouts/timeout.c"
static struct timeouts *global_timeouts = NULL;
-static struct event *global_timer_event = NULL;
+static struct mainloop_event_t *global_timer_event = NULL;
static monotime_t start_of_time;
@@ -147,7 +145,7 @@ libevent_timer_reschedule(void)
if (delay > MIN_CHECK_TICKS)
delay = MIN_CHECK_TICKS;
timeout_to_tv(delay, &d);
- event_add(global_timer_event, &d);
+ mainloop_event_schedule(global_timer_event, &d);
}
/** Run the callback of every timer that has expired, based on the current
@@ -170,10 +168,9 @@ timers_run_pending(void)
* have fired, activate their callbacks, and reschedule the libevent timer.
*/
static void
-libevent_timer_callback(evutil_socket_t fd, short what, void *arg)
+libevent_timer_callback(mainloop_event_t *ev, void *arg)
{
- (void)fd;
- (void)what;
+ (void)ev;
(void)arg;
timers_run_pending();
@@ -203,9 +200,8 @@ timers_initialize(void)
monotime_init();
monotime_get(&start_of_time);
- struct event *timer_event;
- timer_event = tor_event_new(tor_libevent_get_base(),
- -1, 0, libevent_timer_callback, NULL);
+ mainloop_event_t *timer_event;
+ timer_event = mainloop_event_new(libevent_timer_callback, NULL);
tor_assert(timer_event);
global_timer_event = timer_event;
@@ -219,7 +215,7 @@ void
timers_shutdown(void)
{
if (global_timer_event) {
- tor_event_free(global_timer_event);
+ mainloop_event_free(global_timer_event);
global_timer_event = NULL;
}
if (global_timeouts) {
diff --git a/src/common/torlog.h b/src/common/torlog.h
index cadfe3b879..ac632ff521 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -191,6 +191,10 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
const char *format, ...)
CHECK_PRINTF(5,6);
+int log_message_is_interesting(int severity, log_domain_mask_t domain);
+void tor_log_string(int severity, log_domain_mask_t domain,
+ const char *function, const char *string);
+
#if defined(__GNUC__) && __GNUC__ <= 3
/* These are the GCC varidaic macros, so that older versions of GCC don't
@@ -248,6 +252,16 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
args, ##__VA_ARGS__)
#endif /* defined(__GNUC__) && __GNUC__ <= 3 */
+/** This defines log levels that are linked in the Rust log module, rather
+ * than re-defining these in both Rust and C.
+ *
+ * C_RUST_COUPLED src/rust/tor_log LogSeverity, LogDomain
+ */
+extern const int LOG_WARN_;
+extern const int LOG_NOTICE_;
+extern const log_domain_mask_t LD_NET_;
+extern const log_domain_mask_t LD_GENERAL_;
+
#ifdef LOG_PRIVATE
MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format,
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 50609b8ac7..05e29e22ff 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -25,6 +25,7 @@
#include <ws2tcpip.h>
#endif
+#include "crypto.h"
#include "compat.h"
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
@@ -32,7 +33,6 @@
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/opensslv.h>
-#include "crypto.h"
#ifdef OPENSSL_NO_EC
#error "We require OpenSSL with ECC support"
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 1dbf0b332f..7c867bfff2 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -11,7 +11,7 @@
* \brief Headers for tortls.c
**/
-#include "crypto.h"
+#include "crypto_rsa.h"
#include "compat_openssl.h"
#include "compat.h"
#include "testsupport.h"
diff --git a/src/common/util.c b/src/common/util.c
index a68fd30d09..065b3245fe 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -16,7 +16,7 @@
#define UTIL_PRIVATE
#include "util.h"
#include "torlog.h"
-#include "crypto.h"
+#include "crypto_digest.h"
#include "torint.h"
#include "container.h"
#include "address.h"
@@ -5111,30 +5111,6 @@ stream_status_to_string(enum stream_status stream_status)
}
}
-/* DOCDOC */
-static void
-log_portfw_spawn_error_message(const char *buf,
- const char *executable, int *child_status)
-{
- /* Parse error message */
- int retval, child_state, saved_errno;
- retval = tor_sscanf(buf, SPAWN_ERROR_MESSAGE "%x/%x",
- &child_state, &saved_errno);
- if (retval == 2) {
- log_warn(LD_GENERAL,
- "Failed to start child process \"%s\" in state %d: %s",
- executable, child_state, strerror(saved_errno));
- if (child_status)
- *child_status = 1;
- } else {
- /* Failed to parse message from child process, log it as a
- warning */
- log_warn(LD_GENERAL,
- "Unexpected message from port forwarding helper \"%s\": %s",
- executable, buf);
- }
-}
-
#ifdef _WIN32
/** Return a smartlist containing lines outputted from
@@ -5254,42 +5230,6 @@ tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out))
return lines;
}
-/** Read from fd, and send lines to log at the specified log level.
- * Returns 1 if stream is closed normally, -1 if there is a error reading, and
- * 0 otherwise. Handles lines from tor-fw-helper and
- * tor_spawn_background() specially.
- */
-static int
-log_from_pipe(int fd, int severity, const char *executable,
- int *child_status)
-{
- char buf[256];
- enum stream_status r;
-
- for (;;) {
- r = get_string_from_pipe(fd, buf, sizeof(buf) - 1);
-
- if (r == IO_STREAM_CLOSED) {
- return 1;
- } else if (r == IO_STREAM_EAGAIN) {
- return 0;
- } else if (r == IO_STREAM_TERM) {
- return -1;
- }
-
- tor_assert(r == IO_STREAM_OKAY);
-
- /* Check if buf starts with SPAWN_ERROR_MESSAGE */
- if (strcmpstart(buf, SPAWN_ERROR_MESSAGE) == 0) {
- log_portfw_spawn_error_message(buf, executable, child_status);
- } else {
- log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", buf);
- }
- }
-
- /* We should never get here */
- return -1;
-}
#endif /* defined(_WIN32) */
/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making
@@ -5332,294 +5272,6 @@ get_string_from_pipe(int fd, char *buf_out, size_t count)
return IO_STREAM_OKAY;
}
-/** Parse a <b>line</b> from tor-fw-helper and issue an appropriate
- * log message to our user. */
-static void
-handle_fw_helper_line(const char *executable, const char *line)
-{
- smartlist_t *tokens = smartlist_new();
- char *message = NULL;
- char *message_for_log = NULL;
- const char *external_port = NULL;
- const char *internal_port = NULL;
- const char *result = NULL;
- int port = 0;
- int success = 0;
-
- if (strcmpstart(line, SPAWN_ERROR_MESSAGE) == 0) {
- /* We need to check for SPAWN_ERROR_MESSAGE again here, since it's
- * possible that it got sent after we tried to read it in log_from_pipe.
- *
- * XXX Ideally, we should be using one of stdout/stderr for the real
- * output, and one for the output of the startup code. We used to do that
- * before cd05f35d2c.
- */
- int child_status;
- log_portfw_spawn_error_message(line, executable, &child_status);
- goto done;
- }
-
- smartlist_split_string(tokens, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
-
- if (smartlist_len(tokens) < 5)
- goto err;
-
- if (strcmp(smartlist_get(tokens, 0), "tor-fw-helper") ||
- strcmp(smartlist_get(tokens, 1), "tcp-forward"))
- goto err;
-
- external_port = smartlist_get(tokens, 2);
- internal_port = smartlist_get(tokens, 3);
- result = smartlist_get(tokens, 4);
-
- if (smartlist_len(tokens) > 5) {
- /* If there are more than 5 tokens, they are part of [<message>].
- Let's use a second smartlist to form the whole message;
- strncat loops suck. */
- int i;
- int message_words_n = smartlist_len(tokens) - 5;
- smartlist_t *message_sl = smartlist_new();
- for (i = 0; i < message_words_n; i++)
- smartlist_add(message_sl, smartlist_get(tokens, 5+i));
-
- tor_assert(smartlist_len(message_sl) > 0);
- message = smartlist_join_strings(message_sl, " ", 0, NULL);
-
- /* wrap the message in log-friendly wrapping */
- tor_asprintf(&message_for_log, " ('%s')", message);
-
- smartlist_free(message_sl);
- }
-
- port = atoi(external_port);
- if (port < 1 || port > 65535)
- goto err;
-
- port = atoi(internal_port);
- if (port < 1 || port > 65535)
- goto err;
-
- if (!strcmp(result, "SUCCESS"))
- success = 1;
- else if (!strcmp(result, "FAIL"))
- success = 0;
- else
- goto err;
-
- if (!success) {
- log_warn(LD_GENERAL, "Tor was unable to forward TCP port '%s' to '%s'%s. "
- "Please make sure that your router supports port "
- "forwarding protocols (like NAT-PMP). Note that if '%s' is "
- "your ORPort, your relay will be unable to receive inbound "
- "traffic.", external_port, internal_port,
- message_for_log ? message_for_log : "",
- internal_port);
- } else {
- log_info(LD_GENERAL,
- "Tor successfully forwarded TCP port '%s' to '%s'%s.",
- external_port, internal_port,
- message_for_log ? message_for_log : "");
- }
-
- goto done;
-
- err:
- log_warn(LD_GENERAL, "tor-fw-helper sent us a string we could not "
- "parse (%s).", line);
-
- done:
- SMARTLIST_FOREACH(tokens, char *, cp, tor_free(cp));
- smartlist_free(tokens);
- tor_free(message);
- tor_free(message_for_log);
-}
-
-/** Read what tor-fw-helper has to say in its stdout and handle it
- * appropriately */
-static int
-handle_fw_helper_output(const char *executable,
- process_handle_t *process_handle)
-{
- smartlist_t *fw_helper_output = NULL;
- enum stream_status stream_status = 0;
-
- fw_helper_output =
- tor_get_lines_from_handle(tor_process_get_stdout_pipe(process_handle),
- &stream_status);
- if (!fw_helper_output) { /* didn't get any output from tor-fw-helper */
- /* if EAGAIN we should retry in the future */
- return (stream_status == IO_STREAM_EAGAIN) ? 0 : -1;
- }
-
- /* Handle the lines we got: */
- SMARTLIST_FOREACH_BEGIN(fw_helper_output, char *, line) {
- handle_fw_helper_line(executable, line);
- tor_free(line);
- } SMARTLIST_FOREACH_END(line);
-
- smartlist_free(fw_helper_output);
-
- return 0;
-}
-
-/** Spawn tor-fw-helper and ask it to forward the ports in
- * <b>ports_to_forward</b>. <b>ports_to_forward</b> contains strings
- * of the form "<external port>:<internal port>", which is the format
- * that tor-fw-helper expects. */
-void
-tor_check_port_forwarding(const char *filename,
- smartlist_t *ports_to_forward,
- time_t now)
-{
-/* When fw-helper succeeds, how long do we wait until running it again */
-#define TIME_TO_EXEC_FWHELPER_SUCCESS 300
-/* When fw-helper failed to start, how long do we wait until running it again
- */
-#define TIME_TO_EXEC_FWHELPER_FAIL 60
-
- /* Static variables are initialized to zero, so child_handle.status=0
- * which corresponds to it not running on startup */
- static process_handle_t *child_handle=NULL;
-
- static time_t time_to_run_helper = 0;
- int stderr_status, retval;
- int stdout_status = 0;
-
- tor_assert(filename);
-
- /* Start the child, if it is not already running */
- if ((!child_handle || child_handle->status != PROCESS_STATUS_RUNNING) &&
- time_to_run_helper < now) {
- /*tor-fw-helper cli looks like this: tor_fw_helper -p :5555 -p 4555:1111 */
- const char **argv; /* cli arguments */
- int args_n, status;
- int argv_index = 0; /* index inside 'argv' */
-
- tor_assert(smartlist_len(ports_to_forward) > 0);
-
- /* check for overflow during 'argv' allocation:
- (len(ports_to_forward)*2 + 2)*sizeof(char*) > SIZE_MAX ==
- len(ports_to_forward) > (((SIZE_MAX/sizeof(char*)) - 2)/2) */
- if ((size_t) smartlist_len(ports_to_forward) >
- (((SIZE_MAX/sizeof(char*)) - 2)/2)) {
- log_warn(LD_GENERAL,
- "Overflow during argv allocation. This shouldn't happen.");
- return;
- }
- /* check for overflow during 'argv_index' increase:
- ((len(ports_to_forward)*2 + 2) > INT_MAX) ==
- len(ports_to_forward) > (INT_MAX - 2)/2 */
- if (smartlist_len(ports_to_forward) > (INT_MAX - 2)/2) {
- log_warn(LD_GENERAL,
- "Overflow during argv_index increase. This shouldn't happen.");
- return;
- }
-
- /* Calculate number of cli arguments: one for the filename, two
- for each smartlist element (one for "-p" and one for the
- ports), and one for the final NULL. */
- args_n = 1 + 2*smartlist_len(ports_to_forward) + 1;
- argv = tor_calloc(args_n, sizeof(char *));
-
- argv[argv_index++] = filename;
- SMARTLIST_FOREACH_BEGIN(ports_to_forward, const char *, port) {
- argv[argv_index++] = "-p";
- argv[argv_index++] = port;
- } SMARTLIST_FOREACH_END(port);
- argv[argv_index] = NULL;
-
- /* Assume tor-fw-helper will succeed, start it later*/
- time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS;
-
- if (child_handle) {
- tor_process_handle_destroy(child_handle, 1);
- child_handle = NULL;
- }
-
-#ifdef _WIN32
- /* Passing NULL as lpApplicationName makes Windows search for the .exe */
- status = tor_spawn_background(NULL, argv, NULL, &child_handle);
-#else
- status = tor_spawn_background(filename, argv, NULL, &child_handle);
-#endif /* defined(_WIN32) */
-
- tor_free_((void*)argv);
- argv=NULL;
-
- if (PROCESS_STATUS_ERROR == status) {
- log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",
- filename);
- time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
- return;
- }
-
- log_info(LD_GENERAL,
- "Started port forwarding helper (%s) with pid '%d'",
- filename, tor_process_get_pid(child_handle));
- }
-
- /* If child is running, read from its stdout and stderr) */
- if (child_handle && PROCESS_STATUS_RUNNING == child_handle->status) {
- /* Read from stdout/stderr and log result */
- retval = 0;
-#ifdef _WIN32
- stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO);
-#else
- stderr_status = log_from_pipe(child_handle->stderr_pipe,
- LOG_INFO, filename, &retval);
-#endif /* defined(_WIN32) */
- if (handle_fw_helper_output(filename, child_handle) < 0) {
- log_warn(LD_GENERAL, "Failed to handle fw helper output.");
- stdout_status = -1;
- retval = -1;
- }
-
- if (retval) {
- /* There was a problem in the child process */
- time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
- }
-
- /* Combine the two statuses in order of severity */
- if (-1 == stdout_status || -1 == stderr_status)
- /* There was a failure */
- retval = -1;
-#ifdef _WIN32
- else if (!child_handle || tor_get_exit_code(child_handle, 0, NULL) !=
- PROCESS_EXIT_RUNNING) {
- /* process has exited or there was an error */
- /* TODO: Do something with the process return value */
- /* TODO: What if the process output something since
- * between log_from_handle and tor_get_exit_code? */
- retval = 1;
- }
-#else /* !(defined(_WIN32)) */
- else if (1 == stdout_status || 1 == stderr_status)
- /* stdout or stderr was closed, the process probably
- * exited. It will be reaped by waitpid() in main.c */
- /* TODO: Do something with the process return value */
- retval = 1;
-#endif /* defined(_WIN32) */
- else
- /* Both are fine */
- retval = 0;
-
- /* If either pipe indicates a failure, act on it */
- if (0 != retval) {
- if (1 == retval) {
- log_info(LD_GENERAL, "Port forwarding helper terminated");
- child_handle->status = PROCESS_STATUS_NOTRUNNING;
- } else {
- log_warn(LD_GENERAL, "Failed to read from port forwarding helper");
- child_handle->status = PROCESS_STATUS_ERROR;
- }
-
- /* TODO: The child might not actually be finished (maybe it failed or
- closed stdout/stderr), so maybe we shouldn't start another? */
- }
- }
-}
-
/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */
void
tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed)
diff --git a/src/common/util.h b/src/common/util.h
index 9380789128..ae27e5f016 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -73,9 +73,9 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
} \
STMT_END
#else /* !(defined(USE_DMALLOC)) */
-/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup, etc.
- * Unlike the free() function, tor_free() will still work on NULL pointers,
- * and it sets the pointer value to NULL after freeing it.
+/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup,
+ * etc. Unlike the free() function, the tor_free() macro sets the
+ * pointer value to NULL after freeing it.
*
* This is a macro. If you need a function pointer to release memory from
* tor_malloc(), use tor_free_().
@@ -88,17 +88,13 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
#ifdef __GNUC__
#define tor_free(p) STMT_BEGIN \
typeof(&(p)) tor_free__tmpvar = &(p); \
- if (PREDICT_LIKELY((*tor_free__tmpvar)!=NULL)) { \
- raw_free(*tor_free__tmpvar); \
- *tor_free__tmpvar=NULL; \
- } \
+ raw_free(*tor_free__tmpvar); \
+ *tor_free__tmpvar=NULL; \
STMT_END
#else
#define tor_free(p) STMT_BEGIN \
- if (PREDICT_LIKELY((p)!=NULL)) { \
- raw_free(p); \
- (p)=NULL; \
- } \
+ raw_free(p); \
+ (p)=NULL; \
STMT_END
#endif
#endif /* defined(USE_DMALLOC) */
@@ -418,11 +414,6 @@ void start_daemon(void);
void finish_daemon(const char *desired_cwd);
int write_pidfile(const char *filename);
-/* Port forwarding */
-void tor_check_port_forwarding(const char *filename,
- struct smartlist_t *ports_to_forward,
- time_t now);
-
void tor_disable_spawning_background_processes(void);
typedef struct process_handle_t process_handle_t;
@@ -461,9 +452,7 @@ void set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
void (*free_old)(void*),
int free_p);
-/* Values of process_handle_t.status. PROCESS_STATUS_NOTRUNNING must be
- * 0 because tor_check_port_forwarding depends on this being the initial
- * statue of the static instance of process_handle_t */
+/* Values of process_handle_t.status. */
#define PROCESS_STATUS_NOTRUNNING 0
#define PROCESS_STATUS_RUNNING 1
#define PROCESS_STATUS_ERROR -1
diff --git a/src/common/workqueue.c b/src/common/workqueue.c
index ec96959b7d..12e31414e7 100644
--- a/src/common/workqueue.c
+++ b/src/common/workqueue.c
@@ -1,3 +1,4 @@
+
/* copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
@@ -24,6 +25,7 @@
#include "orconfig.h"
#include "compat.h"
+#include "compat_libevent.h"
#include "compat_threads.h"
#include "crypto.h"
#include "util.h"
@@ -31,6 +33,8 @@
#include "tor_queue.h"
#include "torlog.h"
+#include <event2/event.h>
+
#define WORKQUEUE_PRIORITY_FIRST WQ_PRI_HIGH
#define WORKQUEUE_PRIORITY_LAST WQ_PRI_LOW
#define WORKQUEUE_N_PRIORITIES (((int) WORKQUEUE_PRIORITY_LAST)+1)
@@ -63,6 +67,9 @@ struct threadpool_s {
void (*free_update_arg_fn)(void *);
/** Array of n_threads update arguments. */
void **update_args;
+ /** Event to notice when another thread has sent a reply. */
+ struct event *reply_event;
+ void (*reply_cb)(threadpool_t *);
/** Number of elements in threads. */
int n_threads;
@@ -597,15 +604,41 @@ replyqueue_new(uint32_t alertsocks_flags)
return rq;
}
-/**
- * Return the "read socket" for a given reply queue. The main thread should
- * listen for read events on this socket, and call replyqueue_process() every
- * time it triggers.
+/** Internal: Run from the libevent mainloop when there is work to handle in
+ * the reply queue handler. */
+static void
+reply_event_cb(evutil_socket_t sock, short events, void *arg)
+{
+ threadpool_t *tp = arg;
+ (void) sock;
+ (void) events;
+ replyqueue_process(tp->reply_queue);
+ if (tp->reply_cb)
+ tp->reply_cb(tp);
+}
+
+/** Register the threadpool <b>tp</b>'s reply queue with the libevent
+ * mainloop of <b>base</b>. If <b>tp</b> is provided, it is run after
+ * each time there is work to process from the reply queue. Return 0 on
+ * success, -1 on failure.
*/
-tor_socket_t
-replyqueue_get_socket(replyqueue_t *rq)
+int
+threadpool_register_reply_event(threadpool_t *tp,
+ void (*cb)(threadpool_t *tp))
{
- return rq->alert.read_fd;
+ struct event_base *base = tor_libevent_get_base();
+
+ if (tp->reply_event) {
+ tor_event_free(tp->reply_event);
+ }
+ tp->reply_event = tor_event_new(base,
+ tp->reply_queue->alert.read_fd,
+ EV_READ|EV_PERSIST,
+ reply_event_cb,
+ tp);
+ tor_assert(tp->reply_event);
+ tp->reply_cb = cb;
+ return event_add(tp->reply_event, NULL);
}
/**
diff --git a/src/common/workqueue.h b/src/common/workqueue.h
index eb885e680d..e1fe612e2b 100644
--- a/src/common/workqueue.h
+++ b/src/common/workqueue.h
@@ -56,8 +56,11 @@ threadpool_t *threadpool_new(int n_threads,
replyqueue_t *threadpool_get_replyqueue(threadpool_t *tp);
replyqueue_t *replyqueue_new(uint32_t alertsocks_flags);
-tor_socket_t replyqueue_get_socket(replyqueue_t *rq);
void replyqueue_process(replyqueue_t *queue);
+struct event_base;
+int threadpool_register_reply_event(threadpool_t *tp,
+ void (*cb)(threadpool_t *tp));
+
#endif /* !defined(TOR_WORKQUEUE_H) */