summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/compat.h3
-rw-r--r--src/common/compat_threads.c21
-rw-r--r--src/common/container.c6
-rw-r--r--src/common/container.h6
-rw-r--r--src/common/crypto.c11
-rw-r--r--src/common/crypto.h1
-rw-r--r--src/common/crypto_ed25519.c112
-rw-r--r--src/common/workqueue.c3
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);