diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/compat.h | 3 | ||||
-rw-r--r-- | src/common/compat_threads.c | 21 | ||||
-rw-r--r-- | src/common/container.c | 6 | ||||
-rw-r--r-- | src/common/container.h | 6 | ||||
-rw-r--r-- | src/common/crypto.c | 11 | ||||
-rw-r--r-- | src/common/crypto.h | 1 | ||||
-rw-r--r-- | src/common/crypto_ed25519.c | 112 | ||||
-rw-r--r-- | src/common/workqueue.c | 3 |
8 files changed, 102 insertions, 61 deletions
diff --git a/src/common/compat.h b/src/common/compat.h index d3b18eba92..c7c468c754 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -563,6 +563,8 @@ int network_init(void); ((e) == WSAEMFILE || (e) == WSAENOBUFS) /** Return true if e is EADDRINUSE or the local equivalent. */ #define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE) +/** Return true if e is EINTR or the local equivalent */ +#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0) int tor_socket_errno(tor_socket_t sock); const char *tor_socket_strerror(int e); #else @@ -573,6 +575,7 @@ const char *tor_socket_strerror(int e); #else #define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) #endif +#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0) #define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0) #define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0) #define ERRNO_IS_ACCEPT_EAGAIN(e) \ diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c index 15648d2851..85ad737574 100644 --- a/src/common/compat_threads.c +++ b/src/common/compat_threads.c @@ -88,7 +88,7 @@ in_main_thread(void) } #if defined(HAVE_EVENTFD) || defined(HAVE_PIPE) -/* non-interruptable versions */ +/* As write(), but retry on EINTR */ static int write_ni(int fd, const void *buf, size_t n) { @@ -99,6 +99,7 @@ write_ni(int fd, const void *buf, size_t n) goto again; return r; } +/* As read(), but retry on EINTR */ static int read_ni(int fd, void *buf, size_t n) { @@ -111,30 +112,32 @@ read_ni(int fd, void *buf, size_t n) } #endif -/* non-interruptable versions */ +/** As send(), but retry on EINTR. */ static int send_ni(int fd, const void *buf, size_t n, int flags) { int r; again: r = (int) send(fd, buf, n, flags); - if (r < 0 && errno == EINTR) + if (r < 0 && ERRNO_IS_EINTR(tor_socket_errno(fd))) goto again; return r; } +/** As recv(), but retry on EINTR. */ static int recv_ni(int fd, void *buf, size_t n, int flags) { int r; again: - r = (int) recv(fd, buf, n, flags); - if (r < 0 && errno == EINTR) + r = (int) recv(fd, buf, n, flags); + if (r < 0 && ERRNO_IS_EINTR(tor_socket_errno(fd))) goto again; return r; } #ifdef HAVE_EVENTFD +/* Increment the event count on an eventfd <b>fd</b> */ static int eventfd_alert(int fd) { @@ -145,6 +148,7 @@ eventfd_alert(int fd) return 0; } +/* Drain all events from an eventfd <b>fd</b>. */ static int eventfd_drain(int fd) { @@ -157,6 +161,7 @@ eventfd_drain(int fd) #endif #ifdef HAVE_PIPE +/** Send a byte over a pipe. Return 0 on success or EAGAIN; -1 on error */ static int pipe_alert(int fd) { @@ -166,6 +171,8 @@ pipe_alert(int fd) return 0; } +/** Drain all input from a pipe <b>fd</b> and ignore it. Return 0 on + * success, -1 on error. */ static int pipe_drain(int fd) { @@ -181,6 +188,8 @@ pipe_drain(int fd) } #endif +/** Send a byte on socket <b>fd</b>t. Return 0 on success or EAGAIN, + * -1 on error. */ static int sock_alert(tor_socket_t fd) { @@ -190,6 +199,8 @@ sock_alert(tor_socket_t fd) return 0; } +/** Drain all the input from a socket <b>fd</b>, and ignore it. Return 0 on + * success, -1 on error. */ static int sock_drain(tor_socket_t fd) { diff --git a/src/common/container.c b/src/common/container.c index 082afb51ee..636dfb6c57 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -742,7 +742,7 @@ smartlist_sort_strings(smartlist_t *sl) } /** Return the most frequent string in the sorted list <b>sl</b> */ -char * +const char * smartlist_get_most_frequent_string(smartlist_t *sl) { return smartlist_get_most_frequent(sl, compare_string_ptrs_); @@ -752,7 +752,7 @@ smartlist_get_most_frequent_string(smartlist_t *sl) * If <b>count_out</b> is provided, set <b>count_out</b> to the * number of times that string appears. */ -char * +const char * smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) { return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out); @@ -1020,7 +1020,7 @@ smartlist_sort_digests256(smartlist_t *sl) /** Return the most frequent member of the sorted list of DIGEST256_LEN * digests in <b>sl</b> */ -char * +const uint8_t * smartlist_get_most_frequent_digest256(smartlist_t *sl) { return smartlist_get_most_frequent(sl, compare_digests256_); diff --git a/src/common/container.h b/src/common/container.h index 2a6ba01e62..5abd8b48d9 100644 --- a/src/common/container.h +++ b/src/common/container.h @@ -109,9 +109,9 @@ void smartlist_sort_digests(smartlist_t *sl); void smartlist_sort_digests256(smartlist_t *sl); void smartlist_sort_pointers(smartlist_t *sl); -char *smartlist_get_most_frequent_string(smartlist_t *sl); -char *smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out); -char *smartlist_get_most_frequent_digest256(smartlist_t *sl); +const char *smartlist_get_most_frequent_string(smartlist_t *sl); +const char *smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out); +const uint8_t *smartlist_get_most_frequent_digest256(smartlist_t *sl); void smartlist_uniq_strings(smartlist_t *sl); void smartlist_uniq_digests(smartlist_t *sl); diff --git a/src/common/crypto.c b/src/common/crypto.c index 2121383c75..6d4b0d7e16 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -2365,11 +2365,20 @@ crypto_seed_rng(void) } /** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on - * success, -1 on failure. + * success, -1 on failure, with support for mocking for unit tests. */ MOCK_IMPL(int, crypto_rand, (char *to, size_t n)) { + return crypto_rand_unmocked(to, n); +} + +/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on + * success, -1 on failure. Most callers will want crypto_rand instead. + */ +int +crypto_rand_unmocked(char *to, size_t n) +{ int r; tor_assert(n < INT_MAX); tor_assert(to); diff --git a/src/common/crypto.h b/src/common/crypto.h index 368e9d8e32..6256f7346b 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -260,6 +260,7 @@ int crypto_expand_key_material_rfc5869_sha256( /* random numbers */ int crypto_seed_rng(void); MOCK_DECL(int,crypto_rand,(char *to, size_t n)); +int crypto_rand_unmocked(char *to, size_t n); int crypto_strongest_rand(uint8_t *out, size_t out_len); int crypto_rand_int(unsigned int max); int crypto_rand_int_range(unsigned int min, unsigned int max); diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index 3a629322cb..7e995f4616 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -37,6 +37,8 @@ typedef struct { unsigned char *); int (*sign)(unsigned char *, const unsigned char *, size_t, const unsigned char *, const unsigned char *); + int (*open_batch)(const unsigned char **, size_t *, const unsigned char **, + const unsigned char **, size_t, int *); int (*blind_secret_key)(unsigned char *, const unsigned char *, const unsigned char *); @@ -57,6 +59,7 @@ static const ed25519_impl_t impl_ref10 = { ed25519_ref10_open, ed25519_ref10_sign, + NULL, ed25519_ref10_blind_secret_key, ed25519_ref10_blind_public_key, @@ -74,6 +77,7 @@ static const ed25519_impl_t impl_donna = { ed25519_donna_open, ed25519_donna_sign, + ed25519_sign_open_batch_donna, ed25519_donna_blind_secret_key, ed25519_donna_blind_public_key, @@ -197,57 +201,69 @@ ed25519_checksig_batch(int *okay_out, const ed25519_checkable_t *checkable, int n_checkable) { - int res, i; - - res = 0; - for (i = 0; i < n_checkable; ++i) { - const ed25519_checkable_t *ch = &checkable[i]; - int r = ed25519_checksig(&ch->signature, ch->msg, ch->len, ch->pubkey); - if (r < 0) - --res; - if (okay_out) - okay_out[i] = (r == 0); - } - -#if 0 - /* This is how we'd do it if we were using ed25519_donna. I'll keep this - * code around here in case we ever do that. */ - const uint8_t **ms; - size_t *lens; - const uint8_t **pks; - const uint8_t **sigs; - int *oks; - - ms = tor_malloc(sizeof(uint8_t*)*n_checkable); - lens = tor_malloc(sizeof(size_t)*n_checkable); - pks = tor_malloc(sizeof(uint8_t*)*n_checkable); - sigs = tor_malloc(sizeof(uint8_t*)*n_checkable); - oks = okay_out ? okay_out : tor_malloc(sizeof(int)*n_checkable); - - for (i = 0; i < n_checkable; ++i) { - ms[i] = checkable[i].msg; - lens[i] = checkable[i].len; - pks[i] = checkable[i].pubkey->pubkey; - sigs[i] = checkable[i].signature.sig; - oks[i] = 0; - } - - ed25519_sign_open_batch_donna_fb(ms, lens, pks, sigs, n_checkable, oks); + int i, res; + const ed25519_impl_t *impl = get_ed_impl(); - res = 0; - for (i = 0; i < n_checkable; ++i) { - /* XXX/yawning: Propagate to okay_out? */ - if (!oks[i]) - --res; + if (impl->open_batch == NULL) { + /* No batch verification implementation available, fake it by checking the + * each signature individually. + */ + res = 0; + for (i = 0; i < n_checkable; ++i) { + const ed25519_checkable_t *ch = &checkable[i]; + int r = ed25519_checksig(&ch->signature, ch->msg, ch->len, ch->pubkey); + if (r < 0) + --res; + if (okay_out) + okay_out[i] = (r == 0); + } + } else { + /* ed25519-donna style batch verification available. + * + * Theoretically, this should only be called if n_checkable >= 3, since + * that's the threshold where the batch verification actually kicks in, + * but the only difference is a few mallocs/frees. + */ + const uint8_t **ms; + size_t *lens; + const uint8_t **pks; + const uint8_t **sigs; + int *oks; + int all_ok; + + ms = tor_malloc(sizeof(uint8_t*)*n_checkable); + lens = tor_malloc(sizeof(size_t)*n_checkable); + pks = tor_malloc(sizeof(uint8_t*)*n_checkable); + sigs = tor_malloc(sizeof(uint8_t*)*n_checkable); + oks = okay_out ? okay_out : tor_malloc(sizeof(int)*n_checkable); + + for (i = 0; i < n_checkable; ++i) { + ms[i] = checkable[i].msg; + lens[i] = checkable[i].len; + pks[i] = checkable[i].pubkey->pubkey; + sigs[i] = checkable[i].signature.sig; + oks[i] = 0; + } + + res = 0; + all_ok = impl->open_batch(ms, lens, pks, sigs, n_checkable, oks); + for (i = 0; i < n_checkable; ++i) { + if (!oks[i]) + --res; + } + /* XXX: For now sanity check oks with the return value. Once we have + * more confidence in the code, if `all_ok == 0` we can skip iterating + * over oks since all the signatures were found to be valid. + */ + tor_assert(((res == 0) && !all_ok) || ((res < 0) && all_ok)); + + tor_free(ms); + tor_free(lens); + tor_free(pks); + if (! okay_out) + tor_free(oks); } - tor_free(ms); - tor_free(lens); - tor_free(pks); - if (! okay_out) - tor_free(oks); -#endif - return res; } diff --git a/src/common/workqueue.c b/src/common/workqueue.c index cf63634076..b0b004dc25 100644 --- a/src/common/workqueue.c +++ b/src/common/workqueue.c @@ -480,7 +480,8 @@ replyqueue_process(replyqueue_t *queue) if (queue->alert.drain_fn(queue->alert.read_fd) < 0) { static ratelim_t warn_limit = RATELIM_INIT(7200); log_fn_ratelim(&warn_limit, LOG_WARN, LD_GENERAL, - "Failure from drain_fd"); + "Failure from drain_fd: %s", + tor_socket_strerror(tor_socket_errno(queue->alert.read_fd))); } tor_mutex_acquire(&queue->lock); |