summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/address.c22
-rw-r--r--src/common/address.h13
-rw-r--r--src/common/address_set.c6
-rw-r--r--src/common/address_set.h2
-rw-r--r--src/common/aes.c7
-rw-r--r--src/common/aes.h4
-rw-r--r--src/common/buffers.c77
-rw-r--r--src/common/buffers.h13
-rw-r--r--src/common/compat.c33
-rw-r--r--src/common/compat.h6
-rw-r--r--src/common/compat_libevent.c17
-rw-r--r--src/common/compat_libevent.h10
-rw-r--r--src/common/compat_openssl.h4
-rw-r--r--src/common/compat_rust.c39
-rw-r--r--src/common/compat_rust.h28
-rw-r--r--src/common/compat_threads.c23
-rw-r--r--src/common/compat_threads.h74
-rw-r--r--src/common/compat_time.c187
-rw-r--r--src/common/compat_time.h42
-rw-r--r--src/common/compat_winthreads.c4
-rw-r--r--src/common/compress.c2
-rw-r--r--src/common/compress.h4
-rw-r--r--src/common/compress_lzma.c2
-rw-r--r--src/common/compress_lzma.h5
-rw-r--r--src/common/compress_zlib.c2
-rw-r--r--src/common/compress_zlib.h5
-rw-r--r--src/common/compress_zstd.c2
-rw-r--r--src/common/compress_zstd.h5
-rw-r--r--src/common/confline.c96
-rw-r--r--src/common/confline.h12
-rw-r--r--src/common/container.c19
-rw-r--r--src/common/container.h27
-rw-r--r--src/common/crypto.c1169
-rw-r--r--src/common/crypto.h120
-rw-r--r--src/common/crypto_curve25519.h1
-rw-r--r--src/common/crypto_ed25519.c14
-rw-r--r--src/common/crypto_ed25519.h5
-rw-r--r--src/common/crypto_openssl_mgt.c161
-rw-r--r--src/common/crypto_openssl_mgt.h85
-rw-r--r--src/common/crypto_pwbox.h3
-rw-r--r--src/common/crypto_rsa.c923
-rw-r--r--src/common/crypto_rsa.h104
-rw-r--r--src/common/di_ops.c2
-rw-r--r--src/common/di_ops.h7
-rw-r--r--src/common/handles.h4
-rw-r--r--src/common/include.am10
-rw-r--r--src/common/log.c108
-rw-r--r--src/common/memarea.c4
-rw-r--r--src/common/memarea.h7
-rw-r--r--src/common/procmon.c2
-rw-r--r--src/common/procmon.h4
-rw-r--r--src/common/sandbox.c15
-rw-r--r--src/common/storagedir.c2
-rw-r--r--src/common/storagedir.h5
-rw-r--r--src/common/timers.c4
-rw-r--r--src/common/timers.h3
-rw-r--r--src/common/torint.h10
-rw-r--r--src/common/torlog.h6
-rw-r--r--src/common/tortls.c6
-rw-r--r--src/common/tortls.h7
-rw-r--r--src/common/util.c104
-rw-r--r--src/common/util.h33
-rw-r--r--src/common/workqueue.c5
63 files changed, 2243 insertions, 1482 deletions
diff --git a/src/common/address.c b/src/common/address.c
index c7aa97bfd1..ecdbbab7b1 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1125,7 +1125,7 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
case AF_UNIX:
/* HACKHACKHACKHACKHACK:
* tor_addr_t doesn't contain a copy of sun_path, so it's not
- * possible to comapre this at all.
+ * possible to compare this at all.
*
* Since the only time we currently actually should be comparing
* 2 AF_UNIX addresses is when dealing with ISO_CLIENTADDR (which
@@ -1540,6 +1540,18 @@ get_interface_addresses_win32(int severity, sa_family_t family)
#define _SIZEOF_ADDR_IFREQ sizeof
#endif
+/* Free ifc->ifc_buf safely. */
+static void
+ifconf_free_ifc_buf(struct ifconf *ifc)
+{
+ /* On macOS, tor_free() takes the address of ifc.ifc_buf, which leads to
+ * undefined behaviour, because pointer-to-pointers are expected to be
+ * aligned at 8-bytes, but the ifconf structure is packed. So we use
+ * raw_free() instead. */
+ raw_free(ifc->ifc_buf);
+ ifc->ifc_buf = NULL;
+}
+
/** Convert <b>*buf</b>, an ifreq structure array of size <b>buflen</b>,
* into smartlist of <b>tor_addr_t</b> structures.
*/
@@ -1626,7 +1638,7 @@ get_interface_addresses_ioctl(int severity, sa_family_t family)
done:
if (fd >= 0)
close(fd);
- tor_free(ifc.ifc_buf);
+ ifconf_free_ifc_buf(&ifc);
return result;
}
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
@@ -1784,14 +1796,14 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr))
break;
} SMARTLIST_FOREACH_END(a);
- free_interface_address6_list(addrs);
+ interface_address6_list_free(addrs);
return rv;
}
/** Free a smartlist of IP addresses returned by get_interface_address6_list.
*/
void
-free_interface_address6_list(smartlist_t *addrs)
+interface_address6_list_free_(smartlist_t *addrs)
{
if (addrs != NULL) {
SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a));
@@ -1806,7 +1818,7 @@ free_interface_address6_list(smartlist_t *addrs)
* An empty smartlist means that there are no addresses of the selected type
* matching these criteria.
* Returns NULL on failure.
- * Use free_interface_address6_list to free the returned list.
+ * Use interface_address6_list_free to free the returned list.
*/
MOCK_IMPL(smartlist_t *,
get_interface_address6_list,(int severity,
diff --git a/src/common/address.h b/src/common/address.h
index 2b9546782e..c9d9543dee 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -206,7 +206,9 @@ const char * fmt_addr32(uint32_t addr);
MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
tor_addr_t *addr));
-void free_interface_address6_list(smartlist_t * addrs);
+void interface_address6_list_free_(smartlist_t * addrs);// XXXX
+#define interface_address6_list_free(addrs) \
+ FREE_AND_NULL(smartlist_t, interface_address6_list_free_, (addrs))
MOCK_DECL(smartlist_t *,get_interface_address6_list,(int severity,
sa_family_t family,
int include_internal));
@@ -323,13 +325,8 @@ int addr_mask_get_bits(uint32_t mask);
int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr));
-/** Free a smartlist of IP addresses returned by get_interface_address_list.
- */
-static inline void
-free_interface_address_list(smartlist_t *addrs)
-{
- free_interface_address6_list(addrs);
-}
+#define interface_address_list_free(lst)\
+ interface_address6_list_free(lst)
/** Return a smartlist of the IPv4 addresses of all interfaces on the server.
* Excludes loopback and multicast addresses. Only includes internal addresses
* if include_internal is true. (Note that a relay behind NAT may use an
diff --git a/src/common/address_set.c b/src/common/address_set.c
index 4924cb65c2..f61fa294e0 100644
--- a/src/common/address_set.c
+++ b/src/common/address_set.c
@@ -34,7 +34,7 @@
* independent siphashes rather than messing around with bit-shifts. The
* approach here is probably more sound, and we should prefer it if&when we
* unify the implementations.
- **/
+ */
struct address_set_t {
/** siphash keys to make N_HASHES independent hashes for each address. */
@@ -63,7 +63,7 @@ address_set_new(int max_addresses_guess)
}
/**
- * Release all storage associated with <b>set</b>
+ * Release all storage associated with <b>set</b>.
*/
void
address_set_free(address_set_t *set)
@@ -107,7 +107,7 @@ address_set_add_ipv4h(address_set_t *set, uint32_t addr)
}
/**
- * Return true if <b>addr</b> if a member of <b>set</b>. (And probably,
+ * Return true if <b>addr</b> is a member of <b>set</b>. (And probably,
* return false if <b>addr</b> is not a member of set.)
*/
int
diff --git a/src/common/address_set.h b/src/common/address_set.h
index aedf17fc66..28d29f3fdf 100644
--- a/src/common/address_set.h
+++ b/src/common/address_set.h
@@ -2,7 +2,7 @@
/* See LICENSE for licensing information */
/**
- * \file addressset.h
+ * \file address_set.h
* \brief Types to handle sets of addresses.
*
* This module was first written on a semi-emergency basis to improve the
diff --git a/src/common/aes.c b/src/common/aes.c
index 20b51a6758..5d0841dfa3 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -18,6 +18,7 @@
#include <openssl/opensslv.h>
#include "crypto.h"
+#include "crypto_openssl_mgt.h"
#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
#error "We require OpenSSL >= 1.0.0"
@@ -110,7 +111,7 @@ aes_new_cipher(const uint8_t *key, const uint8_t *iv, int key_bits)
return (aes_cnt_cipher_t *) cipher;
}
void
-aes_cipher_free(aes_cnt_cipher_t *cipher_)
+aes_cipher_free_(aes_cnt_cipher_t *cipher_)
{
if (!cipher_)
return;
@@ -254,7 +255,7 @@ evaluate_ctr_for_aes(void)
/* LCOV_EXCL_START */
log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; "
"quitting tor.");
- exit(1);
+ exit(1); // exit ok: openssl is broken.
/* LCOV_EXCL_STOP */
}
return 0;
@@ -324,7 +325,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, int key_bits)
/** Release storage held by <b>cipher</b>
*/
void
-aes_cipher_free(aes_cnt_cipher_t *cipher)
+aes_cipher_free_(aes_cnt_cipher_t *cipher)
{
if (!cipher)
return;
diff --git a/src/common/aes.h b/src/common/aes.h
index 1e400a56e0..0b17cd55a4 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -17,7 +17,9 @@ typedef struct aes_cnt_cipher aes_cnt_cipher_t;
aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv,
int key_bits);
-void aes_cipher_free(aes_cnt_cipher_t *cipher);
+void aes_cipher_free_(aes_cnt_cipher_t *cipher);
+#define aes_cipher_free(cipher) \
+ FREE_AND_NULL(aes_cnt_cipher_t, aes_cipher_free_, (cipher))
void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len);
int evaluate_evp_for_aes(int force_value);
diff --git a/src/common/buffers.c b/src/common/buffers.c
index c45e13d551..a01add9bef 100644
--- a/src/common/buffers.c
+++ b/src/common/buffers.c
@@ -409,7 +409,7 @@ buf_slack(const buf_t *buf)
/** Release storage held by <b>buf</b>. */
void
-buf_free(buf_t *buf)
+buf_free_(buf_t *buf)
{
if (!buf)
return;
@@ -472,7 +472,7 @@ buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
chunk = chunk_new_with_alloc_size(buf_preferred_chunk_size(capacity));
}
- chunk->inserted_time = (uint32_t)monotime_coarse_absolute_msec();
+ chunk->inserted_time = monotime_coarse_get_stamp();
if (buf->tail) {
tor_assert(buf->head);
@@ -487,8 +487,8 @@ buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
}
/** Return the age of the oldest chunk in the buffer <b>buf</b>, in
- * milliseconds. Requires the current monotonic time, in truncated msec,
- * as its input <b>now</b>.
+ * timestamp units. Requires the current monotonic timestamp as its
+ * input <b>now</b>.
*/
uint32_t
buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now)
@@ -714,6 +714,53 @@ buf_add(buf_t *buf, const char *string, size_t string_len)
return (int)buf->datalen;
}
+/** Add a nul-terminated <b>string</b> to <b>buf</b>, not including the
+ * terminating NUL. */
+void
+buf_add_string(buf_t *buf, const char *string)
+{
+ buf_add(buf, string, strlen(string));
+}
+
+/** As tor_snprintf, but write the results into a buf_t */
+void
+buf_add_printf(buf_t *buf, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap,format);
+ buf_add_vprintf(buf, format, ap);
+ va_end(ap);
+}
+
+/** As tor_vsnprintf, but write the results into a buf_t. */
+void
+buf_add_vprintf(buf_t *buf, const char *format, va_list args)
+{
+ /* XXXX Faster implementations are easy enough, but let's optimize later */
+ char *tmp;
+ tor_vasprintf(&tmp, format, args);
+ buf_add(buf, tmp, strlen(tmp));
+ tor_free(tmp);
+}
+
+/** Return a heap-allocated string containing the contents of <b>buf</b>, plus
+ * a NUL byte. If <b>sz_out</b> is provided, set *<b>sz_out</b> to the length
+ * of the returned string, not including the terminating NUL. */
+char *
+buf_extract(buf_t *buf, size_t *sz_out)
+{
+ tor_assert(buf);
+
+ size_t sz = buf_datalen(buf);
+ char *result;
+ result = tor_malloc(sz+1);
+ buf_peek(buf, result, sz);
+ result[sz] = 0;
+ if (sz_out)
+ *sz_out = sz;
+ return result;
+}
+
/** Helper: copy the first <b>string_len</b> bytes from <b>buf</b>
* onto <b>string</b>.
*/
@@ -795,6 +842,28 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
return (int)cp;
}
+/** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying.
+ */
+void
+buf_move_all(buf_t *buf_out, buf_t *buf_in)
+{
+ tor_assert(buf_out);
+ if (!buf_in)
+ return;
+
+ if (buf_out->head == NULL) {
+ buf_out->head = buf_in->head;
+ buf_out->tail = buf_in->tail;
+ } else {
+ buf_out->tail->next = buf_in->head;
+ buf_out->tail = buf_in->tail;
+ }
+
+ buf_out->datalen += buf_in->datalen;
+ buf_in->head = buf_in->tail = NULL;
+ buf_in->datalen = 0;
+}
+
/** Internal structure: represents a position in a buffer. */
typedef struct buf_pos_t {
const chunk_t *chunk; /**< Which chunk are we pointing to? */
diff --git a/src/common/buffers.h b/src/common/buffers.h
index 1eaa5f2d04..22a5f7bfa3 100644
--- a/src/common/buffers.h
+++ b/src/common/buffers.h
@@ -24,7 +24,8 @@ struct tor_compress_state_t;
buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
size_t buf_get_default_chunk_size(const buf_t *buf);
-void buf_free(buf_t *buf);
+void buf_free_(buf_t *buf);
+#define buf_free(b) FREE_AND_NULL(buf_t, buf_free_, (b))
void buf_clear(buf_t *buf);
buf_t *buf_copy(const buf_t *buf);
@@ -43,9 +44,15 @@ int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
size_t *buf_flushlen);
int buf_add(buf_t *buf, const char *string, size_t string_len);
+void buf_add_string(buf_t *buf, const char *string);
+void buf_add_printf(buf_t *buf, const char *format, ...)
+ CHECK_PRINTF(2, 3);
+void buf_add_vprintf(buf_t *buf, const char *format, va_list args)
+ CHECK_PRINTF(2, 0);
int buf_add_compress(buf_t *buf, struct tor_compress_state_t *state,
const char *data, size_t data_len, int done);
int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
+void buf_move_all(buf_t *buf_out, buf_t *buf_in);
void buf_peek(const buf_t *buf, char *string, size_t string_len);
void buf_drain(buf_t *buf, size_t n);
int buf_get_bytes(buf_t *buf, char *string, size_t string_len);
@@ -62,6 +69,7 @@ void buf_assert_ok(buf_t *buf);
int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
void buf_pullup(buf_t *buf, size_t bytes,
const char **head_out, size_t *len_out);
+char *buf_extract(buf_t *buf, size_t *sz_out);
#ifdef BUFFERS_PRIVATE
#ifdef TOR_UNIT_TESTS
@@ -79,8 +87,7 @@ typedef struct chunk_t {
size_t DBG_alloc;
#endif
char *data; /**< A pointer to the first byte of data stored in <b>mem</b>. */
- uint32_t inserted_time; /**< Timestamp in truncated ms since epoch
- * when this chunk was inserted. */
+ uint32_t inserted_time; /**< Timestamp when this chunk was inserted. */
char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in
* this chunk. */
} chunk_t;
diff --git a/src/common/compat.c b/src/common/compat.c
index 83bb707e17..7d9add50b2 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1186,7 +1186,7 @@ mark_socket_open(tor_socket_t s)
bitarray_set(open_sockets, s);
}
#else /* !(defined(DEBUG_SOCKET_COUNTING)) */
-#define mark_socket_open(s) STMT_NIL
+#define mark_socket_open(s) ((void) (s))
#endif /* defined(DEBUG_SOCKET_COUNTING) */
/** @} */
@@ -1273,11 +1273,22 @@ tor_open_socket_with_extensions(int domain, int type, int protocol,
goto socket_ok; /* So that socket_ok will not be unused. */
socket_ok:
+ tor_take_socket_ownership(s);
+ return s;
+}
+
+/**
+ * For socket accounting: remember that we are the owner of the socket
+ * <b>s</b>. This will prevent us from overallocating sockets, and prevent us
+ * from asserting later when we close the socket <b>s</b>.
+ */
+void
+tor_take_socket_ownership(tor_socket_t s)
+{
socket_accounting_lock();
++n_sockets_open;
mark_socket_open(s);
socket_accounting_unlock();
- return s;
}
/** As accept(), but counts the number of open sockets. */
@@ -1358,10 +1369,7 @@ tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr,
goto socket_ok; /* So that socket_ok will not be unused. */
socket_ok:
- socket_accounting_lock();
- ++n_sockets_open;
- mark_socket_open(s);
- socket_accounting_unlock();
+ tor_take_socket_ownership(s);
return s;
}
@@ -1897,9 +1905,12 @@ tor_passwd_dup(const struct passwd *pw)
return new_pw;
}
+#define tor_passwd_free(pw) \
+ FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw))
+
/** Helper: free one of our cached 'struct passwd' values. */
static void
-tor_passwd_free(struct passwd *pw)
+tor_passwd_free_(struct passwd *pw)
{
if (!pw)
return;
@@ -2444,7 +2455,7 @@ get_environment(void)
/** Get name of current host and write it to <b>name</b> array, whose
* length is specified by <b>namelen</b> argument. Return 0 upon
- * successfull completion; otherwise return return -1. (Currently,
+ * successful completion; otherwise return return -1. (Currently,
* this function is merely a mockable wrapper for POSIX gethostname().)
*/
MOCK_IMPL(int,
@@ -2879,7 +2890,7 @@ compute_num_cpus(void)
/** Helper: Deal with confused or out-of-bounds values from localtime_r and
* friends. (On some platforms, they can give out-of-bounds values or can
* return NULL.) If <b>islocal</b>, this is a localtime result; otherwise
- * it's from gmtime. The function returned <b>r</b>, when given <b>timep</b>
+ * it's from gmtime. The function returns <b>r</b>, when given <b>timep</b>
* as its input. If we need to store new results, store them in
* <b>resultbuf</b>. */
static struct tm *
@@ -3398,8 +3409,8 @@ get_total_system_memory_impl(void)
* Try to find out how much physical memory the system has. On success,
* return 0 and set *<b>mem_out</b> to that value. On failure, return -1.
*/
-int
-get_total_system_memory(size_t *mem_out)
+MOCK_IMPL(int,
+get_total_system_memory, (size_t *mem_out))
{
static size_t mem_cached=0;
uint64_t m = get_total_system_memory_impl();
diff --git a/src/common/compat.h b/src/common/compat.h
index fee9e6587d..3088e68355 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -10,6 +10,9 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
+#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
+#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b
+#endif
#endif
#include "torint.h"
#include "testsupport.h"
@@ -483,6 +486,7 @@ typedef int socklen_t;
int tor_close_socket_simple(tor_socket_t s);
MOCK_DECL(int, tor_close_socket, (tor_socket_t s));
+void tor_take_socket_ownership(tor_socket_t s);
tor_socket_t tor_open_socket_with_extensions(
int domain, int type, int protocol,
int cloexec, int nonblock);
@@ -695,7 +699,7 @@ char *make_path_absolute(char *fname);
char **get_environment(void);
-int get_total_system_memory(size_t *mem_out);
+MOCK_DECL(int, get_total_system_memory, (size_t *mem_out));
int compute_num_cpus(void);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 740cc2a11d..735385557c 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -69,7 +69,7 @@ suppress_libevent_log_msg(const char *msg)
/* Wrapper for event_free() that tolerates tor_event_free(NULL) */
void
-tor_event_free(struct event *ev)
+tor_event_free_(struct event *ev)
{
if (ev == NULL)
return;
@@ -126,7 +126,7 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
if (!the_event_base) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
- exit(1);
+ exit(1); // exit ok: libevent is broken.
/* LCOV_EXCL_STOP */
}
@@ -213,7 +213,7 @@ periodic_timer_new(struct event_base *base,
/** Stop and free a periodic timer */
void
-periodic_timer_free(periodic_timer_t *timer)
+periodic_timer_free_(periodic_timer_t *timer)
{
if (!timer)
return;
@@ -237,6 +237,17 @@ tor_init_libevent_rng(void)
return rv;
}
+/**
+ * Un-initialize libevent in preparation for an exit
+ */
+void
+tor_libevent_free_all(void)
+{
+ if (the_event_base)
+ event_base_free(the_event_base);
+ the_event_base = NULL;
+}
+
#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 834354c405..1853e50917 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -19,7 +19,9 @@ void suppress_libevent_log_msg(const char *msg);
evdns_add_server_port_with_base(tor_libevent_get_base(), \
(sock),(tcp),(cb),(data));
-void tor_event_free(struct event *ev);
+void tor_event_free_(struct event *ev);
+#define tor_event_free(ev) \
+ FREE_AND_NULL(struct event, tor_event_free_, (ev))
typedef struct periodic_timer_t periodic_timer_t;
@@ -27,9 +29,12 @@ periodic_timer_t *periodic_timer_new(struct event_base *base,
const struct timeval *tv,
void (*cb)(periodic_timer_t *timer, void *data),
void *data);
-void periodic_timer_free(periodic_timer_t *);
+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
/** Defines a configuration for using libevent with Tor: passed as an argument
* to tor_libevent_initialize() to describe how we want to set up. */
@@ -47,6 +52,7 @@ const char *tor_libevent_get_method(void);
void tor_check_libevent_header_compatibility(void);
const char *tor_libevent_get_version_str(void);
const char *tor_libevent_get_header_version_str(void);
+void tor_libevent_free_all(void);
int tor_init_libevent_rng(void);
diff --git a/src/common/compat_openssl.h b/src/common/compat_openssl.h
index c695f1e9df..1299ac36bb 100644
--- a/src/common/compat_openssl.h
+++ b/src/common/compat_openssl.h
@@ -8,11 +8,11 @@
#define TOR_COMPAT_OPENSSL_H
#include <openssl/opensslv.h>
-
+#include "crypto_openssl_mgt.h"
/**
* \file compat_openssl.h
*
- * \brief compatability definitions for working with different openssl forks
+ * \brief compatibility definitions for working with different openssl forks
**/
#if !defined(LIBRESSL_VERSION_NUMBER) && \
diff --git a/src/common/compat_rust.c b/src/common/compat_rust.c
deleted file mode 100644
index 366fd4037b..0000000000
--- a/src/common/compat_rust.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (c) 2017, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rust_compat.c
- * \brief Rust FFI compatibility functions and helpers. This file is only built
- * if Rust is not used.
- **/
-
-#include "compat_rust.h"
-#include "util.h"
-
-/**
- * Free storage pointed to by <b>str</b>, and itself.
- */
-void
-rust_str_free(rust_str_t str)
-{
- char *s = (char *)str;
- tor_free(s);
-}
-
-/**
- * Return zero-terminated contained string.
- */
-const char *
-rust_str_get(const rust_str_t str)
-{
- return (const char *)str;
-}
-
-/* If we were using Rust, we'd say so on startup. */
-rust_str_t
-rust_welcome_string(void)
-{
- char *s = tor_malloc_zero(1);
- return (rust_str_t)s;
-}
-
diff --git a/src/common/compat_rust.h b/src/common/compat_rust.h
deleted file mode 100644
index 72fde39296..0000000000
--- a/src/common/compat_rust.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright (c) 2017, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rust_compat.h
- * \brief Headers for rust_compat.c
- **/
-
-#ifndef TOR_RUST_COMPAT_H
-#define TOR_RUST_COMPAT_H
-
-#include "torint.h"
-
-/**
- * Strings allocated in Rust must be freed from Rust code again. Let's make
- * it less likely to accidentally mess up and call tor_free() on it, because
- * currently it'll just work but might break at any time.
- */
-typedef uintptr_t rust_str_t;
-
-void rust_str_free(rust_str_t);
-
-const char *rust_str_get(const rust_str_t);
-
-rust_str_t rust_welcome_string(void);
-
-#endif /* !defined(TOR_RUST_COMPAT_H) */
-
diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c
index 208d3138d9..3171c4b2f2 100644
--- a/src/common/compat_threads.c
+++ b/src/common/compat_threads.c
@@ -48,7 +48,7 @@ tor_mutex_new_nonrecursive(void)
}
/** Release all storage and system resources held by <b>m</b>. */
void
-tor_mutex_free(tor_mutex_t *m)
+tor_mutex_free_(tor_mutex_t *m)
{
if (!m)
return;
@@ -68,7 +68,7 @@ tor_cond_new(void)
/** Free all storage held in <b>c</b>. */
void
-tor_cond_free(tor_cond_t *c)
+tor_cond_free_(tor_cond_t *c)
{
if (!c)
return;
@@ -352,12 +352,7 @@ alert_sockets_close(alert_sockets_t *socks)
socks->read_fd = socks->write_fd = -1;
}
-/*
- * XXXX We might be smart to move to compiler intrinsics or real atomic
- * XXXX operations at some point. But not yet.
- *
- */
-
+#ifndef HAVE_STDATOMIC_H
/** Initialize a new atomic counter with the value 0 */
void
atomic_counter_init(atomic_counter_t *counter)
@@ -397,4 +392,16 @@ atomic_counter_get(atomic_counter_t *counter)
tor_mutex_release(&counter->mutex);
return val;
}
+/** Replace the value of an atomic counter; return the old one. */
+size_t
+atomic_counter_exchange(atomic_counter_t *counter, size_t newval)
+{
+ size_t oldval;
+ tor_mutex_acquire(&counter->mutex);
+ oldval = counter->val;
+ counter->val = newval;
+ tor_mutex_release(&counter->mutex);
+ return oldval;
+}
+#endif /* !defined(HAVE_STDATOMIC_H) */
diff --git a/src/common/compat_threads.h b/src/common/compat_threads.h
index 42f14eab2a..c93e601ec5 100644
--- a/src/common/compat_threads.h
+++ b/src/common/compat_threads.h
@@ -14,6 +14,10 @@
#include <pthread.h>
#endif
+#ifdef HAVE_STDATOMIC_H
+#include <stdatomic.h>
+#endif
+
#if defined(_WIN32)
#define USE_WIN32_THREADS
#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE)
@@ -50,7 +54,8 @@ void tor_mutex_init(tor_mutex_t *m);
void tor_mutex_init_nonrecursive(tor_mutex_t *m);
void tor_mutex_acquire(tor_mutex_t *m);
void tor_mutex_release(tor_mutex_t *m);
-void tor_mutex_free(tor_mutex_t *m);
+void tor_mutex_free_(tor_mutex_t *m);
+#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m))
void tor_mutex_uninit(tor_mutex_t *m);
unsigned long tor_get_thread_id(void);
void tor_threads_init(void);
@@ -77,7 +82,8 @@ typedef struct tor_cond_t {
} tor_cond_t;
tor_cond_t *tor_cond_new(void);
-void tor_cond_free(tor_cond_t *cond);
+void tor_cond_free_(tor_cond_t *cond);
+#define tor_cond_free(c) FREE_AND_NULL(tor_cond_t, tor_cond_free_, (c))
int tor_cond_init(tor_cond_t *cond);
void tor_cond_uninit(tor_cond_t *cond);
int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex,
@@ -150,16 +156,68 @@ void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value);
/**
* Atomic counter type; holds a size_t value.
*/
+#ifdef HAVE_STDATOMIC_H
+typedef struct atomic_counter_t {
+ atomic_size_t val;
+} atomic_counter_t;
+#define ATOMIC_LINKAGE static
+#else /* !(defined(HAVE_STDATOMIC_H)) */
typedef struct atomic_counter_t {
tor_mutex_t mutex;
size_t val;
} atomic_counter_t;
-
-void atomic_counter_init(atomic_counter_t *counter);
-void atomic_counter_destroy(atomic_counter_t *counter);
-void atomic_counter_add(atomic_counter_t *counter, size_t add);
-void atomic_counter_sub(atomic_counter_t *counter, size_t sub);
-size_t atomic_counter_get(atomic_counter_t *counter);
+#define ATOMIC_LINKAGE
+#endif /* defined(HAVE_STDATOMIC_H) */
+
+ATOMIC_LINKAGE void atomic_counter_init(atomic_counter_t *counter);
+ATOMIC_LINKAGE void atomic_counter_destroy(atomic_counter_t *counter);
+ATOMIC_LINKAGE void atomic_counter_add(atomic_counter_t *counter, size_t add);
+ATOMIC_LINKAGE void atomic_counter_sub(atomic_counter_t *counter, size_t sub);
+ATOMIC_LINKAGE size_t atomic_counter_get(atomic_counter_t *counter);
+ATOMIC_LINKAGE size_t atomic_counter_exchange(atomic_counter_t *counter,
+ size_t newval);
+#undef ATOMIC_LINKAGE
+
+#ifdef HAVE_STDATOMIC_H
+/** Initialize a new atomic counter with the value 0 */
+static inline void
+atomic_counter_init(atomic_counter_t *counter)
+{
+ atomic_init(&counter->val, 0);
+}
+/** Clean up all resources held by an atomic counter. */
+static inline void
+atomic_counter_destroy(atomic_counter_t *counter)
+{
+ (void)counter;
+}
+/** Add a value to an atomic counter. */
+static inline void
+atomic_counter_add(atomic_counter_t *counter, size_t add)
+{
+ (void) atomic_fetch_add(&counter->val, add);
+}
+/** Subtract a value from an atomic counter. */
+static inline void
+atomic_counter_sub(atomic_counter_t *counter, size_t sub)
+{
+ (void) atomic_fetch_sub(&counter->val, sub);
+}
+/** Return the current value of an atomic counter */
+static inline size_t
+atomic_counter_get(atomic_counter_t *counter)
+{
+ return atomic_load(&counter->val);
+}
+/** Replace the value of an atomic counter; return the old one. */
+static inline size_t
+atomic_counter_exchange(atomic_counter_t *counter, size_t newval)
+{
+ return atomic_exchange(&counter->val, newval);
+}
+
+#else /* !(defined(HAVE_STDATOMIC_H)) */
+#endif /* defined(HAVE_STDATOMIC_H) */
#endif /* !defined(TOR_COMPAT_THREADS_H) */
diff --git a/src/common/compat_time.c b/src/common/compat_time.c
index 1ce6f5ce4e..183a60a480 100644
--- a/src/common/compat_time.c
+++ b/src/common/compat_time.c
@@ -90,7 +90,7 @@ tor_gettimeofday(struct timeval *timeval)
if (ft.ft_64 < EPOCH_BIAS) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"System time is before 1970; failing.");
- exit(1);
+ exit(1); // exit ok: system clock is broken.
/* LCOV_EXCL_STOP */
}
ft.ft_64 -= EPOCH_BIAS;
@@ -102,7 +102,7 @@ tor_gettimeofday(struct timeval *timeval)
log_err(LD_GENERAL,"gettimeofday failed.");
/* If gettimeofday dies, we have either given a bad timezone (we didn't),
or segfaulted.*/
- exit(1);
+ exit(1); // exit ok: gettimeofday failed.
/* LCOV_EXCL_STOP */
}
#elif defined(HAVE_FTIME)
@@ -279,6 +279,7 @@ monotime_reset_ratchets_for_testing(void)
* nanoseconds.
*/
static struct mach_timebase_info mach_time_info;
+static int monotime_shift = 0;
static void
monotime_init_internal(void)
@@ -287,6 +288,14 @@ monotime_init_internal(void)
int r = mach_timebase_info(&mach_time_info);
tor_assert(r == 0);
tor_assert(mach_time_info.denom != 0);
+
+ {
+ // approximate only.
+ uint64_t ns_per_tick = mach_time_info.numer / mach_time_info.denom;
+ uint64_t ms_per_tick = ns_per_tick * ONE_MILLION;
+ // requires that tor_log2(0) == 0.
+ monotime_shift = tor_log2(ms_per_tick);
+ }
}
/**
@@ -305,6 +314,21 @@ monotime_get(monotime_t *out)
out->abstime_ = mach_absolute_time();
}
+#if defined(HAVE_MACH_APPROXIMATE_TIME)
+void
+monotime_coarse_get(monotime_coarse_t *out)
+{
+#ifdef TOR_UNIT_TESTS
+ if (monotime_mocking_enabled) {
+ out->abstime_ = (mock_time_nsec_coarse * mach_time_info.denom)
+ / mach_time_info.numer;
+ return;
+ }
+#endif /* defined(TOR_UNIT_TESTS) */
+ out->abstime_ = mach_approximate_time();
+}
+#endif
+
/**
* Return the number of nanoseconds between <b>start</b> and <b>end</b>.
*/
@@ -321,6 +345,26 @@ monotime_diff_nsec(const monotime_t *start,
return diff_nsec;
}
+uint32_t
+monotime_coarse_to_stamp(const monotime_coarse_t *t)
+{
+ return (uint32_t)(t->abstime_ >> monotime_shift);
+}
+
+int
+monotime_is_zero(const monotime_t *val)
+{
+ return val->abstime_ == 0;
+}
+
+void
+monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec)
+{
+ const uint64_t nsec = msec * ONE_MILLION;
+ const uint64_t ticks = (nsec * mach_time_info.denom) / mach_time_info.numer;
+ out->abstime_ = val->abstime_ + ticks;
+}
+
/* end of "__APPLE__" */
#elif defined(HAVE_CLOCK_GETTIME)
@@ -399,6 +443,37 @@ monotime_diff_nsec(const monotime_t *start,
return diff_nsec;
}
+/* This value is ONE_BILLION >> 20. */
+static const uint32_t STAMP_TICKS_PER_SECOND = 953;
+
+uint32_t
+monotime_coarse_to_stamp(const monotime_coarse_t *t)
+{
+ uint32_t nsec = (uint32_t)t->ts_.tv_nsec;
+ uint32_t sec = (uint32_t)t->ts_.tv_sec;
+
+ return (sec * STAMP_TICKS_PER_SECOND) + (nsec >> 20);
+}
+
+int
+monotime_is_zero(const monotime_t *val)
+{
+ return val->ts_.tv_sec == 0 && val->ts_.tv_nsec == 0;
+}
+
+void
+monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec)
+{
+ const uint32_t sec = msec / 1000;
+ const uint32_t msec_remainder = msec % 1000;
+ out->ts_.tv_sec = val->ts_.tv_sec + sec;
+ out->ts_.tv_nsec = val->ts_.tv_nsec + (msec_remainder * ONE_MILLION);
+ if (out->ts_.tv_nsec > ONE_BILLION) {
+ out->ts_.tv_nsec -= ONE_BILLION;
+ out->ts_.tv_sec += 1;
+ }
+}
+
/* end of "HAVE_CLOCK_GETTIME" */
#elif defined (_WIN32)
@@ -531,6 +606,41 @@ monotime_coarse_diff_nsec(const monotime_coarse_t *start,
return monotime_coarse_diff_msec(start, end) * ONE_MILLION;
}
+static const uint32_t STAMP_TICKS_PER_SECOND = 1000;
+
+uint32_t
+monotime_coarse_to_stamp(const monotime_coarse_t *t)
+{
+ return (uint32_t) t->tick_count_;
+}
+
+int
+monotime_is_zero(const monotime_t *val)
+{
+ return val->pcount_ == 0;
+}
+
+int
+monotime_coarse_is_zero(const monotime_coarse_t *val)
+{
+ return val->tick_count_ == 0;
+}
+
+void
+monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec)
+{
+ const uint64_t nsec = msec * ONE_MILLION;
+ const uint64_t ticks = (nsec * nsec_per_tick_denom) / nsec_per_tick_numer;
+ out->pcount_ = val->pcount_ + ticks;
+}
+
+void
+monotime_coarse_add_msec(monotime_coarse_t *out, const monotime_coarse_t *val,
+ uint32_t msec)
+{
+ out->tick_count_ = val->tick_count_ + msec;
+}
+
/* end of "_WIN32" */
#elif defined(MONOTIME_USING_GETTIMEOFDAY)
@@ -567,6 +677,36 @@ monotime_diff_nsec(const monotime_t *start,
return (diff.tv_sec * ONE_BILLION + diff.tv_usec * 1000);
}
+/* This value is ONE_MILLION >> 10. */
+static const uint32_t STAMP_TICKS_PER_SECOND = 976;
+
+uint32_t
+monotime_coarse_to_stamp(const monotime_coarse_t *t)
+{
+ const uint32_t usec = (uint32_t)t->tv_.tv_usec;
+ const uint32_t sec = (uint32_t)t->tv_.tv_sec;
+ return (sec * STAMP_TICKS_PER_SECOND) | (nsec >> 10);
+}
+
+int
+monotime_is_zero(const monotime_t *val)
+{
+ return val->tv_.tv_sec == 0 && val->tv_.tv_usec == 0;
+}
+
+void
+monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec)
+{
+ const uint32_t sec = msec / 1000;
+ const uint32_t msec_remainder = msec % 1000;
+ out->tv_.tv_sec = val->tv_.tv_sec + sec;
+ out->tv_.tv_usec = val->tv_.tv_nsec + (msec_remainder * 1000);
+ if (out->tv_.tv_usec > ONE_MILLION) {
+ out->tv_.tv_usec -= ONE_MILLION;
+ out->tv_.tv_sec += 1;
+ }
+}
+
/* end of "MONOTIME_USING_GETTIMEOFDAY" */
#else
#error "No way to implement monotonic timers."
@@ -589,6 +729,19 @@ monotime_init(void)
}
}
+void
+monotime_zero(monotime_t *out)
+{
+ memset(out, 0, sizeof(*out));
+}
+#ifdef MONOTIME_COARSE_TYPE_IS_DIFFERENT
+void
+monotime_coarse_zero(monotime_coarse_t *out)
+{
+ memset(out, 0, sizeof(*out));
+}
+#endif
+
int64_t
monotime_diff_usec(const monotime_t *start,
const monotime_t *end)
@@ -653,5 +806,35 @@ monotime_coarse_absolute_msec(void)
{
return monotime_coarse_absolute_nsec() / ONE_MILLION;
}
+#else
+#define initialized_at_coarse initialized_at
#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */
+/**
+ * Return the current time "stamp" as described by monotime_coarse_to_stamp.
+ */
+uint32_t
+monotime_coarse_get_stamp(void)
+{
+ monotime_coarse_t now;
+ monotime_coarse_get(&now);
+ return monotime_coarse_to_stamp(&now);
+}
+
+#ifdef __APPLE__
+uint64_t
+monotime_coarse_stamp_units_to_approx_msec(uint64_t units)
+{
+ /* Recover as much precision as we can. */
+ uint64_t abstime_diff = (units << monotime_shift);
+ return (abstime_diff * mach_time_info.numer) /
+ (mach_time_info.denom * ONE_MILLION);
+}
+#else
+uint64_t
+monotime_coarse_stamp_units_to_approx_msec(uint64_t units)
+{
+ return (units * 1000) / STAMP_TICKS_PER_SECOND;
+}
+#endif
+
diff --git a/src/common/compat_time.h b/src/common/compat_time.h
index 5ea4aae42b..6ddd11883d 100644
--- a/src/common/compat_time.h
+++ b/src/common/compat_time.h
@@ -65,6 +65,9 @@ typedef struct monotime_t {
typedef struct monotime_coarse_t {
uint64_t tick_count_;
} monotime_coarse_t;
+#elif defined(__APPLE__) && defined(HAVE_MACH_APPROXIMATE_TIME)
+#define MONOTIME_COARSE_FN_IS_DIFFERENT
+#define monotime_coarse_t monotime_t
#else
#define monotime_coarse_t monotime_t
#endif /* defined(CLOCK_MONOTONIC_COARSE) && ... || ... */
@@ -102,6 +105,21 @@ uint64_t monotime_absolute_usec(void);
*/
uint64_t monotime_absolute_msec(void);
+/**
+ * Set <b>out</b> to zero.
+ */
+void monotime_zero(monotime_t *out);
+/**
+ * Return true iff <b>out</b> is zero
+ */
+int monotime_is_zero(const monotime_t *out);
+
+/**
+ * Set <b>out</b> to N milliseconds after <b>val</b>.
+ */
+/* XXXX We should add a more generic function here if we ever need to */
+void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec);
+
#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT)
/**
* Set <b>out</b> to the current coarse time.
@@ -117,6 +135,23 @@ uint64_t monotime_coarse_absolute_msec(void);
#define monotime_coarse_absolute_msec monotime_absolute_msec
#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */
+/**
+ * Return a "timestamp" approximation for a coarse monotonic timer.
+ * This timestamp is meant to be fast to calculate and easy to
+ * compare, and have a unit of something roughly around 1 msec.
+ *
+ * It will wrap over from time to time.
+ *
+ * It has no defined zero point.
+ */
+uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t);
+/**
+ * Convert a difference, expressed in the units of monotime_coarse_to_stamp,
+ * into an approximate number of milliseconds.
+ */
+uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units);
+uint32_t monotime_coarse_get_stamp(void);
+
#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)
int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start,
const monotime_coarse_t *end);
@@ -124,10 +159,17 @@ int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start,
const monotime_coarse_t *end);
int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start,
const monotime_coarse_t *end);
+void monotime_coarse_zero(monotime_coarse_t *out);
+int monotime_coarse_is_zero(const monotime_coarse_t *val);
+void monotime_coarse_add_msec(monotime_coarse_t *out,
+ const monotime_coarse_t *val, uint32_t msec);
#else /* !(defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)) */
#define monotime_coarse_diff_nsec monotime_diff_nsec
#define monotime_coarse_diff_usec monotime_diff_usec
#define monotime_coarse_diff_msec monotime_diff_msec
+#define monotime_coarse_zero monotime_zero
+#define monotime_coarse_is_zero monotime_is_zero
+#define monotime_coarse_add_msec monotime_add_msec
#endif /* defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) */
void tor_gettimeofday(struct timeval *timeval);
diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c
index 50a3c498ca..5f7ec94c23 100644
--- a/src/common/compat_winthreads.c
+++ b/src/common/compat_winthreads.c
@@ -48,10 +48,12 @@ void
spawn_exit(void)
{
_endthread();
+ // LCOV_EXCL_START
//we should never get here. my compiler thinks that _endthread returns, this
//is an attempt to fool it.
tor_assert(0);
- _exit(0);
+ _exit(0); // exit ok: unreachable.
+ // LCOV_EXCL_STOP
}
void
diff --git a/src/common/compress.c b/src/common/compress.c
index bc12a58ad6..47c93cf6a9 100644
--- a/src/common/compress.c
+++ b/src/common/compress.c
@@ -598,7 +598,7 @@ tor_compress_process(tor_compress_state_t *state,
/** Deallocate <b>state</b>. */
void
-tor_compress_free(tor_compress_state_t *state)
+tor_compress_free_(tor_compress_state_t *state)
{
if (state == NULL)
return;
diff --git a/src/common/compress.h b/src/common/compress.h
index 23a9817479..952102bf97 100644
--- a/src/common/compress.h
+++ b/src/common/compress.h
@@ -80,7 +80,9 @@ tor_compress_output_t tor_compress_process(tor_compress_state_t *state,
char **out, size_t *out_len,
const char **in, size_t *in_len,
int finish);
-void tor_compress_free(tor_compress_state_t *state);
+void tor_compress_free_(tor_compress_state_t *state);
+#define tor_compress_free(st) \
+ FREE_AND_NULL(tor_compress_state_t, tor_compress_free_, (st))
size_t tor_compress_state_size(const tor_compress_state_t *state);
diff --git a/src/common/compress_lzma.c b/src/common/compress_lzma.c
index 6426ede4fd..051c59ba2d 100644
--- a/src/common/compress_lzma.c
+++ b/src/common/compress_lzma.c
@@ -323,7 +323,7 @@ tor_lzma_compress_process(tor_lzma_compress_state_t *state,
/** Deallocate <b>state</b>. */
void
-tor_lzma_compress_free(tor_lzma_compress_state_t *state)
+tor_lzma_compress_free_(tor_lzma_compress_state_t *state)
{
if (state == NULL)
return;
diff --git a/src/common/compress_lzma.h b/src/common/compress_lzma.h
index 7639d98a70..38a447c1f3 100644
--- a/src/common/compress_lzma.h
+++ b/src/common/compress_lzma.h
@@ -31,7 +31,10 @@ tor_lzma_compress_process(tor_lzma_compress_state_t *state,
const char **in, size_t *in_len,
int finish);
-void tor_lzma_compress_free(tor_lzma_compress_state_t *state);
+void tor_lzma_compress_free_(tor_lzma_compress_state_t *state);
+#define tor_lzma_compress_free(st) \
+ FREE_AND_NULL(tor_lzma_compress_state_t, \
+ tor_lzma_compress_free_, (st))
size_t tor_lzma_compress_state_size(const tor_lzma_compress_state_t *state);
diff --git a/src/common/compress_zlib.c b/src/common/compress_zlib.c
index 284542e885..23d71d27be 100644
--- a/src/common/compress_zlib.c
+++ b/src/common/compress_zlib.c
@@ -265,7 +265,7 @@ tor_zlib_compress_process(tor_zlib_compress_state_t *state,
/** Deallocate <b>state</b>. */
void
-tor_zlib_compress_free(tor_zlib_compress_state_t *state)
+tor_zlib_compress_free_(tor_zlib_compress_state_t *state)
{
if (state == NULL)
return;
diff --git a/src/common/compress_zlib.h b/src/common/compress_zlib.h
index 8ace467bf0..e3c1a2b339 100644
--- a/src/common/compress_zlib.h
+++ b/src/common/compress_zlib.h
@@ -31,7 +31,10 @@ tor_zlib_compress_process(tor_zlib_compress_state_t *state,
const char **in, size_t *in_len,
int finish);
-void tor_zlib_compress_free(tor_zlib_compress_state_t *state);
+void tor_zlib_compress_free_(tor_zlib_compress_state_t *state);
+#define tor_zlib_compress_free(st) \
+ FREE_AND_NULL(tor_zlib_compress_state_t, \
+ tor_zlib_compress_free_, (st))
size_t tor_zlib_compress_state_size(const tor_zlib_compress_state_t *state);
diff --git a/src/common/compress_zstd.c b/src/common/compress_zstd.c
index c1cdaf17ad..0db87d61b7 100644
--- a/src/common/compress_zstd.c
+++ b/src/common/compress_zstd.c
@@ -399,7 +399,7 @@ tor_zstd_compress_process(tor_zstd_compress_state_t *state,
/** Deallocate <b>state</b>. */
void
-tor_zstd_compress_free(tor_zstd_compress_state_t *state)
+tor_zstd_compress_free_(tor_zstd_compress_state_t *state)
{
if (state == NULL)
return;
diff --git a/src/common/compress_zstd.h b/src/common/compress_zstd.h
index 02466010ff..9bca24ded7 100644
--- a/src/common/compress_zstd.h
+++ b/src/common/compress_zstd.h
@@ -31,7 +31,10 @@ tor_zstd_compress_process(tor_zstd_compress_state_t *state,
const char **in, size_t *in_len,
int finish);
-void tor_zstd_compress_free(tor_zstd_compress_state_t *state);
+void tor_zstd_compress_free_(tor_zstd_compress_state_t *state);
+#define tor_zstd_compress_free(st) \
+ FREE_AND_NULL(tor_zstd_compress_state_t, \
+ tor_zstd_compress_free_, (st))
size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state);
diff --git a/src/common/confline.c b/src/common/confline.c
index 04545bc2c3..bf613ab742 100644
--- a/src/common/confline.c
+++ b/src/common/confline.c
@@ -12,15 +12,18 @@
static int config_get_lines_aux(const char *string, config_line_t **result,
int extended, int allow_include,
- int *has_include, int recursion_level,
- config_line_t **last);
-static smartlist_t *config_get_file_list(const char *path);
-static int config_get_included_list(const char *path, int recursion_level,
- int extended, config_line_t **list,
- config_line_t **list_last);
+ int *has_include, smartlist_t *opened_lst,
+ int recursion_level, config_line_t **last);
+static smartlist_t *config_get_file_list(const char *path,
+ smartlist_t *opened_files);
+static int config_get_included_config(const char *path, int recursion_level,
+ int extended, config_line_t **config,
+ config_line_t **config_last,
+ smartlist_t *opened_lst);
static int config_process_include(const char *path, int recursion_level,
int extended, config_line_t **list,
- config_line_t **list_last);
+ config_line_t **list_last,
+ smartlist_t *opened_lst);
/** Helper: allocate a new configuration option mapping 'key' to 'val',
* append it to *<b>lst</b>. */
@@ -80,11 +83,13 @@ config_line_find(const config_line_t *lines,
/** Auxiliary function that does all the work of config_get_lines.
* <b>recursion_level</b> is the count of how many nested %includes we have.
+ * <b>opened_lst</b> will have a list of opened files if provided.
* Returns the a pointer to the last element of the <b>result</b> in
* <b>last</b>. */
static int
config_get_lines_aux(const char *string, config_line_t **result, int extended,
- int allow_include, int *has_include, int recursion_level,
+ int allow_include, int *has_include,
+ smartlist_t *opened_lst, int recursion_level,
config_line_t **last)
{
config_line_t *list = NULL, **next, *list_last = NULL;
@@ -134,7 +139,7 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
config_line_t *include_list;
if (config_process_include(v, recursion_level, extended, &include_list,
- &list_last) < 0) {
+ &list_last, opened_lst) < 0) {
log_warn(LD_CONFIG, "Error reading included configuration "
"file or directory: \"%s\".", v);
config_free_lines(list);
@@ -176,24 +181,27 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
/** Helper: parse the config string and strdup into key/value
* strings. Set *result to the list, or NULL if parsing the string
* failed. Set *has_include to 1 if <b>result</b> has values from
- * %included files. Return 0 on success, -1 on failure. Warn and ignore any
+ * %included files. <b>opened_lst</b> will have a list of opened files if
+ * provided. Return 0 on success, -1 on failure. Warn and ignore any
* misformatted lines.
*
* If <b>extended</b> is set, then treat keys beginning with / and with + as
* indicating "clear" and "append" respectively. */
int
config_get_lines_include(const char *string, config_line_t **result,
- int extended, int *has_include)
+ int extended, int *has_include,
+ smartlist_t *opened_lst)
{
- return config_get_lines_aux(string, result, extended, 1, has_include, 1,
- NULL);
+ return config_get_lines_aux(string, result, extended, 1, has_include,
+ opened_lst, 1, NULL);
}
/** Same as config_get_lines_include but does not allow %include */
int
config_get_lines(const char *string, config_line_t **result, int extended)
{
- return config_get_lines_aux(string, result, extended, 0, NULL, 1, NULL);
+ return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1,
+ NULL);
}
/** Adds a list of configuration files present on <b>path</b> to
@@ -201,12 +209,18 @@ config_get_lines(const char *string, config_line_t **result, int extended)
* only that file will be added to <b>file_list</b>. If it is a directory,
* all paths for files on that directory root (no recursion) except for files
* whose name starts with a dot will be added to <b>file_list</b>.
- * Return 0 on success, -1 on failure. Ignores empty files.
+ * <b>opened_files</b> will have a list of files opened by this function
+ * if provided. Return 0 on success, -1 on failure. Ignores empty files.
*/
static smartlist_t *
-config_get_file_list(const char *path)
+config_get_file_list(const char *path, smartlist_t *opened_files)
{
smartlist_t *file_list = smartlist_new();
+
+ if (opened_files) {
+ smartlist_add_strdup(opened_files, path);
+ }
+
file_status_t file_type = file_status(path);
if (file_type == FN_FILE) {
smartlist_add_strdup(file_list, path);
@@ -228,6 +242,10 @@ config_get_file_list(const char *path)
tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
tor_free(f);
+ if (opened_files) {
+ smartlist_add_strdup(opened_files, fullname);
+ }
+
if (file_status(fullname) != FN_FILE) {
tor_free(fullname);
continue;
@@ -245,19 +263,21 @@ config_get_file_list(const char *path)
}
/** Creates a list of config lines present on included <b>path</b>.
- * Set <b>list</b> to the list and <b>list_last</b> to the last element of
- * <b>list</b>. Return 0 on success, -1 on failure. */
+ * Set <b>config</b> to the list and <b>config_last</b> to the last element of
+ * <b>config</b>. <b>opened_lst</b> will have a list of opened files if
+ * provided. Return 0 on success, -1 on failure. */
static int
-config_get_included_list(const char *path, int recursion_level, int extended,
- config_line_t **list, config_line_t **list_last)
+config_get_included_config(const char *path, int recursion_level, int extended,
+ config_line_t **config, config_line_t **config_last,
+ smartlist_t *opened_lst)
{
char *included_conf = read_file_to_str(path, 0, NULL);
if (!included_conf) {
return -1;
}
- if (config_get_lines_aux(included_conf, list, extended, 1, NULL,
- recursion_level+1, list_last) < 0) {
+ if (config_get_lines_aux(included_conf, config, extended, 1, NULL,
+ opened_lst, recursion_level+1, config_last) < 0) {
tor_free(included_conf);
return -1;
}
@@ -268,41 +288,31 @@ config_get_included_list(const char *path, int recursion_level, int extended,
/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the
* list of configuration settings obtained and <b>list_last</b> to the last
- * element of the same list. Return 0 on success, -1 on failure. */
+ * element of the same list. <b>opened_lst</b> will have a list of opened
+ * files if provided. Return 0 on success, -1 on failure. */
static int
config_process_include(const char *path, int recursion_level, int extended,
- config_line_t **list, config_line_t **list_last)
+ config_line_t **list, config_line_t **list_last,
+ smartlist_t *opened_lst)
{
config_line_t *ret_list = NULL;
config_line_t **next = &ret_list;
-#if 0
- // Disabled -- we already unescape_string() on the result. */
- char *unquoted_path = get_unquoted_path(path);
- if (!unquoted_path) {
- return -1;
- }
- smartlist_t *config_files = config_get_file_list(unquoted_path);
- if (!config_files) {
- tor_free(unquoted_path);
- return -1;
- }
- tor_free(unquoted_path);
-#endif /* 0 */
- smartlist_t *config_files = config_get_file_list(path);
+ smartlist_t *config_files = config_get_file_list(path, opened_lst);
if (!config_files) {
return -1;
}
int rv = -1;
SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
- config_line_t *included_list = NULL;
- if (config_get_included_list(config_file, recursion_level, extended,
- &included_list, list_last) < 0) {
+ config_line_t *included_config = NULL;
+ if (config_get_included_config(config_file, recursion_level, extended,
+ &included_config, list_last,
+ opened_lst) < 0) {
goto done;
}
- *next = included_list;
+ *next = included_config;
if (*list_last)
next = &(*list_last)->next;
@@ -320,7 +330,7 @@ config_process_include(const char *path, int recursion_level, int extended,
* Free all the configuration lines on the linked list <b>front</b>.
*/
void
-config_free_lines(config_line_t *front)
+config_free_lines_(config_line_t *front)
{
config_line_t *tmp;
diff --git a/src/common/confline.h b/src/common/confline.h
index 8256326f2d..772a9bbbdc 100644
--- a/src/common/confline.h
+++ b/src/common/confline.h
@@ -7,6 +7,8 @@
#ifndef TOR_CONFLINE_H
#define TOR_CONFLINE_H
+#include "container.h"
+
/** Ordinary configuration line. */
#define CONFIG_LINE_NORMAL 0
/** Appends to previous configuration for the same option, even if we
@@ -44,8 +46,14 @@ int config_lines_eq(config_line_t *a, config_line_t *b);
int config_count_key(const config_line_t *a, const char *key);
int config_get_lines(const char *string, config_line_t **result, int extended);
int config_get_lines_include(const char *string, config_line_t **result,
- int extended, int *has_include);
-void config_free_lines(config_line_t *front);
+ int extended, int *has_include,
+ smartlist_t *opened_lst);
+void config_free_lines_(config_line_t *front);
+#define config_free_lines(front) \
+ do { \
+ config_free_lines_(front); \
+ (front) = NULL; \
+ } while (0)
const char *parse_config_line_from_str_verbose(const char *line,
char **key_out, char **value_out,
const char **err_out);
diff --git a/src/common/container.c b/src/common/container.c
index 8645cb4826..54b0b2028f 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -42,7 +42,7 @@ smartlist_new,(void))
* list's elements.
*/
MOCK_IMPL(void,
-smartlist_free,(smartlist_t *sl))
+smartlist_free_,(smartlist_t *sl))
{
if (!sl)
return;
@@ -1163,19 +1163,26 @@ HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
digest256map_entry_hash,
digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+#define strmap_entry_free(ent) \
+ FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent))
+#define digestmap_entry_free(ent) \
+ FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent))
+#define digest256map_entry_free(ent) \
+ FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent))
+
static inline void
-strmap_entry_free(strmap_entry_t *ent)
+strmap_entry_free_(strmap_entry_t *ent)
{
tor_free(ent->key);
tor_free(ent);
}
static inline void
-digestmap_entry_free(digestmap_entry_t *ent)
+digestmap_entry_free_(digestmap_entry_t *ent)
{
tor_free(ent);
}
static inline void
-digest256map_entry_free(digest256map_entry_t *ent)
+digest256map_entry_free_(digest256map_entry_t *ent)
{
tor_free(ent);
}
@@ -1335,7 +1342,7 @@ digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key)
* those entries. If free_val is provided, invoked it every value in \
* <b>map</b>. */ \
MOCK_IMPL(void, \
- prefix##_free, (maptype *map, void (*free_val)(void*))) \
+ prefix##_free_, (maptype *map, void (*free_val)(void*))) \
{ \
prefix##_entry_t **ent, **next, *this; \
if (!map) \
@@ -1525,7 +1532,7 @@ digestset_new(int max_elements)
/** Free all storage held in <b>set</b>. */
void
-digestset_free(digestset_t *set)
+digestset_free_(digestset_t *set)
{
if (!set)
return;
diff --git a/src/common/container.h b/src/common/container.h
index f6affd3bc6..5d2dce5416 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -28,7 +28,9 @@ typedef struct smartlist_t {
} smartlist_t;
MOCK_DECL(smartlist_t *, smartlist_new, (void));
-MOCK_DECL(void, smartlist_free, (smartlist_t *sl));
+MOCK_DECL(void, smartlist_free_, (smartlist_t *sl));
+#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl))
+
void smartlist_clear(smartlist_t *sl);
void smartlist_add(smartlist_t *sl, void *element);
void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
@@ -350,7 +352,7 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
void* prefix##set(maptype *map, keytype key, void *val); \
void* prefix##get(const maptype *map, keytype key); \
void* prefix##remove(maptype *map, keytype key); \
- MOCK_DECL(void, prefix##free, (maptype *map, void (*free_val)(void*))); \
+ MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \
int prefix##isempty(const maptype *map); \
int prefix##size(const maptype *map); \
prefix##iter_t *prefix##iter_init(maptype *map); \
@@ -368,6 +370,16 @@ DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
* table. */
DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
+#define MAP_FREE_AND_NULL(maptype, map, fn) \
+ do { \
+ maptype ## _free_((map), (fn)); \
+ (map) = NULL; \
+ } while (0)
+
+#define strmap_free(map, fn) MAP_FREE_AND_NULL(strmap, (map), (fn))
+#define digestmap_free(map, fn) MAP_FREE_AND_NULL(digestmap, (map), (fn))
+#define digest256map_free(map, fn) MAP_FREE_AND_NULL(digest256map, (map), (fn))
+
#undef DECLARE_MAP_FNS
/** Iterates over the key-value pairs in a map <b>map</b> in order.
@@ -528,9 +540,9 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
return (valtype*)digestmap_remove((digestmap_t*)map, key); \
} \
ATTR_UNUSED static inline void \
- prefix##f##ree(maptype *map, void (*free_val)(void*)) \
+ prefix##f##ree_(maptype *map, void (*free_val)(void*)) \
{ \
- digestmap_free((digestmap_t*)map, free_val); \
+ digestmap_free_((digestmap_t*)map, free_val); \
} \
ATTR_UNUSED static inline int \
prefix##isempty(maptype *map) \
@@ -614,10 +626,12 @@ bitarray_expand(bitarray_t *ba,
}
/** Free the bit array <b>ba</b>. */
static inline void
-bitarray_free(bitarray_t *ba)
+bitarray_free_(bitarray_t *ba)
{
tor_free(ba);
}
+#define bitarray_free(ba) FREE_AND_NULL(bitarray_t, bitarray_free_, (ba))
+
/** Set the <b>bit</b>th bit in <b>b</b> to 1. */
static inline void
bitarray_set(bitarray_t *b, int bit)
@@ -679,7 +693,8 @@ digestset_contains(const digestset_t *set, const char *digest)
#undef BIT
digestset_t *digestset_new(int max_elements);
-void digestset_free(digestset_t* set);
+void digestset_free_(digestset_t* set);
+#define digestset_free(set) FREE_AND_NULL(digestset_t, digestset_free_, (set))
/* These functions, given an <b>array</b> of <b>n_elements</b>, return the
* <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element;
diff --git a/src/common/crypto.c b/src/common/crypto.c
index c9db7cb4ba..d85aca4004 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -28,6 +28,7 @@
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
+#include "crypto_rsa.h"
DISABLE_GCC_WARNING(redundant-decls)
@@ -82,80 +83,20 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "keccak-tiny/keccak-tiny.h"
-#ifdef ANDROID
-/* Android's OpenSSL seems to have removed all of its Engine support. */
-#define DISABLE_ENGINES
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \
- !defined(LIBRESSL_VERSION_NUMBER)
-/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require
- * seting up various callbacks.
- *
- * OpenSSL 1.1.0pre4 has a messed up `ERR_remove_thread_state()` prototype,
- * while the previous one was restored in pre5, and the function made a no-op
- * (along with a deprecated annotation, which produces a compiler warning).
- *
- * While it is possible to support all three versions of the thread API,
- * a version that existed only for one snapshot pre-release is kind of
- * pointless, so let's not.
- */
-#define NEW_THREAD_API
-#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */
-
/** Longest recognized */
#define MAX_DNS_LABEL_SIZE 63
/** Largest strong entropy request */
#define MAX_STRONGEST_RAND_SIZE 256
-#ifndef NEW_THREAD_API
-/** A number of preallocated mutexes for use by OpenSSL. */
-static tor_mutex_t **openssl_mutexes_ = NULL;
-/** How many mutexes have we allocated for use by OpenSSL? */
-static int n_openssl_mutexes_ = 0;
-#endif /* !defined(NEW_THREAD_API) */
-
-/** A public key, or a public/private key-pair. */
-struct crypto_pk_t
-{
- int refs; /**< reference count, so we don't have to copy keys */
- RSA *key; /**< The key itself */
-};
-
/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake
* while we're waiting for the second.*/
struct crypto_dh_t {
DH *dh; /**< The openssl DH object */
};
-static int setup_openssl_threading(void);
static int tor_check_dh_key(int severity, const BIGNUM *bn);
-/** Return the number of bytes added by padding method <b>padding</b>.
- */
-static inline int
-crypto_get_rsa_padding_overhead(int padding)
-{
- switch (padding)
- {
- case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
- default: tor_assert(0); return -1; // LCOV_EXCL_LINE
- }
-}
-
-/** Given a padding method <b>padding</b>, return the correct OpenSSL constant.
- */
-static inline int
-crypto_get_rsa_padding(int padding)
-{
- switch (padding)
- {
- case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING;
- default: tor_assert(0); return -1; // LCOV_EXCL_LINE
- }
-}
-
/** Boolean: has OpenSSL's crypto been initialized? */
static int crypto_early_initialized_ = 0;
@@ -220,52 +161,6 @@ try_load_engine(const char *path, const char *engine)
}
#endif /* !defined(DISABLE_ENGINES) */
-/* Returns a trimmed and human-readable version of an openssl version string
-* <b>raw_version</b>. They are usually in the form of 'OpenSSL 1.0.0b 10
-* May 2012' and this will parse them into a form similar to '1.0.0b' */
-static char *
-parse_openssl_version_str(const char *raw_version)
-{
- const char *end_of_version = NULL;
- /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's
- trim that down. */
- if (!strcmpstart(raw_version, "OpenSSL ")) {
- raw_version += strlen("OpenSSL ");
- end_of_version = strchr(raw_version, ' ');
- }
-
- if (end_of_version)
- return tor_strndup(raw_version,
- end_of_version-raw_version);
- else
- return tor_strdup(raw_version);
-}
-
-static char *crypto_openssl_version_str = NULL;
-/* Return a human-readable version of the run-time openssl version number. */
-const char *
-crypto_openssl_get_version_str(void)
-{
- if (crypto_openssl_version_str == NULL) {
- const char *raw_version = OpenSSL_version(OPENSSL_VERSION);
- crypto_openssl_version_str = parse_openssl_version_str(raw_version);
- }
- return crypto_openssl_version_str;
-}
-
-static char *crypto_openssl_header_version_str = NULL;
-/* Return a human-readable version of the compile-time openssl version
-* number. */
-const char *
-crypto_openssl_get_header_version_str(void)
-{
- if (crypto_openssl_header_version_str == NULL) {
- crypto_openssl_header_version_str =
- parse_openssl_version_str(OPENSSL_VERSION_TEXT);
- }
- return crypto_openssl_header_version_str;
-}
-
/** Make sure that openssl is using its default PRNG. Return 1 if we had to
* adjust it; 0 otherwise. */
STATIC int
@@ -283,11 +178,12 @@ crypto_force_rand_ssleay(void)
return 0;
}
+static int have_seeded_siphash = 0;
+
/** Set up the siphash key if we haven't already done so. */
int
crypto_init_siphash_key(void)
{
- static int have_seeded_siphash = 0;
struct sipkey key;
if (have_seeded_siphash)
return 0;
@@ -437,73 +333,6 @@ crypto_thread_cleanup(void)
#endif
}
-/** used internally: quicly validate a crypto_pk_t object as a private key.
- * Return 1 iff the public key is valid, 0 if obviously invalid.
- */
-static int
-crypto_pk_private_ok(const crypto_pk_t *k)
-{
-#ifdef OPENSSL_1_1_API
- if (!k || !k->key)
- return 0;
-
- const BIGNUM *p, *q;
- RSA_get0_factors(k->key, &p, &q);
- return p != NULL; /* XXX/yawning: Should we check q? */
-#else /* !(defined(OPENSSL_1_1_API)) */
- return k && k->key && k->key->p;
-#endif /* defined(OPENSSL_1_1_API) */
-}
-
-/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
-crypto_pk_t *
-crypto_new_pk_from_rsa_(RSA *rsa)
-{
- crypto_pk_t *env;
- tor_assert(rsa);
- env = tor_malloc(sizeof(crypto_pk_t));
- env->refs = 1;
- env->key = rsa;
- return env;
-}
-
-/** Helper, used by tor-gencert.c. Return the RSA from a
- * crypto_pk_t. */
-RSA *
-crypto_pk_get_rsa_(crypto_pk_t *env)
-{
- return env->key;
-}
-
-/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
- * private is set, include the private-key portion of the key. Return a valid
- * pointer on success, and NULL on failure. */
-MOCK_IMPL(EVP_PKEY *,
-crypto_pk_get_evp_pkey_,(crypto_pk_t *env, int private))
-{
- RSA *key = NULL;
- EVP_PKEY *pkey = NULL;
- tor_assert(env->key);
- if (private) {
- if (!(key = RSAPrivateKey_dup(env->key)))
- goto error;
- } else {
- if (!(key = RSAPublicKey_dup(env->key)))
- goto error;
- }
- if (!(pkey = EVP_PKEY_new()))
- goto error;
- if (!(EVP_PKEY_assign_RSA(pkey, key)))
- goto error;
- return pkey;
- error:
- if (pkey)
- EVP_PKEY_free(pkey);
- if (key)
- RSA_free(key);
- return NULL;
-}
-
/** Used by tortls.c: Get the DH* from a crypto_dh_t.
*/
DH *
@@ -512,38 +341,6 @@ crypto_dh_get_dh_(crypto_dh_t *dh)
return dh->dh;
}
-/** Allocate and return storage for a public key. The key itself will not yet
- * be set.
- */
-MOCK_IMPL(crypto_pk_t *,
-crypto_pk_new,(void))
-{
- RSA *rsa;
-
- rsa = RSA_new();
- tor_assert(rsa);
- return crypto_new_pk_from_rsa_(rsa);
-}
-
-/** Release a reference to an asymmetric key; when all the references
- * are released, free the key.
- */
-void
-crypto_pk_free(crypto_pk_t *env)
-{
- if (!env)
- return;
-
- if (--env->refs > 0)
- return;
- tor_assert(env->refs == 0);
-
- if (env->key)
- RSA_free(env->key);
-
- tor_free(env);
-}
-
/** Allocate and return a new symmetric cipher using the provided key and iv.
* The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both
* must be provided. Key length must be 128, 192, or 256 */
@@ -592,7 +389,7 @@ crypto_cipher_new(const char *key)
/** Free a symmetric cipher.
*/
void
-crypto_cipher_free(crypto_cipher_t *env)
+crypto_cipher_free_(crypto_cipher_t *env)
{
if (!env)
return;
@@ -602,543 +399,6 @@ crypto_cipher_free(crypto_cipher_t *env)
/* public key crypto */
-/** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>.
- * Return 0 on success, -1 on failure.
- */
-MOCK_IMPL(int,
-crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits))
-{
- tor_assert(env);
-
- if (env->key) {
- RSA_free(env->key);
- env->key = NULL;
- }
-
- {
- BIGNUM *e = BN_new();
- RSA *r = NULL;
- if (!e)
- goto done;
- if (! BN_set_word(e, 65537))
- goto done;
- r = RSA_new();
- if (!r)
- goto done;
- if (RSA_generate_key_ex(r, bits, e, NULL) == -1)
- goto done;
-
- env->key = r;
- r = NULL;
- done:
- if (e)
- BN_clear_free(e);
- if (r)
- RSA_free(r);
- }
-
- if (!env->key) {
- crypto_log_errors(LOG_WARN, "generating RSA key");
- return -1;
- }
-
- return 0;
-}
-
-/** A PEM callback that always reports a failure to get a password */
-static int
-pem_no_password_cb(char *buf, int size, int rwflag, void *u)
-{
- (void)buf;
- (void)size;
- (void)rwflag;
- (void)u;
- return 0;
-}
-
-/** Read a PEM-encoded private key from the <b>len</b>-byte string <b>s</b>
- * into <b>env</b>. Return 0 on success, -1 on failure. If len is -1,
- * the string is nul-terminated.
- */
-int
-crypto_pk_read_private_key_from_string(crypto_pk_t *env,
- const char *s, ssize_t len)
-{
- BIO *b;
-
- tor_assert(env);
- tor_assert(s);
- tor_assert(len < INT_MAX && len < SSIZE_T_CEILING);
-
- /* Create a read-only memory BIO, backed by the string 's' */
- b = BIO_new_mem_buf((char*)s, (int)len);
- if (!b)
- return -1;
-
- if (env->key)
- RSA_free(env->key);
-
- env->key = PEM_read_bio_RSAPrivateKey(b,NULL,pem_no_password_cb,NULL);
-
- BIO_free(b);
-
- if (!env->key) {
- crypto_log_errors(LOG_WARN, "Error parsing private key");
- return -1;
- }
- return 0;
-}
-
-/** Read a PEM-encoded private key from the file named by
- * <b>keyfile</b> into <b>env</b>. Return 0 on success, -1 on failure.
- */
-int
-crypto_pk_read_private_key_from_filename(crypto_pk_t *env,
- const char *keyfile)
-{
- char *contents;
- int r;
-
- /* Read the file into a string. */
- contents = read_file_to_str(keyfile, 0, NULL);
- if (!contents) {
- log_warn(LD_CRYPTO, "Error reading private key from \"%s\"", keyfile);
- return -1;
- }
-
- /* Try to parse it. */
- r = crypto_pk_read_private_key_from_string(env, contents, -1);
- memwipe(contents, 0, strlen(contents));
- tor_free(contents);
- if (r)
- return -1; /* read_private_key_from_string already warned, so we don't.*/
-
- /* Make sure it's valid. */
- if (crypto_pk_check_key(env) <= 0)
- return -1;
-
- return 0;
-}
-
-/** Helper function to implement crypto_pk_write_*_key_to_string. Return 0 on
- * success, -1 on failure. */
-static int
-crypto_pk_write_key_to_string_impl(crypto_pk_t *env, char **dest,
- size_t *len, int is_public)
-{
- BUF_MEM *buf;
- BIO *b;
- int r;
-
- tor_assert(env);
- tor_assert(env->key);
- tor_assert(dest);
-
- b = BIO_new(BIO_s_mem()); /* Create a memory BIO */
- if (!b)
- return -1;
-
- /* Now you can treat b as if it were a file. Just use the
- * PEM_*_bio_* functions instead of the non-bio variants.
- */
- if (is_public)
- r = PEM_write_bio_RSAPublicKey(b, env->key);
- else
- r = PEM_write_bio_RSAPrivateKey(b, env->key, NULL,NULL,0,NULL,NULL);
-
- if (!r) {
- crypto_log_errors(LOG_WARN, "writing RSA key to string");
- BIO_free(b);
- return -1;
- }
-
- BIO_get_mem_ptr(b, &buf);
-
- *dest = tor_malloc(buf->length+1);
- memcpy(*dest, buf->data, buf->length);
- (*dest)[buf->length] = 0; /* nul terminate it */
- *len = buf->length;
-
- BIO_free(b);
-
- return 0;
-}
-
-/** PEM-encode the public key portion of <b>env</b> and write it to a
- * newly allocated string. On success, set *<b>dest</b> to the new
- * string, *<b>len</b> to the string's length, and return 0. On
- * failure, return -1.
- */
-int
-crypto_pk_write_public_key_to_string(crypto_pk_t *env, char **dest,
- size_t *len)
-{
- return crypto_pk_write_key_to_string_impl(env, dest, len, 1);
-}
-
-/** PEM-encode the private key portion of <b>env</b> and write it to a
- * newly allocated string. On success, set *<b>dest</b> to the new
- * string, *<b>len</b> to the string's length, and return 0. On
- * failure, return -1.
- */
-int
-crypto_pk_write_private_key_to_string(crypto_pk_t *env, char **dest,
- size_t *len)
-{
- return crypto_pk_write_key_to_string_impl(env, dest, len, 0);
-}
-
-/** Read a PEM-encoded public key from the first <b>len</b> characters of
- * <b>src</b>, and store the result in <b>env</b>. Return 0 on success, -1 on
- * failure.
- */
-int
-crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src,
- size_t len)
-{
- BIO *b;
-
- tor_assert(env);
- tor_assert(src);
- tor_assert(len<INT_MAX);
-
- b = BIO_new(BIO_s_mem()); /* Create a memory BIO */
- if (!b)
- return -1;
-
- BIO_write(b, src, (int)len);
-
- if (env->key)
- RSA_free(env->key);
- env->key = PEM_read_bio_RSAPublicKey(b, NULL, pem_no_password_cb, NULL);
- BIO_free(b);
- if (!env->key) {
- crypto_log_errors(LOG_WARN, "reading public key from string");
- return -1;
- }
-
- return 0;
-}
-
-/** Write the private key from <b>env</b> into the file named by <b>fname</b>,
- * PEM-encoded. Return 0 on success, -1 on failure.
- */
-int
-crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
- const char *fname)
-{
- BIO *bio;
- char *cp;
- long len;
- char *s;
- int r;
-
- tor_assert(crypto_pk_private_ok(env));
-
- if (!(bio = BIO_new(BIO_s_mem())))
- return -1;
- if (PEM_write_bio_RSAPrivateKey(bio, env->key, NULL,NULL,0,NULL,NULL)
- == 0) {
- crypto_log_errors(LOG_WARN, "writing private key");
- BIO_free(bio);
- return -1;
- }
- len = BIO_get_mem_data(bio, &cp);
- tor_assert(len >= 0);
- s = tor_malloc(len+1);
- memcpy(s, cp, len);
- s[len]='\0';
- r = write_str_to_file(fname, s, 0);
- BIO_free(bio);
- memwipe(s, 0, strlen(s));
- tor_free(s);
- return r;
-}
-
-/** Return true iff <b>env</b> has a valid key.
- */
-int
-crypto_pk_check_key(crypto_pk_t *env)
-{
- int r;
- tor_assert(env);
-
- r = RSA_check_key(env->key);
- if (r <= 0)
- crypto_log_errors(LOG_WARN,"checking RSA key");
- return r;
-}
-
-/** Return true iff <b>key</b> contains the private-key portion of the RSA
- * key. */
-int
-crypto_pk_key_is_private(const crypto_pk_t *key)
-{
- tor_assert(key);
- return crypto_pk_private_ok(key);
-}
-
-/** Return true iff <b>env</b> contains a public key whose public exponent
- * equals 65537.
- */
-int
-crypto_pk_public_exponent_ok(crypto_pk_t *env)
-{
- tor_assert(env);
- tor_assert(env->key);
-
- const BIGNUM *e;
-
-#ifdef OPENSSL_1_1_API
- const BIGNUM *n, *d;
- RSA_get0_key(env->key, &n, &e, &d);
-#else
- e = env->key->e;
-#endif /* defined(OPENSSL_1_1_API) */
- return BN_is_word(e, 65537);
-}
-
-/** Compare the public-key components of a and b. Return less than 0
- * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is
- * considered to be less than all non-NULL keys, and equal to itself.
- *
- * Note that this may leak information about the keys through timing.
- */
-int
-crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b)
-{
- int result;
- char a_is_non_null = (a != NULL) && (a->key != NULL);
- char b_is_non_null = (b != NULL) && (b->key != NULL);
- char an_argument_is_null = !a_is_non_null | !b_is_non_null;
-
- result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null));
- if (an_argument_is_null)
- return result;
-
- const BIGNUM *a_n, *a_e;
- const BIGNUM *b_n, *b_e;
-
-#ifdef OPENSSL_1_1_API
- const BIGNUM *a_d, *b_d;
- RSA_get0_key(a->key, &a_n, &a_e, &a_d);
- RSA_get0_key(b->key, &b_n, &b_e, &b_d);
-#else
- a_n = a->key->n;
- a_e = a->key->e;
- b_n = b->key->n;
- b_e = b->key->e;
-#endif /* defined(OPENSSL_1_1_API) */
-
- tor_assert(a_n != NULL && a_e != NULL);
- tor_assert(b_n != NULL && b_e != NULL);
-
- result = BN_cmp(a_n, b_n);
- if (result)
- return result;
- return BN_cmp(a_e, b_e);
-}
-
-/** Compare the public-key components of a and b. Return non-zero iff
- * a==b. A NULL key is considered to be distinct from all non-NULL
- * keys, and equal to itself.
- *
- * Note that this may leak information about the keys through timing.
- */
-int
-crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b)
-{
- return (crypto_pk_cmp_keys(a, b) == 0);
-}
-
-/** Return the size of the public key modulus in <b>env</b>, in bytes. */
-size_t
-crypto_pk_keysize(const crypto_pk_t *env)
-{
- tor_assert(env);
- tor_assert(env->key);
-
- return (size_t) RSA_size((RSA*)env->key);
-}
-
-/** Return the size of the public key modulus of <b>env</b>, in bits. */
-int
-crypto_pk_num_bits(crypto_pk_t *env)
-{
- tor_assert(env);
- tor_assert(env->key);
-
-#ifdef OPENSSL_1_1_API
- /* It's so stupid that there's no other way to check that n is valid
- * before calling RSA_bits().
- */
- const BIGNUM *n, *e, *d;
- RSA_get0_key(env->key, &n, &e, &d);
- tor_assert(n != NULL);
-
- return RSA_bits(env->key);
-#else /* !(defined(OPENSSL_1_1_API)) */
- tor_assert(env->key->n);
- return BN_num_bits(env->key->n);
-#endif /* defined(OPENSSL_1_1_API) */
-}
-
-/** Increase the reference count of <b>env</b>, and return it.
- */
-crypto_pk_t *
-crypto_pk_dup_key(crypto_pk_t *env)
-{
- tor_assert(env);
- tor_assert(env->key);
-
- env->refs++;
- return env;
-}
-
-#ifdef TOR_UNIT_TESTS
-/** For testing: replace dest with src. (Dest must have a refcount
- * of 1) */
-void
-crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src)
-{
- tor_assert(dest);
- tor_assert(dest->refs == 1);
- tor_assert(src);
- RSA_free(dest->key);
- dest->key = RSAPrivateKey_dup(src->key);
-}
-#endif /* defined(TOR_UNIT_TESTS) */
-
-/** Make a real honest-to-goodness copy of <b>env</b>, and return it.
- * Returns NULL on failure. */
-crypto_pk_t *
-crypto_pk_copy_full(crypto_pk_t *env)
-{
- RSA *new_key;
- int privatekey = 0;
- tor_assert(env);
- tor_assert(env->key);
-
- if (crypto_pk_private_ok(env)) {
- new_key = RSAPrivateKey_dup(env->key);
- privatekey = 1;
- } else {
- new_key = RSAPublicKey_dup(env->key);
- }
- if (!new_key) {
- /* LCOV_EXCL_START
- *
- * We can't cause RSA*Key_dup() to fail, so we can't really test this.
- */
- log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.",
- privatekey?"private":"public");
- crypto_log_errors(LOG_ERR,
- privatekey ? "Duplicating a private key" :
- "Duplicating a public key");
- tor_fragile_assert();
- return NULL;
- /* LCOV_EXCL_STOP */
- }
-
- return crypto_new_pk_from_rsa_(new_key);
-}
-
-/** 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
- * written. On failure, return -1.
- *
- * <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_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
- const char *from, size_t fromlen, int padding)
-{
- int r;
- tor_assert(env);
- tor_assert(from);
- tor_assert(to);
- tor_assert(fromlen<INT_MAX);
- tor_assert(tolen >= crypto_pk_keysize(env));
-
- r = RSA_public_encrypt((int)fromlen,
- (unsigned char*)from, (unsigned char*)to,
- env->key, crypto_get_rsa_padding(padding));
- if (r<0) {
- crypto_log_errors(LOG_WARN, "performing RSA encryption");
- return -1;
- }
- return r;
-}
-
-/** Decrypt <b>fromlen</b> bytes from <b>from</b> with the private 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
- * written. On failure, return -1.
- *
- * <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_decrypt(crypto_pk_t *env, char *to,
- size_t tolen,
- const char *from, size_t fromlen,
- int padding, int warnOnFailure)
-{
- int r;
- tor_assert(env);
- tor_assert(from);
- tor_assert(to);
- tor_assert(env->key);
- tor_assert(fromlen<INT_MAX);
- tor_assert(tolen >= crypto_pk_keysize(env));
- if (!crypto_pk_key_is_private(env))
- /* Not a private key */
- return -1;
-
- r = RSA_private_decrypt((int)fromlen,
- (unsigned char*)from, (unsigned char*)to,
- env->key, crypto_get_rsa_padding(padding));
-
- if (r<0) {
- crypto_log_errors(warnOnFailure?LOG_WARN:LOG_DEBUG,
- "performing RSA decryption");
- return -1;
- }
- return r;
-}
-
-/** Check the signature in <b>from</b> (<b>fromlen</b> bytes long) with the
- * public key in <b>env</b>, using PKCS1 padding. On success, write the
- * signed data to <b>to</b>, and return the number of bytes written.
- * On failure, return -1.
- *
- * <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>.
- */
-MOCK_IMPL(int,
-crypto_pk_public_checksig,(const crypto_pk_t *env, char *to,
- size_t tolen,
- const char *from, size_t fromlen))
-{
- int r;
- tor_assert(env);
- tor_assert(from);
- tor_assert(to);
- tor_assert(fromlen < INT_MAX);
- tor_assert(tolen >= crypto_pk_keysize(env));
- r = RSA_public_decrypt((int)fromlen,
- (unsigned char*)from, (unsigned char*)to,
- env->key, RSA_PKCS1_PADDING);
-
- if (r<0) {
- crypto_log_errors(LOG_INFO, "checking RSA signature");
- return -1;
- }
- return r;
-}
-
/** 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
@@ -1182,38 +442,6 @@ crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data,
return 0;
}
-/** Sign <b>fromlen</b> bytes of data from <b>from</b> with the private key in
- * <b>env</b>, using PKCS1 padding. On success, write the signature to
- * <b>to</b>, and return the number of bytes written. On failure, return
- * -1.
- *
- * <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(const crypto_pk_t *env, char *to, size_t tolen,
- const char *from, size_t fromlen)
-{
- int r;
- tor_assert(env);
- tor_assert(from);
- tor_assert(to);
- tor_assert(fromlen < INT_MAX);
- tor_assert(tolen >= crypto_pk_keysize(env));
- if (!crypto_pk_key_is_private(env))
- /* Not a private key */
- return -1;
-
- r = RSA_private_encrypt((int)fromlen,
- (unsigned char*)from, (unsigned char*)to,
- (RSA*)env->key, RSA_PKCS1_PADDING);
- if (r<0) {
- crypto_log_errors(LOG_WARN, "generating RSA signature");
- return -1;
- }
- return r;
-}
-
/** 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
@@ -1377,51 +605,6 @@ crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env,
return -1;
}
-/** ASN.1-encode the public portion of <b>pk</b> into <b>dest</b>.
- * Return -1 on error, or the number of characters used on success.
- */
-int
-crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len)
-{
- int len;
- unsigned char *buf = NULL;
-
- len = i2d_RSAPublicKey(pk->key, &buf);
- if (len < 0 || buf == NULL)
- return -1;
-
- if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) {
- OPENSSL_free(buf);
- return -1;
- }
- /* We don't encode directly into 'dest', because that would be illegal
- * type-punning. (C99 is smarter than me, C99 is smarter than me...)
- */
- memcpy(dest,buf,len);
- OPENSSL_free(buf);
- return len;
-}
-
-/** Decode an ASN.1-encoded public key from <b>str</b>; return the result on
- * success and NULL on failure.
- */
-crypto_pk_t *
-crypto_pk_asn1_decode(const char *str, size_t len)
-{
- RSA *rsa;
- unsigned char *buf;
- const unsigned char *cp;
- cp = buf = tor_malloc(len);
- memcpy(buf,str,len);
- rsa = d2i_RSAPublicKey(NULL, &cp, len);
- tor_free(buf);
- if (!rsa) {
- crypto_log_errors(LOG_WARN,"decoding public key");
- return NULL;
- }
- return crypto_new_pk_from_rsa_(rsa);
-}
-
/** 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.
@@ -1429,18 +612,24 @@ crypto_pk_asn1_decode(const char *str, size_t len)
int
crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
{
- unsigned char *buf = NULL;
+ char *buf;
+ size_t buflen;
int len;
+ int rv = -1;
- len = i2d_RSAPublicKey((RSA*)pk->key, &buf);
- if (len < 0 || buf == NULL)
- return -1;
- if (crypto_digest(digest_out, (char*)buf, len) < 0) {
- OPENSSL_free(buf);
- return -1;
- }
- OPENSSL_free(buf);
- return 0;
+ 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
@@ -1448,18 +637,24 @@ 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)
{
- unsigned char *buf = NULL;
+ char *buf;
+ size_t buflen;
int len;
+ int rv = -1;
- len = i2d_RSAPublicKey(pk->key, &buf);
- if (len < 0 || buf == NULL)
- return -1;
- if (crypto_common_digests(digests_out, (char*)buf, len) < 0) {
- OPENSSL_free(buf);
- return -1;
- }
- OPENSSL_free(buf);
- return 0;
+ 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
@@ -1482,127 +677,6 @@ crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in)
*out = '\0';
}
-/** Given a private or public key <b>pk</b>, put a fingerprint of the
- * public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 bytes of
- * space). Return 0 on success, -1 on failure.
- *
- * Fingerprints are computed as the SHA1 digest of the ASN.1 encoding
- * of the public key, converted to hexadecimal, in upper case, with a
- * space after every four digits.
- *
- * If <b>add_space</b> is false, omit the spaces.
- */
-int
-crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
-{
- char digest[DIGEST_LEN];
- char hexdigest[HEX_DIGEST_LEN+1];
- if (crypto_pk_get_digest(pk, digest)) {
- return -1;
- }
- base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN);
- if (add_space) {
- crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest);
- } else {
- strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1);
- }
- return 0;
-}
-
-/** Given a private or public key <b>pk</b>, put a hashed fingerprint of
- * the public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1
- * bytes of space). Return 0 on success, -1 on failure.
- *
- * Hashed fingerprints are computed as the SHA1 digest of the SHA1 digest
- * of the ASN.1 encoding of the public key, converted to hexadecimal, in
- * upper case.
- */
-int
-crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
-{
- char digest[DIGEST_LEN], hashed_digest[DIGEST_LEN];
- if (crypto_pk_get_digest(pk, digest)) {
- return -1;
- }
- if (crypto_digest(hashed_digest, digest, DIGEST_LEN) < 0) {
- return -1;
- }
- base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN);
- return 0;
-}
-
-/** 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
- * sucess, -1 on failure.
- *
- * It is the caller's responsibility to sanitize and free the resulting buffer.
- */
-int
-crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out)
-{
- unsigned char *der = NULL;
- int der_len;
- int ret = -1;
-
- *priv_out = NULL;
-
- der_len = i2d_RSAPrivateKey(pk->key, &der);
- if (der_len < 0 || der == NULL)
- return ret;
-
- size_t priv_len = base64_encode_size(der_len, 0) + 1;
- char *priv = tor_malloc_zero(priv_len);
- if (base64_encode(priv, priv_len, (char *)der, der_len, 0) >= 0) {
- *priv_out = priv;
- ret = 0;
- } else {
- tor_free(priv);
- }
-
- memwipe(der, 0, der_len);
- OPENSSL_free(der);
- return ret;
-}
-
-/** Given a string containing the Base64 encoded DER representation of the
- * private key <b>str</b>, decode and return the result on success, or NULL
- * on failure.
- */
-crypto_pk_t *
-crypto_pk_base64_decode(const char *str, size_t len)
-{
- crypto_pk_t *pk = NULL;
-
- char *der = tor_malloc_zero(len + 1);
- int der_len = base64_decode(der, len, str, len);
- if (der_len <= 0) {
- log_warn(LD_CRYPTO, "Stored RSA private key seems corrupted (base64).");
- goto out;
- }
-
- const unsigned char *dp = (unsigned char*)der; /* Shut the compiler up. */
- RSA *rsa = d2i_RSAPrivateKey(NULL, &dp, der_len);
- if (!rsa) {
- crypto_log_errors(LOG_WARN, "decoding private key");
- goto out;
- }
-
- pk = crypto_new_pk_from_rsa_(rsa);
-
- /* Make sure it's valid. */
- if (crypto_pk_check_key(pk) <= 0) {
- crypto_pk_free(pk);
- pk = NULL;
- goto out;
- }
-
- out:
- memwipe(der, 0, len + 1);
- tor_free(der);
- return pk;
-}
-
/* symmetric crypto */
/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher
@@ -1977,7 +1051,7 @@ crypto_digest512_new(digest_algorithm_t algorithm)
/** Deallocate a digest object.
*/
void
-crypto_digest_free(crypto_digest_t *digest)
+crypto_digest_free_(crypto_digest_t *digest)
{
if (!digest)
return;
@@ -2224,7 +1298,7 @@ crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
/** Cleanse and deallocate a XOF object. */
void
-crypto_xof_free(crypto_xof_t *xof)
+crypto_xof_free_(crypto_xof_t *xof)
{
if (!xof)
return;
@@ -2777,7 +1851,7 @@ crypto_expand_key_material_rfc5869_sha256(
/** Free a DH key exchange object.
*/
void
-crypto_dh_free(crypto_dh_t *dh)
+crypto_dh_free_(crypto_dh_t *dh)
{
if (!dh)
return;
@@ -2817,6 +1891,12 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
{
tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE);
+ /* We only log at notice-level here because in the case that this function
+ * fails the crypto_strongest_rand_raw() caller will log with a warning-level
+ * message and let crypto_strongest_rand() error out and finally terminating
+ * Tor with an assertion error.
+ */
+
#ifdef TOR_UNIT_TESTS
if (break_strongest_rng_syscall)
return -1;
@@ -2829,21 +1909,21 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
if (!provider_set) {
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
- log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
+ log_notice(LD_CRYPTO, "Unable to set Windows CryptoAPI provider [1].");
return -1;
}
provider_set = 1;
}
if (!CryptGenRandom(provider, out_len, out)) {
- log_warn(LD_CRYPTO, "Can't get entropy from CryptoAPI.");
+ log_notice(LD_CRYPTO, "Unable get entropy from the Windows CryptoAPI.");
return -1;
}
return 0;
#elif defined(__linux__) && defined(SYS_getrandom)
- static int getrandom_works = 1; /* Be optimitic about our chances... */
+ static int getrandom_works = 1; /* Be optimistic about our chances... */
- /* getrandom() isn't as straight foward as getentropy(), and has
+ /* getrandom() isn't as straightforward as getentropy(), and has
* no glibc wrapper.
*
* As far as I can tell from getrandom(2) and the source code, the
@@ -2856,7 +1936,7 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
*
* We optimistically assume that getrandom() is available and functional
* because it is the way of the future, and 2 branch mispredicts pale in
- * comparision to the overheads involved with failing to open
+ * comparison to the overheads involved with failing to open
* /dev/srandom followed by opening and reading from /dev/urandom.
*/
if (PREDICT_LIKELY(getrandom_works)) {
@@ -2877,13 +1957,15 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
/* Useful log message for errno. */
if (errno == ENOSYS) {
- log_warn(LD_CRYPTO, "Can't get entropy from getrandom()."
- " You are running a version of Tor built to support"
- " getrandom(), but the kernel doesn't implement this"
- " function--probably because it is too old?");
+ log_notice(LD_CRYPTO, "Can't get entropy from getrandom()."
+ " You are running a version of Tor built to support"
+ " getrandom(), but the kernel doesn't implement this"
+ " function--probably because it is too old?"
+ " Trying fallback method instead.");
} else {
- log_warn(LD_CRYPTO, "Can't get entropy from getrandom(): %s.",
- strerror(errno));
+ log_notice(LD_CRYPTO, "Can't get entropy from getrandom(): %s."
+ " Trying fallback method instead.",
+ strerror(errno));
}
getrandom_works = 0; /* Don't bother trying again. */
@@ -2935,7 +2017,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len)
size_t n;
for (i = 0; filenames[i]; ++i) {
- log_debug(LD_FS, "Considering %s for entropy", filenames[i]);
+ log_debug(LD_FS, "Considering %s as entropy source", filenames[i]);
fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0);
if (fd<0) continue;
log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
@@ -2944,9 +2026,10 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len)
if (n != out_len) {
/* LCOV_EXCL_START
* We can't make /dev/foorandom actually fail. */
- log_warn(LD_CRYPTO,
- "Error reading from entropy source (read only %lu bytes).",
- (unsigned long)n);
+ log_notice(LD_CRYPTO,
+ "Error reading from entropy source %s (read only %lu bytes).",
+ filenames[i],
+ (unsigned long)n);
return -1;
/* LCOV_EXCL_STOP */
}
@@ -3347,110 +2430,7 @@ memwipe(void *mem, uint8_t byte, size_t sz)
memset(mem, byte, sz);
}
-#ifndef OPENSSL_THREADS
-#error OpenSSL has been built without thread support. Tor requires an \
- OpenSSL library with thread support enabled.
-#endif
-
-#ifndef NEW_THREAD_API
-/** Helper: OpenSSL uses this callback to manipulate mutexes. */
-static void
-openssl_locking_cb_(int mode, int n, const char *file, int line)
-{
- (void)file;
- (void)line;
- if (!openssl_mutexes_)
- /* This is not a really good fix for the
- * "release-freed-lock-from-separate-thread-on-shutdown" problem, but
- * it can't hurt. */
- return;
- if (mode & CRYPTO_LOCK)
- tor_mutex_acquire(openssl_mutexes_[n]);
- else
- tor_mutex_release(openssl_mutexes_[n]);
-}
-
-static void
-tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
-{
- CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id());
-}
-#endif /* !defined(NEW_THREAD_API) */
-
-#if 0
-/* This code is disabled, because OpenSSL never actually uses these callbacks.
- */
-
-/** OpenSSL helper type: wraps a Tor mutex so that OpenSSL can use it
- * as a lock. */
-struct CRYPTO_dynlock_value {
- tor_mutex_t *lock;
-};
-
-/** OpenSSL callback function to allocate a lock: see CRYPTO_set_dynlock_*
- * documentation in OpenSSL's docs for more info. */
-static struct CRYPTO_dynlock_value *
-openssl_dynlock_create_cb_(const char *file, int line)
-{
- struct CRYPTO_dynlock_value *v;
- (void)file;
- (void)line;
- v = tor_malloc(sizeof(struct CRYPTO_dynlock_value));
- v->lock = tor_mutex_new();
- return v;
-}
-
-/** OpenSSL callback function to acquire or release a lock: see
- * CRYPTO_set_dynlock_* documentation in OpenSSL's docs for more info. */
-static void
-openssl_dynlock_lock_cb_(int mode, struct CRYPTO_dynlock_value *v,
- const char *file, int line)
-{
- (void)file;
- (void)line;
- if (mode & CRYPTO_LOCK)
- tor_mutex_acquire(v->lock);
- else
- tor_mutex_release(v->lock);
-}
-
-/** OpenSSL callback function to free a lock: see CRYPTO_set_dynlock_*
- * documentation in OpenSSL's docs for more info. */
-static void
-openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
- const char *file, int line)
-{
- (void)file;
- (void)line;
- tor_mutex_free(v->lock);
- tor_free(v);
-}
-#endif /* 0 */
-
/** @{ */
-/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
- * multithreaded. Returns 0. */
-static int
-setup_openssl_threading(void)
-{
-#ifndef NEW_THREAD_API
- int i;
- int n = CRYPTO_num_locks();
- n_openssl_mutexes_ = n;
- openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *));
- for (i=0; i < n; ++i)
- openssl_mutexes_[i] = tor_mutex_new();
- CRYPTO_set_locking_callback(openssl_locking_cb_);
- CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
-#endif /* !defined(NEW_THREAD_API) */
-#if 0
- CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_);
- CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_);
- CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
-#endif
- return 0;
-}
-
/** Uninitialize the crypto library. Return 0 on success. Does not detect
* failure.
*/
@@ -3470,6 +2450,8 @@ crypto_global_cleanup(void)
if (dh_param_g)
BN_clear_free(dh_param_g);
+ dh_param_p = dh_param_p_tls = dh_param_g = NULL;
+
#ifndef DISABLE_ENGINES
ENGINE_cleanup();
#endif
@@ -3477,22 +2459,13 @@ crypto_global_cleanup(void)
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
-#ifndef NEW_THREAD_API
- if (n_openssl_mutexes_) {
- int n = n_openssl_mutexes_;
- tor_mutex_t **ms = openssl_mutexes_;
- int i;
- openssl_mutexes_ = NULL;
- n_openssl_mutexes_ = 0;
- for (i=0;i<n;++i) {
- tor_mutex_free(ms[i]);
- }
- tor_free(ms);
- }
-#endif /* !defined(NEW_THREAD_API) */
+ crypto_openssl_free_all();
+
+ crypto_early_initialized_ = 0;
+ crypto_global_initialized_ = 0;
+ have_seeded_siphash = 0;
+ siphash_unset_global_key();
- tor_free(crypto_openssl_version_str);
- tor_free(crypto_openssl_header_version_str);
return 0;
}
diff --git a/src/common/crypto.h b/src/common/crypto.h
index f9aeeee2c0..a9c8837b9e 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -19,42 +19,11 @@
#include "torint.h"
#include "testsupport.h"
#include "compat.h"
+#include "util.h"
+#include "crypto_rsa.h"
-#include <openssl/engine.h>
#include "keccak-tiny/keccak-tiny.h"
-/*
- Macro to create an arbitrary OpenSSL version number as used by
- OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard
- to read.
-
- Don't use this directly, instead use one of the other OPENSSL_V macros
- below.
-
- The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit
- status.
- */
-#define OPENSSL_VER(a,b,c,d,e) \
- (((a)<<28) | \
- ((b)<<20) | \
- ((c)<<12) | \
- ((d)<< 4) | \
- (e))
-/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the
- * version for the released version of 0.9.8j */
-#define OPENSSL_V(a,b,c,d) \
- OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf)
-/** An openssl release number for the first release in the series. For
- * example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL
- * 1.0.0. */
-#define OPENSSL_V_NOPATCH(a,b,c) \
- OPENSSL_VER((a),(b),(c),0,0xf)
-/** The first version that would occur for any alpha or beta in an openssl
- * series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released
- * 0.9.7, and less than any released 0.9.8. */
-#define OPENSSL_V_SERIES(a,b,c) \
- OPENSSL_VER((a),(b),(c),0,0)
-
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
/** Length of the output of our second (improved) message digests. (For now
@@ -68,8 +37,6 @@
#define CIPHER_IV_LEN 16
/** Length of our symmetric cipher's keys of 256-bit. */
#define CIPHER256_KEY_LEN 32
-/** Length of our public keys. */
-#define PK_BYTES (1024/8)
/** Length of our DH keys. */
#define DH_BYTES (1024/8)
@@ -86,12 +53,6 @@
* signs removed. */
#define BASE64_DIGEST512_LEN 86
-/** Constant used to indicate OAEP padding for public-key encryption */
-#define PK_PKCS1_OAEP_PADDING 60002
-
-/** Number of bytes added for PKCS1-OAEP padding. */
-#define PKCS1_OAEP_PADDING_OVERHEAD 42
-
/** Length of encoded public key fingerprints, including space; but not
* including terminating NUL. */
#define FINGERPRINT_LEN 49
@@ -124,15 +85,12 @@ typedef struct {
char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN];
} common_digests_t;
-typedef struct crypto_pk_t crypto_pk_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 */
-const char * crypto_openssl_get_version_str(void);
-const char * crypto_openssl_get_header_version_str(void);
int crypto_early_init(void) ATTR_WUR;
int crypto_global_init(int hardwareAccel,
const char *accelName,
@@ -145,9 +103,6 @@ void crypto_thread_cleanup(void);
int crypto_global_cleanup(void);
/* environment setup */
-MOCK_DECL(crypto_pk_t *,crypto_pk_new,(void));
-void crypto_pk_free(crypto_pk_t *env);
-
void crypto_set_tls_dh_prime(void);
crypto_cipher_t *crypto_cipher_new(const char *key);
crypto_cipher_t *crypto_cipher_new_with_bits(const char *key, int bits);
@@ -155,49 +110,14 @@ crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv);
crypto_cipher_t *crypto_cipher_new_with_iv_and_bits(const uint8_t *key,
const uint8_t *iv,
int bits);
-void crypto_cipher_free(crypto_cipher_t *env);
-
-/* public key crypto */
-MOCK_DECL(int, crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits));
-#define crypto_pk_generate_key(env) \
- crypto_pk_generate_key_with_bits((env), (PK_BYTES*8))
-
-int crypto_pk_read_private_key_from_filename(crypto_pk_t *env,
- const char *keyfile);
-int crypto_pk_write_public_key_to_string(crypto_pk_t *env,
- char **dest, size_t *len);
-int crypto_pk_write_private_key_to_string(crypto_pk_t *env,
- char **dest, size_t *len);
-int crypto_pk_read_public_key_from_string(crypto_pk_t *env,
- const char *src, size_t len);
-int crypto_pk_read_private_key_from_string(crypto_pk_t *env,
- const char *s, ssize_t len);
-int crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
- const char *fname);
-
-int crypto_pk_check_key(crypto_pk_t *env);
-int crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b);
-int crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b);
-size_t crypto_pk_keysize(const crypto_pk_t *env);
-int crypto_pk_num_bits(crypto_pk_t *env);
-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_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,
- const char *from, size_t fromlen,
- int padding, int warnOnFailure);
-MOCK_DECL(int, crypto_pk_public_checksig,(const crypto_pk_t *env,
- char *to, size_t tolen,
- const char *from, size_t fromlen));
+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(const crypto_pk_t *env, char *to, size_t tolen,
- const char *from, size_t fromlen);
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,
@@ -208,17 +128,9 @@ 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_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len);
-crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
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_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);
-
-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);
/* symmetric crypto */
const char *crypto_cipher_get_key(crypto_cipher_t *env);
@@ -258,7 +170,9 @@ 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);
+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,
@@ -276,7 +190,9 @@ void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
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);
+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
@@ -291,7 +207,8 @@ int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out,
ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_out_len);
-void crypto_dh_free(crypto_dh_t *dh);
+void crypto_dh_free_(crypto_dh_t *dh);
+#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh))
int crypto_expand_key_material_TAP(const uint8_t *key_in,
size_t key_in_len,
@@ -329,13 +246,7 @@ void memwipe(void *mem, uint8_t byte, size_t sz);
/* Prototypes for private functions only used by tortls.c, crypto.c, and the
* unit tests. */
-struct rsa_st;
-struct evp_pkey_st;
struct dh_st;
-struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env);
-crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa);
-MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_evp_pkey_,(crypto_pk_t *env,
- int private));
struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in);
@@ -352,7 +263,6 @@ extern int break_strongest_rng_fallback;
#endif /* defined(CRYPTO_PRIVATE) */
#ifdef TOR_UNIT_TESTS
-void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src);
digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest);
#endif
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
index d024ab79f5..11f7423b07 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_openssl_mgt.h"
/** Length of a curve25519 public key when encoded. */
#define CURVE25519_PUBKEY_LEN 32
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index 94b23e31b9..b962a59de1 100644
--- a/src/common/crypto_ed25519.c
+++ b/src/common/crypto_ed25519.c
@@ -225,8 +225,8 @@ ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey)
/* Return a heap-allocated array that contains <b>msg</b> prefixed by the
* string <b>prefix_str</b>. Set <b>final_msg_len_out</b> to the size of the
- * final array. If an error occured, return NULL. It's the resonsibility of the
- * caller to free the returned array. */
+ * final array. If an error occurred, return NULL. It's the responsibility of
+ * the caller to free the returned array. */
static uint8_t *
get_prefixed_msg(const uint8_t *msg, size_t msg_len,
const char *prefix_str,
@@ -259,7 +259,7 @@ get_prefixed_msg(const uint8_t *msg, size_t msg_len,
* Set <b>signature_out</b> to a signature of the <b>len</b>-byte message
* <b>msg</b>, using the secret and public key in <b>keypair</b>.
*
- * Return 0 if we successfuly signed the message, otherwise return -1.
+ * Return 0 if we successfully signed the message, otherwise return -1.
*/
int
ed25519_sign(ed25519_signature_t *signature_out,
@@ -529,7 +529,7 @@ ed25519_keypair_blind(ed25519_keypair_t *out,
/**
* Given an ed25519 public key in <b>inp</b>, generate a corresponding blinded
* public key in <b>out</b>, blinded with the 32-byte parameter in
- * <b>param</b>. Return 0 on sucess, -1 on railure.
+ * <b>param</b>. Return 0 on success, -1 on railure.
*/
int
ed25519_public_blind(ed25519_public_key_t *out,
@@ -622,7 +622,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
/** Release all storage held for <b>kp</b>. */
void
-ed25519_keypair_free(ed25519_keypair_t *kp)
+ed25519_keypair_free_(ed25519_keypair_t *kp)
{
if (! kp)
return;
@@ -719,7 +719,7 @@ ed25519_impl_spot_check,(void))
return -1;
/* XXX/yawning: Someone that's more paranoid than I am, can write "Assume
- * ref0 is cannonical, and fuzz impl against it" if they want, but I doubt
+ * ref0 is canonical, and fuzz impl against it" if they want, but I doubt
* that will catch anything that the known answer tests won't.
*/
goto end;
@@ -762,7 +762,7 @@ pick_ed25519_impl(void)
/* LCOV_EXCL_STOP */
}
-/* Initialize the Ed25519 implementation. This is neccessary if you're
+/* Initialize the Ed25519 implementation. This is necessary if you're
* going to use them in a multithreaded setting, and not otherwise. */
void
ed25519_init(void)
diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h
index 8d13a487d6..74269ccffd 100644
--- a/src/common/crypto_ed25519.h
+++ b/src/common/crypto_ed25519.h
@@ -7,6 +7,7 @@
#include "testsupport.h"
#include "torint.h"
#include "crypto_curve25519.h"
+#include "util.h"
#define ED25519_PUBKEY_LEN 32
#define ED25519_SECKEY_LEN 64
@@ -117,7 +118,9 @@ int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
char **tag_out,
const char *filename);
-void ed25519_keypair_free(ed25519_keypair_t *kp);
+void ed25519_keypair_free_(ed25519_keypair_t *kp);
+#define ed25519_keypair_free(kp) \
+ FREE_AND_NULL(ed25519_keypair_t, ed25519_keypair_free_, (kp))
int ed25519_pubkey_eq(const ed25519_public_key_t *key1,
const ed25519_public_key_t *key2);
diff --git a/src/common/crypto_openssl_mgt.c b/src/common/crypto_openssl_mgt.c
new file mode 100644
index 0000000000..ea3519efa2
--- /dev/null
+++ b/src/common/crypto_openssl_mgt.c
@@ -0,0 +1,161 @@
+/* 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_openssl.c
+ *
+ * \brief Block of functions related to operations from OpenSSL.
+ **/
+
+#include "compat_openssl.h"
+#include "crypto_openssl_mgt.h"
+
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/conf.h>
+#include <openssl/hmac.h>
+#include <openssl/crypto.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+#ifndef NEW_THREAD_API
+/** A number of preallocated mutexes for use by OpenSSL. */
+static tor_mutex_t **openssl_mutexes_ = NULL;
+/** How many mutexes have we allocated for use by OpenSSL? */
+static int n_openssl_mutexes_ = 0;
+#endif /* !defined(NEW_THREAD_API) */
+
+/** Declare STATIC functions */
+STATIC char * parse_openssl_version_str(const char *raw_version);
+#ifndef NEW_THREAD_API
+STATIC void openssl_locking_cb_(int mode, int n, const char *file, int line);
+STATIC void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid);
+#endif
+
+/* Returns a trimmed and human-readable version of an openssl version string
+* <b>raw_version</b>. They are usually in the form of 'OpenSSL 1.0.0b 10
+* May 2012' and this will parse them into a form similar to '1.0.0b' */
+STATIC char *
+parse_openssl_version_str(const char *raw_version)
+{
+ const char *end_of_version = NULL;
+ /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's
+ trim that down. */
+ if (!strcmpstart(raw_version, "OpenSSL ")) {
+ raw_version += strlen("OpenSSL ");
+ end_of_version = strchr(raw_version, ' ');
+ }
+
+ if (end_of_version)
+ return tor_strndup(raw_version,
+ end_of_version-raw_version);
+ else
+ return tor_strdup(raw_version);
+}
+
+static char *crypto_openssl_version_str = NULL;
+/* Return a human-readable version of the run-time openssl version number. */
+const char *
+crypto_openssl_get_version_str(void)
+{
+ if (crypto_openssl_version_str == NULL) {
+ const char *raw_version = OpenSSL_version(OPENSSL_VERSION);
+ crypto_openssl_version_str = parse_openssl_version_str(raw_version);
+ }
+ return crypto_openssl_version_str;
+}
+
+static char *crypto_openssl_header_version_str = NULL;
+/* Return a human-readable version of the compile-time openssl version
+* number. */
+const char *
+crypto_openssl_get_header_version_str(void)
+{
+ if (crypto_openssl_header_version_str == NULL) {
+ crypto_openssl_header_version_str =
+ parse_openssl_version_str(OPENSSL_VERSION_TEXT);
+ }
+ return crypto_openssl_header_version_str;
+}
+
+#ifndef OPENSSL_THREADS
+#error OpenSSL has been built without thread support. Tor requires an \
+ OpenSSL library with thread support enabled.
+#endif
+
+#ifndef NEW_THREAD_API
+/** Helper: OpenSSL uses this callback to manipulate mutexes. */
+STATIC void
+openssl_locking_cb_(int mode, int n, const char *file, int line)
+{
+ (void)file;
+ (void)line;
+ if (!openssl_mutexes_)
+ /* This is not a really good fix for the
+ * "release-freed-lock-from-separate-thread-on-shutdown" problem, but
+ * it can't hurt. */
+ return;
+ if (mode & CRYPTO_LOCK)
+ tor_mutex_acquire(openssl_mutexes_[n]);
+ else
+ tor_mutex_release(openssl_mutexes_[n]);
+}
+
+STATIC void
+tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
+{
+ CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id());
+}
+#endif /* !defined(NEW_THREAD_API) */
+
+/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
+ * multithreaded. Returns 0. */
+int
+setup_openssl_threading(void)
+{
+#ifndef NEW_THREAD_API
+ int i;
+ int n = CRYPTO_num_locks();
+ n_openssl_mutexes_ = n;
+ openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *));
+ for (i=0; i < n; ++i)
+ openssl_mutexes_[i] = tor_mutex_new();
+ CRYPTO_set_locking_callback(openssl_locking_cb_);
+ CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
+#endif /* !defined(NEW_THREAD_API) */
+ return 0;
+}
+
+/** free OpenSSL variables */
+void
+crypto_openssl_free_all(void)
+{
+ tor_free(crypto_openssl_version_str);
+ tor_free(crypto_openssl_header_version_str);
+
+#ifndef NEW_THREAD_API
+ if (n_openssl_mutexes_) {
+ int n = n_openssl_mutexes_;
+ tor_mutex_t **ms = openssl_mutexes_;
+ int i;
+ openssl_mutexes_ = NULL;
+ n_openssl_mutexes_ = 0;
+ for (i=0;i<n;++i) {
+ tor_mutex_free(ms[i]);
+ }
+ tor_free(ms);
+ }
+#endif /* !defined(NEW_THREAD_API) */
+}
+
diff --git a/src/common/crypto_openssl_mgt.h b/src/common/crypto_openssl_mgt.h
new file mode 100644
index 0000000000..09b6737962
--- /dev/null
+++ b/src/common/crypto_openssl_mgt.h
@@ -0,0 +1,85 @@
+/* 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_openssl.h
+ *
+ * \brief Headers for crypto_openssl.c
+ **/
+
+#ifndef TOR_CRYPTO_OPENSSL_H
+#define TOR_CRYPTO_OPENSSL_H
+
+#include <stdio.h>
+#include "util.h"
+
+#include <openssl/engine.h>
+
+/*
+ Macro to create an arbitrary OpenSSL version number as used by
+ OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard
+ to read.
+
+ Don't use this directly, instead use one of the other OPENSSL_V macros
+ below.
+
+ The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit
+ status.
+ */
+#define OPENSSL_VER(a,b,c,d,e) \
+ (((a)<<28) | \
+ ((b)<<20) | \
+ ((c)<<12) | \
+ ((d)<< 4) | \
+ (e))
+/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the
+ * version for the released version of 0.9.8j */
+#define OPENSSL_V(a,b,c,d) \
+ OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf)
+/** An openssl release number for the first release in the series. For
+ * example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL
+ * 1.0.0. */
+#define OPENSSL_V_NOPATCH(a,b,c) \
+ OPENSSL_VER((a),(b),(c),0,0xf)
+/** The first version that would occur for any alpha or beta in an openssl
+ * series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released
+ * 0.9.7, and less than any released 0.9.8. */
+#define OPENSSL_V_SERIES(a,b,c) \
+ OPENSSL_VER((a),(b),(c),0,0)
+
+#ifdef ANDROID
+/* Android's OpenSSL seems to have removed all of its Engine support. */
+#define DISABLE_ENGINES
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require
+ * seting up various callbacks.
+ *
+ * OpenSSL 1.1.0pre4 has a messed up `ERR_remove_thread_state()` prototype,
+ * while the previous one was restored in pre5, and the function made a no-op
+ * (along with a deprecated annotation, which produces a compiler warning).
+ *
+ * While it is possible to support all three versions of the thread API,
+ * a version that existed only for one snapshot pre-release is kind of
+ * pointless, so let's not.
+ */
+#define NEW_THREAD_API
+#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */
+
+/* global openssl state */
+const char * crypto_openssl_get_version_str(void);
+const char * crypto_openssl_get_header_version_str(void);
+
+/* OpenSSL threading setup function */
+int setup_openssl_threading(void);
+
+/* Tor OpenSSL utility functions */
+void crypto_openssl_free_all(void);
+
+#endif /* !defined(TOR_CRYPTO_OPENSSL_H) */
+
diff --git a/src/common/crypto_pwbox.h b/src/common/crypto_pwbox.h
index cee8653587..a26b6d2c17 100644
--- a/src/common/crypto_pwbox.h
+++ b/src/common/crypto_pwbox.h
@@ -1,3 +1,6 @@
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#ifndef CRYPTO_PWBOX_H_INCLUDED_
#define CRYPTO_PWBOX_H_INCLUDED_
diff --git a/src/common/crypto_rsa.c b/src/common/crypto_rsa.c
new file mode 100644
index 0000000000..fa572580a4
--- /dev/null
+++ b/src/common/crypto_rsa.c
@@ -0,0 +1,923 @@
+/* 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_rsa.c
+ * \brief Block of functions related with RSA utilities and operations.
+ **/
+
+#include "crypto_rsa.h"
+#include "crypto.h"
+#include "compat_openssl.h"
+#include "crypto_curve25519.h"
+#include "crypto_ed25519.h"
+#include "crypto_format.h"
+
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/conf.h>
+#include <openssl/hmac.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+#include "torlog.h"
+#include "util.h"
+#include "util_format.h"
+
+/** Declaration for crypto_pk_t structure. */
+struct crypto_pk_t
+{
+ int refs; /**< reference count, so we don't have to copy keys */
+ RSA *key; /**< The key itself */
+};
+
+/** Log all pending crypto errors at level <b>severity</b>. Use
+ * <b>doing</b> to describe our current activities.
+ */
+static void
+crypto_log_errors(int severity, const char *doing)
+{
+ unsigned long err;
+ const char *msg, *lib, *func;
+ while ((err = ERR_get_error()) != 0) {
+ msg = (const char*)ERR_reason_error_string(err);
+ lib = (const char*)ERR_lib_error_string(err);
+ func = (const char*)ERR_func_error_string(err);
+ if (!msg) msg = "(null)";
+ if (!lib) lib = "(null)";
+ if (!func) func = "(null)";
+ if (BUG(!doing)) doing = "(null)";
+ tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
+ doing, msg, lib, func);
+ }
+}
+
+/** Return the number of bytes added by padding method <b>padding</b>.
+ */
+int
+crypto_get_rsa_padding_overhead(int padding)
+{
+ switch (padding)
+ {
+ case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
+ default: tor_assert(0); return -1; // LCOV_EXCL_LINE
+ }
+}
+
+/** Given a padding method <b>padding</b>, return the correct OpenSSL constant.
+ */
+int
+crypto_get_rsa_padding(int padding)
+{
+ switch (padding)
+ {
+ case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING;
+ default: tor_assert(0); return -1; // LCOV_EXCL_LINE
+ }
+}
+
+/** used internally: quicly validate a crypto_pk_t object as a private key.
+ * Return 1 iff the public key is valid, 0 if obviously invalid.
+ */
+static int
+crypto_pk_private_ok(const crypto_pk_t *k)
+{
+#ifdef OPENSSL_1_1_API
+ if (!k || !k->key)
+ return 0;
+
+ const BIGNUM *p, *q;
+ RSA_get0_factors(k->key, &p, &q);
+ return p != NULL; /* XXX/yawning: Should we check q? */
+#else /* !(defined(OPENSSL_1_1_API)) */
+ return k && k->key && k->key->p;
+#endif /* defined(OPENSSL_1_1_API) */
+}
+
+/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
+crypto_pk_t *
+crypto_new_pk_from_rsa_(RSA *rsa)
+{
+ crypto_pk_t *env;
+ tor_assert(rsa);
+ env = tor_malloc(sizeof(crypto_pk_t));
+ env->refs = 1;
+ env->key = rsa;
+ return env;
+}
+
+/** Helper, used by tor-gencert.c. Return the RSA from a
+ * crypto_pk_t. */
+RSA *
+crypto_pk_get_rsa_(crypto_pk_t *env)
+{
+ return env->key;
+}
+
+/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
+ * private is set, include the private-key portion of the key. Return a valid
+ * pointer on success, and NULL on failure. */
+MOCK_IMPL(EVP_PKEY *,
+crypto_pk_get_evp_pkey_,(crypto_pk_t *env, int private))
+{
+ RSA *key = NULL;
+ EVP_PKEY *pkey = NULL;
+ tor_assert(env->key);
+ if (private) {
+ if (!(key = RSAPrivateKey_dup(env->key)))
+ goto error;
+ } else {
+ if (!(key = RSAPublicKey_dup(env->key)))
+ goto error;
+ }
+ if (!(pkey = EVP_PKEY_new()))
+ goto error;
+ if (!(EVP_PKEY_assign_RSA(pkey, key)))
+ goto error;
+ return pkey;
+ error:
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (key)
+ RSA_free(key);
+ return NULL;
+}
+
+/** Allocate and return storage for a public key. The key itself will not yet
+ * be set.
+ */
+MOCK_IMPL(crypto_pk_t *,
+crypto_pk_new,(void))
+{
+ RSA *rsa;
+
+ rsa = RSA_new();
+ tor_assert(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
+}
+
+/** Release a reference to an asymmetric key; when all the references
+ * are released, free the key.
+ */
+void
+crypto_pk_free_(crypto_pk_t *env)
+{
+ if (!env)
+ return;
+
+ if (--env->refs > 0)
+ return;
+ tor_assert(env->refs == 0);
+
+ if (env->key)
+ RSA_free(env->key);
+
+ tor_free(env);
+}
+
+/** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>.
+ * Return 0 on success, -1 on failure.
+ */
+MOCK_IMPL(int,
+crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits))
+{
+ tor_assert(env);
+
+ if (env->key) {
+ RSA_free(env->key);
+ env->key = NULL;
+ }
+
+ {
+ BIGNUM *e = BN_new();
+ RSA *r = NULL;
+ if (!e)
+ goto done;
+ if (! BN_set_word(e, 65537))
+ goto done;
+ r = RSA_new();
+ if (!r)
+ goto done;
+ if (RSA_generate_key_ex(r, bits, e, NULL) == -1)
+ goto done;
+
+ env->key = r;
+ r = NULL;
+ done:
+ if (e)
+ BN_clear_free(e);
+ if (r)
+ RSA_free(r);
+ }
+
+ if (!env->key) {
+ crypto_log_errors(LOG_WARN, "generating RSA key");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** A PEM callback that always reports a failure to get a password */
+static int
+pem_no_password_cb(char *buf, int size, int rwflag, void *u)
+{
+ (void)buf;
+ (void)size;
+ (void)rwflag;
+ (void)u;
+ return 0;
+}
+
+/** Read a PEM-encoded private key from the <b>len</b>-byte string <b>s</b>
+ * into <b>env</b>. Return 0 on success, -1 on failure. If len is -1,
+ * the string is nul-terminated.
+ */
+int
+crypto_pk_read_private_key_from_string(crypto_pk_t *env,
+ const char *s, ssize_t len)
+{
+ BIO *b;
+
+ tor_assert(env);
+ tor_assert(s);
+ tor_assert(len < INT_MAX && len < SSIZE_T_CEILING);
+
+ /* Create a read-only memory BIO, backed by the string 's' */
+ b = BIO_new_mem_buf((char*)s, (int)len);
+ if (!b)
+ return -1;
+
+ if (env->key)
+ RSA_free(env->key);
+
+ env->key = PEM_read_bio_RSAPrivateKey(b,NULL,pem_no_password_cb,NULL);
+
+ BIO_free(b);
+
+ if (!env->key) {
+ crypto_log_errors(LOG_WARN, "Error parsing private key");
+ return -1;
+ }
+ return 0;
+}
+
+/** Read a PEM-encoded private key from the file named by
+ * <b>keyfile</b> into <b>env</b>. Return 0 on success, -1 on failure.
+ */
+int
+crypto_pk_read_private_key_from_filename(crypto_pk_t *env,
+ const char *keyfile)
+{
+ char *contents;
+ int r;
+
+ /* Read the file into a string. */
+ contents = read_file_to_str(keyfile, 0, NULL);
+ if (!contents) {
+ log_warn(LD_CRYPTO, "Error reading private key from \"%s\"", keyfile);
+ return -1;
+ }
+
+ /* Try to parse it. */
+ r = crypto_pk_read_private_key_from_string(env, contents, -1);
+ memwipe(contents, 0, strlen(contents));
+ tor_free(contents);
+ if (r)
+ return -1; /* read_private_key_from_string already warned, so we don't.*/
+
+ /* Make sure it's valid. */
+ if (crypto_pk_check_key(env) <= 0)
+ return -1;
+
+ return 0;
+}
+
+/** Helper function to implement crypto_pk_write_*_key_to_string. Return 0 on
+ * success, -1 on failure. */
+static int
+crypto_pk_write_key_to_string_impl(crypto_pk_t *env, char **dest,
+ size_t *len, int is_public)
+{
+ BUF_MEM *buf;
+ BIO *b;
+ int r;
+
+ tor_assert(env);
+ tor_assert(env->key);
+ tor_assert(dest);
+
+ b = BIO_new(BIO_s_mem()); /* Create a memory BIO */
+ if (!b)
+ return -1;
+
+ /* Now you can treat b as if it were a file. Just use the
+ * PEM_*_bio_* functions instead of the non-bio variants.
+ */
+ if (is_public)
+ r = PEM_write_bio_RSAPublicKey(b, env->key);
+ else
+ r = PEM_write_bio_RSAPrivateKey(b, env->key, NULL,NULL,0,NULL,NULL);
+
+ if (!r) {
+ crypto_log_errors(LOG_WARN, "writing RSA key to string");
+ BIO_free(b);
+ return -1;
+ }
+
+ BIO_get_mem_ptr(b, &buf);
+
+ *dest = tor_malloc(buf->length+1);
+ memcpy(*dest, buf->data, buf->length);
+ (*dest)[buf->length] = 0; /* nul terminate it */
+ *len = buf->length;
+
+ BIO_free(b);
+
+ return 0;
+}
+
+/** PEM-encode the public key portion of <b>env</b> and write it to a
+ * newly allocated string. On success, set *<b>dest</b> to the new
+ * string, *<b>len</b> to the string's length, and return 0. On
+ * failure, return -1.
+ */
+int
+crypto_pk_write_public_key_to_string(crypto_pk_t *env, char **dest,
+ size_t *len)
+{
+ return crypto_pk_write_key_to_string_impl(env, dest, len, 1);
+}
+
+/** PEM-encode the private key portion of <b>env</b> and write it to a
+ * newly allocated string. On success, set *<b>dest</b> to the new
+ * string, *<b>len</b> to the string's length, and return 0. On
+ * failure, return -1.
+ */
+int
+crypto_pk_write_private_key_to_string(crypto_pk_t *env, char **dest,
+ size_t *len)
+{
+ return crypto_pk_write_key_to_string_impl(env, dest, len, 0);
+}
+
+/** Read a PEM-encoded public key from the first <b>len</b> characters of
+ * <b>src</b>, and store the result in <b>env</b>. Return 0 on success, -1 on
+ * failure.
+ */
+int
+crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src,
+ size_t len)
+{
+ BIO *b;
+
+ tor_assert(env);
+ tor_assert(src);
+ tor_assert(len<INT_MAX);
+
+ b = BIO_new(BIO_s_mem()); /* Create a memory BIO */
+ if (!b)
+ return -1;
+
+ BIO_write(b, src, (int)len);
+
+ if (env->key)
+ RSA_free(env->key);
+ env->key = PEM_read_bio_RSAPublicKey(b, NULL, pem_no_password_cb, NULL);
+ BIO_free(b);
+ if (!env->key) {
+ crypto_log_errors(LOG_WARN, "reading public key from string");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Write the private key from <b>env</b> into the file named by <b>fname</b>,
+ * PEM-encoded. Return 0 on success, -1 on failure.
+ */
+int
+crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
+ const char *fname)
+{
+ BIO *bio;
+ char *cp;
+ long len;
+ char *s;
+ int r;
+
+ tor_assert(crypto_pk_private_ok(env));
+
+ if (!(bio = BIO_new(BIO_s_mem())))
+ return -1;
+ if (PEM_write_bio_RSAPrivateKey(bio, env->key, NULL,NULL,0,NULL,NULL)
+ == 0) {
+ crypto_log_errors(LOG_WARN, "writing private key");
+ BIO_free(bio);
+ return -1;
+ }
+ len = BIO_get_mem_data(bio, &cp);
+ tor_assert(len >= 0);
+ s = tor_malloc(len+1);
+ memcpy(s, cp, len);
+ s[len]='\0';
+ r = write_str_to_file(fname, s, 0);
+ BIO_free(bio);
+ memwipe(s, 0, strlen(s));
+ tor_free(s);
+ return r;
+}
+
+/** Return true iff <b>env</b> has a valid key.
+ */
+int
+crypto_pk_check_key(crypto_pk_t *env)
+{
+ int r;
+ tor_assert(env);
+
+ r = RSA_check_key(env->key);
+ if (r <= 0)
+ crypto_log_errors(LOG_WARN,"checking RSA key");
+ return r;
+}
+
+/** Return true iff <b>key</b> contains the private-key portion of the RSA
+ * key. */
+int
+crypto_pk_key_is_private(const crypto_pk_t *key)
+{
+ tor_assert(key);
+ return crypto_pk_private_ok(key);
+}
+
+/** Return true iff <b>env</b> contains a public key whose public exponent
+ * equals 65537.
+ */
+int
+crypto_pk_public_exponent_ok(crypto_pk_t *env)
+{
+ tor_assert(env);
+ tor_assert(env->key);
+
+ const BIGNUM *e;
+
+#ifdef OPENSSL_1_1_API
+ const BIGNUM *n, *d;
+ RSA_get0_key(env->key, &n, &e, &d);
+#else
+ e = env->key->e;
+#endif /* defined(OPENSSL_1_1_API) */
+ return BN_is_word(e, 65537);
+}
+
+/** Compare the public-key components of a and b. Return less than 0
+ * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is
+ * considered to be less than all non-NULL keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
+ */
+int
+crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b)
+{
+ int result;
+ char a_is_non_null = (a != NULL) && (a->key != NULL);
+ char b_is_non_null = (b != NULL) && (b->key != NULL);
+ char an_argument_is_null = !a_is_non_null | !b_is_non_null;
+
+ result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null));
+ if (an_argument_is_null)
+ return result;
+
+ const BIGNUM *a_n, *a_e;
+ const BIGNUM *b_n, *b_e;
+
+#ifdef OPENSSL_1_1_API
+ const BIGNUM *a_d, *b_d;
+ RSA_get0_key(a->key, &a_n, &a_e, &a_d);
+ RSA_get0_key(b->key, &b_n, &b_e, &b_d);
+#else
+ a_n = a->key->n;
+ a_e = a->key->e;
+ b_n = b->key->n;
+ b_e = b->key->e;
+#endif /* defined(OPENSSL_1_1_API) */
+
+ tor_assert(a_n != NULL && a_e != NULL);
+ tor_assert(b_n != NULL && b_e != NULL);
+
+ result = BN_cmp(a_n, b_n);
+ if (result)
+ return result;
+ return BN_cmp(a_e, b_e);
+}
+
+/** Compare the public-key components of a and b. Return non-zero iff
+ * a==b. A NULL key is considered to be distinct from all non-NULL
+ * keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
+ */
+int
+crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b)
+{
+ return (crypto_pk_cmp_keys(a, b) == 0);
+}
+
+/** Return the size of the public key modulus in <b>env</b>, in bytes. */
+size_t
+crypto_pk_keysize(const crypto_pk_t *env)
+{
+ tor_assert(env);
+ tor_assert(env->key);
+
+ return (size_t) RSA_size((RSA*)env->key);
+}
+
+/** Return the size of the public key modulus of <b>env</b>, in bits. */
+int
+crypto_pk_num_bits(crypto_pk_t *env)
+{
+ tor_assert(env);
+ tor_assert(env->key);
+
+#ifdef OPENSSL_1_1_API
+ /* It's so stupid that there's no other way to check that n is valid
+ * before calling RSA_bits().
+ */
+ const BIGNUM *n, *e, *d;
+ RSA_get0_key(env->key, &n, &e, &d);
+ tor_assert(n != NULL);
+
+ return RSA_bits(env->key);
+#else /* !(defined(OPENSSL_1_1_API)) */
+ tor_assert(env->key->n);
+ return BN_num_bits(env->key->n);
+#endif /* defined(OPENSSL_1_1_API) */
+}
+
+/** Increase the reference count of <b>env</b>, and return it.
+ */
+crypto_pk_t *
+crypto_pk_dup_key(crypto_pk_t *env)
+{
+ tor_assert(env);
+ tor_assert(env->key);
+
+ env->refs++;
+ return env;
+}
+
+#ifdef TOR_UNIT_TESTS
+/** For testing: replace dest with src. (Dest must have a refcount
+ * of 1) */
+void
+crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src)
+{
+ tor_assert(dest);
+ tor_assert(dest->refs == 1);
+ tor_assert(src);
+ RSA_free(dest->key);
+ dest->key = RSAPrivateKey_dup(src->key);
+}
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/** Make a real honest-to-goodness copy of <b>env</b>, and return it.
+ * Returns NULL on failure. */
+crypto_pk_t *
+crypto_pk_copy_full(crypto_pk_t *env)
+{
+ RSA *new_key;
+ int privatekey = 0;
+ tor_assert(env);
+ tor_assert(env->key);
+
+ if (crypto_pk_private_ok(env)) {
+ new_key = RSAPrivateKey_dup(env->key);
+ privatekey = 1;
+ } else {
+ new_key = RSAPublicKey_dup(env->key);
+ }
+ if (!new_key) {
+ /* LCOV_EXCL_START
+ *
+ * We can't cause RSA*Key_dup() to fail, so we can't really test this.
+ */
+ log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.",
+ privatekey?"private":"public");
+ crypto_log_errors(LOG_ERR,
+ privatekey ? "Duplicating a private key" :
+ "Duplicating a public key");
+ tor_fragile_assert();
+ return NULL;
+ /* LCOV_EXCL_STOP */
+ }
+
+ return crypto_new_pk_from_rsa_(new_key);
+}
+
+/** 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
+ * written. On failure, return -1.
+ *
+ * <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_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen, int padding)
+{
+ int r;
+ tor_assert(env);
+ tor_assert(from);
+ tor_assert(to);
+ tor_assert(fromlen<INT_MAX);
+ tor_assert(tolen >= crypto_pk_keysize(env));
+
+ r = RSA_public_encrypt((int)fromlen,
+ (unsigned char*)from, (unsigned char*)to,
+ env->key, crypto_get_rsa_padding(padding));
+ if (r<0) {
+ crypto_log_errors(LOG_WARN, "performing RSA encryption");
+ return -1;
+ }
+ return r;
+}
+
+/** Decrypt <b>fromlen</b> bytes from <b>from</b> with the private 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
+ * written. On failure, return -1.
+ *
+ * <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_decrypt(crypto_pk_t *env, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen,
+ int padding, int warnOnFailure)
+{
+ int r;
+ tor_assert(env);
+ tor_assert(from);
+ tor_assert(to);
+ tor_assert(env->key);
+ tor_assert(fromlen<INT_MAX);
+ tor_assert(tolen >= crypto_pk_keysize(env));
+ if (!crypto_pk_key_is_private(env))
+ /* Not a private key */
+ return -1;
+
+ r = RSA_private_decrypt((int)fromlen,
+ (unsigned char*)from, (unsigned char*)to,
+ env->key, crypto_get_rsa_padding(padding));
+
+ if (r<0) {
+ crypto_log_errors(warnOnFailure?LOG_WARN:LOG_DEBUG,
+ "performing RSA decryption");
+ return -1;
+ }
+ return r;
+}
+
+/** Check the signature in <b>from</b> (<b>fromlen</b> bytes long) with the
+ * public key in <b>env</b>, using PKCS1 padding. On success, write the
+ * signed data to <b>to</b>, and return the number of bytes written.
+ * On failure, return -1.
+ *
+ * <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>.
+ */
+MOCK_IMPL(int,
+crypto_pk_public_checksig,(const crypto_pk_t *env, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen))
+{
+ int r;
+ tor_assert(env);
+ tor_assert(from);
+ tor_assert(to);
+ tor_assert(fromlen < INT_MAX);
+ tor_assert(tolen >= crypto_pk_keysize(env));
+ r = RSA_public_decrypt((int)fromlen,
+ (unsigned char*)from, (unsigned char*)to,
+ env->key, RSA_PKCS1_PADDING);
+
+ if (r<0) {
+ crypto_log_errors(LOG_INFO, "checking RSA signature");
+ return -1;
+ }
+ return r;
+}
+
+/** Sign <b>fromlen</b> bytes of data from <b>from</b> with the private key in
+ * <b>env</b>, using PKCS1 padding. On success, write the signature to
+ * <b>to</b>, and return the number of bytes written. On failure, return
+ * -1.
+ *
+ * <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(const crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen)
+{
+ int r;
+ tor_assert(env);
+ tor_assert(from);
+ tor_assert(to);
+ tor_assert(fromlen < INT_MAX);
+ tor_assert(tolen >= crypto_pk_keysize(env));
+ if (!crypto_pk_key_is_private(env))
+ /* Not a private key */
+ return -1;
+
+ r = RSA_private_encrypt((int)fromlen,
+ (unsigned char*)from, (unsigned char*)to,
+ (RSA*)env->key, RSA_PKCS1_PADDING);
+ if (r<0) {
+ crypto_log_errors(LOG_WARN, "generating RSA signature");
+ return -1;
+ }
+ return r;
+}
+
+/** ASN.1-encode the public portion of <b>pk</b> into <b>dest</b>.
+ * Return -1 on error, or the number of characters used on success.
+ */
+int
+crypto_pk_asn1_encode(const crypto_pk_t *pk, char *dest, size_t dest_len)
+{
+ int len;
+ unsigned char *buf = NULL;
+
+ len = i2d_RSAPublicKey(pk->key, &buf);
+ if (len < 0 || buf == NULL)
+ return -1;
+
+ if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) {
+ OPENSSL_free(buf);
+ return -1;
+ }
+ /* We don't encode directly into 'dest', because that would be illegal
+ * type-punning. (C99 is smarter than me, C99 is smarter than me...)
+ */
+ memcpy(dest,buf,len);
+ OPENSSL_free(buf);
+ return len;
+}
+
+/** Decode an ASN.1-encoded public key from <b>str</b>; return the result on
+ * success and NULL on failure.
+ */
+crypto_pk_t *
+crypto_pk_asn1_decode(const char *str, size_t len)
+{
+ RSA *rsa;
+ unsigned char *buf;
+ const unsigned char *cp;
+ cp = buf = tor_malloc(len);
+ memcpy(buf,str,len);
+ rsa = d2i_RSAPublicKey(NULL, &cp, len);
+ tor_free(buf);
+ if (!rsa) {
+ crypto_log_errors(LOG_WARN,"decoding public key");
+ return NULL;
+ }
+ return crypto_new_pk_from_rsa_(rsa);
+}
+
+/** Given a private or public key <b>pk</b>, put a fingerprint of the
+ * public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 bytes of
+ * space). Return 0 on success, -1 on failure.
+ *
+ * Fingerprints are computed as the SHA1 digest of the ASN.1 encoding
+ * of the public key, converted to hexadecimal, in upper case, with a
+ * space after every four digits.
+ *
+ * If <b>add_space</b> is false, omit the spaces.
+ */
+int
+crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
+{
+ char digest[DIGEST_LEN];
+ char hexdigest[HEX_DIGEST_LEN+1];
+ if (crypto_pk_get_digest(pk, digest)) {
+ return -1;
+ }
+ base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN);
+ if (add_space) {
+ crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest);
+ } else {
+ strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1);
+ }
+ return 0;
+}
+
+/** Given a private or public key <b>pk</b>, put a hashed fingerprint of
+ * the public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1
+ * bytes of space). Return 0 on success, -1 on failure.
+ *
+ * Hashed fingerprints are computed as the SHA1 digest of the SHA1 digest
+ * of the ASN.1 encoding of the public key, converted to hexadecimal, in
+ * upper case.
+ */
+int
+crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
+{
+ char digest[DIGEST_LEN], hashed_digest[DIGEST_LEN];
+ if (crypto_pk_get_digest(pk, digest)) {
+ return -1;
+ }
+ if (crypto_digest(hashed_digest, digest, DIGEST_LEN) < 0) {
+ return -1;
+ }
+ base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN);
+ return 0;
+}
+
+/** 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
+ * success, -1 on failure.
+ *
+ * It is the caller's responsibility to sanitize and free the resulting buffer.
+ */
+int
+crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ int ret = -1;
+
+ *priv_out = NULL;
+
+ der_len = i2d_RSAPrivateKey(pk->key, &der);
+ if (der_len < 0 || der == NULL)
+ return ret;
+
+ size_t priv_len = base64_encode_size(der_len, 0) + 1;
+ char *priv = tor_malloc_zero(priv_len);
+ if (base64_encode(priv, priv_len, (char *)der, der_len, 0) >= 0) {
+ *priv_out = priv;
+ ret = 0;
+ } else {
+ tor_free(priv);
+ }
+
+ memwipe(der, 0, der_len);
+ OPENSSL_free(der);
+ return ret;
+}
+
+/** Given a string containing the Base64 encoded DER representation of the
+ * private key <b>str</b>, decode and return the result on success, or NULL
+ * on failure.
+ */
+crypto_pk_t *
+crypto_pk_base64_decode(const char *str, size_t len)
+{
+ crypto_pk_t *pk = NULL;
+
+ char *der = tor_malloc_zero(len + 1);
+ int der_len = base64_decode(der, len, str, len);
+ if (der_len <= 0) {
+ log_warn(LD_CRYPTO, "Stored RSA private key seems corrupted (base64).");
+ goto out;
+ }
+
+ const unsigned char *dp = (unsigned char*)der; /* Shut the compiler up. */
+ RSA *rsa = d2i_RSAPrivateKey(NULL, &dp, der_len);
+ if (!rsa) {
+ crypto_log_errors(LOG_WARN, "decoding private key");
+ goto out;
+ }
+
+ pk = crypto_new_pk_from_rsa_(rsa);
+
+ /* Make sure it's valid. */
+ if (crypto_pk_check_key(pk) <= 0) {
+ crypto_pk_free(pk);
+ pk = NULL;
+ goto out;
+ }
+
+ out:
+ memwipe(der, 0, len + 1);
+ tor_free(der);
+ return pk;
+}
+
diff --git a/src/common/crypto_rsa.h b/src/common/crypto_rsa.h
new file mode 100644
index 0000000000..5b9025c629
--- /dev/null
+++ b/src/common/crypto_rsa.h
@@ -0,0 +1,104 @@
+/* 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_rsa.h
+ *
+ * \brief Headers for crypto_rsa.c
+ **/
+
+#ifndef TOR_CRYPTO_RSA_H
+#define TOR_CRYPTO_RSA_H
+
+#include "orconfig.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)
+
+/** Constant used to indicate OAEP padding for public-key encryption */
+#define PK_PKCS1_OAEP_PADDING 60002
+
+/** Number of bytes added for PKCS1-OAEP padding. */
+#define PKCS1_OAEP_PADDING_OVERHEAD 42
+
+/** A public key, or a public/private key-pair. */
+typedef struct crypto_pk_t crypto_pk_t;
+
+/* RSA enviroment setup */
+MOCK_DECL(crypto_pk_t *,crypto_pk_new,(void));
+void crypto_pk_free_(crypto_pk_t *env);
+#define crypto_pk_free(pk) FREE_AND_NULL(crypto_pk_t, crypto_pk_free_, (pk))
+int crypto_get_rsa_padding_overhead(int padding);
+int crypto_get_rsa_padding(int padding);
+
+/* public key crypto */
+MOCK_DECL(int, crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits));
+#define crypto_pk_generate_key(env) \
+ crypto_pk_generate_key_with_bits((env), (PK_BYTES*8))
+
+int crypto_pk_read_private_key_from_filename(crypto_pk_t *env,
+ const char *keyfile);
+int crypto_pk_write_public_key_to_string(crypto_pk_t *env,
+ char **dest, size_t *len);
+int crypto_pk_write_private_key_to_string(crypto_pk_t *env,
+ char **dest, size_t *len);
+int crypto_pk_read_public_key_from_string(crypto_pk_t *env,
+ const char *src, size_t len);
+int crypto_pk_read_private_key_from_string(crypto_pk_t *env,
+ const char *s, ssize_t len);
+int crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
+ const char *fname);
+
+int crypto_pk_check_key(crypto_pk_t *env);
+int crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b);
+int crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b);
+size_t crypto_pk_keysize(const crypto_pk_t *env);
+int crypto_pk_num_bits(crypto_pk_t *env);
+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_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,
+ const char *from, size_t fromlen,
+ int padding, int warnOnFailure);
+MOCK_DECL(int, crypto_pk_public_checksig,(const crypto_pk_t *env,
+ char *to, size_t tolen,
+ const char *from, size_t fromlen));
+int crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen);
+int crypto_pk_asn1_encode(const crypto_pk_t *pk, char *dest, size_t dest_len);
+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);
+
+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);
+
+/* Prototypes for private functions only used by tortls.c, crypto.c, and the
+ * unit tests. */
+struct rsa_st;
+struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env);
+crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa);
+MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_evp_pkey_,(crypto_pk_t *env,
+ int private));
+struct evp_pkey_st;
+
+#ifdef TOR_UNIT_TESTS
+void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src);
+#endif
+
+#endif
+
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index 7c0b4e7630..90e9357c8e 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -148,7 +148,7 @@ struct di_digest256_map_t {
/** Release all storage held in <b>map</b>, calling free_fn on each value
* as we go. */
void
-dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn)
+dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn)
{
while (map) {
di_digest256_map_t *victim = map;
diff --git a/src/common/di_ops.h b/src/common/di_ops.h
index e79973ba52..67d9c9f0df 100644
--- a/src/common/di_ops.h
+++ b/src/common/di_ops.h
@@ -37,7 +37,12 @@ int safe_mem_is_zero(const void *mem, size_t sz);
typedef struct di_digest256_map_t di_digest256_map_t;
typedef void (*dimap_free_fn)(void *);
-void dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn);
+void dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn);
+#define dimap_free(map, free_fn) \
+ do { \
+ dimap_free_((map), (free_fn)); \
+ (map) = NULL; \
+ } while (0)
void dimap_add_entry(di_digest256_map_t **map,
const uint8_t *key, void *val);
void *dimap_search(const di_digest256_map_t *map, const uint8_t *key,
diff --git a/src/common/handles.h b/src/common/handles.h
index a610753a1c..aef8cd89ef 100644
--- a/src/common/handles.h
+++ b/src/common/handles.h
@@ -59,7 +59,7 @@
#define HANDLE_DECL(name, structname, linkage) \
typedef struct name ## _handle_t name ## _handle_t; \
linkage name ## _handle_t *name ## _handle_new(struct structname *object); \
- linkage void name ## _handle_free(name ## _handle_t *); \
+ linkage void name ## _handle_free_(name ## _handle_t *); \
linkage struct structname *name ## _handle_get(name ## _handle_t *); \
linkage void name ## _handles_clear(struct structname *object);
@@ -113,7 +113,7 @@
} \
\
linkage void \
- name ## _handle_free(struct name ## _handle_t *ref) \
+ name ## _handle_free_(struct name ## _handle_t *ref) \
{ \
if (! ref) return; \
name ## _handle_head_t *head = ref->head; \
diff --git a/src/common/include.am b/src/common/include.am
index 715ec0264c..6945285108 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -102,11 +102,6 @@ LIBOR_A_SRC = \
$(threads_impl_source) \
$(readpassphrase_source)
-if USE_RUST
-else
-LIBOR_A_SRC += src/common/compat_rust.c
-endif
-
src/common/src_common_libor_testing_a-log.$(OBJEXT) \
src/common/log.$(OBJEXT): micro-revision.i
@@ -119,6 +114,8 @@ LIBOR_CRYPTO_A_SRC = \
src/common/compress_zlib.c \
src/common/compress_zstd.c \
src/common/crypto.c \
+ src/common/crypto_rsa.c \
+ src/common/crypto_openssl_mgt.c \
src/common/crypto_pwbox.c \
src/common/crypto_s2k.c \
src/common/crypto_format.c \
@@ -158,7 +155,6 @@ COMMONHEADERS = \
src/common/compat.h \
src/common/compat_libevent.h \
src/common/compat_openssl.h \
- src/common/compat_rust.h \
src/common/compat_threads.h \
src/common/compat_time.h \
src/common/compress.h \
@@ -172,6 +168,8 @@ COMMONHEADERS = \
src/common/crypto_curve25519.h \
src/common/crypto_ed25519.h \
src/common/crypto_format.h \
+ src/common/crypto_openssl_mgt.h \
+ src/common/crypto_rsa.h \
src/common/crypto_pwbox.h \
src/common/crypto_s2k.h \
src/common/di_ops.h \
diff --git a/src/common/log.c b/src/common/log.c
index e4d5cd8fd8..9f4a8b2bc2 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -35,6 +35,9 @@
#define LOG_PRIVATE
#include "torlog.h"
#include "container.h"
+#ifdef HAVE_ANDROID_LOG_H
+#include <android/log.h>
+#endif // HAVE_ANDROID_LOG_H.
/** Given a severity, yields an index into log_severity_list_t.masks to use
* for that severity. */
@@ -58,12 +61,16 @@ typedef struct logfile_t {
int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
int is_syslog; /**< Boolean: send messages to syslog. */
+ int is_android; /**< Boolean: send messages to Android's log subsystem. */
+ char *android_tag; /**< Identity Tag used in Android's log subsystem. */
log_callback callback; /**< If not NULL, send messages to this function. */
log_severity_list_t *severities; /**< Which severity of messages should we
* log for each log domain? */
} logfile_t;
-static void log_free(logfile_t *victim);
+static void log_free_(logfile_t *victim);
+#define log_free(lg) \
+ FREE_AND_NULL(logfile_t, log_free_, (lg))
/** Helper: map a log severity to descriptive string. */
static inline const char *
@@ -101,6 +108,33 @@ should_log_function_name(log_domain_mask_t domain, int severity)
}
}
+#ifdef HAVE_ANDROID_LOG_H
+/** Helper function to convert Tor's log severity into the matching
+ * Android log priority.
+ */
+static int
+severity_to_android_log_priority(int severity)
+{
+ switch (severity) {
+ case LOG_DEBUG:
+ return ANDROID_LOG_VERBOSE;
+ case LOG_INFO:
+ return ANDROID_LOG_DEBUG;
+ case LOG_NOTICE:
+ return ANDROID_LOG_INFO;
+ case LOG_WARN:
+ return ANDROID_LOG_WARN;
+ case LOG_ERR:
+ return ANDROID_LOG_ERROR;
+ default:
+ // LCOV_EXCL_START
+ raw_assert(0);
+ return 0;
+ // LCOV_EXCL_STOP
+ }
+}
+#endif // HAVE_ANDROID_LOG_H.
+
/** A mutex to guard changes to logfiles and logging. */
static tor_mutex_t log_mutex;
/** True iff we have initialized log_mutex */
@@ -385,9 +419,12 @@ pending_log_message_new(int severity, log_domain_mask_t domain,
return m;
}
+#define pending_log_message_free(msg) \
+ FREE_AND_NULL(pending_log_message_t, pending_log_message_free_, (msg))
+
/** Release all storage held by <b>msg</b>. */
static void
-pending_log_message_free(pending_log_message_t *msg)
+pending_log_message_free_(pending_log_message_t *msg)
{
if (!msg)
return;
@@ -396,6 +433,16 @@ pending_log_message_free(pending_log_message_t *msg)
tor_free(msg);
}
+/** Helper function: returns true iff the log file, given in <b>lf</b>, is
+ * handled externally via the system log API, the Android logging API, or is an
+ * external callback function. */
+static inline int
+logfile_is_external(const logfile_t *lf)
+{
+ raw_assert(lf);
+ return lf->is_syslog || lf->is_android || lf->callback;
+}
+
/** Return true iff <b>lf</b> would like to receive a message with the
* specified <b>severity</b> in the specified <b>domain</b>.
*/
@@ -406,7 +453,7 @@ logfile_wants_message(const logfile_t *lf, int severity,
if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
return 0;
}
- if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
+ if (! (lf->fd >= 0 || logfile_is_external(lf))) {
return 0;
}
if (lf->seems_dead) {
@@ -449,6 +496,11 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
syslog(severity, "%s", msg_after_prefix);
#endif /* defined(MAXLINE) */
#endif /* defined(HAVE_SYSLOG_H) */
+ } else if (lf->is_android) {
+#ifdef HAVE_ANDROID_LOG_H
+ int priority = severity_to_android_log_priority(severity);
+ __android_log_write(priority, lf->android_tag, msg_after_prefix);
+#endif // HAVE_ANDROID_LOG_H.
} else if (lf->callback) {
if (domain & LD_NOCB) {
if (!*callbacks_deferred && pending_cb_messages) {
@@ -641,8 +693,8 @@ tor_log_update_sigsafe_err_fds(void)
/* Don't try callback to the control port, or syslogs: We can't
* do them from a signal handler. Don't try stdout: we always do stderr.
*/
- if (lf->is_temporary || lf->is_syslog ||
- lf->callback || lf->seems_dead || lf->fd < 0)
+ if (lf->is_temporary || logfile_is_external(lf)
+ || lf->seems_dead || lf->fd < 0)
continue;
if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
(LD_BUG|LD_GENERAL)) {
@@ -678,7 +730,7 @@ tor_log_get_logfile_names(smartlist_t *out)
LOCK_LOGS();
for (lf = logfiles; lf; lf = lf->next) {
- if (lf->is_temporary || lf->is_syslog || lf->callback)
+ if (lf->is_temporary || logfile_is_external(lf))
continue;
if (lf->filename == NULL)
continue;
@@ -721,12 +773,13 @@ log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
/** Free all storage held by <b>victim</b>. */
static void
-log_free(logfile_t *victim)
+log_free_(logfile_t *victim)
{
if (!victim)
return;
tor_free(victim->severities);
tor_free(victim->filename);
+ tor_free(victim->android_tag);
tor_free(victim);
}
@@ -1146,6 +1199,39 @@ add_syslog_log(const log_severity_list_t *severity,
}
#endif /* defined(HAVE_SYSLOG_H) */
+#ifdef HAVE_ANDROID_LOG_H
+/**
+ * Add a log handler to send messages to the Android platform log facility.
+ */
+int
+add_android_log(const log_severity_list_t *severity,
+ const char *android_tag)
+{
+ logfile_t *lf = NULL;
+
+ lf = tor_malloc_zero(sizeof(logfile_t));
+ lf->fd = -1;
+ lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
+ lf->filename = tor_strdup("<android>");
+ lf->is_android = 1;
+
+ if (android_tag == NULL)
+ lf->android_tag = tor_strdup("Tor");
+ else {
+ char buf[256];
+ tor_snprintf(buf, sizeof(buf), "Tor-%s", android_tag);
+ lf->android_tag = tor_strdup(buf);
+ }
+
+ LOCK_LOGS();
+ lf->next = logfiles;
+ logfiles = lf;
+ log_global_min_severity_ = get_min_log_level();
+ UNLOCK_LOGS();
+ return 0;
+}
+#endif // HAVE_ANDROID_LOG_H.
+
/** If <b>level</b> is a valid log severity, return the corresponding
* numeric value. Otherwise, return -1. */
int
@@ -1172,7 +1258,10 @@ log_level_to_string(int level)
}
/** NULL-terminated array of names for log domains such that domain_list[dom]
- * is a description of <b>dom</b>. */
+ * is a description of <b>dom</b>.
+ *
+ * Remember to update doc/tor.1.txt if you modify this list.
+ * */
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
@@ -1313,7 +1402,8 @@ parse_log_severity_config(const char **cfg_ptr,
if (!strcasecmpstart(cfg, "file") ||
!strcasecmpstart(cfg, "stderr") ||
!strcasecmpstart(cfg, "stdout") ||
- !strcasecmpstart(cfg, "syslog")) {
+ !strcasecmpstart(cfg, "syslog") ||
+ !strcasecmpstart(cfg, "android")) {
goto done;
}
if (got_an_unqualified_range > 1)
diff --git a/src/common/memarea.c b/src/common/memarea.c
index b059987e0e..68c1625fe4 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -153,7 +153,7 @@ memarea_new(void)
/** Free <b>area</b>, invalidating all pointers returned from memarea_alloc()
* and friends for this area */
void
-memarea_drop_all(memarea_t *area)
+memarea_drop_all_(memarea_t *area)
{
memarea_chunk_t *chunk, *next;
for (chunk = area->first; chunk; chunk = next) {
@@ -322,7 +322,7 @@ memarea_new(void)
return ma;
}
void
-memarea_drop_all(memarea_t *area)
+memarea_drop_all_(memarea_t *area)
{
memarea_clear(area);
smartlist_free(area->pieces);
diff --git a/src/common/memarea.h b/src/common/memarea.h
index c3d954e1ce..5207e8a5bd 100644
--- a/src/common/memarea.h
+++ b/src/common/memarea.h
@@ -8,7 +8,12 @@
typedef struct memarea_t memarea_t;
memarea_t *memarea_new(void);
-void memarea_drop_all(memarea_t *area);
+void memarea_drop_all_(memarea_t *area);
+#define memarea_drop_all(area) \
+ do { \
+ memarea_drop_all_(area); \
+ (area) = NULL; \
+ } while (0)
void memarea_clear(memarea_t *area);
int memarea_owns_ptr(const memarea_t *area, const void *ptr);
void *memarea_alloc(memarea_t *area, size_t sz);
diff --git a/src/common/procmon.c b/src/common/procmon.c
index 26c11823e8..abcbbeaa21 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -325,7 +325,7 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
/** Free the process-termination monitor <b>procmon</b>. */
void
-tor_process_monitor_free(tor_process_monitor_t *procmon)
+tor_process_monitor_free_(tor_process_monitor_t *procmon)
{
if (procmon == NULL)
return;
diff --git a/src/common/procmon.h b/src/common/procmon.h
index 10ead11ba8..63777e4111 100644
--- a/src/common/procmon.h
+++ b/src/common/procmon.h
@@ -27,7 +27,9 @@ tor_process_monitor_t *tor_process_monitor_new(struct event_base *base,
tor_procmon_callback_t cb,
void *cb_arg,
const char **msg);
-void tor_process_monitor_free(tor_process_monitor_t *procmon);
+void tor_process_monitor_free_(tor_process_monitor_t *procmon);
+#define tor_process_monitor_free(procmon) \
+ FREE_AND_NULL(tor_process_monitor_t, tor_process_monitor_free_, (procmon))
#endif /* !defined(TOR_PROCMON_H) */
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index 97acf894f3..440f8722f2 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -162,6 +162,7 @@ static int filter_nopar_gen[] = {
SCMP_SYS(fstat64),
#endif
SCMP_SYS(futex),
+ SCMP_SYS(getdents),
SCMP_SYS(getdents64),
SCMP_SYS(getegid),
#ifdef __NR_getegid32
@@ -437,9 +438,9 @@ libc_uses_openat_for_everything(void)
return 1;
else
return 0;
-#else
+#else /* !(defined(CHECK_LIBC_VERSION)) */
return 0;
-#endif
+#endif /* defined(CHECK_LIBC_VERSION) */
}
/** Allow a single file to be opened. If <b>use_openat</b> is true,
@@ -1115,7 +1116,7 @@ sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
SCMP_CMP(1, SCMP_CMP_EQ, 0));
#else
return 0;
-#endif
+#endif /* defined(__NR_kill) */
}
/**
@@ -1484,8 +1485,12 @@ cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
return (a->family == b->family) && 0 == strcmp(a->name, b->name);
}
+#define cached_getaddrinfo_item_free(item) \
+ FREE_AND_NULL(cached_getaddrinfo_item_t, \
+ cached_getaddrinfo_item_free_, (item))
+
static void
-cached_getaddrinfo_item_free(cached_getaddrinfo_item_t *item)
+cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item)
{
if (item == NULL)
return;
@@ -1796,7 +1801,7 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context)
#endif
#if defined(DEBUGGING_CLOSE)
- _exit(1);
+ _exit(1); // exit ok: programming error has led to sandbox failure.
#endif // DEBUGGING_CLOSE
}
diff --git a/src/common/storagedir.c b/src/common/storagedir.c
index c471ea911f..e2c7b4bb87 100644
--- a/src/common/storagedir.c
+++ b/src/common/storagedir.c
@@ -59,7 +59,7 @@ storage_dir_new(const char *dirname, int max_files)
* Drop all in-RAM storage for <b>d</b>. Does not delete any files.
*/
void
-storage_dir_free(storage_dir_t *d)
+storage_dir_free_(storage_dir_t *d)
{
if (d == NULL)
return;
diff --git a/src/common/storagedir.h b/src/common/storagedir.h
index 3de0afc361..d99bd7ec52 100644
--- a/src/common/storagedir.h
+++ b/src/common/storagedir.h
@@ -9,7 +9,10 @@ struct config_line_t;
struct sandbox_cfg_elem;
storage_dir_t * storage_dir_new(const char *dirname, int n_files);
-void storage_dir_free(storage_dir_t *d);
+void storage_dir_free_(storage_dir_t *d);
+#define storage_dir_free(d) \
+ FREE_AND_NULL(storage_dir_t, storage_dir_free_, (d))
+
int storage_dir_register_with_sandbox(storage_dir_t *d,
struct sandbox_cfg_elem **cfg);
const smartlist_t *storage_dir_list(storage_dir_t *d);
diff --git a/src/common/timers.c b/src/common/timers.c
index c8e09414f4..552080b11e 100644
--- a/src/common/timers.c
+++ b/src/common/timers.c
@@ -63,7 +63,7 @@ struct timeout_cb {
#define TIMEOUT_CB_OVERRIDE
/* We're going to support timers that are pretty far out in advance. Making
* this big can be inefficient, but having a significant number of timers
- * above TIMEOUT_MAX can also be super-inefficent. Choosing 5 here sets
+ * above TIMEOUT_MAX can also be super-inefficient. Choosing 5 here sets
* timeout_max to 2^30 ticks, or 29 hours with our value for USEC_PER_TICK */
#define WHEEL_NUM 5
#include "src/ext/timeouts/timeout.c"
@@ -245,7 +245,7 @@ timer_new(timer_cb_fn_t cb, void *arg)
* scheduled.
*/
void
-timer_free(tor_timer_t *t)
+timer_free_(tor_timer_t *t)
{
if (! t)
return;
diff --git a/src/common/timers.h b/src/common/timers.h
index d4d4fb00a9..6d27f3e01e 100644
--- a/src/common/timers.h
+++ b/src/common/timers.h
@@ -17,7 +17,8 @@ void timer_get_cb(const tor_timer_t *t,
timer_cb_fn_t *cb_out, void **arg_out);
void timer_schedule(tor_timer_t *t, const struct timeval *delay);
void timer_disable(tor_timer_t *t);
-void timer_free(tor_timer_t *t);
+void timer_free_(tor_timer_t *t);
+#define timer_free(t) FREE_AND_NULL(tor_timer_t, timer_free_, (t))
void timers_initialize(void);
void timers_shutdown(void);
diff --git a/src/common/torint.h b/src/common/torint.h
index bc81c114f8..0b8061d24f 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -348,6 +348,16 @@ typedef uint32_t uintptr_t;
#endif /* (SIZEOF_SIZE_T == 4) || ... */
#endif /* !defined(SIZE_MAX) */
+#ifdef _WIN32
+# ifdef _WIN64
+# define TOR_PRIuSZ PRIu64
+# else
+# define TOR_PRIuSZ PRIu32
+# endif
+#else
+# define TOR_PRIuSZ "zu"
+#endif
+
#ifndef SSIZE_MAX
#if (SIZEOF_SIZE_T == 4)
#define SSIZE_MAX INT32_MAX
diff --git a/src/common/torlog.h b/src/common/torlog.h
index be24b2b908..cadfe3b879 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -148,7 +148,11 @@ int add_file_log(const log_severity_list_t *severity, const char *filename,
#ifdef HAVE_SYSLOG_H
int add_syslog_log(const log_severity_list_t *severity,
const char* syslog_identity_tag);
-#endif
+#endif // HAVE_SYSLOG_H.
+#ifdef HAVE_ANDROID_LOG_H
+int add_android_log(const log_severity_list_t *severity,
+ const char *android_identity_tag);
+#endif // HAVE_ANDROID_LOG_H.
int add_callback_log(const log_severity_list_t *severity, log_callback cb);
void logs_set_domain_logging(int enabled);
int get_min_log_level(void);
diff --git a/src/common/tortls.c b/src/common/tortls.c
index e8c51879bd..50609b8ac7 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -669,7 +669,7 @@ static const char CLIENT_CIPHER_LIST[] =
/** Free all storage held in <b>cert</b> */
void
-tor_x509_cert_free(tor_x509_cert_t *cert)
+tor_x509_cert_free_(tor_x509_cert_t *cert)
{
if (! cert)
return;
@@ -1817,7 +1817,7 @@ tor_tls_is_server(tor_tls_t *tls)
* underlying file descriptor.
*/
void
-tor_tls_free(tor_tls_t *tls)
+tor_tls_free_(tor_tls_t *tls)
{
if (!tls)
return;
@@ -1964,7 +1964,7 @@ tor_tls_handshake(tor_tls_t *tls)
return r;
}
-/** Perform the final part of the intial TLS handshake on <b>tls</b>. This
+/** Perform the final part of the initial TLS handshake on <b>tls</b>. This
* should be called for the first handshake only: it determines whether the v1
* or the v2 handshake was used, and adjusts things for the renegotiation
* handshake as appropriate.
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 6145f7dbc9..1dbf0b332f 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -216,7 +216,8 @@ void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
void (*cb)(tor_tls_t *, void *arg),
void *arg);
int tor_tls_is_server(tor_tls_t *tls);
-void tor_tls_free(tor_tls_t *tls);
+void tor_tls_free_(tor_tls_t *tls);
+#define tor_tls_free(tls) FREE_AND_NULL(tor_tls_t, tor_tls_free_, (tls))
int tor_tls_peer_has_cert(tor_tls_t *tls);
MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls));
MOCK_DECL(tor_x509_cert_t *,tor_tls_get_own_cert,(tor_tls_t *tls));
@@ -263,7 +264,9 @@ void check_no_tls_errors_(const char *fname, int line);
void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
int severity, int domain, const char *doing);
-void tor_x509_cert_free(tor_x509_cert_t *cert);
+void tor_x509_cert_free_(tor_x509_cert_t *cert);
+#define tor_x509_cert_free(c) \
+ FREE_AND_NULL(tor_x509_cert_t, tor_x509_cert_free_, (c))
tor_x509_cert_t *tor_x509_cert_decode(const uint8_t *certificate,
size_t certificate_len);
void tor_x509_cert_get_der(const tor_x509_cert_t *cert,
diff --git a/src/common/util.c b/src/common/util.c
index 5ff7e104d6..a68fd30d09 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -156,7 +156,7 @@ tor_malloc_(size_t size DMALLOC_PARAMS)
/* If these functions die within a worker process, they won't call
* spawn_exit, but that's ok, since the parent will run out of memory soon
* anyway. */
- exit(1);
+ exit(1); // exit ok: alloc failed.
/* LCOV_EXCL_STOP */
}
return result;
@@ -244,7 +244,7 @@ tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS)
if (PREDICT_UNLIKELY(result == NULL)) {
/* LCOV_EXCL_START */
log_err(LD_MM,"Out of memory on realloc(). Dying.");
- exit(1);
+ exit(1); // exit ok: alloc failed.
/* LCOV_EXCL_STOP */
}
return result;
@@ -282,7 +282,7 @@ tor_strdup_(const char *s DMALLOC_PARAMS)
if (PREDICT_UNLIKELY(duplicate == NULL)) {
/* LCOV_EXCL_START */
log_err(LD_MM,"Out of memory on strdup(). Dying.");
- exit(1);
+ exit(1); // exit ok: alloc failed.
/* LCOV_EXCL_STOP */
}
return duplicate;
@@ -1071,6 +1071,36 @@ string_is_valid_ipv6_address(const char *string)
return (tor_inet_pton(AF_INET6,string,&addr) == 1);
}
+/** Return true iff <b>string</b> is a valid destination address,
+ * i.e. either a DNS hostname or IPv4/IPv6 address string.
+ */
+int
+string_is_valid_dest(const char *string)
+{
+ char *tmp = NULL;
+ int retval;
+ size_t len;
+
+ if (string == NULL)
+ return 0;
+
+ len = strlen(string);
+
+ if (len == 0)
+ return 0;
+
+ if (string[0] == '[' && string[len - 1] == ']')
+ string = tmp = tor_strndup(string + 1, len - 2);
+
+ retval = string_is_valid_ipv4_address(string) ||
+ string_is_valid_ipv6_address(string) ||
+ string_is_valid_nonrfc_hostname(string);
+
+ tor_free(tmp);
+
+ return retval;
+}
+
/** Return true iff <b>string</b> matches a pattern of DNS names
* that we allow Tor clients to connect to.
*
@@ -1078,37 +1108,51 @@ string_is_valid_ipv6_address(const char *string)
* with misconfigured zones that have been encountered in the wild.
*/
int
-string_is_valid_hostname(const char *string)
+string_is_valid_nonrfc_hostname(const char *string)
{
int result = 1;
+ int has_trailing_dot;
+ char *last_label;
smartlist_t *components;
+ if (!string || strlen(string) == 0)
+ return 0;
+
+ if (string_is_valid_ipv4_address(string))
+ return 0;
+
components = smartlist_new();
smartlist_split_string(components,string,".",0,0);
+ if (BUG(smartlist_len(components) == 0))
+ return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks.
+
+ /* Allow a single terminating '.' used rarely to indicate domains
+ * are FQDNs rather than relative. */
+ last_label = (char *)smartlist_get(components,
+ smartlist_len(components) - 1);
+ has_trailing_dot = (last_label[0] == '\0');
+ if (has_trailing_dot) {
+ smartlist_pop_last(components);
+ tor_free(last_label);
+ last_label = NULL;
+ }
+
SMARTLIST_FOREACH_BEGIN(components, char *, c) {
if ((c[0] == '-') || (*c == '_')) {
result = 0;
break;
}
- /* Allow a single terminating '.' used rarely to indicate domains
- * are FQDNs rather than relative. */
- if ((c_sl_idx > 0) && (c_sl_idx + 1 == c_sl_len) && !*c) {
- continue;
- }
-
do {
- if ((*c >= 'a' && *c <= 'z') ||
- (*c >= 'A' && *c <= 'Z') ||
- (*c >= '0' && *c <= '9') ||
- (*c == '-') || (*c == '_'))
- c++;
- else
- result = 0;
+ result = (TOR_ISALNUM(*c) || (*c == '-') || (*c == '_'));
+ c++;
} while (result && *c);
+ if (result == 0) {
+ break;
+ }
} SMARTLIST_FOREACH_END(c);
SMARTLIST_FOREACH_BEGIN(components, char *, c) {
@@ -3047,7 +3091,7 @@ unescape_string(const char *s, char **result, size_t *size_out)
/** Removes enclosing quotes from <b>path</b> and unescapes quotes between the
* enclosing quotes. Backslashes are not unescaped. Return the unquoted
- * <b>path</b> on sucess or 0 if <b>path</b> is not quoted correctly. */
+ * <b>path</b> on success or 0 if <b>path</b> is not quoted correctly. */
char *
get_unquoted_path(const char *path)
{
@@ -3590,14 +3634,14 @@ start_daemon(void)
if (pipe(daemon_filedes)) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno));
- exit(1);
+ exit(1); // exit ok: during daemonize, pipe failed.
/* LCOV_EXCL_STOP */
}
pid = fork();
if (pid < 0) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"fork failed. Exiting.");
- exit(1);
+ exit(1); // exit ok: during daemonize, fork failed
/* LCOV_EXCL_STOP */
}
if (pid) { /* Parent */
@@ -3612,9 +3656,9 @@ start_daemon(void)
}
fflush(stdout);
if (ok == 1)
- exit(0);
+ exit(0); // exit ok: during daemonize, daemonizing.
else
- exit(1); /* child reported error */
+ exit(1); /* child reported error. exit ok: daemonize failed. */
} else { /* Child */
close(daemon_filedes[0]); /* we only write */
@@ -3626,7 +3670,7 @@ start_daemon(void)
* _Advanced Programming in the Unix Environment_.
*/
if (fork() != 0) {
- exit(0);
+ exit(0); // exit ok: during daemonize, fork failed (2)
}
set_main_thread(); /* We are now the main thread. */
@@ -3655,14 +3699,14 @@ finish_daemon(const char *desired_cwd)
/* Don't hold the wrong FS mounted */
if (chdir(desired_cwd) < 0) {
log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd);
- exit(1);
+ exit(1); // exit ok: during daemonize, chdir failed.
}
nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0);
if (nullfd < 0) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"/dev/null can't be opened. Exiting.");
- exit(1);
+ exit(1); // exit ok: during daemonize, couldn't open /dev/null
/* LCOV_EXCL_STOP */
}
/* close fds linking to invoking terminal, but
@@ -3674,7 +3718,7 @@ finish_daemon(const char *desired_cwd)
dup2(nullfd,2) < 0) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"dup2 failed. Exiting.");
- exit(1);
+ exit(1); // exit ok: during daemonize, dup2 failed.
/* LCOV_EXCL_STOP */
}
if (nullfd > 2)
@@ -3898,7 +3942,7 @@ format_number_sigsafe(unsigned long x, char *buf, int buf_len,
* call it with a signed int and an unsigned char, and since the C standard
* does not guarantee that an int is wider than a char (an int must be at
* least 16 bits but it is permitted for a char to be that wide as well), we
- * can't assume a signed int is sufficient to accomodate an unsigned char.
+ * can't assume a signed int is sufficient to accommodate an unsigned char.
* Thus, format_helper_exit_status() will still need to emit any require '-'
* on its own.
*
@@ -3928,7 +3972,7 @@ format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len)
*
* The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded
* with spaces. CHILD_STATE indicates where
- * in the processs of starting the child process did the failure occur (see
+ * in the process of starting the child process did the failure occur (see
* CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of
* errno when the failure occurred.
*
@@ -4474,7 +4518,7 @@ tor_spawn_background(const char *const filename, const char **argv,
err += (nbytes < 0);
}
- _exit(err?254:255);
+ _exit(err?254:255); // exit ok: in child.
}
/* Never reached, but avoids compiler warning */
@@ -4713,7 +4757,7 @@ environment_variable_names_equal(const char *s1, const char *s2)
/** Free <b>env</b> (assuming it was produced by
* process_environment_make). */
void
-process_environment_free(process_environment_t *env)
+process_environment_free_(process_environment_t *env)
{
if (env == NULL) return;
diff --git a/src/common/util.h b/src/common/util.h
index 6bc853da26..9380789128 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -79,13 +79,28 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
*
* This is a macro. If you need a function pointer to release memory from
* tor_malloc(), use tor_free_().
+ *
+ * Note that this macro takes the address of the pointer it is going to
+ * free and clear. If that pointer is stored with a nonstandard
+ * alignment (eg because of a "packed" pragma) it is not correct to use
+ * tor_free().
*/
+#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; \
+ } \
+ STMT_END
+#else
#define tor_free(p) STMT_BEGIN \
if (PREDICT_LIKELY((p)!=NULL)) { \
raw_free(p); \
(p)=NULL; \
} \
STMT_END
+#endif
#endif /* defined(USE_DMALLOC) */
#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS)
@@ -109,6 +124,17 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
void tor_log_mallinfo(int severity);
+/* Helper macro: free a variable of type 'typename' using freefn, and
+ * set the variable to NULL.
+ */
+#define FREE_AND_NULL(typename, freefn, var) \
+ do { \
+ /* only evaluate (var) once. */ \
+ typename **tmp__free__ptr ## freefn = &(var); \
+ freefn(*tmp__free__ptr ## freefn); \
+ (*tmp__free__ptr ## freefn) = NULL; \
+ } while (0)
+
/** Macro: yield a pointer to the field at position <b>off</b> within the
* structure <b>st</b>. Example:
* <pre>
@@ -207,7 +233,8 @@ const char *find_str_at_start_of_line(const char *haystack,
const char *needle);
int string_is_C_identifier(const char *string);
int string_is_key_value(int severity, const char *string);
-int string_is_valid_hostname(const char *string);
+int string_is_valid_dest(const char *string);
+int string_is_valid_nonrfc_hostname(const char *string);
int string_is_valid_ipv4_address(const char *string);
int string_is_valid_ipv6_address(const char *string);
@@ -423,7 +450,9 @@ struct process_environment_t {
};
process_environment_t *process_environment_make(struct smartlist_t *env_vars);
-void process_environment_free(process_environment_t *env);
+void process_environment_free_(process_environment_t *env);
+#define process_environment_free(env) \
+ FREE_AND_NULL(process_environment_t, process_environment_free_, (env))
struct smartlist_t *get_current_process_environment_variables(void);
diff --git a/src/common/workqueue.c b/src/common/workqueue.c
index 42723224d3..ec96959b7d 100644
--- a/src/common/workqueue.c
+++ b/src/common/workqueue.c
@@ -148,12 +148,15 @@ workqueue_entry_new(workqueue_reply_t (*fn)(void*, void*),
return ent;
}
+#define workqueue_entry_free(ent) \
+ FREE_AND_NULL(workqueue_entry_t, workqueue_entry_free_, (ent))
+
/**
* Release all storage held in <b>ent</b>. Call only when <b>ent</b> is not on
* any queue.
*/
static void
-workqueue_entry_free(workqueue_entry_t *ent)
+workqueue_entry_free_(workqueue_entry_t *ent)
{
if (!ent)
return;