summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/address.c81
-rw-r--r--src/common/address.h15
-rw-r--r--src/common/backtrace.c7
-rw-r--r--src/common/compat.c6
-rw-r--r--src/common/compat.h2
-rw-r--r--src/common/compat_openssl.h9
-rw-r--r--src/common/crypto.c249
-rw-r--r--src/common/crypto.h14
-rw-r--r--src/common/crypto_ed25519.c22
-rw-r--r--src/common/crypto_ed25519.h5
-rw-r--r--src/common/di_ops.c4
-rw-r--r--src/common/include.am3
-rw-r--r--src/common/tortls.c16
13 files changed, 346 insertions, 87 deletions
diff --git a/src/common/address.c b/src/common/address.c
index 19e9fddd08..f495cad5aa 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1327,7 +1327,7 @@ typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
* into smartlist of <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
-ifaddrs_to_smartlist(const struct ifaddrs *ifa)
+ifaddrs_to_smartlist(const struct ifaddrs *ifa, sa_family_t family)
{
smartlist_t *result = smartlist_new();
const struct ifaddrs *i;
@@ -1341,6 +1341,8 @@ ifaddrs_to_smartlist(const struct ifaddrs *ifa)
if (i->ifa_addr->sa_family != AF_INET &&
i->ifa_addr->sa_family != AF_INET6)
continue;
+ if (family != AF_UNSPEC && i->ifa_addr->sa_family != family)
+ continue;
if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0)
continue;
smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
@@ -1354,7 +1356,7 @@ ifaddrs_to_smartlist(const struct ifaddrs *ifa)
* <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
-get_interface_addresses_ifaddrs(int severity)
+get_interface_addresses_ifaddrs(int severity, sa_family_t family)
{
/* Most free Unixy systems provide getifaddrs, which gives us a linked list
@@ -1367,7 +1369,7 @@ get_interface_addresses_ifaddrs(int severity)
return NULL;
}
- result = ifaddrs_to_smartlist(ifa);
+ result = ifaddrs_to_smartlist(ifa, family);
freeifaddrs(ifa);
@@ -1409,7 +1411,7 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
* <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
-get_interface_addresses_win32(int severity)
+get_interface_addresses_win32(int severity, sa_family_t family)
{
/* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
@@ -1443,7 +1445,7 @@ get_interface_addresses_win32(int severity)
/* Guess how much space we need. */
size = 15*1024;
addresses = tor_malloc(size);
- res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ res = fn(family, FLAGS, NULL, addresses, &size);
if (res == ERROR_BUFFER_OVERFLOW) {
/* we didn't guess that we needed enough space; try again */
tor_free(addresses);
@@ -1517,7 +1519,7 @@ ifreq_to_smartlist(char *buf, size_t buflen)
* <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
-get_interface_addresses_ioctl(int severity)
+get_interface_addresses_ioctl(int severity, sa_family_t family)
{
/* Some older unixy systems make us use ioctl(SIOCGIFCONF) */
struct ifconf ifc;
@@ -1526,7 +1528,17 @@ get_interface_addresses_ioctl(int severity)
/* This interface, AFAICT, only supports AF_INET addresses,
* except on AIX. For Solaris, we could use SIOCGLIFCONF. */
- fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ /* Bail out if family is neither AF_INET nor AF_UNSPEC since
+ * ioctl() technique supports non-IPv4 interface addresses on
+ * a small number of niche systems only. If family is AF_UNSPEC,
+ * fall back to getting AF_INET addresses only. */
+ if (family == AF_UNSPEC)
+ family = AF_INET;
+ else if (family != AF_INET)
+ return NULL;
+
+ fd = socket(family, SOCK_DGRAM, 0);
if (fd < 0) {
tor_log(severity, LD_NET, "socket failed: %s", strerror(errno));
goto done;
@@ -1561,21 +1573,23 @@ get_interface_addresses_ioctl(int severity)
/** Try to ask our network interfaces what addresses they are bound to.
* Return a new smartlist of tor_addr_t on success, and NULL on failure.
* (An empty smartlist indicates that we successfully learned that we have no
- * addresses.) Log failure messages at <b>severity</b>. */
+ * addresses.) Log failure messages at <b>severity</b>. Only return the
+ * interface addresses of requested <b>family</b> and ignore the addresses
+ * of other address families. */
MOCK_IMPL(smartlist_t *,
-get_interface_addresses_raw,(int severity))
+get_interface_addresses_raw,(int severity, sa_family_t family))
{
smartlist_t *result = NULL;
#if defined(HAVE_IFADDRS_TO_SMARTLIST)
- if ((result = get_interface_addresses_ifaddrs(severity)))
+ if ((result = get_interface_addresses_ifaddrs(severity, family)))
return result;
#endif
#if defined(HAVE_IP_ADAPTER_TO_SMARTLIST)
- if ((result = get_interface_addresses_win32(severity)))
+ if ((result = get_interface_addresses_win32(severity, family)))
return result;
#endif
#if defined(HAVE_IFCONF_TO_SMARTLIST)
- if ((result = get_interface_addresses_ioctl(severity)))
+ if ((result = get_interface_addresses_ioctl(severity, family)))
return result;
#endif
(void) severity;
@@ -1600,8 +1614,9 @@ tor_addr_is_multicast(const tor_addr_t *a)
}
/** Attempt to retrieve IP address of current host by utilizing some
- * UDP socket trickery. Only look for address of given <b>family</b>.
- * Set result to *<b>addr</b>. Return 0 on success, -1 on failure.
+ * UDP socket trickery. Only look for address of given <b>family</b>
+ * (only AF_INET and AF_INET6 are supported). Set result to *<b>addr</b>.
+ * Return 0 on success, -1 on failure.
*/
MOCK_IMPL(int,
get_interface_address6_via_udp_socket_hack,(int severity,
@@ -1739,15 +1754,9 @@ MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity,
tor_addr_t addr;
/* Try to do this the smart way if possible. */
- if ((addrs = get_interface_addresses_raw(severity))) {
+ if ((addrs = get_interface_addresses_raw(severity, family))) {
SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a)
{
- if (family != AF_UNSPEC && family != tor_addr_family(a)) {
- SMARTLIST_DEL_CURRENT(addrs, a);
- tor_free(a);
- continue;
- }
-
if (tor_addr_is_loopback(a) ||
tor_addr_is_multicast(a)) {
SMARTLIST_DEL_CURRENT(addrs, a);
@@ -1773,15 +1782,27 @@ MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity,
}
/* Okay, the smart way is out. */
- if (get_interface_address6_via_udp_socket_hack(severity,family,&addr))
- return smartlist_new();
- if (!include_internal && tor_addr_is_internal(&addr, 0)) {
- return smartlist_new();
- } else {
- addrs = smartlist_new();
- smartlist_add(addrs, tor_dup_addr(&addr));
- return addrs;
+ addrs = smartlist_new();
+
+ if (family == AF_INET || family == AF_UNSPEC) {
+ if (get_interface_address6_via_udp_socket_hack(severity,AF_INET,
+ &addr) == 0) {
+ if (include_internal || !tor_addr_is_internal(&addr, 0)) {
+ smartlist_add(addrs, tor_dup_addr(&addr));
+ }
+ }
}
+
+ if (family == AF_INET6 || family == AF_UNSPEC) {
+ if (get_interface_address6_via_udp_socket_hack(severity,AF_INET6,
+ &addr) == 0) {
+ if (include_internal || !tor_addr_is_internal(&addr, 0)) {
+ smartlist_add(addrs, tor_dup_addr(&addr));
+ }
+ }
+ }
+
+ return addrs;
}
/* ======
@@ -1837,7 +1858,7 @@ tor_addr_port_parse(int severity, const char *addrport,
}
/** Given an address of the form "host[:port]", try to divide it into its host
- * ane port portions, setting *<b>address_out</b> to a newly allocated string
+ * and port portions, setting *<b>address_out</b> to a newly allocated string
* holding the address portion and *<b>port_out</b> to the port (or 0 if no
* port is given). Return 0 on success, -1 on failure. */
int
diff --git a/src/common/address.h b/src/common/address.h
index 918b024ea6..558eb52b35 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -332,26 +332,31 @@ get_interface_address_list(int severity, int include_internal)
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
#ifdef ADDRESS_PRIVATE
-MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity));
+MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity,
+ sa_family_t family));
MOCK_DECL(int,get_interface_address6_via_udp_socket_hack,(int severity,
sa_family_t family,
tor_addr_t *addr));
#ifdef HAVE_IFADDRS_TO_SMARTLIST
-STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa);
-STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity);
+STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa,
+ sa_family_t family);
+STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity,
+ sa_family_t family);
#endif
#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
STATIC smartlist_t *ip_adapter_addresses_to_smartlist(
const IP_ADAPTER_ADDRESSES *addresses);
-STATIC smartlist_t *get_interface_addresses_win32(int severity);
+STATIC smartlist_t *get_interface_addresses_win32(int severity,
+ sa_family_t family);
#endif
#ifdef HAVE_IFCONF_TO_SMARTLIST
STATIC smartlist_t *ifreq_to_smartlist(char *ifr,
size_t buflen);
-STATIC smartlist_t *get_interface_addresses_ioctl(int severity);
+STATIC smartlist_t *get_interface_addresses_ioctl(int severity,
+ sa_family_t family);
#endif
#endif // ADDRESS_PRIVATE
diff --git a/src/common/backtrace.c b/src/common/backtrace.c
index bed0442471..94de1eb5ee 100644
--- a/src/common/backtrace.c
+++ b/src/common/backtrace.c
@@ -215,9 +215,10 @@ int
configure_backtrace_handler(const char *tor_version)
{
tor_free(bt_version);
- if (!tor_version)
- tor_version = "";
- tor_asprintf(&bt_version, "Tor %s", tor_version);
+ if (tor_version)
+ tor_asprintf(&bt_version, "Tor %s", tor_version);
+ else
+ tor_asprintf(&bt_version, "Tor");
return install_bt_handler();
}
diff --git a/src/common/compat.c b/src/common/compat.c
index 7e8eec189a..c1d4f89621 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -2207,8 +2207,7 @@ switch_id(const char *user, const unsigned flags)
(void)user;
(void)flags;
- log_warn(LD_CONFIG,
- "User specified but switching users is unsupported on your OS.");
+ log_warn(LD_CONFIG, "Switching users is unsupported on your OS.");
return -1;
#endif
}
@@ -2692,8 +2691,7 @@ static int uname_result_is_set = 0;
/** Return a pointer to a description of our platform.
*/
-const char *
-get_uname(void)
+MOCK_IMPL(const char *, get_uname, (void))
{
#ifdef HAVE_UNAME
struct utsname u;
diff --git a/src/common/compat.h b/src/common/compat.h
index d38adca598..8f35dfd110 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -601,7 +601,7 @@ typedef enum {
} socks5_reply_status_t;
/* ===== OS compatibility */
-const char *get_uname(void);
+MOCK_DECL(const char *, get_uname, (void));
uint16_t get_uint16(const void *cp) ATTR_NONNULL((1));
uint32_t get_uint32(const void *cp) ATTR_NONNULL((1));
diff --git a/src/common/compat_openssl.h b/src/common/compat_openssl.h
index 3fcd684c0c..9c98181bdd 100644
--- a/src/common/compat_openssl.h
+++ b/src/common/compat_openssl.h
@@ -19,7 +19,14 @@
#error "We require OpenSSL >= 1.0.0"
#endif
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && \
+ ! defined(LIBRESSL_VERSION_NUMBER)
+/* We define this macro if we're trying to build with the majorly refactored
+ * API in OpenSSL 1.1 */
+#define OPENSSL_1_1_API
+#endif
+
+#ifndef OPENSSL_1_1_API
#define OPENSSL_VERSION SSLEAY_VERSION
#define OpenSSL_version(v) SSLeay_version(v)
#define OpenSSL_version_num() SSLeay()
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 7f0f842419..a42c461b14 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -64,6 +64,8 @@
#include "sandbox.h"
#include "util_format.h"
+#include "keccak-tiny/keccak-tiny.h"
+
#ifdef ANDROID
/* Android's OpenSSL seems to have removed all of its Engine support. */
#define DISABLE_ENGINES
@@ -250,7 +252,7 @@ crypto_openssl_get_header_version_str(void)
/** Make sure that openssl is using its default PRNG. Return 1 if we had to
* adjust it; 0 otherwise. */
-static int
+STATIC int
crypto_force_rand_ssleay(void)
{
RAND_METHOD *default_method;
@@ -1616,8 +1618,12 @@ crypto_digest256(char *digest, const char *m, size_t len,
{
tor_assert(m);
tor_assert(digest);
- tor_assert(algorithm == DIGEST_SHA256);
- return (SHA256((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+ if (algorithm == DIGEST_SHA256)
+ return (SHA256((const uint8_t*)m,len,(uint8_t*)digest) == NULL);
+ else
+ return (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
+ == -1);
}
/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
@@ -1629,8 +1635,13 @@ crypto_digest512(char *digest, const char *m, size_t len,
{
tor_assert(m);
tor_assert(digest);
- tor_assert(algorithm == DIGEST_SHA512);
- return (SHA512((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+ if (algorithm == DIGEST_SHA512)
+ return (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
+ == NULL);
+ else
+ return (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
+ == -1);
}
/** Set the digests_t in <b>ds_out</b> to contain every digest on the
@@ -1646,11 +1657,13 @@ crypto_digest_all(digests_t *ds_out, const char *m, size_t len)
return -1;
for (i = DIGEST_SHA256; i < N_DIGEST_ALGORITHMS; ++i) {
switch (i) {
- case DIGEST_SHA256:
+ case DIGEST_SHA256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_256:
if (crypto_digest256(ds_out->d[i], m, len, i) < 0)
return -1;
break;
case DIGEST_SHA512:
+ case DIGEST_SHA3_512: /* FALLSTHROUGH */
if (crypto_digest512(ds_out->d[i], m, len, i) < 0)
return -1;
break;
@@ -1672,6 +1685,10 @@ crypto_digest_algorithm_get_name(digest_algorithm_t alg)
return "sha256";
case DIGEST_SHA512:
return "sha512";
+ case DIGEST_SHA3_256:
+ return "sha3-256";
+ case DIGEST_SHA3_512:
+ return "sha3-512";
default:
tor_fragile_assert();
return "??unknown_digest??";
@@ -1689,28 +1706,88 @@ crypto_digest_algorithm_parse_name(const char *name)
return DIGEST_SHA256;
else if (!strcmp(name, "sha512"))
return DIGEST_SHA512;
+ else if (!strcmp(name, "sha3-256"))
+ return DIGEST_SHA3_256;
+ else if (!strcmp(name, "sha3-512"))
+ return DIGEST_SHA3_512;
else
return -1;
}
+/** Given an algorithm, return the digest length in bytes. */
+static inline size_t
+crypto_digest_algorithm_get_length(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1:
+ return DIGEST_LEN;
+ case DIGEST_SHA256:
+ return DIGEST256_LEN;
+ case DIGEST_SHA512:
+ return DIGEST512_LEN;
+ case DIGEST_SHA3_256:
+ return DIGEST256_LEN;
+ case DIGEST_SHA3_512:
+ return DIGEST512_LEN;
+ default:
+ tor_assert(0);
+ return 0; /* Unreachable */
+ }
+}
+
/** Intermediate information about the digest of a stream of data. */
struct crypto_digest_t {
+ digest_algorithm_t algorithm; /**< Which algorithm is in use? */
+ /** State for the digest we're using. Only one member of the
+ * union is usable, depending on the value of <b>algorithm</b>. Note also
+ * that space for other members might not even be allocated!
+ */
union {
SHA_CTX sha1; /**< state for SHA1 */
SHA256_CTX sha2; /**< state for SHA256 */
SHA512_CTX sha512; /**< state for SHA512 */
- } d; /**< State for the digest we're using. Only one member of the
- * union is usable, depending on the value of <b>algorithm</b>. */
- digest_algorithm_bitfield_t algorithm : 8; /**< Which algorithm is in use? */
+ keccak_state sha3; /**< state for SHA3-[256,512] */
+ } d;
};
+/**
+ * Return the number of bytes we need to malloc in order to get a
+ * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
+ * when we free one.
+ */
+static size_t
+crypto_digest_alloc_bytes(digest_algorithm_t alg)
+{
+ /* Helper: returns the number of bytes in the 'f' field of 'st' */
+#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
+ /* Gives the length of crypto_digest_t through the end of the field 'd' */
+#define END_OF_FIELD(f) (STRUCT_OFFSET(crypto_digest_t, f) + \
+ STRUCT_FIELD_SIZE(crypto_digest_t, f))
+ switch (alg) {
+ case DIGEST_SHA1:
+ return END_OF_FIELD(d.sha1);
+ case DIGEST_SHA256:
+ return END_OF_FIELD(d.sha2);
+ case DIGEST_SHA512:
+ return END_OF_FIELD(d.sha512);
+ case DIGEST_SHA3_256:
+ case DIGEST_SHA3_512:
+ return END_OF_FIELD(d.sha3);
+ default:
+ tor_assert(0);
+ return 0;
+ }
+#undef END_OF_FIELD
+#undef STRUCT_FIELD_SIZE
+}
+
/** Allocate and return a new digest object to compute SHA1 digests.
*/
crypto_digest_t *
crypto_digest_new(void)
{
crypto_digest_t *r;
- r = tor_malloc(sizeof(crypto_digest_t));
+ r = tor_malloc(crypto_digest_alloc_bytes(DIGEST_SHA1));
SHA1_Init(&r->d.sha1);
r->algorithm = DIGEST_SHA1;
return r;
@@ -1722,9 +1799,12 @@ crypto_digest_t *
crypto_digest256_new(digest_algorithm_t algorithm)
{
crypto_digest_t *r;
- tor_assert(algorithm == DIGEST_SHA256);
- r = tor_malloc(sizeof(crypto_digest_t));
- SHA256_Init(&r->d.sha2);
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+ r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
+ if (algorithm == DIGEST_SHA256)
+ SHA256_Init(&r->d.sha2);
+ else
+ keccak_digest_init(&r->d.sha3, 256);
r->algorithm = algorithm;
return r;
}
@@ -1735,9 +1815,12 @@ crypto_digest_t *
crypto_digest512_new(digest_algorithm_t algorithm)
{
crypto_digest_t *r;
- tor_assert(algorithm == DIGEST_SHA512);
- r = tor_malloc(sizeof(crypto_digest_t));
- SHA512_Init(&r->d.sha512);
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+ r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
+ if (algorithm == DIGEST_SHA512)
+ SHA512_Init(&r->d.sha512);
+ else
+ keccak_digest_init(&r->d.sha3, 512);
r->algorithm = algorithm;
return r;
}
@@ -1749,7 +1832,8 @@ crypto_digest_free(crypto_digest_t *digest)
{
if (!digest)
return;
- memwipe(digest, 0, sizeof(crypto_digest_t));
+ size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memwipe(digest, 0, bytes);
tor_free(digest);
}
@@ -1776,6 +1860,10 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
case DIGEST_SHA512:
SHA512_Update(&digest->d.sha512, (void*)data, len);
break;
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
+ break;
default:
tor_fragile_assert();
break;
@@ -1794,27 +1882,35 @@ crypto_digest_get_digest(crypto_digest_t *digest,
crypto_digest_t tmpenv;
tor_assert(digest);
tor_assert(out);
+ tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
+
+ /* The SHA-3 code handles copying into a temporary ctx, and also can handle
+ * short output buffers by truncating appropriately. */
+ if (digest->algorithm == DIGEST_SHA3_256 ||
+ digest->algorithm == DIGEST_SHA3_512) {
+ keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
+ return;
+ }
+
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
/* memcpy into a temporary ctx, since SHA*_Final clears the context */
- memcpy(&tmpenv, digest, sizeof(crypto_digest_t));
+ memcpy(&tmpenv, digest, alloc_bytes);
switch (digest->algorithm) {
case DIGEST_SHA1:
- tor_assert(out_len <= DIGEST_LEN);
SHA1_Final(r, &tmpenv.d.sha1);
break;
case DIGEST_SHA256:
- tor_assert(out_len <= DIGEST256_LEN);
SHA256_Final(r, &tmpenv.d.sha2);
break;
case DIGEST_SHA512:
- tor_assert(out_len <= DIGEST512_LEN);
SHA512_Final(r, &tmpenv.d.sha512);
break;
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
+ tor_assert(0); /* This is fatal, because it should never happen. */
default:
- log_warn(LD_BUG, "Called with unknown algorithm %d", digest->algorithm);
- /* If fragile_assert is not enabled, then we should at least not
- * leak anything. */
- memwipe(r, 0xff, sizeof(r));
- tor_fragile_assert();
+ tor_assert(0); /* Unreachable. */
break;
}
memcpy(out, r, out_len);
@@ -1827,15 +1923,14 @@ crypto_digest_get_digest(crypto_digest_t *digest,
crypto_digest_t *
crypto_digest_dup(const crypto_digest_t *digest)
{
- crypto_digest_t *r;
tor_assert(digest);
- r = tor_malloc(sizeof(crypto_digest_t));
- memcpy(r,digest,sizeof(crypto_digest_t));
- return r;
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ return tor_memdup(digest, alloc_bytes);
}
/** Replace the state of the digest object <b>into</b> with the state
- * of the digest object <b>from</b>.
+ * of the digest object <b>from</b>. Requires that 'into' and 'from'
+ * have the same digest type.
*/
void
crypto_digest_assign(crypto_digest_t *into,
@@ -1843,7 +1938,9 @@ crypto_digest_assign(crypto_digest_t *into,
{
tor_assert(into);
tor_assert(from);
- memcpy(into,from,sizeof(crypto_digest_t));
+ tor_assert(into->algorithm == from->algorithm);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
+ memcpy(into,from,alloc_bytes);
}
/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
@@ -1878,10 +1975,12 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
case DIGEST_SHA1:
d = crypto_digest_new();
break;
- case DIGEST_SHA256:
+ case DIGEST_SHA256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_256:
d = crypto_digest256_new(alg);
break;
- case DIGEST_SHA512:
+ case DIGEST_SHA512: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
d = crypto_digest512_new(alg);
break;
default:
@@ -1923,6 +2022,56 @@ crypto_hmac_sha256(char *hmac_out,
tor_assert(rv);
}
+/** Internal state for a eXtendable-Output Function (XOF). */
+struct crypto_xof_t {
+ keccak_state s;
+};
+
+/** Allocate a new XOF object backed by SHAKE-256. The security level
+ * provided is a function of the length of the output used. Read and
+ * understand FIPS-202 A.2 "Additional Consideration for Extendable-Output
+ * Functions" before using this construct.
+ */
+crypto_xof_t *
+crypto_xof_new(void)
+{
+ crypto_xof_t *xof;
+ xof = tor_malloc(sizeof(crypto_xof_t));
+ keccak_xof_init(&xof->s, 256);
+ return xof;
+}
+
+/** Absorb bytes into a XOF object. Must not be called after a call to
+ * crypto_xof_squeeze_bytes() for the same instance, and will assert
+ * if attempted.
+ */
+void
+crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len)
+{
+ int i = keccak_xof_absorb(&xof->s, data, len);
+ tor_assert(i == 0);
+}
+
+/** Squeeze bytes out of a XOF object. Calling this routine will render
+ * the XOF instance ineligible to absorb further data.
+ */
+void
+crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
+{
+ int i = keccak_xof_squeeze(&xof->s, out, len);
+ tor_assert(i == 0);
+}
+
+/** Cleanse and deallocate a XOF object. */
+void
+crypto_xof_free(crypto_xof_t *xof)
+{
+ if (!xof)
+ return;
+ memwipe(xof, 0, sizeof(crypto_xof_t));
+ tor_free(xof);
+}
+
/* DH */
/** Our DH 'g' parameter */
@@ -2790,6 +2939,7 @@ smartlist_shuffle(smartlist_t *sl)
/**
* Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
* the value <b>byte</b>.
+ * If <b>mem</b> is NULL or <b>sz</b> is zero, nothing happens.
*
* This function is preferable to memset, since many compilers will happily
* optimize out memset() when they can convince themselves that the data being
@@ -2807,10 +2957,31 @@ smartlist_shuffle(smartlist_t *sl)
void
memwipe(void *mem, uint8_t byte, size_t sz)
{
+ if (sz == 0) {
+ return;
+ }
+ /* If sz is nonzero, then mem must not be NULL. */
+ tor_assert(mem != NULL);
+
+ /* Data this large is likely to be an underflow. */
+ tor_assert(sz < SIZE_T_CEILING);
+
/* Because whole-program-optimization exists, we may not be able to just
* have this function call "memset". A smart compiler could inline it, then
* eliminate dead memsets, and declare itself to be clever. */
+#if defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY)
+ /* Here's what you do on windows. */
+ SecureZeroMemory(mem,sz);
+#elif defined(HAVE_RTLSECUREZEROMEMORY)
+ RtlSecureZeroMemory(mem,sz);
+#elif defined(HAVE_EXPLICIT_BZERO)
+ /* The BSDs provide this. */
+ explicit_bzero(mem, sz);
+#elif defined(HAVE_MEMSET_S)
+ /* This is in the C99 standard. */
+ memset_s(mem, sz, 0, sz);
+#else
/* This is a slow and ugly function from OpenSSL that fills 'mem' with junk
* based on the pointer value, then uses that junk to update a global
* variable. It's an elaborate ruse to trick the compiler into not
@@ -2821,7 +2992,10 @@ memwipe(void *mem, uint8_t byte, size_t sz)
* ...or maybe not. In practice, there are pure-asm implementations of
* OPENSSL_cleanse() on most platforms, which ought to do the job.
**/
+
OPENSSL_cleanse(mem, sz);
+#endif
+
/* Just in case some caller of memwipe() is relying on getting a buffer
* filled with a particular value, fill the buffer.
*
@@ -2856,6 +3030,10 @@ openssl_locking_cb_(int mode, int n, const char *file, int line)
tor_mutex_release(openssl_mutexes_[n]);
}
+#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 {
@@ -2900,6 +3078,7 @@ openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
tor_mutex_free(v->lock);
tor_free(v);
}
+#endif
static void
tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
@@ -2921,9 +3100,11 @@ setup_openssl_threading(void)
openssl_mutexes_[i] = tor_mutex_new();
CRYPTO_set_locking_callback(openssl_locking_cb_);
CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
+#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;
}
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 0fba958f8d..fa2ed610c7 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -96,9 +96,10 @@ typedef enum {
DIGEST_SHA1 = 0,
DIGEST_SHA256 = 1,
DIGEST_SHA512 = 2,
+ DIGEST_SHA3_256 = 3,
+ DIGEST_SHA3_512 = 4,
} digest_algorithm_t;
-#define N_DIGEST_ALGORITHMS (DIGEST_SHA512+1)
-#define digest_algorithm_bitfield_t ENUM_BF(digest_algorithm_t)
+#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1)
/** A set of all the digests we know how to compute, taken on a single
* string. Any digests that are shorter than 512 bits are right-padded
@@ -115,6 +116,7 @@ typedef struct {
typedef struct crypto_pk_t crypto_pk_t;
typedef struct crypto_cipher_t 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 */
@@ -244,6 +246,10 @@ void crypto_digest_assign(crypto_digest_t *into,
void crypto_hmac_sha256(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len);
+crypto_xof_t *crypto_xof_new(void);
+void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len);
+void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
+void crypto_xof_free(crypto_xof_t *xof);
/* Key negotiation */
#define DH_TYPE_CIRCUIT 1
@@ -307,5 +313,9 @@ struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in);
+#ifdef CRYPTO_PRIVATE
+STATIC int crypto_force_rand_ssleay(void);
+#endif
+
#endif
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index 41ec486f0a..9df665f66a 100644
--- a/src/common/crypto_ed25519.c
+++ b/src/common/crypto_ed25519.c
@@ -96,6 +96,28 @@ get_ed_impl(void)
return ed25519_impl;
}
+#ifdef TOR_UNIT_TESTS
+static const ed25519_impl_t *saved_ed25519_impl = NULL;
+void
+crypto_ed25519_testing_force_impl(const char *name)
+{
+ tor_assert(saved_ed25519_impl == NULL);
+ saved_ed25519_impl = ed25519_impl;
+ if (! strcmp(name, "donna")) {
+ ed25519_impl = &impl_donna;
+ } else {
+ tor_assert(!strcmp(name, "ref10"));
+ ed25519_impl = &impl_ref10;
+ }
+}
+void
+crypto_ed25519_testing_restore_impl(void)
+{
+ ed25519_impl = saved_ed25519_impl;
+ saved_ed25519_impl = NULL;
+}
+#endif
+
/**
* Initialize a new ed25519 secret key in <b>seckey_out</b>. If
* <b>extra_strong</b>, take the RNG inputs directly from the operating
diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h
index bdac12eb27..4fa7ea11cf 100644
--- a/src/common/crypto_ed25519.h
+++ b/src/common/crypto_ed25519.h
@@ -111,5 +111,10 @@ int ed25519_pubkey_eq(const ed25519_public_key_t *key1,
void ed25519_set_impl_params(int use_donna);
void ed25519_init(void);
+#ifdef TOR_UNIT_TESTS
+void crypto_ed25519_testing_force_impl(const char *name);
+void crypto_ed25519_testing_restore_impl(void);
+#endif
+
#endif
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index c9d1350880..70f2da7377 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -25,6 +25,9 @@
int
tor_memcmp(const void *a, const void *b, size_t len)
{
+#ifdef HAVE_TIMINGSAFE_MEMCMP
+ return timingsafe_memcmp(a, b, len);
+#else
const uint8_t *x = a;
const uint8_t *y = b;
size_t i = len;
@@ -83,6 +86,7 @@ tor_memcmp(const void *a, const void *b, size_t len)
}
return retval;
+#endif /* timingsafe_memcmp */
}
/**
diff --git a/src/common/include.am b/src/common/include.am
index 2fc92e2ceb..5afb30da6a 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -78,7 +78,8 @@ LIBOR_A_SOURCES = \
$(threads_impl_source) \
$(readpassphrase_source)
-src/common/log.o: micro-revision.i
+src/common/src_common_libor_testing_a-log.$(OBJEXT) \
+ src/common/log.$(OBJEXT): micro-revision.i
LIBOR_CRYPTO_A_SOURCES = \
src/common/aes.c \
diff --git a/src/common/tortls.c b/src/common/tortls.c
index b1d3f6f9e8..6e4cd3d480 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -884,7 +884,7 @@ tor_tls_cert_is_valid(int severity,
EVP_PKEY *cert_key;
int r, key_ok = 0;
- if (!signing_cert)
+ if (!signing_cert || !cert)
goto bad;
EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert);
@@ -1310,6 +1310,7 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
{
const SSL_CIPHER *c;
#ifdef HAVE_SSL_CIPHER_FIND
+ (void) m;
{
unsigned char cipherid[3];
tor_assert(ssl);
@@ -1322,7 +1323,9 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
tor_assert((SSL_CIPHER_get_id(c) & 0xffff) == cipher);
return c != NULL;
}
-#elif defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR)
+#else
+
+# if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR)
if (m && m->get_cipher_by_char) {
unsigned char cipherid[3];
set_uint16(cipherid, htons(cipher));
@@ -1333,9 +1336,9 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
if (c)
tor_assert((c->id & 0xffff) == cipher);
return c != NULL;
- } else
-#endif
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+ }
+# endif
+# if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
if (m && m->get_cipher && m->num_ciphers) {
/* It would seem that some of the "let's-clean-up-openssl" forks have
* removed the get_cipher_by_char function. Okay, so now you get a
@@ -1350,11 +1353,12 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
}
return 0;
}
-#endif
+# endif
(void) ssl;
(void) m;
(void) cipher;
return 1; /* No way to search */
+#endif
}
/** Remove from v2_cipher_list every cipher that we don't support, so that