diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/address.c | 3 | ||||
-rw-r--r-- | src/common/compat.c | 105 | ||||
-rw-r--r-- | src/common/compat.h | 2 | ||||
-rw-r--r-- | src/common/compat_libevent.c | 35 | ||||
-rw-r--r-- | src/common/compat_libevent.h | 37 | ||||
-rw-r--r-- | src/common/compat_openssl.h | 37 | ||||
-rw-r--r-- | src/common/container.c | 24 | ||||
-rw-r--r-- | src/common/crypto.c | 233 | ||||
-rw-r--r-- | src/common/crypto.h | 38 | ||||
-rw-r--r-- | src/common/crypto_curve25519.c | 3 | ||||
-rw-r--r-- | src/common/include.am | 1 | ||||
-rw-r--r-- | src/common/log.c | 17 | ||||
-rw-r--r-- | src/common/procmon.c | 3 | ||||
-rw-r--r-- | src/common/torlog.h | 17 | ||||
-rw-r--r-- | src/common/tortls.c | 416 | ||||
-rw-r--r-- | src/common/tortls.h | 116 | ||||
-rw-r--r-- | src/common/util.c | 104 | ||||
-rw-r--r-- | src/common/util.h | 1 |
18 files changed, 652 insertions, 540 deletions
diff --git a/src/common/address.c b/src/common/address.c index cfa8fd1dca..aef229b02c 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -1469,7 +1469,8 @@ get_interface_addresses_ioctl(int severity) int fd; smartlist_t *result = NULL; - /* This interface, AFAICT, only supports AF_INET addresses */ + /* This interface, AFAICT, only supports AF_INET addresses, + * except on AIX. For Solaris, we could use SIOCGLIFCONF. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { tor_log(severity, LD_NET, "socket failed: %s", strerror(errno)); diff --git a/src/common/compat.c b/src/common/compat.c index 7d72b4b7fd..55fb55a045 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -1486,6 +1486,20 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) } #ifdef NEED_ERSATZ_SOCKETPAIR + +static INLINE socklen_t +SIZEOF_SOCKADDR(int domain) +{ + switch (domain) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + default: + return 0; + } +} + /** * Helper used to implement socketpair on systems that lack it, by * making a direct connection to localhost. @@ -1501,13 +1515,21 @@ tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) tor_socket_t listener = TOR_INVALID_SOCKET; tor_socket_t connector = TOR_INVALID_SOCKET; tor_socket_t acceptor = TOR_INVALID_SOCKET; - struct sockaddr_in listen_addr; - struct sockaddr_in connect_addr; + tor_addr_t listen_tor_addr; + struct sockaddr_storage connect_addr_ss, listen_addr_ss; + struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss; + uint16_t listen_port = 0; + tor_addr_t connect_tor_addr; + uint16_t connect_port = 0; + struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss; socklen_t size; int saved_errno = -1; + int ersatz_domain = AF_INET; - memset(&connect_addr, 0, sizeof(connect_addr)); - memset(&listen_addr, 0, sizeof(listen_addr)); + memset(&connect_tor_addr, 0, sizeof(connect_tor_addr)); + memset(&connect_addr_ss, 0, sizeof(connect_addr_ss)); + memset(&listen_tor_addr, 0, sizeof(listen_tor_addr)); + memset(&listen_addr_ss, 0, sizeof(listen_addr_ss)); if (protocol #ifdef AF_UNIX @@ -1524,47 +1546,71 @@ tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) return -EINVAL; } - listener = tor_open_socket(AF_INET, type, 0); - if (!SOCKET_OK(listener)) - return -tor_socket_errno(-1); - memset(&listen_addr, 0, sizeof(listen_addr)); - listen_addr.sin_family = AF_INET; - listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - listen_addr.sin_port = 0; /* kernel chooses port. */ - if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr)) - == -1) + listener = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(listener)) { + int first_errno = tor_socket_errno(-1); + if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT) + && ersatz_domain == AF_INET) { + /* Assume we're on an IPv6-only system */ + ersatz_domain = AF_INET6; + listener = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(listener)) { + /* Keep the previous behaviour, which was to return the IPv4 error. + * (This may be less informative on IPv6-only systems.) + * XX/teor - is there a better way to decide which errno to return? + * (I doubt we care much either way, once there is an error.) + */ + return -first_errno; + } + } + } + /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we + * risk exposing a socketpair on a routable IP address. (Some BSD jails + * use a routable address for localhost. Fortunately, they have the real + * AF_UNIX socketpair.) */ + if (ersatz_domain == AF_INET) { + tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK); + } else { + tor_addr_parse(&listen_tor_addr, "[::1]"); + } + tor_assert(tor_addr_is_loopback(&listen_tor_addr)); + size = tor_addr_to_sockaddr(&listen_tor_addr, + 0 /* kernel chooses port. */, + listen_addr, + sizeof(listen_addr_ss)); + if (bind(listener, listen_addr, size) == -1) goto tidy_up_and_fail; if (listen(listener, 1) == -1) goto tidy_up_and_fail; - connector = tor_open_socket(AF_INET, type, 0); + connector = tor_open_socket(ersatz_domain, type, 0); if (!SOCKET_OK(connector)) goto tidy_up_and_fail; /* We want to find out the port number to connect to. */ - size = sizeof(connect_addr); - if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) + size = sizeof(connect_addr_ss); + if (getsockname(listener, connect_addr, &size) == -1) goto tidy_up_and_fail; - if (size != sizeof (connect_addr)) + if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)) goto abort_tidy_up_and_fail; - if (connect(connector, (struct sockaddr *) &connect_addr, - sizeof(connect_addr)) == -1) + if (connect(connector, connect_addr, size) == -1) goto tidy_up_and_fail; - size = sizeof(listen_addr); - acceptor = tor_accept_socket(listener, - (struct sockaddr *) &listen_addr, &size); + size = sizeof(listen_addr_ss); + acceptor = tor_accept_socket(listener, listen_addr, &size); if (!SOCKET_OK(acceptor)) goto tidy_up_and_fail; - if (size != sizeof(listen_addr)) + if (size != SIZEOF_SOCKADDR(listen_addr->sa_family)) goto abort_tidy_up_and_fail; /* Now check we are talking to ourself by matching port and host on the two sockets. */ - if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1) + if (getsockname(connector, connect_addr, &size) == -1) goto tidy_up_and_fail; - if (size != sizeof (connect_addr) - || listen_addr.sin_family != connect_addr.sin_family - || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr - || listen_addr.sin_port != connect_addr.sin_port) { + /* Set *_tor_addr and *_port to the address and port that was used */ + tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port); + tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port); + if (size != SIZEOF_SOCKADDR (connect_addr->sa_family) + || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC) + || listen_port != connect_port) { goto abort_tidy_up_and_fail; } tor_close_socket(listener); @@ -1590,6 +1636,9 @@ tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) tor_close_socket(acceptor); return -saved_errno; } + +#undef SIZEOF_SOCKADDR + #endif /* Return the maximum number of allowed sockets. */ diff --git a/src/common/compat.h b/src/common/compat.h index c7c468c754..c3d6abd07c 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -118,6 +118,7 @@ #define ATTR_CONST __attribute__((const)) #define ATTR_MALLOC __attribute__((malloc)) #define ATTR_NORETURN __attribute__((noreturn)) +#define ATTR_WUR __attribute__((warn_unused_result)) /* Alas, nonnull is not at present a good idea for us. We'd like to get * warnings when we pass NULL where we shouldn't (which nonnull does, albeit * spottily), but we don't want to tell the compiler to make optimizations @@ -153,6 +154,7 @@ #define ATTR_NORETURN #define ATTR_NONNULL(x) #define ATTR_UNUSED +#define ATTR_WUR #define PREDICT_LIKELY(exp) (exp) #define PREDICT_UNLIKELY(exp) (exp) #endif diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c index a366b6c9c6..29e5c5f63c 100644 --- a/src/common/compat_libevent.c +++ b/src/common/compat_libevent.c @@ -11,6 +11,7 @@ #include "orconfig.h" #include "compat.h" +#define COMPAT_LIBEVENT_PRIVATE #include "compat_libevent.h" #include "crypto.h" @@ -28,39 +29,11 @@ #include <event.h> #endif -/** A number representing a version of Libevent. - - This is a 4-byte number, with the first three bytes representing the - major, minor, and patchlevel respectively of the library. The fourth - byte is unused. - - This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent - 2.0.1 or later. For versions of Libevent before 1.4.0, which followed the - format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a - to be equivalent to 1.0.1, and so on. -*/ -typedef uint32_t le_version_t; - -/** @{ */ -/** Macros: returns the number of a libevent version as a le_version_t */ -#define V(major, minor, patch) \ - (((major) << 24) | ((minor) << 16) | ((patch) << 8)) -#define V_OLD(major, minor, patch) \ - V((major), (minor), (patch)-'a'+1) -/** @} */ - -/** Represetns a version of libevent so old we can't figure out what version - * it is. */ -#define LE_OLD V(0,0,0) -/** Represents a version of libevent so weird we can't figure out what version - * it is. */ -#define LE_OTHER V(0,0,99) - /** A string which, if it appears in a libevent log, should be ignored. */ static const char *suppress_msg = NULL; /** Callback function passed to event_set_log() so we can intercept * log messages from libevent. */ -static void +STATIC void libevent_logging_callback(int severity, const char *msg) { char buf[1024]; @@ -291,7 +264,7 @@ tor_libevent_get_method(void) /** Return the le_version_t for the version of libevent specified in the * string <b>v</b>. If the version is very new or uses an unrecognized * version, format, return LE_OTHER. */ -static le_version_t +STATIC le_version_t tor_decode_libevent_version(const char *v) { unsigned major, minor, patchlevel; @@ -322,7 +295,7 @@ tor_decode_libevent_version(const char *v) * Two different versions with different numbers are sure not to be binary * compatible. Two different versions with the same numbers have a decent * chance of binary compatibility.*/ -static int +STATIC int le_versions_compatibility(le_version_t v) { if (v == LE_OTHER) diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h index 39181efb7b..8ee02c0b6d 100644 --- a/src/common/compat_libevent.h +++ b/src/common/compat_libevent.h @@ -91,5 +91,42 @@ void tor_gettimeofday_cache_set(const struct timeval *tv); #endif void tor_gettimeofday_cached_monotonic(struct timeval *tv); +#ifdef COMPAT_LIBEVENT_PRIVATE +/** A number representing a version of Libevent. + + This is a 4-byte number, with the first three bytes representing the + major, minor, and patchlevel respectively of the library. The fourth + byte is unused. + + This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent + 2.0.1 or later. For versions of Libevent before 1.4.0, which followed the + format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a + to be equivalent to 1.0.1, and so on. +*/ +typedef uint32_t le_version_t; + +/** @{ */ +/** Macros: returns the number of a libevent version as a le_version_t */ +#define V(major, minor, patch) \ + (((major) << 24) | ((minor) << 16) | ((patch) << 8)) +#define V_OLD(major, minor, patch) \ + V((major), (minor), (patch)-'a'+1) +/** @} */ + +/** Represetns a version of libevent so old we can't figure out what version + * it is. */ +#define LE_OLD V(0,0,0) +/** Represents a version of libevent so weird we can't figure out what version + * it is. */ +#define LE_OTHER V(0,0,99) + +STATIC void +libevent_logging_callback(int severity, const char *msg); +STATIC le_version_t +tor_decode_libevent_version(const char *v); +STATIC int +le_versions_compatibility(le_version_t v); +#endif + #endif diff --git a/src/common/compat_openssl.h b/src/common/compat_openssl.h new file mode 100644 index 0000000000..3fcd684c0c --- /dev/null +++ b/src/common/compat_openssl.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_OPENSSL_H +#define TOR_COMPAT_OPENSSL_H + +#include <openssl/opensslv.h> + +/** + * \file compat_openssl.h + * + * \brief compatability definitions for working with different openssl forks + **/ + +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) +#error "We require OpenSSL >= 1.0.0" +#endif + +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) +#define OPENSSL_VERSION SSLEAY_VERSION +#define OpenSSL_version(v) SSLeay_version(v) +#define OpenSSL_version_num() SSLeay() +#define RAND_OpenSSL() RAND_SSLeay() +#define STATE_IS_SW_SERVER_HELLO(st) \ + (((st) == SSL3_ST_SW_SRVR_HELLO_A) || \ + ((st) == SSL3_ST_SW_SRVR_HELLO_B)) +#define OSSL_HANDSHAKE_STATE int +#else +#define STATE_IS_SW_SERVER_HELLO(st) \ + ((st) == TLS_ST_SW_SRVR_HELLO) +#endif + +#endif + diff --git a/src/common/container.c b/src/common/container.c index 636dfb6c57..c6f059170e 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -55,6 +55,7 @@ smartlist_free,(smartlist_t *sl)) void smartlist_clear(smartlist_t *sl) { + memset(sl->list, 0, sizeof(void *) * sl->num_used); sl->num_used = 0; } @@ -82,9 +83,11 @@ smartlist_ensure_capacity(smartlist_t *sl, int size) while (size > higher) higher *= 2; } - sl->capacity = higher; sl->list = tor_reallocarray(sl->list, sizeof(void *), - ((size_t)sl->capacity)); + ((size_t)higher)); + memset(sl->list + sl->capacity, 0, + sizeof(void *) * (higher - sl->capacity)); + sl->capacity = higher; } #undef ASSERT_CAPACITY #undef MAX_CAPACITY @@ -123,6 +126,7 @@ smartlist_remove(smartlist_t *sl, const void *element) if (sl->list[i] == element) { sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ i--; /* so we process the new i'th element */ + sl->list[sl->num_used] = NULL; } } @@ -132,9 +136,11 @@ void * smartlist_pop_last(smartlist_t *sl) { tor_assert(sl); - if (sl->num_used) - return sl->list[--sl->num_used]; - else + if (sl->num_used) { + void *tmp = sl->list[--sl->num_used]; + sl->list[sl->num_used] = NULL; + return tmp; + } else return NULL; } @@ -165,6 +171,7 @@ smartlist_string_remove(smartlist_t *sl, const char *element) tor_free(sl->list[i]); sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ i--; /* so we process the new i'th element */ + sl->list[sl->num_used] = NULL; } } } @@ -321,6 +328,7 @@ smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) if (!smartlist_contains(sl2, sl1->list[i])) { sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */ i--; /* so we process the new i'th element */ + sl1->list[sl1->num_used] = NULL; } } @@ -345,6 +353,7 @@ smartlist_del(smartlist_t *sl, int idx) tor_assert(idx>=0); tor_assert(idx < sl->num_used); sl->list[idx] = sl->list[--sl->num_used]; + sl->list[sl->num_used] = NULL; } /** Remove the <b>idx</b>th element of sl; if idx is not the last element, @@ -360,6 +369,7 @@ smartlist_del_keeporder(smartlist_t *sl, int idx) --sl->num_used; if (idx < sl->num_used) memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); + sl->list[sl->num_used] = NULL; } /** Insert the value <b>val</b> as the new <b>idx</b>th element of @@ -937,9 +947,11 @@ smartlist_pqueue_pop(smartlist_t *sl, *IDXP(top)=-1; if (--sl->num_used) { sl->list[0] = sl->list[sl->num_used]; + sl->list[sl->num_used] = NULL; UPDATE_IDX(0); smartlist_heapify(sl, compare, idx_field_offset, 0); } + sl->list[sl->num_used] = NULL; return top; } @@ -959,9 +971,11 @@ smartlist_pqueue_remove(smartlist_t *sl, --sl->num_used; *IDXP(item) = -1; if (idx == sl->num_used) { + sl->list[sl->num_used] = NULL; return; } else { sl->list[idx] = sl->list[sl->num_used]; + sl->list[sl->num_used] = NULL; UPDATE_IDX(idx); smartlist_heapify(sl, compare, idx_field_offset, idx); } diff --git a/src/common/crypto.c b/src/common/crypto.c index 815c2ec0c5..baef755d00 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -21,18 +21,13 @@ #undef OCSP_RESPONSE #endif -#include <openssl/opensslv.h> - #define CRYPTO_PRIVATE #include "crypto.h" +#include "compat_openssl.h" #include "crypto_curve25519.h" #include "crypto_ed25519.h" #include "crypto_format.h" -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) -#error "We require OpenSSL >= 1.0.0" -#endif - #include <openssl/err.h> #include <openssl/rsa.h> #include <openssl/pem.h> @@ -227,7 +222,7 @@ const char * crypto_openssl_get_version_str(void) { if (crypto_openssl_version_str == NULL) { - const char *raw_version = SSLeay_version(SSLEAY_VERSION); + const char *raw_version = OpenSSL_version(OPENSSL_VERSION); crypto_openssl_version_str = parse_openssl_version_str(raw_version); } return crypto_openssl_version_str; @@ -251,11 +246,13 @@ crypto_openssl_get_header_version_str(void) static int crypto_force_rand_ssleay(void) { - if (RAND_get_rand_method() != RAND_SSLeay()) { + RAND_METHOD *default_method; + default_method = RAND_OpenSSL(); + if (RAND_get_rand_method() != default_method) { log_notice(LD_CRYPTO, "It appears that one of our engines has provided " "a replacement the OpenSSL RNG. Resetting it to the default " "implementation."); - RAND_set_rand_method(RAND_SSLeay()); + RAND_set_rand_method(default_method); return 1; } return 0; @@ -270,8 +267,7 @@ crypto_init_siphash_key(void) if (have_seeded_siphash) return 0; - if (crypto_rand((char*) &key, sizeof(key)) < 0) - return -1; + crypto_rand((char*) &key, sizeof(key)); siphash_set_global_key(&key); have_seeded_siphash = 1; return 0; @@ -291,16 +287,18 @@ crypto_early_init(void) setup_openssl_threading(); - if (SSLeay() == OPENSSL_VERSION_NUMBER && - !strcmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT)) { + unsigned long version_num = OpenSSL_version_num(); + const char *version_str = OpenSSL_version(OPENSSL_VERSION); + if (version_num == OPENSSL_VERSION_NUMBER && + !strcmp(version_str, OPENSSL_VERSION_TEXT)) { log_info(LD_CRYPTO, "OpenSSL version matches version from headers " - "(%lx: %s).", SSLeay(), SSLeay_version(SSLEAY_VERSION)); + "(%lx: %s).", version_num, version_str); } else { log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " "version we're running with. If you get weird crashes, that " "might be why. (Compiled with %lx: %s; running with %lx: %s).", (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, - SSLeay(), SSLeay_version(SSLEAY_VERSION)); + version_num, version_str); } crypto_force_rand_ssleay(); @@ -322,7 +320,8 @@ int crypto_global_init(int useAccel, const char *accelName, const char *accelDir) { if (!crypto_global_initialized_) { - crypto_early_init(); + if (crypto_early_init() < 0) + return -1; crypto_global_initialized_ = 1; @@ -404,11 +403,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir) void crypto_thread_cleanup(void) { -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) ERR_remove_thread_state(NULL); -#else - ERR_remove_state(0); -#endif } /** used by tortls.c: wrap an RSA* in a crypto_pk_t. */ @@ -432,9 +427,10 @@ crypto_pk_get_rsa_(crypto_pk_t *env) } /** 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. */ -EVP_PKEY * -crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private) + * 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; @@ -470,8 +466,8 @@ crypto_dh_get_dh_(crypto_dh_t *dh) /** Allocate and return storage for a public key. The key itself will not yet * be set. */ -crypto_pk_t * -crypto_pk_new(void) +MOCK_IMPL(crypto_pk_t *, + crypto_pk_new,(void)) { RSA *rsa; @@ -553,8 +549,8 @@ crypto_cipher_free(crypto_cipher_t *env) /** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>. * Return 0 on success, -1 on failure. */ -int -crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits) +MOCK_IMPL(int, + crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits)) { tor_assert(env); @@ -656,7 +652,8 @@ crypto_pk_read_private_key_from_filename(crypto_pk_t *env, return 0; } -/** Helper function to implement crypto_pk_write_*_key_to_string. */ +/** 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) @@ -897,7 +894,8 @@ crypto_pk_dup_key(crypto_pk_t *env) return env; } -/** Make a real honest-to-goodness copy of <b>env</b>, and return it. */ +/** 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) { @@ -1189,7 +1187,8 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, return -1; } -/** Invert crypto_pk_public_hybrid_encrypt. */ +/** Invert crypto_pk_public_hybrid_encrypt. Returns the number of bytes + * written on success, -1 on failure. */ int crypto_pk_private_hybrid_decrypt(crypto_pk_t *env, char *to, @@ -1332,7 +1331,7 @@ crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out) } /** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces - * every four spaces. */ + * every four characters. */ void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) { @@ -1484,7 +1483,7 @@ crypto_cipher_get_key(crypto_cipher_t *env) /** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * On failure, return -1. + * Does not check for failure. */ int crypto_cipher_encrypt(crypto_cipher_t *env, char *to, @@ -1503,7 +1502,7 @@ crypto_cipher_encrypt(crypto_cipher_t *env, char *to, /** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * On failure, return -1. + * Does not check for failure. */ int crypto_cipher_decrypt(crypto_cipher_t *env, char *to, @@ -1519,7 +1518,7 @@ crypto_cipher_decrypt(crypto_cipher_t *env, char *to, } /** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; - * on success, return 0. On failure, return -1. + * on success, return 0. Does not check for failure. */ int crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) @@ -1591,7 +1590,7 @@ crypto_cipher_decrypt_with_iv(const char *key, /** Compute the SHA1 digest of the <b>len</b> bytes on data stored in * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>. - * Return 0 on success, -1 on failure. + * Return 0 on success, 1 on failure. */ int crypto_digest(char *digest, const char *m, size_t len) @@ -1603,7 +1602,7 @@ crypto_digest(char *digest, const char *m, size_t len) /** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>, * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result - * into <b>digest</b>. Return 0 on success, -1 on failure. */ + * into <b>digest</b>. Return 0 on success, 1 on failure. */ int crypto_digest256(char *digest, const char *m, size_t len, digest_algorithm_t algorithm) @@ -1614,6 +1613,19 @@ crypto_digest256(char *digest, const char *m, size_t len, return (SHA256((const unsigned char*)m,len,(unsigned char*)digest) == NULL); } +/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>, + * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result + * into <b>digest</b>. Return 0 on success, 1 on failure. */ +int +crypto_digest512(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA512); + return (SHA512((const unsigned char*)m,len,(unsigned char*)digest) == NULL); +} + /** Set the digests_t in <b>ds_out</b> to contain every digest on the * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on * success, -1 on failure. */ @@ -1626,8 +1638,18 @@ crypto_digest_all(digests_t *ds_out, const char *m, size_t len) if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0) return -1; for (i = DIGEST_SHA256; i < N_DIGEST_ALGORITHMS; ++i) { - if (crypto_digest256(ds_out->d[i], m, len, i) < 0) - return -1; + switch (i) { + case DIGEST_SHA256: + if (crypto_digest256(ds_out->d[i], m, len, i) < 0) + return -1; + break; + case DIGEST_SHA512: + if (crypto_digest512(ds_out->d[i], m, len, i) < 0) + return -1; + break; + default: + return -1; + } } return 0; } @@ -1641,6 +1663,8 @@ crypto_digest_algorithm_get_name(digest_algorithm_t alg) return "sha1"; case DIGEST_SHA256: return "sha256"; + case DIGEST_SHA512: + return "sha512"; default: tor_fragile_assert(); return "??unknown_digest??"; @@ -1656,6 +1680,8 @@ crypto_digest_algorithm_parse_name(const char *name) return DIGEST_SHA1; else if (!strcmp(name, "sha256")) return DIGEST_SHA256; + else if (!strcmp(name, "sha512")) + return DIGEST_SHA512; else return -1; } @@ -1665,6 +1691,7 @@ struct crypto_digest_t { 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? */ @@ -1695,6 +1722,19 @@ crypto_digest256_new(digest_algorithm_t algorithm) return r; } +/** Allocate and return a new digest object to compute 512-bit digests + * using <b>algorithm</b>. */ +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); + r->algorithm = algorithm; + return r; +} + /** Deallocate a digest object. */ void @@ -1726,6 +1766,9 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, case DIGEST_SHA256: SHA256_Update(&digest->d.sha2, (void*)data, len); break; + case DIGEST_SHA512: + SHA512_Update(&digest->d.sha512, (void*)data, len); + break; default: tor_fragile_assert(); break; @@ -1734,13 +1777,13 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, /** Compute the hash of the data that has been passed to the digest * object; write the first out_len bytes of the result to <b>out</b>. - * <b>out_len</b> must be \<= DIGEST256_LEN. + * <b>out_len</b> must be \<= DIGEST512_LEN. */ void crypto_digest_get_digest(crypto_digest_t *digest, char *out, size_t out_len) { - unsigned char r[DIGEST256_LEN]; + unsigned char r[DIGEST512_LEN]; crypto_digest_t tmpenv; tor_assert(digest); tor_assert(out); @@ -1755,6 +1798,10 @@ crypto_digest_get_digest(crypto_digest_t *digest, 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; default: log_warn(LD_BUG, "Called with unknown algorithm %d", digest->algorithm); /* If fragile_assert is not enabled, then we should at least not @@ -1796,7 +1843,7 @@ crypto_digest_assign(crypto_digest_t *into, * at <b>digest_out</b> to the hash of the concatenation of those strings, * plus the optional string <b>append</b>, computed with the algorithm * <b>alg</b>. - * <b>out_len</b> must be \<= DIGEST256_LEN. */ + * <b>out_len</b> must be \<= DIGEST512_LEN. */ void crypto_digest_smartlist(char *digest_out, size_t len_out, const smartlist_t *lst, @@ -1811,7 +1858,7 @@ crypto_digest_smartlist(char *digest_out, size_t len_out, * optional string <b>prepend</b>, those strings, * and the optional string <b>append</b>, computed with the algorithm * <b>alg</b>. - * <b>out_len</b> must be \<= DIGEST256_LEN. */ + * <b>len_out</b> must be \<= DIGEST512_LEN. */ void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, const char *prepend, @@ -1819,11 +1866,25 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, const char *append, digest_algorithm_t alg) { - crypto_digest_t *d; - if (alg == DIGEST_SHA1) - d = crypto_digest_new(); - else - d = crypto_digest256_new(alg); + crypto_digest_t *d = NULL; + switch (alg) { + case DIGEST_SHA1: + d = crypto_digest_new(); + break; + case DIGEST_SHA256: + d = crypto_digest256_new(alg); + break; + case DIGEST_SHA512: + d = crypto_digest512_new(alg); + break; + default: + log_warn(LD_BUG, "Called with unknown algorithm %d", alg); + /* If fragile_assert is not enabled, wipe output and return + * without running any calculations */ + memwipe(digest_out, 0xff, len_out); + tor_fragile_assert(); + goto free; + } if (prepend) crypto_digest_add_bytes(d, prepend, strlen(prepend)); SMARTLIST_FOREACH(lst, const char *, cp, @@ -1831,23 +1892,28 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, if (append) crypto_digest_add_bytes(d, append, strlen(append)); crypto_digest_get_digest(d, digest_out, len_out); + + free: crypto_digest_free(d); } /** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte - * result in <b>hmac_out</b>. + * result in <b>hmac_out</b>. Asserts on failure. */ void crypto_hmac_sha256(char *hmac_out, const char *key, size_t key_len, const char *msg, size_t msg_len) { + unsigned char *rv = NULL; /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ tor_assert(key_len < INT_MAX); tor_assert(msg_len < INT_MAX); - HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, - (unsigned char*)hmac_out, NULL); + tor_assert(hmac_out); + rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, + (unsigned char*)hmac_out, NULL); + tor_assert(rv); } /* DH */ @@ -1941,7 +2007,8 @@ init_dh_param(void) */ #define DH_PRIVATE_KEY_BITS 320 -/** Allocate and return a new DH object for a key exchange. +/** Allocate and return a new DH object for a key exchange. Returns NULL on + * failure. */ crypto_dh_t * crypto_dh_new(int dh_type) @@ -2164,7 +2231,7 @@ int crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, uint8_t *key_out, size_t key_out_len) { - int i; + int i, r = -1; uint8_t *cp, *tmp = tor_malloc(key_in_len+1); uint8_t digest[DIGEST_LEN]; @@ -2176,19 +2243,16 @@ crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, ++i, cp += DIGEST_LEN) { tmp[key_in_len] = i; if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1)) - goto err; + goto exit; memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); } - memwipe(tmp, 0, key_in_len+1); - tor_free(tmp); - memwipe(digest, 0, sizeof(digest)); - return 0; - err: + r = 0; + exit: memwipe(tmp, 0, key_in_len+1); tor_free(tmp); memwipe(digest, 0, sizeof(digest)); - return -1; + return r; } /** Expand some secret key material according to RFC5869, using SHA256 as the @@ -2196,7 +2260,7 @@ crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" * and "info" parameters respectively. On success, write <b>key_out_len</b> - * bytes to <b>key_out</b> and return 0. On failure, return -1. + * bytes to <b>key_out</b> and return 0. Assert on failure. */ int crypto_expand_key_material_rfc5869_sha256( @@ -2280,7 +2344,7 @@ crypto_seed_weak_rng(tor_weak_rng_t *rng) } /** Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * storing it into <b>out</b>. + * storing it into <b>out</b>. Return -1 on success, 0 on failure. */ int crypto_strongest_rand(uint8_t *out, size_t out_len) @@ -2335,8 +2399,7 @@ crypto_strongest_rand(uint8_t *out, size_t out_len) } /** Seed OpenSSL's random number generator with bytes from the operating - * system. <b>startup</b> should be true iff we have just started Tor and - * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure. + * system. Return 0 on success, -1 on failure. */ int crypto_seed_rng(void) @@ -2358,34 +2421,41 @@ crypto_seed_rng(void) memwipe(buf, 0, sizeof(buf)); - if (rand_poll_ok || load_entropy_ok) + if ((rand_poll_ok || load_entropy_ok) && RAND_status() == 1) return 0; else return -1; } -/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on - * success, -1 on failure, with support for mocking for unit tests. +/** Write <b>n</b> bytes of strong random data to <b>to</b>. Supports mocking + * for unit tests. + * + * This function is not allowed to fail; if it would fail to generate strong + * entropy, it must terminate the process instead. */ -MOCK_IMPL(int, +MOCK_IMPL(void, crypto_rand, (char *to, size_t n)) { - return crypto_rand_unmocked(to, n); + crypto_rand_unmocked(to, n); } -/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on - * success, -1 on failure. Most callers will want crypto_rand instead. +/** Write <b>n</b> bytes of strong random data to <b>to</b>. Most callers + * will want crypto_rand instead. + * + * This function is not allowed to fail; if it would fail to generate strong + * entropy, it must terminate the process instead. */ -int +void crypto_rand_unmocked(char *to, size_t n) { int r; + if (n == 0) + return; + tor_assert(n < INT_MAX); tor_assert(to); r = RAND_bytes((unsigned char*)to, (int)n); - if (r == 0) - crypto_log_errors(LOG_WARN, "generating random data"); - return (r == 1) ? 0 : -1; + tor_assert(r >= 0); } /** Return a pseudorandom integer, chosen uniformly from the values @@ -2411,8 +2481,8 @@ crypto_rand_int(unsigned int max) } } -/** Return a pseudorandom integer, chosen uniformly from the values <i>i</i> - * such that <b>min</b> <= <i>i</i> < <b>max</b>. +/** Return a pseudorandom integer, chosen uniformly from the values i such + * that min <= i < max. * * <b>min</b> MUST be in range [0, <b>max</b>). * <b>max</b> MUST be in range (min, INT_MAX]. @@ -2489,7 +2559,7 @@ crypto_rand_double(void) /** Generate and return a new random hostname starting with <b>prefix</b>, * ending with <b>suffix</b>, and containing no fewer than * <b>min_rand_len</b> and no more than <b>max_rand_len</b> random base32 - * characters between. + * characters. Does not check for failure. * * Clip <b>max_rand_len</b> to MAX_DNS_LABEL_SIZE. **/ @@ -2671,7 +2741,7 @@ tor_set_openssl_thread_id(CRYPTO_THREADID *threadid) /** @{ */ /** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being - * multithreaded. */ + * multithreaded. Returns 0. */ static int setup_openssl_threading(void) { @@ -2689,17 +2759,14 @@ setup_openssl_threading(void) return 0; } -/** Uninitialize the crypto library. Return 0 on success, -1 on failure. +/** Uninitialize the crypto library. Return 0 on success. Does not detect + * failure. */ int crypto_global_cleanup(void) { EVP_cleanup(); -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) ERR_remove_thread_state(NULL); -#else - ERR_remove_state(0); -#endif ERR_free_strings(); if (dh_param_p) diff --git a/src/common/crypto.h b/src/common/crypto.h index 6256f7346b..9b922ff818 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -16,6 +16,7 @@ #include <stdio.h> #include "torint.h" #include "testsupport.h" +#include "compat.h" /* Macro to create an arbitrary OpenSSL version number as used by @@ -54,6 +55,8 @@ /** Length of the output of our second (improved) message digests. (For now * this is just sha256, but it could be any other 256-bit digest.) */ #define DIGEST256_LEN 32 +/** Length of the output of our 64-bit optimized message digests (SHA512). */ +#define DIGEST512_LEN 64 /** Length of our symmetric cipher's keys. */ #define CIPHER_KEY_LEN 16 /** Length of our symmetric cipher's IV. */ @@ -69,6 +72,9 @@ /** Length of a sha256 message digest when encoded in base64 with trailing = * signs removed. */ #define BASE64_DIGEST256_LEN 43 +/** Length of a sha512 message digest when encoded in base64 with trailing = + * signs removed. */ +#define BASE64_DIGEST512_LEN 86 /** Constant used to indicate OAEP padding for public-key encryption */ #define PK_PKCS1_OAEP_PADDING 60002 @@ -83,24 +89,27 @@ #define HEX_DIGEST_LEN 40 /** Length of hex encoding of SHA256 digest, not including final NUL. */ #define HEX_DIGEST256_LEN 64 +/** Length of hex encoding of SHA512 digest, not including final NUL. */ +#define HEX_DIGEST512_LEN 128 typedef enum { DIGEST_SHA1 = 0, DIGEST_SHA256 = 1, + DIGEST_SHA512 = 2, } digest_algorithm_t; -#define N_DIGEST_ALGORITHMS (DIGEST_SHA256+1) +#define N_DIGEST_ALGORITHMS (DIGEST_SHA512+1) #define digest_algorithm_bitfield_t ENUM_BF(digest_algorithm_t) /** A set of all the digests we know how to compute, taken on a single - * string. Any digests that are shorter than 256 bits are right-padded + * string. Any digests that are shorter than 512 bits are right-padded * with 0 bits. * - * Note that this representation wastes 12 bytes for the SHA1 case, so + * Note that this representation wastes 44 bytes for the SHA1 case, so * don't use it for anything where we need to allocate a whole bunch at * once. **/ typedef struct { - char d[N_DIGEST_ALGORITHMS][DIGEST256_LEN]; + char d[N_DIGEST_ALGORITHMS][DIGEST512_LEN]; } digests_t; typedef struct crypto_pk_t crypto_pk_t; @@ -111,15 +120,15 @@ 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); +int crypto_early_init(void) ATTR_WUR; int crypto_global_init(int hardwareAccel, const char *accelName, - const char *accelPath); + const char *accelPath) ATTR_WUR; void crypto_thread_cleanup(void); int crypto_global_cleanup(void); /* environment setup */ -crypto_pk_t *crypto_pk_new(void); +MOCK_DECL(crypto_pk_t *,crypto_pk_new,(void)); void crypto_pk_free(crypto_pk_t *env); void crypto_set_tls_dh_prime(void); @@ -128,7 +137,7 @@ crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv); void crypto_cipher_free(crypto_cipher_t *env); /* public key crypto */ -int crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits); +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)) @@ -207,6 +216,8 @@ int crypto_cipher_decrypt_with_iv(const char *key, int crypto_digest(char *digest, const char *m, size_t len); int crypto_digest256(char *digest, const char *m, size_t len, digest_algorithm_t algorithm); +int crypto_digest512(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm); int crypto_digest_all(digests_t *ds_out, const char *m, size_t len); struct smartlist_t; void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, @@ -221,6 +232,7 @@ const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg); 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_add_bytes(crypto_digest_t *digest, const char *data, size_t len); @@ -258,9 +270,9 @@ int crypto_expand_key_material_rfc5869_sha256( uint8_t *key_out, size_t key_out_len); /* random numbers */ -int crypto_seed_rng(void); -MOCK_DECL(int,crypto_rand,(char *to, size_t n)); -int crypto_rand_unmocked(char *to, size_t n); +int crypto_seed_rng(void) ATTR_WUR; +MOCK_DECL(void,crypto_rand,(char *to, size_t n)); +void crypto_rand_unmocked(char *to, size_t n); int crypto_strongest_rand(uint8_t *out, size_t out_len); int crypto_rand_int(unsigned int max); int crypto_rand_int_range(unsigned int min, unsigned int max); @@ -289,8 +301,8 @@ 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); -struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env, - int private); +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); diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c index ac0b08a552..00302a2ff0 100644 --- a/src/common/crypto_curve25519.c +++ b/src/common/crypto_curve25519.c @@ -113,8 +113,7 @@ curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong) { uint8_t k_tmp[CURVE25519_SECKEY_LEN]; - if (crypto_rand((char*)out, CURVE25519_SECKEY_LEN) < 0) - return -1; + crypto_rand((char*)out, CURVE25519_SECKEY_LEN); if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) { /* If they asked for extra-strong entropy and we have some, use it as an * HMAC key to improve not-so-good entropy rather than using it directly, diff --git a/src/common/include.am b/src/common/include.am index 7de93ba2ac..2fc92e2ceb 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -118,6 +118,7 @@ COMMONHEADERS = \ src/common/ciphers.inc \ src/common/compat.h \ src/common/compat_libevent.h \ + src/common/compat_openssl.h \ src/common/compat_threads.h \ src/common/container.h \ src/common/crypto.h \ diff --git a/src/common/log.c b/src/common/log.c index e23691b6ab..7ede6100a2 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -1097,14 +1097,25 @@ add_file_log(const log_severity_list_t *severity, const char *filename, #ifdef HAVE_SYSLOG_H /** * Add a log handler to send messages to they system log facility. + * + * If this is the first log handler, opens syslog with ident Tor or + * Tor-<syslog_identity_tag> if that is not NULL. */ int -add_syslog_log(const log_severity_list_t *severity) +add_syslog_log(const log_severity_list_t *severity, + const char* syslog_identity_tag) { logfile_t *lf; - if (syslog_count++ == 0) + if (syslog_count++ == 0) { /* This is the first syslog. */ - openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY); + static char buf[256]; + if (syslog_identity_tag) { + tor_snprintf(buf, sizeof(buf), "Tor-%s", syslog_identity_tag); + } else { + tor_snprintf(buf, sizeof(buf), "Tor"); + } + openlog(buf, LOG_PID | LOG_NDELAY, LOGFACILITY); + } lf = tor_malloc_zero(sizeof(logfile_t)); lf->fd = -1; diff --git a/src/common/procmon.c b/src/common/procmon.c index 2d0f021724..346a0c6943 100644 --- a/src/common/procmon.c +++ b/src/common/procmon.c @@ -192,7 +192,8 @@ tor_process_monitor_new(struct event_base *base, tor_procmon_callback_t cb, void *cb_arg, const char **msg) { - tor_process_monitor_t *procmon = tor_malloc(sizeof(tor_process_monitor_t)); + tor_process_monitor_t *procmon = tor_malloc_zero( + sizeof(tor_process_monitor_t)); struct parsed_process_specifier_t ppspec; tor_assert(msg != NULL); diff --git a/src/common/torlog.h b/src/common/torlog.h index 67edf14c04..3e8667895f 100644 --- a/src/common/torlog.h +++ b/src/common/torlog.h @@ -135,7 +135,8 @@ void add_stream_log(const log_severity_list_t *severity, const char *name, int add_file_log(const log_severity_list_t *severity, const char *filename, const int truncate); #ifdef HAVE_SYSLOG_H -int add_syslog_log(const log_severity_list_t *severity); +int add_syslog_log(const log_severity_list_t *severity, + const char* syslog_identity_tag); #endif int add_callback_log(const log_severity_list_t *severity, log_callback cb); void logs_set_domain_logging(int enabled); @@ -183,25 +184,25 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity, /** Log a message at level <b>severity</b>, using a pretty-printed version * of the current function name. */ #define log_fn(severity, domain, args...) \ - log_fn_(severity, domain, __PRETTY_FUNCTION__, args) + log_fn_(severity, domain, __FUNCTION__, args) /** As log_fn, but use <b>ratelim</b> (an instance of ratelim_t) to control * the frequency at which messages can appear. */ #define log_fn_ratelim(ratelim, severity, domain, args...) \ - log_fn_ratelim_(ratelim, severity, domain, __PRETTY_FUNCTION__, args) + log_fn_ratelim_(ratelim, severity, domain, __FUNCTION__, args) #define log_debug(domain, args...) \ STMT_BEGIN \ if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \ - log_fn_(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \ + log_fn_(LOG_DEBUG, domain, __FUNCTION__, args); \ STMT_END #define log_info(domain, args...) \ - log_fn_(LOG_INFO, domain, __PRETTY_FUNCTION__, args) + log_fn_(LOG_INFO, domain, __FUNCTION__, args) #define log_notice(domain, args...) \ - log_fn_(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args) + log_fn_(LOG_NOTICE, domain, __FUNCTION__, args) #define log_warn(domain, args...) \ - log_fn_(LOG_WARN, domain, __PRETTY_FUNCTION__, args) + log_fn_(LOG_WARN, domain, __FUNCTION__, args) #define log_err(domain, args...) \ - log_fn_(LOG_ERR, domain, __PRETTY_FUNCTION__, args) + log_fn_(LOG_ERR, domain, __FUNCTION__, args) #else /* ! defined(__GNUC__) */ diff --git a/src/common/tortls.c b/src/common/tortls.c index 536043e558..79c6998806 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -16,6 +16,8 @@ #include "orconfig.h" +#define TORTLS_PRIVATE + #include <assert.h> #ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ #include <winsock2.h> @@ -38,9 +40,6 @@ #include <openssl/opensslv.h> #include "crypto.h" -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) -#error "We require OpenSSL >= 1.0.0" -#endif #ifdef OPENSSL_NO_EC #error "We require OpenSSL with ECC support" #endif @@ -69,6 +68,7 @@ #include "compat_libevent.h" #endif +#define TORTLS_PRIVATE #include "tortls.h" #include "util.h" #include "torlog.h" @@ -80,11 +80,6 @@ #define X509_get_notAfter_const(cert) \ ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert)) -/* Enable the "v2" TLS handshake. - */ -#define V2_HANDSHAKE_SERVER -#define V2_HANDSHAKE_CLIENT - /* Copied from or.h */ #define LEGAL_NICKNAME_CHARACTERS \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" @@ -113,29 +108,6 @@ #define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010 #endif -/** Structure that we use for a single certificate. */ -struct tor_x509_cert_t { - X509 *cert; - uint8_t *encoded; - size_t encoded_len; - unsigned pkey_digests_set : 1; - digests_t cert_digests; - digests_t pkey_digests; -}; - -/** Holds a SSL_CTX object and related state used to configure TLS - * connections. - */ -typedef struct tor_tls_context_t { - int refcnt; - SSL_CTX *ctx; - tor_x509_cert_t *my_link_cert; - tor_x509_cert_t *my_id_cert; - tor_x509_cert_t *my_auth_cert; - crypto_pk_t *link_key; - crypto_pk_t *auth_key; -} tor_tls_context_t; - /** Return values for tor_tls_classify_client_ciphers. * * @{ @@ -154,60 +126,12 @@ typedef struct tor_tls_context_t { #define CIPHERS_UNRESTRICTED 3 /** @} */ -#define TOR_TLS_MAGIC 0x71571571 - -typedef enum { - TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE, - TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE, - TOR_TLS_ST_BUFFEREVENT -} tor_tls_state_t; -#define tor_tls_state_bitfield_t ENUM_BF(tor_tls_state_t) - -/** Holds a SSL object and its associated data. Members are only - * accessed from within tortls.c. - */ -struct tor_tls_t { - uint32_t magic; - tor_tls_context_t *context; /** A link to the context object for this tls. */ - SSL *ssl; /**< An OpenSSL SSL object. */ - int socket; /**< The underlying file descriptor for this TLS connection. */ - char *address; /**< An address to log when describing this connection. */ - tor_tls_state_bitfield_t state : 3; /**< The current SSL state, - * depending on which operations - * have completed successfully. */ - unsigned int isServer:1; /**< True iff this is a server-side connection */ - unsigned int wasV2Handshake:1; /**< True iff the original handshake for - * this connection used the updated version - * of the connection protocol (client sends - * different cipher list, server sends only - * one certificate). */ - /** True iff we should call negotiated_callback when we're done reading. */ - unsigned int got_renegotiate:1; - /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't - * called that function yet. */ - int8_t client_cipher_list_type; - /** Incremented every time we start the server side of a handshake. */ - uint8_t server_handshake_count; - size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last - * time. */ - /** Last values retrieved from BIO_number_read()/write(); see - * tor_tls_get_n_raw_bytes() for usage. - */ - unsigned long last_write_count; - unsigned long last_read_count; - /** If set, a callback to invoke whenever the client tries to renegotiate - * the handshake. */ - void (*negotiated_callback)(tor_tls_t *tls, void *arg); - /** Argument to pass to negotiated_callback. */ - void *callback_arg; -}; - /** The ex_data index in which we store a pointer to an SSL object's * corresponding tor_tls_t object. */ -static int tor_tls_object_ex_data_index = -1; +STATIC int tor_tls_object_ex_data_index = -1; /** Helper: Allocate tor_tls_object_ex_data_index. */ -static void +STATIC void tor_tls_allocate_tor_tls_object_ex_data_index(void) { if (tor_tls_object_ex_data_index == -1) { @@ -219,7 +143,7 @@ tor_tls_allocate_tor_tls_object_ex_data_index(void) /** Helper: given a SSL* pointer, return the tor_tls_t object using that * pointer. */ -static INLINE tor_tls_t * +STATIC INLINE tor_tls_t * tor_tls_get_by_ssl(const SSL *ssl) { tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index); @@ -230,21 +154,7 @@ tor_tls_get_by_ssl(const SSL *ssl) static void tor_tls_context_decref(tor_tls_context_t *ctx); static void tor_tls_context_incref(tor_tls_context_t *ctx); -static X509* tor_tls_create_certificate(crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime); - -static int tor_tls_context_init_one(tor_tls_context_t **ppcontext, - crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client); -static tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client); + static int check_cert_lifetime_internal(int severity, const X509 *cert, int past_tolerance, int future_tolerance); @@ -252,8 +162,8 @@ static int check_cert_lifetime_internal(int severity, const X509 *cert, * to touch them. * * @{ */ -static tor_tls_context_t *server_tls_context = NULL; -static tor_tls_context_t *client_tls_context = NULL; +STATIC tor_tls_context_t *server_tls_context = NULL; +STATIC tor_tls_context_t *client_tls_context = NULL; /**@}*/ /** True iff tor_tls_init() has been called. */ @@ -347,7 +257,7 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, /** Log all pending tls errors at level <b>severity</b> in log domain * <b>domain</b>. Use <b>doing</b> to describe our current activities. */ -static void +STATIC void tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) { unsigned long err; @@ -359,7 +269,7 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) /** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error * code. */ -static int +STATIC int tor_errno_to_tls_error(int e) { switch (e) { @@ -410,7 +320,7 @@ tor_tls_err_to_string(int err) * If an error has occurred, log it at level <b>severity</b> and describe the * current action as <b>doing</b>. */ -static int +STATIC int tor_tls_get_error(tor_tls_t *tls, int r, int extra, const char *doing, int severity, int domain) { @@ -466,8 +376,9 @@ tor_tls_init(void) #if (SIZEOF_VOID_P >= 8 && \ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) - long version = SSLeay(); + long version = OpenSSL_version_num(); + /* LCOV_EXCL_START : we can't test these lines on the same machine */ if (version >= OPENSSL_V_SERIES(1,0,1)) { /* Warn if we could *almost* be running with much faster ECDH. If we're built for a 64-bit target, using OpenSSL 1.0.1, but we @@ -494,6 +405,7 @@ tor_tls_init(void) "support (using the enable-ec_nistp_64_gcc_128 option " "when configuring it) would make ECDH much faster."); } + /* LCOV_EXCL_STOP */ #endif tor_tls_allocate_tor_tls_object_ex_data_index(); @@ -524,7 +436,7 @@ tor_tls_free_all(void) * it: We always accept peer certs and complete the handshake. We * don't validate them until later. */ -static int +STATIC int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) { @@ -539,16 +451,20 @@ tor_x509_name_new(const char *cname) { int nid; X509_NAME *name; + /* LCOV_EXCL_BR_START : these branches will only fail on OOM errors */ if (!(name = X509_NAME_new())) return NULL; if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error; if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char*)cname, -1, -1, 0))) goto error; + /* LCOV_EXCL_BR_STOP */ return name; error: + /* LCOV_EXCL_START : these lines will only execute on out of memory errors*/ X509_NAME_free(name); return NULL; + /* LCOV_EXCL_STOP */ } /** Generate and sign an X509 certificate with the public key <b>rsa</b>, @@ -559,12 +475,12 @@ tor_x509_name_new(const char *cname) * * Return a certificate on success, NULL on failure. */ -static X509 * -tor_tls_create_certificate(crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime) +MOCK_IMPL(STATIC X509 *, + tor_tls_create_certificate,(crypto_pk_t *rsa, + crypto_pk_t *rsa_sign, + const char *cname, + const char *cname_sign, + unsigned int cert_lifetime)) { /* OpenSSL generates self-signed certificates with random 64-bit serial * numbers, so let's do that too. */ @@ -601,8 +517,7 @@ tor_tls_create_certificate(crypto_pk_t *rsa, goto error; { /* our serial number is 8 random bytes. */ - if (crypto_rand((char *)serial_tmp, sizeof(serial_tmp)) < 0) - goto error; + crypto_rand((char *)serial_tmp, sizeof(serial_tmp)); if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL))) goto error; if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509)))) @@ -731,7 +646,9 @@ tor_x509_cert_free(tor_x509_cert_t *cert) X509_free(cert->cert); tor_free(cert->encoded); memwipe(cert, 0x03, sizeof(*cert)); + /* LCOV_EXCL_BR_START since cert will never be NULL here */ tor_free(cert); + /* LCOV_EXCL_BR_STOP */ } /** @@ -739,8 +656,8 @@ tor_x509_cert_free(tor_x509_cert_t *cert) * * Steals a reference to x509_cert. */ -static tor_x509_cert_t * -tor_x509_cert_new(X509 *x509_cert) +MOCK_IMPL(STATIC tor_x509_cert_t *, + tor_x509_cert_new,(X509 *x509_cert)) { tor_x509_cert_t *cert; EVP_PKEY *pkey; @@ -754,10 +671,12 @@ tor_x509_cert_new(X509 *x509_cert) length = i2d_X509(x509_cert, &buf); cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); if (length <= 0 || buf == NULL) { + /* LCOV_EXCL_START for the same reason as the exclusion above */ tor_free(cert); log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate"); X509_free(x509_cert); return NULL; + /* LCOV_EXCL_STOP */ } cert->encoded_len = (size_t) length; cert->encoded = tor_malloc(length); @@ -864,7 +783,9 @@ tor_tls_context_decref(tor_tls_context_t *ctx) tor_x509_cert_free(ctx->my_auth_cert); crypto_pk_free(ctx->link_key); crypto_pk_free(ctx->auth_key); + /* LCOV_EXCL_BR_START since ctx will never be NULL here */ tor_free(ctx); + /* LCOV_EXCL_BR_STOP */ } } @@ -960,11 +881,13 @@ tor_tls_cert_is_valid(int severity, int check_rsa_1024) { check_no_tls_errors(); - EVP_PKEY *cert_key; - EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert); int r, key_ok = 0; + if (!signing_cert) + goto bad; + + EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert); if (!signing_key) goto bad; r = X509_verify(cert->cert, signing_key); @@ -1085,7 +1008,7 @@ tor_tls_context_init(unsigned flags, * it generates new certificates; all new connections will use * the new SSL context. */ -static int +STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext, crypto_pk_t *identity, unsigned int key_lifetime, @@ -1119,7 +1042,7 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext, * <b>identity</b> should be set to the identity key used to sign the * certificate. */ -static tor_tls_context_t * +STATIC tor_tls_context_t * tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, unsigned flags, int is_client) { @@ -1200,23 +1123,6 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, * historically been chosen for fingerprinting resistance. */ SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - /* Disable TLS1.1 and TLS1.2 if they exist. We need to do this to - * workaround a bug present in all OpenSSL 1.0.1 versions (as of 1 - * June 2012), wherein renegotiating while using one of these TLS - * protocols will cause the client to send a TLS 1.0 ServerHello - * rather than a ServerHello written with the appropriate protocol - * version. Once some version of OpenSSL does TLS1.1 and TLS1.2 - * renegotiation properly, we can turn them back on when built with - * that version. */ -#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,1,'e') -#ifdef SSL_OP_NO_TLSv1_2 - SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_2); -#endif -#ifdef SSL_OP_NO_TLSv1_1 - SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_1); -#endif -#endif - /* Disable TLS tickets if they're supported. We never want to use them; * using them can make our perfect forward secrecy a little worse, *and* * create an opportunity to fingerprint us (since it's unusual to use them @@ -1343,11 +1249,13 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, } /** Invoked when a TLS state changes: log the change at severity 'debug' */ -static void +STATIC void tor_tls_debug_state_callback(const SSL *ssl, int type, int val) { + /* LCOV_EXCL_START since this depends on whether debug is captured or not */ log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].", ssl, SSL_state_string_long(ssl), type, val); + /* LCOV_EXCL_STOP */ } /* Return the name of the negotiated ciphersuite in use on <b>tls</b> */ @@ -1357,13 +1265,11 @@ tor_tls_get_ciphersuite_name(tor_tls_t *tls) return SSL_get_cipher(tls->ssl); } -#ifdef V2_HANDSHAKE_SERVER - /* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers * that it claims to support. We'll prune this list to remove the ciphers * *we* don't recognize. */ -static uint16_t v2_cipher_list[] = { +STATIC uint16_t v2_cipher_list[] = { 0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */ 0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */ 0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */ @@ -1399,7 +1305,7 @@ static int v2_cipher_list_pruned = 0; /** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>; * return 1 if it does support it, or if we have no way to tell. */ -static int +STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) { const SSL_CIPHER *c; @@ -1481,7 +1387,7 @@ prune_v2_cipher_list(const SSL *ssl) * client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2, * CIPHERS_UNRESTRICTED. **/ -static int +STATIC int tor_tls_classify_client_ciphers(const SSL *ssl, STACK_OF(SSL_CIPHER) *peer_ciphers) { @@ -1563,7 +1469,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl, /** Return true iff the cipher list suggested by the client for <b>ssl</b> is * a list that indicates that the client knows how to do the v2 TLS connection * handshake. */ -static int +STATIC int tor_tls_client_is_using_v2_ciphers(const SSL *ssl) { STACK_OF(SSL_CIPHER) *ciphers; @@ -1587,11 +1493,10 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl) * do not send or request extra certificates in v2 handshakes.</li> * <li>To detect renegotiation</li></ul> */ -static void +STATIC void tor_tls_server_info_callback(const SSL *ssl, int type, int val) { tor_tls_t *tls; - int ssl_state; (void) val; tor_tls_debug_state_callback(ssl, type, val); @@ -1599,11 +1504,9 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) if (type != SSL_CB_ACCEPT_LOOP) return; - ssl_state = SSL_state(ssl); - if ((ssl_state != SSL3_ST_SW_SRVR_HELLO_A) && - (ssl_state != SSL3_ST_SW_SRVR_HELLO_B)) + OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl); + if (! STATE_IS_SW_SERVER_HELLO(ssl_state)) return; - tls = tor_tls_get_by_ssl(ssl); if (tls) { /* Check whether we're watching for renegotiates. If so, this is one! */ @@ -1633,11 +1536,12 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) if (tls) { tls->wasV2Handshake = 1; } else { + /* LCOV_EXCL_START this line is not reachable */ log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); + /* LCOV_EXCL_STOP */ } } } -#endif /** Callback to get invoked on a server after we've read the list of ciphers * the client supports, but before we pick our own ciphersuite. @@ -1651,7 +1555,7 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) * authentication on the fly. But as long as we return 0, we won't actually be * setting up a shared secret, and all will be fine. */ -static int +STATIC int tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg) @@ -1747,12 +1651,9 @@ tor_tls_new(int sock, int isServer) log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu", result->last_read_count, result->last_write_count); } -#ifdef V2_HANDSHAKE_SERVER if (isServer) { SSL_set_info_callback(result->ssl, tor_tls_server_info_callback); - } else -#endif - { + } else { SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); } @@ -1791,13 +1692,11 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls, tls->negotiated_callback = cb; tls->callback_arg = arg; tls->got_renegotiate = 0; -#ifdef V2_HANDSHAKE_SERVER if (cb) { SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback); } else { SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback); } -#endif } /** If this version of openssl requires it, turn on renegotiation on @@ -1884,7 +1783,6 @@ tor_tls_read,(tor_tls_t *tls, char *cp, size_t len)) tor_assert(len<INT_MAX); r = SSL_read(tls->ssl, cp, (int)len); if (r > 0) { -#ifdef V2_HANDSHAKE_SERVER if (tls->got_renegotiate) { /* Renegotiation happened! */ log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls)); @@ -1892,7 +1790,6 @@ tor_tls_read,(tor_tls_t *tls, char *cp, size_t len)) tls->negotiated_callback(tls, tls->callback_arg); tls->got_renegotiate = 0; } -#endif return r; } err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); @@ -1909,10 +1806,10 @@ tor_tls_read,(tor_tls_t *tls, char *cp, size_t len)) /** Total number of bytes that we've used TLS to send. Used to track TLS * overhead. */ -static uint64_t total_bytes_written_over_tls = 0; +STATIC uint64_t total_bytes_written_over_tls = 0; /** Total number of bytes that TLS has put on the network for us. Used to * track TLS overhead. */ -static uint64_t total_bytes_written_by_tls = 0; +STATIC uint64_t total_bytes_written_by_tls = 0; /** Underlying function for TLS writing. Write up to <b>n</b> * characters from <b>cp</b> onto <b>tls</b>. On success, returns the @@ -1957,12 +1854,14 @@ int tor_tls_handshake(tor_tls_t *tls) { int r; - int oldstate; tor_assert(tls); tor_assert(tls->ssl); tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE); + check_no_tls_errors(); - oldstate = SSL_state(tls->ssl); + + OSSL_HANDSHAKE_STATE oldstate = SSL_get_state(tls->ssl); + if (tls->isServer) { log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls, SSL_state_string_long(tls->ssl)); @@ -1972,7 +1871,10 @@ tor_tls_handshake(tor_tls_t *tls) SSL_state_string_long(tls->ssl)); r = SSL_connect(tls->ssl); } - if (oldstate != SSL_state(tls->ssl)) + + OSSL_HANDSHAKE_STATE newstate = SSL_get_state(tls->ssl); + + if (oldstate != newstate) log_debug(LD_HANDSHAKE, "After call, %p was in state %s", tls, SSL_state_string_long(tls->ssl)); /* We need to call this here and not earlier, since OpenSSL has a penchant @@ -2008,7 +1910,6 @@ tor_tls_finish_handshake(tor_tls_t *tls) SSL_set_info_callback(tls->ssl, NULL); SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb); SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN); -#ifdef V2_HANDSHAKE_SERVER if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) { /* This check is redundant, but back when we did it in the callback, * we might have not been able to look up the tor_tls_t if the code @@ -2023,26 +1924,10 @@ tor_tls_finish_handshake(tor_tls_t *tls) } else { tls->wasV2Handshake = 0; } -#endif } else { -#ifdef V2_HANDSHAKE_CLIENT - /* If we got no ID cert, we're a v2 handshake. */ - X509 *cert = SSL_get_peer_certificate(tls->ssl); - STACK_OF(X509) *chain = SSL_get_peer_cert_chain(tls->ssl); - int n_certs = sk_X509_num(chain); - if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0))) { - log_debug(LD_HANDSHAKE, "Server sent back multiple certificates; it " - "looks like a v1 handshake on %p", tls); - tls->wasV2Handshake = 0; - } else { - log_debug(LD_HANDSHAKE, - "Server sent back a single certificate; looks like " - "a v2 handshake on %p.", tls); - tls->wasV2Handshake = 1; - } - if (cert) - X509_free(cert); -#endif + /* Client-side */ + tls->wasV2Handshake = 1; + /* XXXX this can move, probably? -NM */ if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) { tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers"); r = TOR_TLS_ERROR_MISC; @@ -2052,52 +1937,6 @@ tor_tls_finish_handshake(tor_tls_t *tls) return r; } -#ifdef USE_BUFFEREVENTS -/** Put <b>tls</b>, which must be a client connection, into renegotiation - * mode. */ -int -tor_tls_start_renegotiating(tor_tls_t *tls) -{ - int r = SSL_renegotiate(tls->ssl); - if (r <= 0) { - return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN, - LD_HANDSHAKE); - } - return 0; -} -#endif - -/** Client only: Renegotiate a TLS session. When finished, returns - * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, or - * TOR_TLS_WANTWRITE. - */ -int -tor_tls_renegotiate(tor_tls_t *tls) -{ - int r; - tor_assert(tls); - /* We could do server-initiated renegotiation too, but that would be tricky. - * Instead of "SSL_renegotiate, then SSL_do_handshake until done" */ - tor_assert(!tls->isServer); - - check_no_tls_errors(); - if (tls->state != TOR_TLS_ST_RENEGOTIATE) { - int r = SSL_renegotiate(tls->ssl); - if (r <= 0) { - return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN, - LD_HANDSHAKE); - } - tls->state = TOR_TLS_ST_RENEGOTIATE; - } - r = SSL_do_handshake(tls->ssl); - if (r == 1) { - tls->state = TOR_TLS_ST_OPEN; - return TOR_TLS_DONE; - } else - return tor_tls_get_error(tls, r, 0, "renegotiating handshake", LOG_INFO, - LD_HANDSHAKE); -} - /** Shut down an open tls connection <b>tls</b>. When finished, returns * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, * or TOR_TLS_WANTWRITE. @@ -2251,15 +2090,14 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem) * * Note that a reference is added to cert_out, so it needs to be * freed. id_cert_out doesn't. */ -static void -try_to_extract_certs_from_tls(int severity, tor_tls_t *tls, - X509 **cert_out, X509 **id_cert_out) +MOCK_IMPL(STATIC void, +try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, + X509 **cert_out, X509 **id_cert_out)) { X509 *cert = NULL, *id_cert = NULL; STACK_OF(X509) *chain = NULL; int num_in_chain, i; *cert_out = *id_cert_out = NULL; - if (!(cert = SSL_get_peer_certificate(tls->ssl))) return; *cert_out = cert; @@ -2476,114 +2314,7 @@ check_no_tls_errors_(const char *fname, int line) int tor_tls_used_v1_handshake(tor_tls_t *tls) { -#if defined(V2_HANDSHAKE_SERVER) && defined(V2_HANDSHAKE_CLIENT) return ! tls->wasV2Handshake; -#else - if (tls->isServer) { -# ifdef V2_HANDSHAKE_SERVER - return ! tls->wasV2Handshake; -# endif - } else { -# ifdef V2_HANDSHAKE_CLIENT - return ! tls->wasV2Handshake; -# endif - } - return 1; -#endif -} - -/** Return true iff <b>name</b> is a DN of a kind that could only - * occur in a v3-handshake-indicating certificate */ -static int -dn_indicates_v3_cert(X509_NAME *name) -{ -#ifdef DISABLE_V3_LINKPROTO_CLIENTSIDE - (void)name; - return 0; -#else - X509_NAME_ENTRY *entry; - int n_entries; - ASN1_OBJECT *obj; - ASN1_STRING *str; - unsigned char *s; - int len, r; - - n_entries = X509_NAME_entry_count(name); - if (n_entries != 1) - return 1; /* More than one entry in the DN. */ - entry = X509_NAME_get_entry(name, 0); - - obj = X509_NAME_ENTRY_get_object(entry); - if (OBJ_obj2nid(obj) != OBJ_txt2nid("commonName")) - return 1; /* The entry isn't a commonName. */ - - str = X509_NAME_ENTRY_get_data(entry); - len = ASN1_STRING_to_UTF8(&s, str); - if (len < 0) - return 0; - if (len < 4) { - OPENSSL_free(s); - return 1; - } - r = fast_memneq(s + len - 4, ".net", 4); - OPENSSL_free(s); - return r; -#endif -} - -/** Return true iff the peer certificate we're received on <b>tls</b> - * indicates that this connection should use the v3 (in-protocol) - * authentication handshake. - * - * Only the connection initiator should use this, and only once the initial - * handshake is done; the responder detects a v1 handshake by cipher types, - * and a v3/v2 handshake by Versions cell vs renegotiation. - */ -int -tor_tls_received_v3_certificate(tor_tls_t *tls) -{ - check_no_tls_errors(); - - X509 *cert = SSL_get_peer_certificate(tls->ssl); - EVP_PKEY *key = NULL; - X509_NAME *issuer_name, *subject_name; - int is_v3 = 0; - - if (!cert) { - log_warn(LD_BUG, "Called on a connection with no peer certificate"); - goto done; - } - - subject_name = X509_get_subject_name(cert); - issuer_name = X509_get_issuer_name(cert); - - if (X509_name_cmp(subject_name, issuer_name) == 0) { - is_v3 = 1; /* purportedly self signed */ - goto done; - } - - if (dn_indicates_v3_cert(subject_name) || - dn_indicates_v3_cert(issuer_name)) { - is_v3 = 1; /* DN is fancy */ - goto done; - } - - key = X509_get_pubkey(cert); - if (EVP_PKEY_bits(key) != 1024 || - EVP_PKEY_type(key->type) != EVP_PKEY_RSA) { - is_v3 = 1; /* Key is fancy */ - goto done; - } - - done: - tls_log_errors(tls, LOG_WARN, LD_NET, "checking for a v3 cert"); - - if (key) - EVP_PKEY_free(key); - if (cert) - X509_free(cert); - - return is_v3; } /** Return the number of server handshakes that we've noticed doing on @@ -2629,7 +2360,7 @@ SSL_get_server_random(SSL *s, uint8_t *out, size_t len) #endif #ifndef HAVE_SSL_SESSION_GET_MASTER_KEY -static size_t +STATIC size_t SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len) { tor_assert(s); @@ -2652,7 +2383,6 @@ tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) #define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification" uint8_t buf[128]; size_t len; - tor_assert(tls); SSL *const ssl = tls->ssl; @@ -2676,12 +2406,14 @@ tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) size_t r = SSL_get_client_random(ssl, buf, client_random_len); tor_assert(r == client_random_len); } + { size_t r = SSL_get_server_random(ssl, buf+client_random_len, server_random_len); tor_assert(r == server_random_len); } + uint8_t *master_key = tor_malloc_zero(master_key_len); { size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len); diff --git a/src/common/tortls.h b/src/common/tortls.h index 124b77160f..6a4ef9aebe 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -12,6 +12,7 @@ **/ #include "crypto.h" +#include "compat_openssl.h" #include "compat.h" #include "testsupport.h" @@ -51,6 +52,119 @@ typedef struct tor_x509_cert_t tor_x509_cert_t; case TOR_TLS_ERROR_IO #define TOR_TLS_IS_ERROR(rv) ((rv) < TOR_TLS_CLOSE) + +#ifdef TORTLS_PRIVATE +#define TOR_TLS_MAGIC 0x71571571 + +typedef enum { + TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE, + TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE, + TOR_TLS_ST_BUFFEREVENT +} tor_tls_state_t; +#define tor_tls_state_bitfield_t ENUM_BF(tor_tls_state_t) + +/** Holds a SSL_CTX object and related state used to configure TLS + * connections. + */ +typedef struct tor_tls_context_t { + int refcnt; + SSL_CTX *ctx; + tor_x509_cert_t *my_link_cert; + tor_x509_cert_t *my_id_cert; + tor_x509_cert_t *my_auth_cert; + crypto_pk_t *link_key; + crypto_pk_t *auth_key; +} tor_tls_context_t; + +/** Structure that we use for a single certificate. */ +struct tor_x509_cert_t { + X509 *cert; + uint8_t *encoded; + size_t encoded_len; + unsigned pkey_digests_set : 1; + digests_t cert_digests; + digests_t pkey_digests; +}; + +/** Holds a SSL object and its associated data. Members are only + * accessed from within tortls.c. + */ +struct tor_tls_t { + uint32_t magic; + tor_tls_context_t *context; /** A link to the context object for this tls. */ + SSL *ssl; /**< An OpenSSL SSL object. */ + int socket; /**< The underlying file descriptor for this TLS connection. */ + char *address; /**< An address to log when describing this connection. */ + tor_tls_state_bitfield_t state : 3; /**< The current SSL state, + * depending on which operations + * have completed successfully. */ + unsigned int isServer:1; /**< True iff this is a server-side connection */ + unsigned int wasV2Handshake:1; /**< True iff the original handshake for + * this connection used the updated version + * of the connection protocol (client sends + * different cipher list, server sends only + * one certificate). */ + /** True iff we should call negotiated_callback when we're done reading. */ + unsigned int got_renegotiate:1; + /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't + * called that function yet. */ + int8_t client_cipher_list_type; + /** Incremented every time we start the server side of a handshake. */ + uint8_t server_handshake_count; + size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last + * time. */ + /** Last values retrieved from BIO_number_read()/write(); see + * tor_tls_get_n_raw_bytes() for usage. + */ + unsigned long last_write_count; + unsigned long last_read_count; + /** If set, a callback to invoke whenever the client tries to renegotiate + * the handshake. */ + void (*negotiated_callback)(tor_tls_t *tls, void *arg); + /** Argument to pass to negotiated_callback. */ + void *callback_arg; +}; + +STATIC int tor_errno_to_tls_error(int e); +STATIC int tor_tls_get_error(tor_tls_t *tls, int r, int extra, + const char *doing, int severity, int domain); +STATIC tor_tls_t *tor_tls_get_by_ssl(const SSL *ssl); +STATIC void tor_tls_allocate_tor_tls_object_ex_data_index(void); +STATIC int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx); +STATIC int tor_tls_classify_client_ciphers(const SSL *ssl, + STACK_OF(SSL_CIPHER) *peer_ciphers); +STATIC int tor_tls_client_is_using_v2_ciphers(const SSL *ssl); +MOCK_DECL(STATIC void, try_to_extract_certs_from_tls, + (int severity, tor_tls_t *tls, X509 **cert_out, X509 **id_cert_out)); +#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY +STATIC size_t SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, + size_t len); +#endif +STATIC void tor_tls_debug_state_callback(const SSL *ssl, int type, int val); +STATIC void tor_tls_server_info_callback(const SSL *ssl, int type, int val); +STATIC int tor_tls_session_secret_cb(SSL *ssl, void *secret, + int *secret_len, + STACK_OF(SSL_CIPHER) *peer_ciphers, + SSL_CIPHER **cipher, void *arg); +STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, + uint16_t cipher); +MOCK_DECL(STATIC X509*, tor_tls_create_certificate,(crypto_pk_t *rsa, + crypto_pk_t *rsa_sign, + const char *cname, + const char *cname_sign, + unsigned int cert_lifetime)); +STATIC tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity, + unsigned int key_lifetime, unsigned flags, int is_client); +MOCK_DECL(STATIC tor_x509_cert_t *, tor_x509_cert_new,(X509 *x509_cert)); +STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext, + crypto_pk_t *identity, + unsigned int key_lifetime, + unsigned int flags, + int is_client); +STATIC void tls_log_errors(tor_tls_t *tls, int severity, int domain, + const char *doing); +#endif + const char *tor_tls_err_to_string(int err); void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz); @@ -81,7 +195,6 @@ MOCK_DECL(int, tor_tls_read, (tor_tls_t *tls, char *cp, size_t len)); int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n); int tor_tls_handshake(tor_tls_t *tls); int tor_tls_finish_handshake(tor_tls_t *tls); -int tor_tls_renegotiate(tor_tls_t *tls); void tor_tls_unblock_renegotiation(tor_tls_t *tls); void tor_tls_block_renegotiation(tor_tls_t *tls); void tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls); @@ -99,7 +212,6 @@ int tor_tls_get_buffer_sizes(tor_tls_t *tls, MOCK_DECL(double, tls_get_write_overhead_ratio, (void)); int tor_tls_used_v1_handshake(tor_tls_t *tls); -int tor_tls_received_v3_certificate(tor_tls_t *tls); int tor_tls_get_num_server_handshakes(tor_tls_t *tls); int tor_tls_server_got_renegotiate(tor_tls_t *tls); MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)); diff --git a/src/common/util.c b/src/common/util.c index b33c80fd45..ce3646cd64 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -488,42 +488,58 @@ round_to_power_of_2(uint64_t u64) } /** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. */ + * <b>divisor</b> == 0. If no such x can be expressed as an unsigned, return + * UINT_MAX */ unsigned round_to_next_multiple_of(unsigned number, unsigned divisor) { + tor_assert(divisor > 0); + if (UINT_MAX - divisor + 1 < number) + return UINT_MAX; number += divisor - 1; number -= number % divisor; return number; } /** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. */ + * <b>divisor</b> == 0. If no such x can be expressed as a uint32_t, return + * UINT32_MAX */ uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor) { + tor_assert(divisor > 0); + if (UINT32_MAX - divisor + 1 < number) + return UINT32_MAX; + number += divisor - 1; number -= number % divisor; return number; } /** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. */ + * <b>divisor</b> == 0. If no such x can be expressed as a uint64_t, return + * UINT64_MAX */ uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) { + tor_assert(divisor > 0); + if (UINT64_MAX - divisor + 1 < number) + return UINT64_MAX; number += divisor - 1; number -= number % divisor; return number; } /** Return the lowest x in [INT64_MIN, INT64_MAX] such that x is at least - * <b>number</b>, and x modulo <b>divisor</b> == 0. */ + * <b>number</b>, and x modulo <b>divisor</b> == 0. If no such x can be + * expressed as an int64_t, return INT64_MAX */ int64_t round_int64_to_next_multiple_of(int64_t number, int64_t divisor) { tor_assert(divisor > 0); - if (number >= 0 && INT64_MAX - divisor + 1 >= number) + if (INT64_MAX - divisor + 1 < number) + return INT64_MAX; + if (number >= 0) number += divisor - 1; number -= number % divisor; return number; @@ -537,33 +553,44 @@ int64_t sample_laplace_distribution(double mu, double b, double p) { double result; - tor_assert(p >= 0.0 && p < 1.0); + /* This is the "inverse cumulative distribution function" from: * http://en.wikipedia.org/wiki/Laplace_distribution */ - result = mu - b * (p > 0.5 ? 1.0 : -1.0) - * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); - - if (result >= INT64_MAX) - return INT64_MAX; - else if (result <= INT64_MIN) + if (p <= 0.0) { + /* Avoid taking log(0.0) == -INFINITY, as some processors or compiler + * options can cause the program to trap. */ return INT64_MIN; - else - return (int64_t) result; + } + + result = mu - b * (p > 0.5 ? 1.0 : -1.0) + * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); + + return clamp_double_to_int64(result); } -/** Add random noise between INT64_MIN and INT64_MAX coming from a - * Laplace distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b> - * to <b>signal</b> based on the provided <b>random</b> value in - * [0.0, 1.0[. */ +/** Add random noise between INT64_MIN and INT64_MAX coming from a Laplace + * distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b> to + * <b>signal</b> based on the provided <b>random</b> value in [0.0, 1.0[. + * The epsilon value must be between ]0.0, 1.0]. delta_f must be greater + * than 0. */ int64_t add_laplace_noise(int64_t signal, double random, double delta_f, double epsilon) { - int64_t noise = sample_laplace_distribution( - 0.0, /* just add noise, no further signal */ - delta_f / epsilon, random); + int64_t noise; + + /* epsilon MUST be between ]0.0, 1.0] */ + tor_assert(epsilon > 0.0 && epsilon <= 1.0); + /* delta_f MUST be greater than 0. */ + tor_assert(delta_f > 0.0); + /* Just add noise, no further signal */ + noise = sample_laplace_distribution(0.0, + delta_f / epsilon, + random); + + /* Clip (signal + noise) to [INT64_MIN, INT64_MAX] */ if (noise > 0 && INT64_MAX - noise < signal) return INT64_MAX; else if (noise < 0 && INT64_MIN - noise > signal) @@ -5385,3 +5412,38 @@ tor_weak_random_range(tor_weak_rng_t *rng, int32_t top) return result; } +/** Cast a given double value to a int64_t. Return 0 if number is NaN. + * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t + * range. */ +int64_t +clamp_double_to_int64(double number) +{ + int exp; + + /* NaN is a special case that can't be used with the logic below. */ + if (isnan(number)) { + return 0; + } + + /* Time to validate if result can overflows a int64_t value. Fun with + * float! Find that exponent exp such that + * number == x * 2^exp + * for some x with abs(x) in [0.5, 1.0). Note that this implies that the + * magnitude of number is strictly less than 2^exp. + * + * If number is infinite, the call to frexp is legal but the contents of + * exp are unspecified. */ + frexp(number, &exp); + + /* If the magnitude of number is strictly less than 2^63, the truncated + * version of number is guaranteed to be representable. The only + * representable integer for which this is not the case is INT64_MIN, but + * it is covered by the logic below. */ + if (isfinite(number) && exp <= 63) { + return number; + } + + /* Handle infinities and finite numbers with magnitude >= 2^63. */ + return signbit(number) ? INT64_MIN : INT64_MAX; +} + diff --git a/src/common/util.h b/src/common/util.h index 8bb4505e86..165bc0dcb3 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -185,6 +185,7 @@ int64_t sample_laplace_distribution(double mu, double b, double p); int64_t add_laplace_noise(int64_t signal, double random, double delta_f, double epsilon); int n_bits_set_u8(uint8_t v); +int64_t clamp_double_to_int64(double number); /* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> * and positive <b>b</b>. Works on integer types only. Not defined if a+b can |