diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/address.c | 81 | ||||
-rw-r--r-- | src/common/address.h | 15 | ||||
-rw-r--r-- | src/common/backtrace.c | 7 | ||||
-rw-r--r-- | src/common/compat.c | 6 | ||||
-rw-r--r-- | src/common/compat.h | 2 | ||||
-rw-r--r-- | src/common/compat_openssl.h | 9 | ||||
-rw-r--r-- | src/common/crypto.c | 249 | ||||
-rw-r--r-- | src/common/crypto.h | 14 | ||||
-rw-r--r-- | src/common/crypto_ed25519.c | 22 | ||||
-rw-r--r-- | src/common/crypto_ed25519.h | 5 | ||||
-rw-r--r-- | src/common/di_ops.c | 4 | ||||
-rw-r--r-- | src/common/include.am | 3 | ||||
-rw-r--r-- | src/common/tortls.c | 16 |
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 |