summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/Makefile.am49
-rw-r--r--src/common/Makefile.nmake20
-rw-r--r--src/common/address.c280
-rw-r--r--src/common/address.h27
-rw-r--r--src/common/aes.c1162
-rw-r--r--src/common/aes.h5
-rw-r--r--src/common/compat.c245
-rw-r--r--src/common/compat.h28
-rw-r--r--src/common/compat_libevent.c137
-rw-r--r--src/common/compat_libevent.h22
-rw-r--r--src/common/container.c1
-rw-r--r--src/common/container.h28
-rw-r--r--src/common/crypto.c550
-rw-r--r--src/common/crypto.h41
-rw-r--r--src/common/log.c31
-rw-r--r--src/common/mempool.c3
-rw-r--r--src/common/torgzip.c4
-rw-r--r--src/common/torint.h9
-rw-r--r--src/common/torlog.h5
-rw-r--r--src/common/tortls.c1045
-rw-r--r--src/common/tortls.h44
-rw-r--r--src/common/tortls_states.h414
-rw-r--r--src/common/util.c1377
-rw-r--r--src/common/util.h153
24 files changed, 3925 insertions, 1755 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 6952591d67..04c411556a 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -1,7 +1,7 @@
noinst_LIBRARIES = libor.a libor-crypto.a libor-event.a
-EXTRA_DIST = common_sha1.i sha256.c
+EXTRA_DIST = common_sha1.i sha256.c Makefile.nmake
#CFLAGS = -Wall -Wpointer-arith -O2
@@ -11,18 +11,53 @@ else
libor_extra_source=
endif
-libor_a_SOURCES = address.c log.c util.c compat.c container.c mempool.c \
- memarea.c di_ops.c procmon.c util_codedigest.c $(libor_extra_source)
-libor_crypto_a_SOURCES = crypto.c aes.c tortls.c torgzip.c
+libor_a_SOURCES = \
+ address.c \
+ compat.c \
+ container.c \
+ di_ops.c \
+ log.c \
+ memarea.c \
+ mempool.c \
+ procmon.c \
+ util.c \
+ util_codedigest.c \
+ $(libor_extra_source)
+
+libor_crypto_a_SOURCES = \
+ aes.c \
+ crypto.c \
+ torgzip.c \
+ tortls.c
+
libor_event_a_SOURCES = compat_libevent.c
-noinst_HEADERS = address.h torlog.h crypto.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h ht.h mempool.h memarea.h ciphers.inc compat_libevent.h tortls_states.h di_ops.h procmon.h
+noinst_HEADERS = \
+ address.h \
+ aes.h \
+ ciphers.inc \
+ compat.h \
+ compat_libevent.h \
+ container.h \
+ crypto.h \
+ di_ops.h \
+ ht.h \
+ memarea.h \
+ mempool.h \
+ procmon.h \
+ strlcat.c \
+ strlcpy.c \
+ torgzip.h \
+ torint.h \
+ torlog.h \
+ tortls.h \
+ util.h
common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
if test "@SHA1SUM@" != none; then \
- @SHA1SUM@ $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS) | @SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
+ (cd "$(srcdir)" && @SHA1SUM@ $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | @SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
elif test "@OPENSSL@" != none; then \
- @OPENSSL@ sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS) | @SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
+ (cd "$(srcdir)" && @OPENSSL@ sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | @SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
else \
rm common_sha1.i; \
touch common_sha1.i; \
diff --git a/src/common/Makefile.nmake b/src/common/Makefile.nmake
new file mode 100644
index 0000000000..c8b5988666
--- /dev/null
+++ b/src/common/Makefile.nmake
@@ -0,0 +1,20 @@
+all: libor.lib libor-crypto.lib libor-event.lib
+
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include
+
+LIBOR_OBJECTS = address.obj compat.obj container.obj di_ops.obj \
+ log.obj memarea.obj mempool.obj procmon.obj util.obj \
+ util_codedigest.obj
+
+LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj torgzip.obj tortls.obj
+
+LIBOR_EVENT_OBJECTS = compat_libevent.obj
+
+libor.lib: $(LIBOR_OBJECTS)
+ lib $(LIBOR_OBJECTS) /out:libor.lib
+
+libor-crypto.lib: $(LIBOR_CRYPTO_OBJECTS)
+ lib $(LIBOR_CRYPTO_OBJECTS) /out:libor-crypto.lib
+
+libor-event.lib: $(LIBOR_EVENT_OBJECTS)
+ lib $(LIBOR_EVENT_OBJECTS) /out:libor-event.lib
diff --git a/src/common/address.c b/src/common/address.c
index 17bdea9238..2e9892c4dc 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -13,10 +13,16 @@
#include "util.h"
#include "address.h"
#include "torlog.h"
+#include "container.h"
#ifdef MS_WINDOWS
#include <process.h>
#include <windows.h>
+#include <winsock2.h>
+/* For access to structs needed by GetAdaptersAddresses */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <iphlpapi.h>
#endif
#ifdef HAVE_SYS_TIME_H
@@ -46,12 +52,28 @@
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+/* tor_addr_is_null() and maybe other functions rely on AF_UNSPEC being 0 to
+ * work correctly. Bail out here if we've found a platform where AF_UNSPEC
+ * isn't 0. */
+#if AF_UNSPEC != 0
+#error We rely on AF_UNSPEC being 0. Let us know about your platform, please!
+#endif
+
/** Convert the tor_addr_t in <b>a</b>, with port in <b>port</b>, into a
* sockaddr object in *<b>sa_out</b> of object size <b>len</b>. If not enough
* room is available in sa_out, or on error, return 0. On success, return
@@ -343,22 +365,28 @@ tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
* brackets.
*/
const char *
-tor_addr_to_str(char *dest, const tor_addr_t *addr, int len, int decorate)
+tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate)
{
const char *ptr;
tor_assert(addr && dest);
switch (tor_addr_family(addr)) {
case AF_INET:
- if (len<3)
+ /* Shortest addr x.x.x.x + \0 */
+ if (len < 8)
return NULL;
- ptr = tor_inet_ntop(AF_INET, &addr->addr.in_addr, dest, len);
+ ptr = tor_inet_ntop(AF_INET, &addr->addr.in_addr, dest, len);
break;
case AF_INET6:
+ /* Shortest addr [ :: ] + \0 */
+ if (len < (3 + (decorate ? 2 : 0)))
+ return NULL;
+
if (decorate)
ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest+1, len-2);
else
ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest, len);
+
if (ptr && decorate) {
*dest = '[';
memcpy(dest+strlen(dest), "]", 2);
@@ -384,7 +412,7 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, int len, int decorate)
* IPv4 or IPv6 address too.
*/
int
-tor_addr_parse_reverse_lookup_name(tor_addr_t *result, const char *address,
+tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
int family, int accept_regular)
{
if (!strcasecmpend(address, ".in-addr.arpa")) {
@@ -455,7 +483,7 @@ tor_addr_parse_reverse_lookup_name(tor_addr_t *result, const char *address,
if (accept_regular) {
tor_addr_t tmp;
- int r = tor_addr_from_str(&tmp, address);
+ int r = tor_addr_parse(&tmp, address);
if (r < 0)
return 0;
if (r != family && family != AF_UNSPEC)
@@ -470,13 +498,17 @@ tor_addr_parse_reverse_lookup_name(tor_addr_t *result, const char *address,
return 0;
}
-/** Convert <b>addr</b> to an in-addr.arpa name or a .ip6.arpa name, and store
- * the result in the <b>outlen</b>-byte buffer at <b>out</b>. Return 0 on
- * success, -1 on failure. */
+/** Convert <b>addr</b> to an in-addr.arpa name or a .ip6.arpa name,
+ * and store the result in the <b>outlen</b>-byte buffer at
+ * <b>out</b>. Return the number of chars written to <b>out</b>, not
+ * including the trailing \0, on success. Returns -1 on failure. */
int
-tor_addr_to_reverse_lookup_name(char *out, size_t outlen,
- const tor_addr_t *addr)
+tor_addr_to_PTR_name(char *out, size_t outlen,
+ const tor_addr_t *addr)
{
+ tor_assert(out);
+ tor_assert(addr);
+
if (addr->family == AF_INET) {
uint32_t a = tor_addr_to_ipv4h(addr);
@@ -499,7 +531,7 @@ tor_addr_to_reverse_lookup_name(char *out, size_t outlen,
*cp++ = '.';
}
memcpy(cp, "ip6.arpa", 9); /* 8 characters plus NUL */
- return 0;
+ return 32 * 2 + 8;
}
return -1;
}
@@ -967,6 +999,19 @@ fmt_addr(const tor_addr_t *addr)
return "???";
}
+/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4
+ * addresses. Also not thread-safe, also clobbers its return buffer on
+ * repeated calls. */
+const char *
+fmt_addr32(uint32_t addr)
+{
+ static char buf[INET_NTOA_BUF_LEN];
+ struct in_addr in;
+ in.s_addr = htonl(addr);
+ tor_inet_ntoa(&in, buf, sizeof(buf));
+ return buf;
+}
+
/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string
* may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by
* square brackets.
@@ -974,7 +1019,7 @@ fmt_addr(const tor_addr_t *addr)
* Return an address family on success, or -1 if an invalid address string is
* provided. */
int
-tor_addr_from_str(tor_addr_t *addr, const char *src)
+tor_addr_parse(tor_addr_t *addr, const char *src)
{
char *tmp = NULL; /* Holds substring if we got a dotted quad. */
int result;
@@ -1002,7 +1047,7 @@ tor_addr_from_str(tor_addr_t *addr, const char *src)
* address as needed, and put the result in <b>addr_out</b> and (optionally)
* <b>port_out</b>. Return 0 on success, negative on failure. */
int
-tor_addr_port_parse(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
+tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
{
const char *port;
tor_addr_t addr;
@@ -1056,6 +1101,169 @@ tor_addr_port_parse(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
return -1;
}
+#ifdef MS_WINDOWS
+typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
+ ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
+#endif
+
+/** 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>. */
+static smartlist_t *
+get_interface_addresses_raw(int severity)
+{
+#if defined(HAVE_GETIFADDRS)
+ /* Most free Unixy systems provide getifaddrs, which gives us a linked list
+ * of struct ifaddrs. */
+ struct ifaddrs *ifa = NULL;
+ const struct ifaddrs *i;
+ smartlist_t *result;
+ if (getifaddrs(&ifa) < 0) {
+ log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ result = smartlist_create();
+ for (i = ifa; i; i = i->ifa_next) {
+ tor_addr_t tmp;
+ if (!i->ifa_addr)
+ continue;
+ if (i->ifa_addr->sa_family != AF_INET &&
+ i->ifa_addr->sa_family != AF_INET6)
+ continue;
+ if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0)
+ continue;
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+ }
+
+ freeifaddrs(ifa);
+ return result;
+#elif defined(MS_WINDOWS)
+ /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
+ "GetAdaptersInfo", but that's deprecated; let's just try
+ GetAdaptersAddresses and fall back to connect+getsockname.
+ */
+ HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll"));
+ smartlist_t *result = NULL;
+ GetAdaptersAddresses_fn_t fn;
+ ULONG size, res;
+ IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
+
+ (void) severity;
+
+#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \
+ GAA_FLAG_SKIP_MULTICAST | \
+ GAA_FLAG_SKIP_DNS_SERVER)
+
+ if (!lib) {
+ log_fn(severity, LD_NET, "Unable to load iphlpapi.dll");
+ goto done;
+ }
+
+ if (!(fn = (GetAdaptersAddresses_fn_t)
+ GetProcAddress(lib, "GetAdaptersAddresses"))) {
+ log_fn(severity, LD_NET, "Unable to obtain pointer to "
+ "GetAdaptersAddresses");
+ goto done;
+ }
+
+ /* Guess how much space we need. */
+ size = 15*1024;
+ addresses = tor_malloc(size);
+ res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ if (res == ERROR_BUFFER_OVERFLOW) {
+ /* we didn't guess that we needed enough space; try again */
+ tor_free(addresses);
+ addresses = tor_malloc(size);
+ res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ }
+ if (res != NO_ERROR) {
+ log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res);
+ goto done;
+ }
+
+ result = smartlist_create();
+ for (address = addresses; address; address = address->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS *a;
+ for (a = address->FirstUnicastAddress; a; a = a->Next) {
+ /* Yes, it's a linked list inside a linked list */
+ struct sockaddr *sa = a->Address.lpSockaddr;
+ tor_addr_t tmp;
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ continue;
+ if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
+ continue;
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+ }
+ }
+
+ done:
+ if (lib)
+ FreeLibrary(lib);
+ tor_free(addresses);
+ return result;
+#elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL)
+ /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */
+ struct ifconf ifc;
+ int fd, i, sz, n;
+ smartlist_t *result = NULL;
+ /* This interface, AFAICT, only supports AF_INET addresses */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ log(severity, LD_NET, "socket failed: %s", strerror(errno));
+ goto done;
+ }
+ /* Guess how much space we need. */
+ ifc.ifc_len = sz = 15*1024;
+ ifc.ifc_ifcu.ifcu_req = tor_malloc(sz);
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
+ close(fd);
+ goto done;
+ }
+ close(fd);
+ result = smartlist_create();
+ if (ifc.ifc_len < sz)
+ sz = ifc.ifc_len;
+ n = sz / sizeof(struct ifreq);
+ for (i = 0; i < n ; ++i) {
+ struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i];
+ struct sockaddr *sa = &r->ifr_addr;
+ tor_addr_t tmp;
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ continue; /* should be impossible */
+ if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
+ continue;
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+ }
+ done:
+ tor_free(ifc.ifc_ifcu.ifcu_req);
+ return result;
+#else
+ (void) severity;
+ return NULL;
+#endif
+}
+
+/** Return true iff <b>a</b> is a multicast address. */
+static int
+tor_addr_is_multicast(const tor_addr_t *a)
+{
+ sa_family_t family = tor_addr_family(a);
+ if (family == AF_INET) {
+ uint32_t ipv4h = tor_addr_to_ipv4h(a);
+ if ((ipv4h >> 24) == 0xe0)
+ return 1; /* Multicast */
+ } else if (family == AF_INET6) {
+ const uint8_t *a32 = tor_addr_to_in6_addr8(a);
+ if (a32[0] == 0xff)
+ return 1;
+ }
+ return 0;
+}
+
/** Set *<b>addr</b> to the IP address (if any) of whatever interface
* connects to the Internet. This address should only be used in checking
* whether our address has changed. Return 0 on success, -1 on failure.
@@ -1063,12 +1271,38 @@ tor_addr_port_parse(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
int
get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr)
{
+ /* XXX really, this function should yield a smartlist of addresses. */
+ smartlist_t *addrs;
int sock=-1, r=-1;
struct sockaddr_storage my_addr, target_addr;
socklen_t addr_len;
-
tor_assert(addr);
+ /* Try to do this the smart way if possible. */
+ if ((addrs = get_interface_addresses_raw(severity))) {
+ int rv = -1;
+ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) {
+ if (family != AF_UNSPEC && family != tor_addr_family(a))
+ continue;
+ if (tor_addr_is_loopback(a) ||
+ tor_addr_is_multicast(a))
+ continue;
+
+ tor_addr_copy(addr, a);
+ rv = 0;
+
+ /* If we found a non-internal address, declare success. Otherwise,
+ * keep looking. */
+ if (!tor_addr_is_internal(a, 0))
+ break;
+ } SMARTLIST_FOREACH_END(a);
+
+ SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a));
+ smartlist_free(addrs);
+ return rv;
+ }
+
+ /* Okay, the smart way is out. */
memset(addr, 0, sizeof(tor_addr_t));
memset(&target_addr, 0, sizeof(target_addr));
/* Don't worry: no packets are sent. We just need to use a real address
@@ -1138,6 +1372,20 @@ is_internal_IP(uint32_t ip, int for_listening)
return tor_addr_is_internal(&myaddr, for_listening);
}
+/** 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
+ * 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
+tor_addr_port_split(int severity, const char *addrport,
+ char **address_out, uint16_t *port_out)
+{
+ tor_assert(addrport);
+ tor_assert(address_out);
+ tor_assert(port_out);
+ return addr_port_lookup(severity, addrport, address_out, NULL, port_out);
+}
+
/** Parse a string of the form "host[:port]" from <b>addrport</b>. If
* <b>address</b> is provided, set *<b>address</b> to a copy of the
* host portion of the string. If <b>addr</b> is provided, try to
@@ -1149,7 +1397,7 @@ is_internal_IP(uint32_t ip, int for_listening)
* Return 0 on success, -1 on failure.
*/
int
-parse_addr_port(int severity, const char *addrport, char **address,
+addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out)
{
const char *colon;
@@ -1159,7 +1407,7 @@ parse_addr_port(int severity, const char *addrport, char **address,
tor_assert(addrport);
- colon = strchr(addrport, ':');
+ colon = strrchr(addrport, ':');
if (colon) {
_address = tor_strndup(addrport, colon-addrport);
_port = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
diff --git a/src/common/address.h b/src/common/address.h
index 9a7656f69b..4568c32bf9 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -31,6 +31,13 @@ typedef struct tor_addr_t
} addr;
} tor_addr_t;
+/** Holds an IP address and a TCP/UDP port. */
+typedef struct tor_addr_port_t
+{
+ tor_addr_t addr;
+ uint16_t port;
+} tor_addr_port_t;
+
static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
static INLINE uint32_t tor_addr_to_ipv4h(const tor_addr_t *a);
@@ -127,6 +134,7 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u)
int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr_out);
char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
const char *fmt_addr(const tor_addr_t *addr);
+const char * fmt_addr32(uint32_t addr);
int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr);
/** Flag to specify how to do a comparison between addresses. In an "exact"
@@ -148,24 +156,24 @@ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
unsigned int tor_addr_hash(const tor_addr_t *addr);
int tor_addr_is_v4(const tor_addr_t *addr);
-int tor_addr_is_internal(const tor_addr_t *ip, int for_listening) ATTR_PURE;
+int tor_addr_is_internal(const tor_addr_t *ip, int for_listening);
/** Longest length that can be required for a reverse lookup name. */
/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */
#define REVERSE_LOOKUP_NAME_BUF_LEN 73
-int tor_addr_to_reverse_lookup_name(char *out, size_t outlen,
+int tor_addr_to_PTR_name(char *out, size_t outlen,
const tor_addr_t *addr);
-int tor_addr_parse_reverse_lookup_name(tor_addr_t *result, const char *address,
+int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
int family, int accept_regular);
-int tor_addr_port_parse(const char *s, tor_addr_t *addr_out,
+int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out,
uint16_t *port_out);
int tor_addr_parse_mask_ports(const char *s,
tor_addr_t *addr_out, maskbits_t *mask_out,
uint16_t *port_min_out, uint16_t *port_max_out);
-const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, int len,
+const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len,
int decorate);
-int tor_addr_from_str(tor_addr_t *addr, const char *src);
+int tor_addr_parse(tor_addr_t *addr, const char *src);
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src);
void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr);
/** Set <b>dest</b> to the IPv4 address encoded in <b>v4addr</b> in host
@@ -180,9 +188,12 @@ void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6);
int tor_addr_is_null(const tor_addr_t *addr);
int tor_addr_is_loopback(const tor_addr_t *addr);
+int tor_addr_port_split(int severity, const char *addrport,
+ char **address_out, uint16_t *port_out);
+
/* IPv4 helpers */
-int is_internal_IP(uint32_t ip, int for_listening) ATTR_PURE;
-int parse_addr_port(int severity, const char *addrport, char **address,
+int is_internal_IP(uint32_t ip, int for_listening);
+int addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out);
int parse_port_range(const char *port, uint16_t *port_min_out,
uint16_t *port_max_out);
diff --git a/src/common/aes.c b/src/common/aes.c
index c2fdeb594a..da7220fe19 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -6,11 +6,7 @@
/**
* \file aes.c
- * \brief Implements the AES cipher (with 128-bit keys and blocks),
- * and a counter-mode stream cipher on top of AES. This code is
- * taken from the main Rijndael distribution. (We include this
- * because many people are running older versions of OpenSSL without
- * AES support.)
+ * \brief Implements a counter-mode stream cipher on top of AES.
**/
#include "orconfig.h"
@@ -18,120 +14,42 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+#include "crypto.h"
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
+/* See comments about which counter mode implementation to use below. */
+#include <openssl/modes.h>
+#define CAN_USE_OPENSSL_CTR
+#endif
#include "compat.h"
#include "aes.h"
#include "util.h"
#include "torlog.h"
-/* We have 3 strategies for getting AES: Via OpenSSL's AES_encrypt function,
- * via OpenSSL's EVP_EncryptUpdate function, or via the built-in AES
- * implementation below. */
-
-/** Defined iff we're using OpenSSL's AES functions for AES. */
-#undef USE_OPENSSL_AES
-/** Defined iff we're using OpenSSL's EVP code for AES. */
-#undef USE_OPENSSL_EVP
-/** Defined iff we're using Tor's internal AES implementation, defined
- * below. */
-#undef USE_BUILTIN_AES
-
-/* Figure out our CPU type. We use this to pick an AES implementation.
- * Macros are as listed at http://predef.sourceforge.net/prearch.html
- */
-#if (defined(i386) || defined(__i386__) || defined(__i386) || defined(_X86_) \
- || defined(_M_IX86) || defined(__THW_INTEL__) || defined(__I86__))
-# define CPU_IS_X86
-#elif (defined(__amd64__) || defined(__amd64) || \
- defined(__x86_64__) || defined(__x86_64) || \
- defined(_M_X64))
-# define CPU_IS_X86_64
-#elif (defined(__ia64__) || defined(__ia64) || defined(_IA64) || \
- defined(_M_IA64))
-# define CPU_IS_IA64
-#elif (defined(__sparc__) || defined(__sparc))
-# define CPU_IS_SPARC
-#elif (defined(__arm__) || defined (__TARGET_ARCH_ARM))
-# define CPU_IS_ARM
+#ifdef ANDROID
+/* Android's OpenSSL seems to have removed all of its Engine support. */
+#define DISABLE_ENGINES
#endif
-/* Here we pick which to use, if none is force-defined. See
- * http://archives.seul.org/or/dev/Feb-2007/msg00045.html
- * for a summary of the most recent benchmarking results that led to this
- * nutty decision tree.
-*/
-#if (!defined(USE_BUILTIN_AES) && \
- !defined(USE_OPENSSL_AES) && \
- !defined(USE_OPENSSL_EVP))
-
-/* OpenSSL 0.9.7 was the first to support AES. It was slower than our
- * built-in implementation.
- * OpenSSL 0.9.8 added assembly implementations for i386 and ia64.
- * Either the i386 stuff isn't used for x86-64, or it isn't faster.
- * OpenSSL 0.9.9 (not yet out) has added assembly implementations for
- * x86_64 (aka amd64), sparc9, and arm
+/* We have 2 strategies for getting AES: Via OpenSSL's AES_encrypt function,
+ * via OpenSSL's EVP_EncryptUpdate function.
*
- * Note: the "f" at the end of OpenSSL version numbers below means
- * "release". */
-# if defined(CPU_IS_X86) || defined(CPU_IS_IA64)
-# if OPENSSL_VERSION_NUMBER >= 0x0090800fL
-# define USE_OPENSSL_AES
-# endif
-# endif
-
-# if defined(CPU_IS_X86_64) || defined(CPU_IS_ARM) || defined(CPU_IS_SPARC)
-# if OPENSSL_VERSION_NUMBER >= 0x0090900fL
-# define USE_OPENSSL_AES
-# endif
-# endif
-
-/* Otherwise, use the built-in implementation below. */
-# ifndef USE_OPENSSL_AES
-# define USE_BUILTIN_AES
-# endif
-#endif /* endif need to pick a method */
-
-/* Include OpenSSL headers as needed. */
-#ifdef USE_OPENSSL_AES
-# include <openssl/aes.h>
-#endif
-#ifdef USE_OPENSSL_EVP
-# include <openssl/evp.h>
-#endif
-
-/* Figure out which AES optimizations to use. */
-#ifdef USE_BUILTIN_AES
-/** If this is defined, we take advantage of the fact that AES treats its
- * input as a set of 4 32-bit words, so that there is no need to encode and
- * decode the 128-bit counter before every block encryption */
-# define USE_RIJNDAEL_COUNTER_OPTIMIZATION
-# if 0 && (defined(__powerpc__) || defined(__powerpc64__))
-/* XXXX do more experimentation before concluding this is actually
- * a good idea. */
-# define FULL_UNROLL
-# endif
-#endif
-
-/*======================================================================*/
-/* From rijndael-alg-fst.h */
-
-typedef uint64_t u64;
-typedef uint32_t u32;
-typedef uint8_t u8;
-
-#ifdef USE_BUILTIN_AES
-#define MAXNR 14
+ * If there's any hardware acceleration in play, we want to be using EVP_* so
+ * we can get it. Otherwise, we'll want AES_*, which seems to be about 5%
+ * faster than indirecting through the EVP layer.
+ */
-static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/],
- const u8 cipherKey[], int keyBits);
-#ifdef USE_RIJNDAEL_COUNTER_OPTIMIZATION
-static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr,
- u32 ctr3, u32 ctr2,
- u32 ctr1, u32 ctr0, u8 ct[16]);
-#else
-static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr,
- const u8 pt[16], u8 ct[16]);
-#endif
-#endif
+/* We have 2 strategies for counter mode: use our own, or use OpenSSL's.
+ *
+ * Here we have a counter mode that's faster than the one shipping with
+ * OpenSSL pre-1.0 (by about 10%!). But OpenSSL 1.0.0 added a counter mode
+ * implementation faster than the one here (by about 7%). So we pick which
+ * one to used based on the Openssl version above. (OpenSSL 1.0.0a fixed a
+ * critical bug in that counter mode implementation, so we need to test to
+ * make sure that we have a fixed version.)
+ */
/*======================================================================*/
/* Interface to AES code, and counter implementation */
@@ -139,42 +57,129 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr,
/** Implements an AES counter-mode cipher. */
struct aes_cnt_cipher {
/** This next element (however it's defined) is the AES key. */
-#if defined(USE_OPENSSL_EVP)
- EVP_CIPHER_CTX key;
-#elif defined(USE_OPENSSL_AES)
- AES_KEY key;
-#else
- u32 rk[4*(MAXNR+1)];
- int nr;
-#endif
+ union {
+ EVP_CIPHER_CTX evp;
+ AES_KEY aes;
+ } key;
-#if !defined(WORDS_BIGENDIAN) || defined(USE_RIJNDAEL_COUNTER_OPTIMIZATION)
+#if !defined(WORDS_BIGENDIAN)
#define USING_COUNTER_VARS
/** These four values, together, implement a 128-bit counter, with
* counter0 as the low-order word and counter3 as the high-order word. */
- u32 counter3;
- u32 counter2;
- u32 counter1;
- u32 counter0;
+ uint32_t counter3;
+ uint32_t counter2;
+ uint32_t counter1;
+ uint32_t counter0;
#endif
-#ifndef USE_RIJNDAEL_COUNTER_OPTIMIZATION
-#define USING_COUNTER_BUFS
union {
/** The counter, in big-endian order, as bytes. */
- u8 buf[16];
+ uint8_t buf[16];
/** The counter, in big-endian order, as big-endian words. Note that
* on big-endian platforms, this is redundant with counter3...0,
* so we just use these values instead. */
- u32 buf32[4];
+ uint32_t buf32[4];
} ctr_buf;
-#endif
+
/** The encrypted value of ctr_buf. */
- u8 buf[16];
+ uint8_t buf[16];
/** Our current stream position within buf. */
- u8 pos;
+ unsigned int pos;
+
+ /** True iff we're using the evp implementation of this cipher. */
+ uint8_t using_evp;
};
+/** True iff we should prefer the EVP implementation for AES, either because
+ * we're testing it or because we have hardware acceleration configured */
+static int should_use_EVP = 0;
+
+#ifdef CAN_USE_OPENSSL_CTR
+/** True iff we have tested the counter-mode implementation and found that it
+ * doesn't have the counter-mode bug from OpenSSL 1.0.0. */
+static int should_use_openssl_CTR = 0;
+#endif
+
+/** Check whether we should use the EVP interface for AES. If <b>force_val</b>
+ * is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP
+ * if there is an engine enabled for aes-ecb. */
+int
+evaluate_evp_for_aes(int force_val)
+{
+ ENGINE *e;
+
+ if (force_val >= 0) {
+ should_use_EVP = force_val;
+ return 0;
+ }
+#ifdef DISABLE_ENGINES
+ should_use_EVP = 0;
+#else
+ e = ENGINE_get_cipher_engine(NID_aes_128_ecb);
+
+ if (e) {
+ log_notice(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
+ ENGINE_get_name(e));
+ should_use_EVP = 1;
+ } else {
+ log_notice(LD_CRYPTO, "No AES engine found; using AES_* functions.");
+ should_use_EVP = 0;
+ }
+#endif
+
+ return 0;
+}
+
+/** Test the OpenSSL counter mode implementation to see whether it has the
+ * counter-mode bug from OpenSSL 1.0.0. If the implementation works, then
+ * we will use it for future encryption/decryption operations.
+ *
+ * We can't just look at the OpenSSL version, since some distributions update
+ * their OpenSSL packages without changing the version number.
+ **/
+int
+evaluate_ctr_for_aes(void)
+{
+#ifdef CAN_USE_OPENSSL_CTR
+ /* Result of encrypting an all-zero block with an all-zero 128-bit AES key.
+ * This should be the same as encrypting an all-zero block with an all-zero
+ * 128-bit AES key in counter mode, starting at position 0 of the stream.
+ */
+ static const unsigned char encrypt_zero[] =
+ "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e";
+ unsigned char zero[16];
+ unsigned char output[16];
+ unsigned char ivec[16];
+ unsigned char ivec_tmp[16];
+ unsigned int pos, i;
+ AES_KEY key;
+ memset(zero, 0, sizeof(zero));
+ memset(ivec, 0, sizeof(ivec));
+ AES_set_encrypt_key(zero, 128, &key);
+
+ pos = 0;
+ /* Encrypting a block one byte at a time should make the error manifest
+ * itself for known bogus openssl versions. */
+ for (i=0; i<16; ++i)
+ AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos);
+
+ if (memcmp(output, encrypt_zero, 16)) {
+ /* Counter mode is buggy */
+ log_notice(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; "
+ "not using it.");
+ } else {
+ /* Counter mode is okay */
+ log_notice(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
+ "mode; using it.");
+ should_use_openssl_CTR = 1;
+ }
+#else
+ log_notice(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
+ "counter mode; not using it.");
+#endif
+ return 0;
+}
+
#if !defined(USING_COUNTER_VARS)
#define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)])
#else
@@ -194,24 +199,14 @@ _aes_fill_buf(aes_cnt_cipher_t *cipher)
* 3) changing the counter position was not trivial, last time I looked.
* None of these issues are insurmountable in principle.
*/
-#if defined(USE_BUILTIN_AES) && defined(USE_RIJNDAEL_COUNTER_OPTIMIZATION)
- rijndaelEncrypt(cipher->rk, cipher->nr,
- cipher->counter3, cipher->counter2,
- cipher->counter1, cipher->counter0, cipher->buf);
-#else
-#if defined(USE_OPENSSL_EVP)
- {
+ if (cipher->using_evp) {
int outl=16, inl=16;
- EVP_EncryptUpdate(&cipher->key, cipher->buf, &outl,
+ EVP_EncryptUpdate(&cipher->key.evp, cipher->buf, &outl,
cipher->ctr_buf.buf, inl);
+ } else {
+ AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key.aes);
}
-#elif defined(USE_OPENSSL_AES)
- AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key);
-#else
- rijndaelEncrypt(cipher->rk, cipher->nr, cipher->ctr_buf.buf, cipher->buf);
-#endif
-#endif
}
/**
@@ -232,33 +227,38 @@ aes_new_cipher(void)
void
aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
{
-#if defined(USE_OPENSSL_EVP)
- const EVP_CIPHER *c;
- switch (key_bits) {
- case 128: c = EVP_aes_128_ecb(); break;
- case 192: c = EVP_aes_192_ecb(); break;
- case 256: c = EVP_aes_256_ecb(); break;
- default: tor_assert(0);
+ if (should_use_EVP) {
+ const EVP_CIPHER *c;
+ switch (key_bits) {
+ case 128: c = EVP_aes_128_ecb(); break;
+ case 192: c = EVP_aes_192_ecb(); break;
+ case 256: c = EVP_aes_256_ecb(); break;
+ default: tor_assert(0);
+ }
+ EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL);
+ cipher->using_evp = 1;
+ } else {
+ AES_set_encrypt_key((const unsigned char *)key, key_bits, &cipher->key.aes);
+ cipher->using_evp = 0;
}
- EVP_EncryptInit(&cipher->key, c, (const unsigned char*)key, NULL);
-#elif defined(USE_OPENSSL_AES)
- AES_set_encrypt_key((const unsigned char *)key, key_bits, &(cipher->key));
-#else
- cipher->nr = rijndaelKeySetupEnc(cipher->rk, (const unsigned char*)key,
- key_bits);
-#endif
+
#ifdef USING_COUNTER_VARS
cipher->counter0 = 0;
cipher->counter1 = 0;
cipher->counter2 = 0;
cipher->counter3 = 0;
#endif
-#ifdef USING_COUNTER_BUFS
+
memset(cipher->ctr_buf.buf, 0, sizeof(cipher->ctr_buf.buf));
-#endif
cipher->pos = 0;
- _aes_fill_buf(cipher);
+
+#ifdef CAN_USE_OPENSSL_CTR
+ if (should_use_openssl_CTR)
+ memset(cipher->buf, 0, sizeof(cipher->buf));
+ else
+#endif
+ _aes_fill_buf(cipher);
}
/** Release storage held by <b>cipher</b>
@@ -268,14 +268,14 @@ aes_free_cipher(aes_cnt_cipher_t *cipher)
{
if (!cipher)
return;
-#ifdef USE_OPENSSL_EVP
- EVP_CIPHER_CTX_cleanup(&cipher->key);
-#endif
+ if (cipher->using_evp) {
+ EVP_CIPHER_CTX_cleanup(&cipher->key.evp);
+ }
memset(cipher, 0, sizeof(aes_cnt_cipher_t));
tor_free(cipher);
}
-#if defined(USING_COUNTER_VARS) && defined(USING_COUNTER_BUFS)
+#if defined(USING_COUNTER_VARS)
#define UPDATE_CTR_BUF(c, n) STMT_BEGIN \
(c)->ctr_buf.buf32[3-(n)] = htonl((c)->counter ## n); \
STMT_END
@@ -283,6 +283,18 @@ aes_free_cipher(aes_cnt_cipher_t *cipher)
#define UPDATE_CTR_BUF(c, n)
#endif
+#ifdef CAN_USE_OPENSSL_CTR
+/* Helper function to use EVP with openssl's counter-mode wrapper. */
+static void evp_block128_fn(const uint8_t in[16],
+ uint8_t out[16],
+ const void *key)
+{
+ EVP_CIPHER_CTX *ctx = (void*)key;
+ int inl=16, outl=16;
+ EVP_EncryptUpdate(ctx, out, &outl, in, inl);
+}
+#endif
+
/** Encrypt <b>len</b> bytes from <b>input</b>, storing the result in
* <b>output</b>. Uses the key in <b>cipher</b>, and advances the counter
* by <b>len</b> bytes as it encrypts.
@@ -291,32 +303,56 @@ void
aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
char *output)
{
-
- /* XXXX This function is up to 5% of our runtime in some profiles;
- * we should look into unrolling some of the loops; taking advantage
- * of alignment, using a bigger buffer, and so on. Not till after 0.1.2.x,
- * though. */
- int c = cipher->pos;
- if (PREDICT_UNLIKELY(!len)) return;
-
- while (1) {
- do {
- if (len-- == 0) { cipher->pos = c; return; }
- *(output++) = *(input++) ^ cipher->buf[c];
- } while (++c != 16);
- cipher->pos = c = 0;
- if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) {
- if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) {
- if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) {
- ++COUNTER(cipher, 3);
- UPDATE_CTR_BUF(cipher, 3);
+#ifdef CAN_USE_OPENSSL_CTR
+ if (should_use_openssl_CTR) {
+ if (cipher->using_evp) {
+ /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If
+ * it weren't disabled, it might be better just to use that.
+ */
+ CRYPTO_ctr128_encrypt((const unsigned char *)input,
+ (unsigned char *)output,
+ len,
+ &cipher->key.evp,
+ cipher->ctr_buf.buf,
+ cipher->buf,
+ &cipher->pos,
+ evp_block128_fn);
+ } else {
+ AES_ctr128_encrypt((const unsigned char *)input,
+ (unsigned char *)output,
+ len,
+ &cipher->key.aes,
+ cipher->ctr_buf.buf,
+ cipher->buf,
+ &cipher->pos);
+ }
+ return;
+ }
+ else
+#endif
+ {
+ int c = cipher->pos;
+ if (PREDICT_UNLIKELY(!len)) return;
+
+ while (1) {
+ do {
+ if (len-- == 0) { cipher->pos = c; return; }
+ *(output++) = *(input++) ^ cipher->buf[c];
+ } while (++c != 16);
+ cipher->pos = c = 0;
+ if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) {
+ if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) {
+ if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) {
+ ++COUNTER(cipher, 3);
+ UPDATE_CTR_BUF(cipher, 3);
+ }
+ UPDATE_CTR_BUF(cipher, 2);
}
- UPDATE_CTR_BUF(cipher, 2);
+ UPDATE_CTR_BUF(cipher, 1);
}
- UPDATE_CTR_BUF(cipher, 1);
+ UPDATE_CTR_BUF(cipher, 0);
+ _aes_fill_buf(cipher);
}
- UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
}
}
@@ -327,32 +363,36 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
void
aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
{
-
- /* XXXX This function is up to 5% of our runtime in some profiles;
- * we should look into unrolling some of the loops; taking advantage
- * of alignment, using a bigger buffer, and so on. Not till after 0.1.2.x,
- * though. */
- int c = cipher->pos;
- if (PREDICT_UNLIKELY(!len)) return;
-
- while (1) {
- do {
- if (len-- == 0) { cipher->pos = c; return; }
- *(data++) ^= cipher->buf[c];
- } while (++c != 16);
- cipher->pos = c = 0;
- if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) {
- if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) {
- if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) {
- ++COUNTER(cipher, 3);
- UPDATE_CTR_BUF(cipher, 3);
+#ifdef CAN_USE_OPENSSL_CTR
+ if (should_use_openssl_CTR) {
+ aes_crypt(cipher, data, len, data);
+ return;
+ }
+ else
+#endif
+ {
+ int c = cipher->pos;
+ if (PREDICT_UNLIKELY(!len)) return;
+
+ while (1) {
+ do {
+ if (len-- == 0) { cipher->pos = c; return; }
+ *(data++) ^= cipher->buf[c];
+ } while (++c != 16);
+ cipher->pos = c = 0;
+ if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) {
+ if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) {
+ if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) {
+ ++COUNTER(cipher, 3);
+ UPDATE_CTR_BUF(cipher, 3);
+ }
+ UPDATE_CTR_BUF(cipher, 2);
}
- UPDATE_CTR_BUF(cipher, 2);
+ UPDATE_CTR_BUF(cipher, 1);
}
- UPDATE_CTR_BUF(cipher, 1);
+ UPDATE_CTR_BUF(cipher, 0);
+ _aes_fill_buf(cipher);
}
- UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
}
}
@@ -368,705 +408,11 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
cipher->counter0 = ntohl(get_uint32(iv+12));
#endif
cipher->pos = 0;
-#ifndef USE_RIJNDAEL_COUNTER_OPTIMIZATION
memcpy(cipher->ctr_buf.buf, iv, 16);
-#endif
-
- _aes_fill_buf(cipher);
-}
-
-#ifdef USE_BUILTIN_AES
-/*======================================================================*/
-/* From rijndael-alg-fst.c */
-
-/**
- * rijndael-alg-fst.c
- *
- * @version 3.0 (December 2000)
- *
- * Optimized ANSI C code for the Rijndael cipher (now AES)
- *
- * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
- * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
- * @author Paulo Barreto <paulo.barreto@terra.com.br>
- *
- * This code is hereby placed in the public domain.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
-Te0[x] = S [x].[02, 01, 01, 03];
-Te1[x] = S [x].[03, 02, 01, 01];
-Te2[x] = S [x].[01, 03, 02, 01];
-Te3[x] = S [x].[01, 01, 03, 02];
-Te4[x] = S [x].[01, 01, 01, 01];
-
-Td0[x] = Si[x].[0e, 09, 0d, 0b];
-Td1[x] = Si[x].[0b, 0e, 09, 0d];
-Td2[x] = Si[x].[0d, 0b, 0e, 09];
-Td3[x] = Si[x].[09, 0d, 0b, 0e];
-Td4[x] = Si[x].[01, 01, 01, 01];
-*/
-
-static const u32 Te0[256] = {
- 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
- 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
- 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
- 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
- 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
- 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
- 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
- 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
- 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
- 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
- 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
- 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
- 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
- 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
- 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
- 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
- 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
- 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
- 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
- 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
- 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
- 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
- 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
- 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
- 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
- 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
- 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
- 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
- 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
- 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
- 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
- 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
- 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
- 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
- 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
- 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
- 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
- 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
- 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
- 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
- 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
- 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
- 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
- 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
- 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
- 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
- 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
- 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
- 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
- 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
- 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
- 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
- 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
- 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
- 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
- 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
- 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
- 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
- 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
- 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
- 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
- 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
- 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
- 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
-};
-static const u32 Te1[256] = {
- 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
- 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
- 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
- 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
- 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
- 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
- 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
- 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
- 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
- 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
- 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
- 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
- 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
- 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
- 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
- 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
- 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
- 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
- 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
- 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
- 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
- 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
- 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
- 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
- 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
- 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
- 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
- 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
- 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
- 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
- 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
- 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
- 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
- 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
- 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
- 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
- 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
- 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
- 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
- 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
- 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
- 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
- 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
- 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
- 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
- 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
- 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
- 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
- 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
- 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
- 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
- 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
- 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
- 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
- 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
- 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
- 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
- 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
- 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
- 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
- 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
- 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
- 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
- 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
-};
-static const u32 Te2[256] = {
- 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
- 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
- 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
- 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
- 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
- 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
- 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
- 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
- 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
- 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
- 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
- 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
- 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
- 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
- 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
- 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
- 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
- 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
- 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
- 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
- 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
- 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
- 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
- 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
- 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
- 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
- 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
- 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
- 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
- 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
- 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
- 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
- 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
- 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
- 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
- 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
- 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
- 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
- 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
- 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
- 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
- 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
- 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
- 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
- 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
- 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
- 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
- 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
- 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
- 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
- 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
- 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
- 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
- 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
- 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
- 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
- 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
- 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
- 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
- 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
- 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
- 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
- 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
- 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
-};
-static const u32 Te3[256] = {
-
- 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
- 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
- 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
- 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
- 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
- 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
- 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
- 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
- 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
- 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
- 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
- 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
- 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
- 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
- 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
- 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
- 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
- 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
- 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
- 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
- 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
- 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
- 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
- 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
- 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
- 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
- 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
- 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
- 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
- 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
- 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
- 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
- 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
- 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
- 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
- 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
- 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
- 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
- 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
- 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
- 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
- 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
- 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
- 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
- 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
- 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
- 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
- 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
- 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
- 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
- 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
- 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
- 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
- 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
- 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
- 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
- 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
- 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
- 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
- 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
- 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
- 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
- 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
- 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
-};
-static const u32 Te4[256] = {
- 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
- 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
- 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
- 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
- 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
- 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
- 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
- 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
- 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
- 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
- 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
- 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
- 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
- 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
- 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
- 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
- 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
- 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
- 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
- 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
- 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
- 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
- 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
- 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
- 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
- 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
- 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
- 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
- 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
- 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
- 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
- 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
- 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
- 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
- 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
- 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
- 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
- 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
- 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
- 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
- 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
- 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
- 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
- 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
- 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
- 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
- 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
- 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
- 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
- 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
- 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
- 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
- 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
- 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
- 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
- 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
- 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
- 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
- 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
- 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
- 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
- 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
- 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
- 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
-};
-
-static const u32 rcon[] = {
- 0x01000000, 0x02000000, 0x04000000, 0x08000000,
- 0x10000000, 0x20000000, 0x40000000, 0x80000000,
- 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
-};
-#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
-
-#ifdef _MSC_VER
-#define GETU32(p) SWAP(*((u32 *)(p)))
-#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
-#else
-#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
-#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
-#endif
-
-/**
- * Expand the cipher key into the encryption key schedule.
- *
- * @return the number of rounds for the given cipher key size.
- */
-static int
-rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits)
-{
- int i = 0;
- u32 temp;
-
- rk[0] = GETU32(cipherKey );
- rk[1] = GETU32(cipherKey + 4);
- rk[2] = GETU32(cipherKey + 8);
- rk[3] = GETU32(cipherKey + 12);
- if (keyBits == 128) {
- for (;;) {
- temp = rk[3];
- rk[4] = rk[0] ^
- (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
- (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
- (Te4[(temp ) & 0xff] & 0x0000ff00) ^
- (Te4[(temp >> 24) ] & 0x000000ff) ^
- rcon[i];
- rk[5] = rk[1] ^ rk[4];
- rk[6] = rk[2] ^ rk[5];
- rk[7] = rk[3] ^ rk[6];
- if (++i == 10) {
- return 10;
- }
- rk += 4;
- }
- }
- rk[4] = GETU32(cipherKey + 16);
- rk[5] = GETU32(cipherKey + 20);
- if (keyBits == 192) {
- for (;;) {
- temp = rk[ 5];
- rk[ 6] = rk[ 0] ^
- (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
- (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
- (Te4[(temp ) & 0xff] & 0x0000ff00) ^
- (Te4[(temp >> 24) ] & 0x000000ff) ^
- rcon[i];
- rk[ 7] = rk[ 1] ^ rk[ 6];
- rk[ 8] = rk[ 2] ^ rk[ 7];
- rk[ 9] = rk[ 3] ^ rk[ 8];
- if (++i == 8) {
- return 12;
- }
- rk[10] = rk[ 4] ^ rk[ 9];
- rk[11] = rk[ 5] ^ rk[10];
- rk += 6;
- }
- }
- rk[6] = GETU32(cipherKey + 24);
- rk[7] = GETU32(cipherKey + 28);
- if (keyBits == 256) {
- for (;;) {
- temp = rk[ 7];
- rk[ 8] = rk[ 0] ^
- (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
- (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
- (Te4[(temp ) & 0xff] & 0x0000ff00) ^
- (Te4[(temp >> 24) ] & 0x000000ff) ^
- rcon[i];
- rk[ 9] = rk[ 1] ^ rk[ 8];
- rk[10] = rk[ 2] ^ rk[ 9];
- rk[11] = rk[ 3] ^ rk[10];
- if (++i == 7) {
- return 14;
- }
- temp = rk[11];
- rk[12] = rk[ 4] ^
- (Te4[(temp >> 24) ] & 0xff000000) ^
- (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(temp ) & 0xff] & 0x000000ff);
- rk[13] = rk[ 5] ^ rk[12];
- rk[14] = rk[ 6] ^ rk[13];
- rk[15] = rk[ 7] ^ rk[14];
-
- rk += 8;
- }
- }
- return 0;
-}
-
-#ifdef USE_RIJNDAEL_COUNTER_OPTIMIZATION
-static void
-rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, u32 ctr3, u32 ctr2, u32 ctr1, u32 ctr0, u8 ct[16])
-#else
-static void
-rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16])
-#endif
-{
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
-#ifndef FULL_UNROLL
- int r;
-#endif /* ?FULL_UNROLL */
-
- /*
- * map byte array block to cipher state
- * and add initial round key:
- */
-#ifdef USE_RIJNDAEL_COUNTER_OPTIMIZATION
- s0 = ctr3 ^ rk[0];
- s1 = ctr2 ^ rk[1];
- s2 = ctr1 ^ rk[2];
- s3 = ctr0 ^ rk[3];
-#else
- s0 = GETU32(pt ) ^ rk[0];
- s1 = GETU32(pt + 4) ^ rk[1];
- s2 = GETU32(pt + 8) ^ rk[2];
- s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef CAN_USE_OPENSSL_CTR
+ if (!should_use_openssl_CTR)
#endif
-
-#ifdef FULL_UNROLL
- /* round 1: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
- /* round 2: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
- /* round 3: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
- /* round 4: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
- /* round 5: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
- /* round 6: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
- /* round 7: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
- /* round 8: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
- /* round 9: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
- if (Nr > 10) {
- /* round 10: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
- /* round 11: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
- if (Nr > 12) {
- /* round 12: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
- /* round 13: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
- }
- }
- rk += Nr << 2;
-#else /* !FULL_UNROLL */
- /*
- * Nr - 1 full rounds:
- */
- r = Nr >> 1;
- for (;;) {
- t0 =
- Te0[(s0 >> 24) ] ^
- Te1[(s1 >> 16) & 0xff] ^
- Te2[(s2 >> 8) & 0xff] ^
- Te3[(s3 ) & 0xff] ^
- rk[4];
- t1 =
- Te0[(s1 >> 24) ] ^
- Te1[(s2 >> 16) & 0xff] ^
- Te2[(s3 >> 8) & 0xff] ^
- Te3[(s0 ) & 0xff] ^
- rk[5];
- t2 =
- Te0[(s2 >> 24) ] ^
- Te1[(s3 >> 16) & 0xff] ^
- Te2[(s0 >> 8) & 0xff] ^
- Te3[(s1 ) & 0xff] ^
- rk[6];
- t3 =
- Te0[(s3 >> 24) ] ^
- Te1[(s0 >> 16) & 0xff] ^
- Te2[(s1 >> 8) & 0xff] ^
- Te3[(s2 ) & 0xff] ^
- rk[7];
-
- rk += 8;
- if (--r == 0) {
- break;
- }
-
- s0 =
- Te0[(t0 >> 24) ] ^
- Te1[(t1 >> 16) & 0xff] ^
- Te2[(t2 >> 8) & 0xff] ^
- Te3[(t3 ) & 0xff] ^
- rk[0];
- s1 =
- Te0[(t1 >> 24) ] ^
- Te1[(t2 >> 16) & 0xff] ^
- Te2[(t3 >> 8) & 0xff] ^
- Te3[(t0 ) & 0xff] ^
- rk[1];
- s2 =
- Te0[(t2 >> 24) ] ^
- Te1[(t3 >> 16) & 0xff] ^
- Te2[(t0 >> 8) & 0xff] ^
- Te3[(t1 ) & 0xff] ^
- rk[2];
- s3 =
- Te0[(t3 >> 24) ] ^
- Te1[(t0 >> 16) & 0xff] ^
- Te2[(t1 >> 8) & 0xff] ^
- Te3[(t2 ) & 0xff] ^
- rk[3];
- }
-#endif /* ?FULL_UNROLL */
- /*
- * apply last round and
- * map cipher state to byte array block:
- */
- s0 =
- (Te4[(t0 >> 24) ] & 0xff000000) ^
- (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t3 ) & 0xff] & 0x000000ff) ^
- rk[0];
- PUTU32(ct , s0);
- s1 =
- (Te4[(t1 >> 24) ] & 0xff000000) ^
- (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t0 ) & 0xff] & 0x000000ff) ^
- rk[1];
- PUTU32(ct + 4, s1);
- s2 =
- (Te4[(t2 >> 24) ] & 0xff000000) ^
- (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t1 ) & 0xff] & 0x000000ff) ^
- rk[2];
- PUTU32(ct + 8, s2);
- s3 =
- (Te4[(t3 >> 24) ] & 0xff000000) ^
- (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t2 ) & 0xff] & 0x000000ff) ^
- rk[3];
- PUTU32(ct + 12, s3);
-}
-#endif
-
-#ifdef AES_BENCHMARK
-int
-main(int c, char **v)
-{
- int i;
- char blob[509]; /* the size of a cell payload. */
- char blob_out[509];
- aes_cnt_cipher_t *cipher = aes_new_cipher();
- aes_set_key(cipher, "aesbenchmarkkey!", 128);
- memset(blob, 'z', sizeof(blob));
-
- for (i=0;i<1000000; ++i) {
- aes_crypt(cipher, blob, sizeof(blob), blob_out);
- }
- return 0;
+ _aes_fill_buf(cipher);
}
-#endif
diff --git a/src/common/aes.h b/src/common/aes.h
index eb633dbcce..f7f0319183 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -13,8 +13,6 @@
* \brief Headers for aes.c
*/
-#include "torint.h"
-
struct aes_cnt_cipher;
typedef struct aes_cnt_cipher aes_cnt_cipher_t;
@@ -26,5 +24,8 @@ void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len);
void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv);
+int evaluate_evp_for_aes(int force_value);
+int evaluate_ctr_for_aes(void);
+
#endif
diff --git a/src/common/compat.c b/src/common/compat.c
index a4e50747cd..3af43e80c9 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -58,6 +58,14 @@
#endif
#endif
+/* Includes for the process attaching prevention */
+#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
+#include <sys/prctl.h>
+#elif defined(__APPLE__)
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#endif
+
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
@@ -103,6 +111,35 @@
#include "strlcat.c"
#endif
+/** As open(path, flags, mode), but return an fd with the close-on-exec mode
+ * set. */
+int
+tor_open_cloexec(const char *path, int flags, unsigned mode)
+{
+#ifdef O_CLOEXEC
+ return open(path, flags|O_CLOEXEC, mode);
+#else
+ int fd = open(path, flags, mode);
+#ifdef FD_CLOEXEC
+ if (fd >= 0)
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+ return fd;
+#endif
+}
+
+/** DOCDOC */
+FILE *
+tor_fopen_cloexec(const char *path, const char *mode)
+{
+ FILE *result = fopen(path, mode);
+#ifdef FD_CLOEXEC
+ if (result != NULL)
+ fcntl(fileno(result), F_SETFD, FD_CLOEXEC);
+#endif
+ return result;
+}
+
#ifdef HAVE_SYS_MMAN_H
/** Try to create a memory mapping for <b>filename</b> and return it. On
* failure, return NULL. Sets errno properly, using ERANGE to mean
@@ -118,7 +155,7 @@ tor_mmap_file(const char *filename)
tor_assert(filename);
- fd = open(filename, O_RDONLY, 0);
+ fd = tor_open_cloexec(filename, O_RDONLY, 0);
if (fd<0) {
int save_errno = errno;
int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN;
@@ -695,7 +732,7 @@ tor_lockfile_lock(const char *filename, int blocking, int *locked_out)
*locked_out = 0;
log_info(LD_FS, "Locking \"%s\"", filename);
- fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
if (fd < 0) {
log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename,
strerror(errno));
@@ -922,8 +959,16 @@ mark_socket_open(tor_socket_t s)
tor_socket_t
tor_open_socket(int domain, int type, int protocol)
{
- tor_socket_t s = socket(domain, type, protocol);
+ tor_socket_t s;
+#ifdef SOCK_CLOEXEC
+#define LINUX_CLOEXEC_OPEN_SOCKET
+ type |= SOCK_CLOEXEC;
+#endif
+ s = socket(domain, type, protocol);
if (SOCKET_OK(s)) {
+#if !defined(LINUX_CLOEXEC_OPEN_SOCKET) && defined(FD_CLOEXEC)
+ fcntl(s, F_SETFD, FD_CLOEXEC);
+#endif
socket_accounting_lock();
++n_sockets_open;
mark_socket_open(s);
@@ -936,8 +981,17 @@ tor_open_socket(int domain, int type, int protocol)
tor_socket_t
tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
{
- tor_socket_t s = accept(sockfd, addr, len);
+ tor_socket_t s;
+#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
+#define LINUX_CLOEXEC_ACCEPT
+ s = accept4(sockfd, addr, len, SOCK_CLOEXEC);
+#else
+ s = accept(sockfd, addr, len);
+#endif
if (SOCKET_OK(s)) {
+#if !defined(LINUX_CLOEXEC_ACCEPT) && defined(FD_CLOEXEC)
+ fcntl(s, F_SETFD, FD_CLOEXEC);
+#endif
socket_accounting_lock();
++n_sockets_open;
mark_socket_open(s);
@@ -993,8 +1047,17 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
//don't use win32 socketpairs (they are always bad)
#if defined(HAVE_SOCKETPAIR) && !defined(MS_WINDOWS)
int r;
+#ifdef SOCK_CLOEXEC
+ type |= SOCK_CLOEXEC;
+#endif
r = socketpair(family, type, protocol, fd);
if (r == 0) {
+#if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC)
+ if (fd[0] >= 0)
+ fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ if (fd[1] >= 0)
+ fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+#endif
socket_accounting_lock();
if (fd[0] >= 0) {
++n_sockets_open;
@@ -1288,31 +1351,19 @@ log_credential_status(void)
return -1;
} else {
int i, retval = 0;
- char *strgid;
char *s = NULL;
smartlist_t *elts = smartlist_create();
for (i = 0; i<ngids; i++) {
- strgid = tor_malloc(11);
- if (tor_snprintf(strgid, 11, "%u", (unsigned)sup_gids[i]) < 0) {
- log_warn(LD_GENERAL, "Error printing supplementary GIDs");
- tor_free(strgid);
- retval = -1;
- goto error;
- }
- smartlist_add(elts, strgid);
+ smartlist_add_asprintf(elts, "%u", (unsigned)sup_gids[i]);
}
s = smartlist_join_strings(elts, " ", 0, NULL);
log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Supplementary groups are: %s",s);
- error:
tor_free(s);
- SMARTLIST_FOREACH(elts, char *, cp,
- {
- tor_free(cp);
- });
+ SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
tor_free(sup_gids);
@@ -1464,6 +1515,58 @@ switch_id(const char *user)
#endif
}
+/* We only use the linux prctl for now. There is no Win32 support; this may
+ * also work on various BSD systems and Mac OS X - send testing feedback!
+ *
+ * On recent Gnu/Linux kernels it is possible to create a system-wide policy
+ * that will prevent non-root processes from attaching to other processes
+ * unless they are the parent process; thus gdb can attach to programs that
+ * they execute but they cannot attach to other processes running as the same
+ * user. The system wide policy may be set with the sysctl
+ * kernel.yama.ptrace_scope or by inspecting
+ * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04.
+ *
+ * This ptrace scope will be ignored on Gnu/Linux for users with
+ * CAP_SYS_PTRACE and so it is very likely that root will still be able to
+ * attach to the Tor process.
+ */
+/** Attempt to disable debugger attachment: return 1 on success, -1 on
+ * failure, and 0 if we don't know how to try on this platform. */
+int
+tor_disable_debugger_attach(void)
+{
+ int r, attempted;
+ r = -1;
+ attempted = 0;
+ log_debug(LD_CONFIG,
+ "Attemping to disable debugger attachment to Tor for "
+ "unprivileged users.");
+#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && defined(HAVE_PRCTL)
+#ifdef PR_SET_DUMPABLE
+ attempted = 1;
+ r = prctl(PR_SET_DUMPABLE, 0);
+#endif
+#endif
+#if defined(__APPLE__) && defined(PT_DENY_ATTACH)
+ if (r < 0) {
+ attempted = 1;
+ r = ptrace(PT_DENY_ATTACH, 0, 0, 0);
+ }
+#endif
+
+ // XXX: TODO - Mac OS X has dtrace and this may be disabled.
+ // XXX: TODO - Windows probably has something similar
+ if (r == 0 && attempted) {
+ log_debug(LD_CONFIG,"Debugger attachment disabled for "
+ "unprivileged users.");
+ return 1;
+ } else if (attempted) {
+ log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s",
+ strerror(errno));
+ }
+ return r;
+}
+
#ifdef HAVE_PWD_H
/** Allocate and return a string containing the home directory for the
* user <b>username</b>. Only works on posix-like systems. */
@@ -1520,6 +1623,42 @@ get_parent_directory(char *fname)
return -1;
}
+/** Expand possibly relative path <b>fname</b> to an absolute path.
+ * Return a newly allocated string, possibly equal to <b>fname</b>. */
+char *
+make_path_absolute(char *fname)
+{
+#ifdef WINDOWS
+ char *absfname_malloced = _fullpath(NULL, fname, 1);
+
+ /* We don't want to assume that tor_free can free a string allocated
+ * with malloc. On failure, return fname (it's better than nothing). */
+ char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname);
+ if (absfname_malloced) free(absfname_malloced);
+
+ return absfname;
+#else
+ char path[PATH_MAX+1];
+ char *absfname = NULL;
+
+ tor_assert(fname);
+
+ if (fname[0] == '/') {
+ absfname = tor_strdup(fname);
+ } else {
+ if (getcwd(path, PATH_MAX) != NULL) {
+ tor_asprintf(&absfname, "%s/%s", path, fname);
+ } else {
+ /* If getcwd failed, the best we can do here is keep using the
+ * relative path. (Perhaps / isn't readable by this UID/GID.) */
+ absfname = tor_strdup(fname);
+ }
+ }
+
+ return absfname;
+#endif
+}
+
/** Set *addr to the IP address (in dotted-quad notation) stored in c.
* Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr),
* but works on Windows and Solaris.)
@@ -1577,7 +1716,7 @@ tor_inet_ntop(int af, const void *src, char *dst, size_t len)
addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
}
- if (strlen(buf) > len)
+ if ((strlen(buf) + 1) > len) /* +1 for \0 */
return NULL;
strlcpy(dst, buf, len);
return dst;
@@ -1618,7 +1757,7 @@ tor_inet_ntop(int af, const void *src, char *dst, size_t len)
}
}
*cp = '\0';
- if (strlen(buf) > len)
+ if ((strlen(buf) + 1) > len) /* +1 for \0 */
return NULL;
strlcpy(dst, buf, len);
return dst;
@@ -1678,24 +1817,30 @@ tor_inet_pton(int af, const char *src, void *dst)
return 0;
if (TOR_ISXDIGIT(*src)) {
char *next;
+ ssize_t len;
long r = strtol(src, &next, 16);
- if (next > 4+src)
- return 0;
- if (next == src)
- return 0;
- if (r<0 || r>65536)
+ tor_assert(next != NULL);
+ tor_assert(next != src);
+
+ len = *next == '\0' ? eow - src : next - src;
+ if (len > 4)
return 0;
+ if (len > 1 && !TOR_ISXDIGIT(src[1]))
+ return 0; /* 0x is not valid */
+ tor_assert(r >= 0);
+ tor_assert(r < 65536);
words[i++] = (uint16_t)r;
setWords++;
src = next;
if (*src != ':' && src != eow)
return 0;
++src;
- } else if (*src == ':' && i > 0 && gapPos==-1) {
+ } else if (*src == ':' && i > 0 && gapPos == -1) {
gapPos = i;
++src;
- } else if (*src == ':' && i == 0 && src[1] == ':' && gapPos==-1) {
+ } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
+ gapPos == -1) {
gapPos = i;
src += 2;
} else {
@@ -1995,6 +2140,52 @@ spawn_exit(void)
#endif
}
+/** Implementation logic for compute_num_cpus(). */
+static int
+compute_num_cpus_impl(void)
+{
+#ifdef MS_WINDOWS
+ SYSTEM_INFO info;
+ memset(&info, 0, sizeof(info));
+ GetSystemInfo(&info);
+ if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX)
+ return (int)info.dwNumberOfProcessors;
+ else
+ return -1;
+#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
+ long cpus = sysconf(_SC_NPROCESSORS_CONF);
+ if (cpus >= 1 && cpus < INT_MAX)
+ return (int)cpus;
+ else
+ return -1;
+#else
+ return -1;
+#endif
+}
+
+#define MAX_DETECTABLE_CPUS 16
+
+/** Return how many CPUs we are running with. We assume that nobody is
+ * using hot-swappable CPUs, so we don't recompute this after the first
+ * time. Return -1 if we don't know how to tell the number of CPUs on this
+ * system.
+ */
+int
+compute_num_cpus(void)
+{
+ static int num_cpus = -2;
+ if (num_cpus == -2) {
+ num_cpus = compute_num_cpus_impl();
+ tor_assert(num_cpus != -2);
+ if (num_cpus > MAX_DETECTABLE_CPUS)
+ log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I "
+ "will not autodetect any more than %d, though. If you "
+ "want to configure more, set NumCPUs in your torrc",
+ num_cpus, MAX_DETECTABLE_CPUS);
+ }
+ return num_cpus;
+}
+
/** Set *timeval to the current time of day. On error, log and terminate.
* (Same as gettimeofday(timeval,NULL), but never returns -1.)
*/
diff --git a/src/common/compat.h b/src/common/compat.h
index d2f1fd1295..5bf12cdf89 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -9,8 +9,12 @@
#include "orconfig.h"
#include "torint.h"
#ifdef MS_WINDOWS
+#ifndef WIN32_WINNT
#define WIN32_WINNT 0x400
+#endif
+#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
+#endif
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER) && (_MSC_VER < 1300)
#include <winsock.h>
@@ -41,9 +45,6 @@
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -51,6 +52,8 @@
#include <netinet6/in6.h>
#endif
+#include <stdio.h>
+
#if defined (WINCE)
#include <fcntl.h>
#include <io.h>
@@ -132,7 +135,6 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
/* GCC has several useful attributes. */
#if defined(__GNUC__) && __GNUC__ >= 3
#define ATTR_NORETURN __attribute__((noreturn))
-#define ATTR_PURE __attribute__((pure))
#define ATTR_CONST __attribute__((const))
#define ATTR_MALLOC __attribute__((malloc))
#define ATTR_NORETURN __attribute__((noreturn))
@@ -165,7 +167,6 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define PREDICT_UNLIKELY(exp) __builtin_expect(!!(exp), 0)
#else
#define ATTR_NORETURN
-#define ATTR_PURE
#define ATTR_CONST
#define ATTR_MALLOC
#define ATTR_NORETURN
@@ -268,9 +269,9 @@ int tor_asprintf(char **strp, const char *fmt, ...)
int tor_vasprintf(char **strp, const char *fmt, va_list args);
const void *tor_memmem(const void *haystack, size_t hlen, const void *needle,
- size_t nlen) ATTR_PURE ATTR_NONNULL((1,3));
+ size_t nlen) ATTR_NONNULL((1,3));
static const void *tor_memstr(const void *haystack, size_t hlen,
- const char *needle) ATTR_PURE ATTR_NONNULL((1,3));
+ const char *needle) ATTR_NONNULL((1,3));
static INLINE const void *
tor_memstr(const void *haystack, size_t hlen, const char *needle)
{
@@ -371,6 +372,9 @@ struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
#endif
/* ===== File compatibility */
+int tor_open_cloexec(const char *path, int flags, unsigned mode);
+FILE *tor_fopen_cloexec(const char *path, const char *mode);
+
int replace_file(const char *from, const char *to);
int touch_file(const char *fname);
@@ -540,9 +544,9 @@ long tor_weak_random(void);
/* ===== OS compatibility */
const char *get_uname(void);
-uint16_t get_uint16(const void *cp) ATTR_PURE ATTR_NONNULL((1));
-uint32_t get_uint32(const void *cp) ATTR_PURE ATTR_NONNULL((1));
-uint64_t get_uint64(const void *cp) ATTR_PURE ATTR_NONNULL((1));
+uint16_t get_uint16(const void *cp) ATTR_NONNULL((1));
+uint32_t get_uint32(const void *cp) ATTR_NONNULL((1));
+uint64_t get_uint64(const void *cp) ATTR_NONNULL((1));
void set_uint16(void *cp, uint16_t v) ATTR_NONNULL((1));
void set_uint32(void *cp, uint32_t v) ATTR_NONNULL((1));
void set_uint64(void *cp, uint64_t v) ATTR_NONNULL((1));
@@ -560,12 +564,14 @@ set_uint8(void *cp, uint8_t v)
typedef unsigned long rlim_t;
#endif
int set_max_file_descriptors(rlim_t limit, int *max);
+int tor_disable_debugger_attach(void);
int switch_id(const char *user);
#ifdef HAVE_PWD_H
char *get_user_homedir(const char *username);
#endif
int get_parent_directory(char *fname);
+char *make_path_absolute(char *fname);
int spawn_func(void (*func)(void *), void *data);
void spawn_exit(void) ATTR_NORETURN;
@@ -581,6 +587,8 @@ void spawn_exit(void) ATTR_NORETURN;
#undef TOR_IS_MULTITHREADED
#endif
+int compute_num_cpus(void);
+
/* Because we use threads instead of processes on most platforms (Windows,
* Linux, etc), we need locking for them. On platforms with poor thread
* support or broken gethostbyname_r, these functions are no-ops. */
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index ddb2da68aa..0cedef8d5e 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -19,6 +19,10 @@
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
+#include <event2/thread.h>
+#ifdef USE_BUFFEREVENTS
+#include <event2/bufferevent.h>
+#endif
#else
#include <event.h>
#endif
@@ -163,11 +167,24 @@ struct event_base *the_event_base = NULL;
#endif
#endif
+#ifdef USE_BUFFEREVENTS
+static int using_iocp_bufferevents = 0;
+static void tor_libevent_set_tick_timeout(int msec_per_tick);
+
+int
+tor_libevent_using_iocp_bufferevents(void)
+{
+ return using_iocp_bufferevents;
+}
+#endif
+
/** Initialize the Libevent library and set up the event base. */
void
-tor_libevent_initialize(void)
+tor_libevent_initialize(tor_libevent_cfg *torcfg)
{
tor_assert(the_event_base == NULL);
+ /* some paths below don't use torcfg, so avoid unused variable warnings */
+ (void)torcfg;
#ifdef __APPLE__
if (MACOSX_KQUEUE_IS_BROKEN ||
@@ -178,17 +195,65 @@ tor_libevent_initialize(void)
#ifdef HAVE_EVENT2_EVENT_H
{
- struct event_config *cfg = event_config_new();
+ int attempts = 0;
+ int using_threads;
+ struct event_config *cfg;
+
+ retry:
+ ++attempts;
+ using_threads = 0;
+ cfg = event_config_new();
tor_assert(cfg);
- /* In 0.2.2, we don't use locking at all. Telling Libevent not to try to
- * turn it on can avoid a needless socketpair() attempt.
- */
- event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK);
+#if defined(MS_WINDOWS) && defined(USE_BUFFEREVENTS)
+ if (! torcfg->disable_iocp) {
+ evthread_use_windows_threads();
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
+ using_iocp_bufferevents = 1;
+ using_threads = 1;
+ } else {
+ using_iocp_bufferevents = 0;
+ }
+#endif
+
+ if (!using_threads) {
+ /* Telling Libevent not to try to turn locking on can avoid a needless
+ * socketpair() attempt. */
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK);
+ }
+
+#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
+ if (torcfg->num_cpus > 0)
+ event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
+#endif
+
+#if LIBEVENT_VERSION_NUMBER >= V(2,0,9)
+ /* We can enable changelist support with epoll, since we don't give
+ * Libevent any dup'd fds. This lets us avoid some syscalls. */
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
+#endif
the_event_base = event_base_new_with_config(cfg);
event_config_free(cfg);
+
+ if (using_threads && the_event_base == NULL && attempts < 2) {
+ /* This could be a socketpair() failure, which can happen sometimes on
+ * windows boxes with obnoxious firewall rules. Downgrade and try
+ * again. */
+#if defined(MS_WINDOWS) && defined(USE_BUFFEREVENTS)
+ if (torcfg->disable_iocp == 0) {
+ log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again "
+ "with IOCP disabled.");
+ } else
+#endif
+ {
+ log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again.");
+ }
+
+ torcfg->disable_iocp = 1;
+ goto retry;
+ }
}
#else
the_event_base = event_init();
@@ -212,6 +277,10 @@ tor_libevent_initialize(void)
"You have a *VERY* old version of libevent. It is likely to be buggy; "
"please build Tor with a more recent version.");
#endif
+
+#ifdef USE_BUFFEREVENTS
+ tor_libevent_set_tick_timeout(torcfg->msec_per_tick);
+#endif
}
/** Return the current Libevent event base that we're set up to use. */
@@ -257,7 +326,7 @@ tor_decode_libevent_version(const char *v)
/* Try the new preferred "1.4.11-stable" format.
* Also accept "1.4.14b-stable". */
- fields = sscanf(v, "%u.%u.%u%c%c", &major, &minor, &patchlevel, &c, &e);
+ fields = tor_sscanf(v, "%u.%u.%u%c%c", &major, &minor, &patchlevel, &c, &e);
if (fields == 3 ||
((fields == 4 || fields == 5 ) && (c == '-' || c == '_')) ||
(fields == 5 && TOR_ISALPHA(c) && (e == '-' || e == '_'))) {
@@ -265,7 +334,7 @@ tor_decode_libevent_version(const char *v)
}
/* Try the old "1.3e" format. */
- fields = sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra);
+ fields = tor_sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra);
if (fields == 3 && TOR_ISALPHA(c)) {
return V_OLD(major, minor, c);
} else if (fields == 2) {
@@ -569,3 +638,55 @@ periodic_timer_free(periodic_timer_t *timer)
tor_free(timer);
}
+#ifdef USE_BUFFEREVENTS
+static const struct timeval *one_tick = NULL;
+/**
+ * Return a special timeout to be passed whenever libevent's O(1) timeout
+ * implementation should be used. Only use this when the timer is supposed
+ * to fire after msec_per_tick ticks have elapsed.
+*/
+const struct timeval *
+tor_libevent_get_one_tick_timeout(void)
+{
+ tor_assert(one_tick);
+ return one_tick;
+}
+
+/** Initialize the common timeout that we'll use to refill the buckets every
+ * time a tick elapses. */
+static void
+tor_libevent_set_tick_timeout(int msec_per_tick)
+{
+ struct event_base *base = tor_libevent_get_base();
+ struct timeval tv;
+
+ tor_assert(! one_tick);
+ tv.tv_sec = msec_per_tick / 1000;
+ tv.tv_usec = (msec_per_tick % 1000) * 1000;
+ one_tick = event_base_init_common_timeout(base, &tv);
+}
+
+static struct bufferevent *
+tor_get_root_bufferevent(struct bufferevent *bev)
+{
+ struct bufferevent *u;
+ while ((u = bufferevent_get_underlying(bev)) != NULL)
+ bev = u;
+ return bev;
+}
+
+int
+tor_set_bufferevent_rate_limit(struct bufferevent *bev,
+ struct ev_token_bucket_cfg *cfg)
+{
+ return bufferevent_set_rate_limit(tor_get_root_bufferevent(bev), cfg);
+}
+
+int
+tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
+ struct bufferevent_rate_limit_group *g)
+{
+ return bufferevent_add_to_rate_limit_group(tor_get_root_bufferevent(bev), g);
+}
+#endif
+
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 89b256396b..0247297177 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -8,6 +8,11 @@
struct event;
struct event_base;
+#ifdef USE_BUFFEREVENTS
+struct bufferevent;
+struct ev_token_bucket_cfg;
+struct bufferevent_rate_limit_group;
+#endif
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/util.h>
@@ -54,7 +59,13 @@ struct timeval;
int tor_event_base_loopexit(struct event_base *base, struct timeval *tv);
#endif
-void tor_libevent_initialize(void);
+typedef struct tor_libevent_cfg {
+ int disable_iocp;
+ int num_cpus;
+ int msec_per_tick;
+} tor_libevent_cfg;
+
+void tor_libevent_initialize(tor_libevent_cfg *cfg);
struct event_base *tor_libevent_get_base(void);
const char *tor_libevent_get_method(void);
void tor_check_libevent_version(const char *m, int server,
@@ -62,5 +73,14 @@ void tor_check_libevent_version(const char *m, int server,
void tor_check_libevent_header_compatibility(void);
const char *tor_libevent_get_version_str(void);
+#ifdef USE_BUFFEREVENTS
+const struct timeval *tor_libevent_get_one_tick_timeout(void);
+int tor_libevent_using_iocp_bufferevents(void);
+int tor_set_bufferevent_rate_limit(struct bufferevent *bev,
+ struct ev_token_bucket_cfg *cfg);
+int tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
+ struct bufferevent_rate_limit_group *g);
+#endif
+
#endif
diff --git a/src/common/container.c b/src/common/container.c
index 5f53222374..31cc6c5a6c 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -296,7 +296,6 @@ smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2)
/** Remove the <b>idx</b>th element of sl; if idx is not the last
* element, swap the last element of sl into the <b>idx</b>th space.
- * Return the old value of the <b>idx</b>th element.
*/
void
smartlist_del(smartlist_t *sl, int idx)
diff --git a/src/common/container.h b/src/common/container.h
index 4a6eba789d..fe071cc1b3 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -35,19 +35,14 @@ void smartlist_remove(smartlist_t *sl, const void *element);
void *smartlist_pop_last(smartlist_t *sl);
void smartlist_reverse(smartlist_t *sl);
void smartlist_string_remove(smartlist_t *sl, const char *element);
-int smartlist_isin(const smartlist_t *sl, const void *element) ATTR_PURE;
-int smartlist_string_isin(const smartlist_t *sl, const char *element)
- ATTR_PURE;
-int smartlist_string_pos(const smartlist_t *, const char *elt) ATTR_PURE;
-int smartlist_string_isin_case(const smartlist_t *sl, const char *element)
- ATTR_PURE;
-int smartlist_string_num_isin(const smartlist_t *sl, int num) ATTR_PURE;
-int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2)
- ATTR_PURE;
-int smartlist_digest_isin(const smartlist_t *sl, const char *element)
- ATTR_PURE;
-int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2)
- ATTR_PURE;
+int smartlist_isin(const smartlist_t *sl, const void *element);
+int smartlist_string_isin(const smartlist_t *sl, const char *element);
+int smartlist_string_pos(const smartlist_t *, const char *elt);
+int smartlist_string_isin_case(const smartlist_t *sl, const char *element);
+int smartlist_string_num_isin(const smartlist_t *sl, int num);
+int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2);
+int smartlist_digest_isin(const smartlist_t *sl, const char *element);
+int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
@@ -55,14 +50,14 @@ void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
#ifdef DEBUG_SMARTLIST
/** Return the number of items in sl.
*/
-static INLINE int smartlist_len(const smartlist_t *sl) ATTR_PURE;
+static INLINE int smartlist_len(const smartlist_t *sl);
static INLINE int smartlist_len(const smartlist_t *sl) {
tor_assert(sl);
return (sl)->num_used;
}
/** Return the <b>idx</b>th element of sl.
*/
-static INLINE void *smartlist_get(const smartlist_t *sl, int idx) ATTR_PURE;
+static INLINE void *smartlist_get(const smartlist_t *sl, int idx);
static INLINE void *smartlist_get(const smartlist_t *sl, int idx) {
tor_assert(sl);
tor_assert(idx>=0);
@@ -114,8 +109,7 @@ void smartlist_uniq_strings(smartlist_t *sl);
void smartlist_uniq_digests(smartlist_t *sl);
void smartlist_uniq_digests256(smartlist_t *sl);
void *smartlist_bsearch(smartlist_t *sl, const void *key,
- int (*compare)(const void *key, const void **member))
- ATTR_PURE;
+ int (*compare)(const void *key, const void **member));
int smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
int (*compare)(const void *key, const void **member),
int *found_out);
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 235bd88ffa..e377b01d41 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -13,8 +13,12 @@
#include "orconfig.h"
#ifdef MS_WINDOWS
+#ifndef WIN32_WINNT
#define WIN32_WINNT 0x400
+#endif
+#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
+#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>
@@ -56,18 +60,19 @@
#include "container.h"
#include "compat.h"
-#if OPENSSL_VERSION_NUMBER < 0x00907000l
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
#error "We require OpenSSL >= 0.9.7"
#endif
-#include <openssl/engine.h>
-
#ifdef ANDROID
/* Android's OpenSSL seems to have removed all of its Engine support. */
#define DISABLE_ENGINES
#endif
-#if OPENSSL_VERSION_NUMBER < 0x00908000l
+/** Longest recognized */
+#define MAX_DNS_LABEL_SIZE 63
+
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
/** @{ */
/** On OpenSSL versions before 0.9.8, there is no working SHA256
* implementation, so we use Tom St Denis's nice speedy one, slightly adapted
@@ -274,6 +279,10 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
} else {
log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
}
+
+ evaluate_evp_for_aes(-1);
+ evaluate_ctr_for_aes();
+
return crypto_seed_rng(1);
}
return 0;
@@ -286,37 +295,6 @@ crypto_thread_cleanup(void)
ERR_remove_state(0);
}
-/** Uninitialize the crypto library. Return 0 on success, -1 on failure.
- */
-int
-crypto_global_cleanup(void)
-{
- EVP_cleanup();
- ERR_remove_state(0);
- ERR_free_strings();
-
-#ifndef DISABLE_ENGINES
- ENGINE_cleanup();
-#endif
-
- CONF_modules_unload(1);
- CRYPTO_cleanup_all_ex_data();
-#ifdef TOR_IS_MULTITHREADED
- if (_n_openssl_mutexes) {
- int n = _n_openssl_mutexes;
- tor_mutex_t **ms = _openssl_mutexes;
- int i;
- _openssl_mutexes = NULL;
- _n_openssl_mutexes = 0;
- for (i=0;i<n;++i) {
- tor_mutex_free(ms[i]);
- }
- tor_free(ms);
- }
-#endif
- return 0;
-}
-
/** used by tortls.c: wrap an RSA* in a crypto_pk_env_t. */
crypto_pk_env_t *
_crypto_new_pk_env_rsa(RSA *rsa)
@@ -475,7 +453,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_env_t *env, int bits)
if (env->key)
RSA_free(env->key);
-#if OPENSSL_VERSION_NUMBER < 0x00908000l
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
/* In OpenSSL 0.9.7, RSA_generate_key is all we have. */
env->key = RSA_generate_key(bits, 65537, NULL, NULL);
#else
@@ -948,7 +926,7 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
log_warn(LD_BUG, "couldn't compute digest");
return -1;
}
- buflen = crypto_pk_keysize(env)+1;
+ buflen = crypto_pk_keysize(env);
buf = tor_malloc(buflen);
r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
if (r != DIGEST_LEN) {
@@ -1133,8 +1111,8 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
warnOnFailure);
}
- buf = tor_malloc(pkeylen+1);
- outlen = crypto_pk_private_decrypt(env,buf,pkeylen+1,from,pkeylen,padding,
+ buf = tor_malloc(pkeylen);
+ outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding,
warnOnFailure);
if (outlen<0) {
log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
@@ -1202,9 +1180,6 @@ crypto_pk_asn1_decode(const char *str, size_t len)
{
RSA *rsa;
unsigned char *buf;
- /* This ifdef suppresses a type warning. Take out the first case once
- * everybody is using OpenSSL 0.9.7 or later.
- */
const unsigned char *cp;
cp = buf = tor_malloc(len);
memcpy(buf,str,len);
@@ -1245,6 +1220,32 @@ crypto_pk_get_digest(crypto_pk_env_t *pk, char *digest_out)
return 0;
}
+/** Compute all digests of the DER encoding of <b>pk</b>, and store them
+ * in <b>digests_out</b>. Return 0 on success, -1 on failure. */
+int
+crypto_pk_get_all_digests(crypto_pk_env_t *pk, digests_t *digests_out)
+{
+ unsigned char *buf, *bufp;
+ int len;
+
+ len = i2d_RSAPublicKey(pk->key, NULL);
+ if (len < 0)
+ return -1;
+ buf = bufp = tor_malloc(len+1);
+ len = i2d_RSAPublicKey(pk->key, &bufp);
+ if (len < 0) {
+ crypto_log_errors(LOG_WARN,"encoding public key");
+ tor_free(buf);
+ return -1;
+ }
+ if (crypto_digest_all(digests_out, (char*)buf, len) < 0) {
+ tor_free(buf);
+ return -1;
+ }
+ tor_free(buf);
+ return 0;
+}
+
/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces
* every four spaces. */
/* static */ void
@@ -1714,8 +1715,79 @@ crypto_hmac_sha1(char *hmac_out,
(unsigned char*)hmac_out, NULL);
}
+/** 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 DIGEST_LEN-byte result
+ * in <b>hmac_out</b>.
+ */
+void
+crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len)
+{
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,8)
+ /* 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);
+#else
+ /* OpenSSL doesn't have an EVP implementation for SHA256. We'll need
+ to do HMAC on our own.
+
+ HMAC isn't so hard: To compute HMAC(key, msg):
+ 1. If len(key) > blocksize, key = H(key).
+ 2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes.
+ 3. let ipad = key xor 0x363636363636....36
+ let opad = key xor 0x5c5c5c5c5c5c....5c
+ The result is H(opad | H( ipad | msg ) )
+ */
+#define BLOCKSIZE 64
+#define DIGESTSIZE 32
+ uint8_t k[BLOCKSIZE];
+ uint8_t pad[BLOCKSIZE];
+ uint8_t d[DIGESTSIZE];
+ int i;
+ SHA256_CTX st;
+
+ tor_assert(key_len < INT_MAX);
+ tor_assert(msg_len < INT_MAX);
+
+ if (key_len <= BLOCKSIZE) {
+ memset(k, 0, sizeof(k));
+ memcpy(k, key, key_len); /* not time invariant in key_len */
+ } else {
+ SHA256((const uint8_t *)key, key_len, k);
+ memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE);
+ }
+ for (i = 0; i < BLOCKSIZE; ++i)
+ pad[i] = k[i] ^ 0x36;
+ SHA256_Init(&st);
+ SHA256_Update(&st, pad, BLOCKSIZE);
+ SHA256_Update(&st, (uint8_t*)msg, msg_len);
+ SHA256_Final(d, &st);
+
+ for (i = 0; i < BLOCKSIZE; ++i)
+ pad[i] = k[i] ^ 0x5c;
+ SHA256_Init(&st);
+ SHA256_Update(&st, pad, BLOCKSIZE);
+ SHA256_Update(&st, d, DIGESTSIZE);
+ SHA256_Final((uint8_t*)hmac_out, &st);
+
+ /* Now clear everything. */
+ memset(k, 0, sizeof(k));
+ memset(pad, 0, sizeof(pad));
+ memset(d, 0, sizeof(d));
+ memset(&st, 0, sizeof(st));
+#undef BLOCKSIZE
+#undef DIGESTSIZE
+#endif
+}
+
/* DH */
+/** Our DH 'g' parameter */
+#define DH_GENERATOR 2
+
/** Shared P parameter for our circuit-crypto DH key exchanges. */
static BIGNUM *dh_param_p = NULL;
/** Shared P parameter for our TLS DH key exchanges. */
@@ -1723,49 +1795,327 @@ static BIGNUM *dh_param_p_tls = NULL;
/** Shared G parameter for our DH key exchanges. */
static BIGNUM *dh_param_g = NULL;
+/** Generate and return a reasonable and safe DH parameter p. */
+static BIGNUM *
+crypto_generate_dynamic_dh_modulus(void)
+{
+ BIGNUM *dynamic_dh_modulus;
+ DH *dh_parameters;
+ int r, dh_codes;
+ char *s;
+
+ dynamic_dh_modulus = BN_new();
+ tor_assert(dynamic_dh_modulus);
+
+ dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL);
+ tor_assert(dh_parameters);
+
+ r = DH_check(dh_parameters, &dh_codes);
+ tor_assert(r && !dh_codes);
+
+ BN_copy(dynamic_dh_modulus, dh_parameters->p);
+ tor_assert(dynamic_dh_modulus);
+
+ DH_free(dh_parameters);
+
+ { /* log the dynamic DH modulus: */
+ s = BN_bn2hex(dynamic_dh_modulus);
+ tor_assert(s);
+ log_info(LD_OR, "Dynamic DH modulus generated: [%s]", s);
+ OPENSSL_free(s);
+ }
+
+ return dynamic_dh_modulus;
+}
+
+/** Store our dynamic DH modulus (and its group parameters) to
+ <b>fname</b> for future use. */
+static int
+crypto_store_dynamic_dh_modulus(const char *fname)
+{
+ int len, new_len;
+ DH *dh = NULL;
+ unsigned char *dh_string_repr = NULL, *cp = NULL;
+ char *base64_encoded_dh = NULL;
+ char *file_string = NULL;
+ int retval = -1;
+ static const char file_header[] = "# This file contains stored Diffie-"
+ "Hellman parameters for future use.\n# You *do not* need to edit this "
+ "file.\n\n";
+
+ tor_assert(fname);
+
+ if (!dh_param_p_tls) {
+ log_info(LD_CRYPTO, "Tried to store a DH modulus that does not exist.");
+ goto done;
+ }
+
+ if (!(dh = DH_new()))
+ goto done;
+ if (!(dh->p = BN_dup(dh_param_p_tls)))
+ goto done;
+ if (!(dh->g = BN_new()))
+ goto done;
+ if (!BN_set_word(dh->g, DH_GENERATOR))
+ goto done;
+
+ len = i2d_DHparams(dh, NULL);
+ if (len < 0) {
+ log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (1).");
+ goto done;
+ }
+
+ cp = dh_string_repr = tor_malloc_zero(len+1);
+ len = i2d_DHparams(dh, &cp);
+ if ((len < 0) || ((cp - dh_string_repr) != len)) {
+ log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2).");
+ goto done;
+ }
+
+ base64_encoded_dh = tor_malloc_zero(len * 2); /* should be enough */
+ new_len = base64_encode(base64_encoded_dh, len * 2,
+ (char *)dh_string_repr, len);
+ if (new_len < 0) {
+ log_warn(LD_CRYPTO, "Error occured while base64-encoding DH modulus.");
+ goto done;
+ }
+
+ /* concatenate file header and the dh parameters blob */
+ new_len = tor_asprintf(&file_string, "%s%s", file_header, base64_encoded_dh);
+
+ /* write to file */
+ if (write_bytes_to_new_file(fname, file_string, new_len, 0) < 0) {
+ log_info(LD_CRYPTO, "'%s' was already occupied.", fname);
+ goto done;
+ }
+
+ retval = 0;
+
+ done:
+ if (dh)
+ DH_free(dh);
+ tor_free(dh_string_repr);
+ tor_free(base64_encoded_dh);
+ tor_free(file_string);
+
+ return retval;
+}
+
+/** Return the dynamic DH modulus stored in <b>fname</b>. If there is no
+ dynamic DH modulus stored in <b>fname</b>, return NULL. */
+static BIGNUM *
+crypto_get_stored_dynamic_dh_modulus(const char *fname)
+{
+ int retval;
+ char *contents = NULL;
+ const char *contents_tmp = NULL;
+ int dh_codes;
+ char *fname_new = NULL;
+ DH *stored_dh = NULL;
+ BIGNUM *dynamic_dh_modulus = NULL;
+ int length = 0;
+ unsigned char *base64_decoded_dh = NULL;
+ const unsigned char *cp = NULL;
+
+ tor_assert(fname);
+
+ contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
+ if (!contents) {
+ log_info(LD_CRYPTO, "Could not open file '%s'", fname);
+ goto done; /*usually means that ENOENT. don't try to move file to broken.*/
+ }
+
+ /* skip the file header */
+ contents_tmp = eat_whitespace(contents);
+ if (!*contents_tmp) {
+ log_warn(LD_CRYPTO, "Stored dynamic DH modulus file "
+ "seems corrupted (eat_whitespace).");
+ goto err;
+ }
+
+ /* 'fname' contains the DH parameters stored in base64-ed DER
+ * format. We are only interested in the DH modulus.
+ * NOTE: We allocate more storage here than we need. Since we're already
+ * doing that, we can also add 1 byte extra to appease Coverity's
+ * scanner. */
+
+ cp = base64_decoded_dh = tor_malloc_zero(strlen(contents_tmp) + 1);
+ length = base64_decode((char *)base64_decoded_dh, strlen(contents_tmp),
+ contents_tmp, strlen(contents_tmp));
+ if (length < 0) {
+ log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (base64).");
+ goto err;
+ }
+
+ stored_dh = d2i_DHparams(NULL, &cp, length);
+ if ((!stored_dh) || (cp - base64_decoded_dh != length)) {
+ log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (d2i).");
+ goto err;
+ }
+
+ { /* check the cryptographic qualities of the stored dynamic DH modulus: */
+ retval = DH_check(stored_dh, &dh_codes);
+ if (!retval || dh_codes) {
+ log_warn(LD_CRYPTO, "Stored dynamic DH modulus is not a safe prime.");
+ goto err;
+ }
+
+ retval = DH_size(stored_dh);
+ if (retval < DH_BYTES) {
+ log_warn(LD_CRYPTO, "Stored dynamic DH modulus is smaller "
+ "than '%d' bits.", DH_BYTES*8);
+ goto err;
+ }
+
+ if (!BN_is_word(stored_dh->g, 2)) {
+ log_warn(LD_CRYPTO, "Stored dynamic DH parameters do not use '2' "
+ "as the group generator.");
+ goto err;
+ }
+ }
+
+ { /* log the dynamic DH modulus: */
+ char *s = BN_bn2hex(stored_dh->p);
+ tor_assert(s);
+ log_info(LD_OR, "Found stored dynamic DH modulus: [%s]", s);
+ OPENSSL_free(s);
+ }
+
+ goto done;
+
+ err:
+
+ { /* move broken prime to $filename.broken */
+ fname_new = tor_malloc(strlen(fname) + 8);
+
+ /* no can do if these functions return error */
+ strlcpy(fname_new, fname, strlen(fname) + 8);
+ strlcat(fname_new, ".broken", strlen(fname) + 8);
+
+ log_warn(LD_CRYPTO, "Moving broken dynamic DH prime to '%s'.", fname_new);
+
+ if (replace_file(fname, fname_new))
+ log_notice(LD_CRYPTO, "Error while moving '%s' to '%s'.",
+ fname, fname_new);
+
+ tor_free(fname_new);
+ }
+
+ if (stored_dh) {
+ DH_free(stored_dh);
+ stored_dh = NULL;
+ }
+
+ done:
+ tor_free(contents);
+ tor_free(base64_decoded_dh);
+
+ if (stored_dh) {
+ dynamic_dh_modulus = BN_dup(stored_dh->p);
+ DH_free(stored_dh);
+ }
+
+ return dynamic_dh_modulus;
+}
+
+/** Set the global TLS Diffie-Hellman modulus.
+ * If <b>dynamic_dh_modulus_fname</b> is set, try to read a dynamic DH modulus
+ * off it and use it as the DH modulus. If that's not possible,
+ * generate a new dynamic DH modulus.
+ * If <b>dynamic_dh_modulus_fname</b> is NULL, use the Apache mod_ssl DH
+ * modulus. */
+void
+crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname)
+{
+ BIGNUM *tls_prime = NULL;
+ int store_dh_prime_afterwards = 0;
+ int r;
+
+ /* If the space is occupied, free the previous TLS DH prime */
+ if (dh_param_p_tls) {
+ BN_free(dh_param_p_tls);
+ dh_param_p_tls = NULL;
+ }
+
+ if (dynamic_dh_modulus_fname) { /* use dynamic DH modulus: */
+ log_info(LD_OR, "Using stored dynamic DH modulus.");
+ tls_prime = crypto_get_stored_dynamic_dh_modulus(dynamic_dh_modulus_fname);
+
+ if (!tls_prime) {
+ log_notice(LD_OR, "Generating fresh dynamic DH modulus. "
+ "This might take a while...");
+ tls_prime = crypto_generate_dynamic_dh_modulus();
+
+ store_dh_prime_afterwards++;
+ }
+ } else { /* use the static DH prime modulus used by Apache in mod_ssl: */
+ tls_prime = BN_new();
+ tor_assert(tls_prime);
+
+ /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see
+ * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this
+ * prime.
+ */
+ r =BN_hex2bn(&tls_prime,
+ "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98"
+ "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A"
+ "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7"
+ "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68"
+ "B0E7393E0F24218EB3");
+ tor_assert(r);
+ }
+
+ tor_assert(tls_prime);
+
+ dh_param_p_tls = tls_prime;
+
+ if (store_dh_prime_afterwards)
+ /* save the new dynamic DH modulus to disk. */
+ if (crypto_store_dynamic_dh_modulus(dynamic_dh_modulus_fname)) {
+ log_notice(LD_CRYPTO, "Failed while storing dynamic DH modulus. "
+ "Make sure your data directory is sane.");
+ }
+}
+
/** Initialize dh_param_p and dh_param_g if they are not already
* set. */
static void
init_dh_param(void)
{
- BIGNUM *p, *p2, *g;
+ BIGNUM *circuit_dh_prime, *generator;
int r;
- if (dh_param_p && dh_param_g && dh_param_p_tls)
+ if (dh_param_p && dh_param_g)
return;
- p = BN_new();
- p2 = BN_new();
- g = BN_new();
- tor_assert(p);
- tor_assert(p2);
- tor_assert(g);
+ circuit_dh_prime = BN_new();
+ generator = BN_new();
+ tor_assert(circuit_dh_prime && generator);
+
+ /* Set our generator for all DH parameters */
+ r = BN_set_word(generator, DH_GENERATOR);
+ tor_assert(r);
/* This is from rfc2409, section 6.2. It's a safe prime, and
supposedly it equals:
2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
*/
- r = BN_hex2bn(&p,
+ r = BN_hex2bn(&circuit_dh_prime,
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
"49286651ECE65381FFFFFFFFFFFFFFFF");
tor_assert(r);
- /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see
- * modules/ssl/ssl_engine_dh.c */
- r = BN_hex2bn(&p2,
- "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98"
- "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A"
- "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7"
- "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68"
- "B0E7393E0F24218EB3");
- tor_assert(r);
- r = BN_set_word(g, 2);
- tor_assert(r);
- dh_param_p = p;
- dh_param_p_tls = p2;
- dh_param_g = g;
+ /* Set the new values as the global DH parameters. */
+ dh_param_p = circuit_dh_prime;
+ dh_param_g = generator;
+
+ /* Ensure that we have TLS DH parameters set up, too, even if we're
+ going to change them soon. */
+ if (!dh_param_p_tls) {
+ crypto_set_tls_dh_prime(NULL);
+ }
}
/** Number of bits to use when choosing the x or y value in a Diffie-Hellman
@@ -2029,13 +2379,6 @@ crypto_dh_free(crypto_dh_env_t *dh)
* work for us too. */
#define ADD_ENTROPY 32
-/** True iff we should use OpenSSL's RAND_poll function to add entropy to its
- * pool.
- *
- * Use RAND_poll if OpenSSL is 0.9.6 release or later. (The "f" means
- *"release".) */
-#define HAVE_RAND_POLL (OPENSSL_VERSION_NUMBER >= 0x0090600fl)
-
/** True iff it's safe to use RAND_poll after setup.
*
* Versions of OpenSSL prior to 0.9.7k and 0.9.8c had a bug where RAND_poll
@@ -2043,9 +2386,9 @@ crypto_dh_free(crypto_dh_env_t *dh)
* that fd without checking whether it fit in the fd_set. Thus, if the
* system has not just been started up, it is unsafe to call */
#define RAND_POLL_IS_SAFE \
- ((OPENSSL_VERSION_NUMBER >= 0x009070afl && \
- OPENSSL_VERSION_NUMBER <= 0x00907fffl) || \
- (OPENSSL_VERSION_NUMBER >= 0x0090803fl))
+ ((OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,7,'j') && \
+ OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)) || \
+ OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
/** Set the seed of the weak RNG to a random value. */
static void
@@ -2079,8 +2422,7 @@ crypto_seed_rng(int startup)
size_t n;
#endif
-#if HAVE_RAND_POLL
- /* OpenSSL 0.9.6 adds a RAND_poll function that knows about more kinds of
+ /* OpenSSL has a RAND_poll function that knows about more kinds of
* entropy than we do. We'll try calling that, *and* calling our own entropy
* functions. If one succeeds, we'll accept the RNG as seeded. */
if (startup || RAND_POLL_IS_SAFE) {
@@ -2088,7 +2430,6 @@ crypto_seed_rng(int startup)
if (rand_poll_status == 0)
log_warn(LD_CRYPTO, "RAND_poll() failed.");
}
-#endif
#ifdef MS_WINDOWS
if (!provider_set) {
@@ -2214,9 +2555,12 @@ crypto_rand_double(void)
}
/** Generate and return a new random hostname starting with <b>prefix</b>,
- * ending with <b>suffix</b>, and containing no less than
+ * 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 between.
+ *
+ * Clip <b>max_rand_len</b> to MAX_DNS_LABEL_SIZE.
+ **/
char *
crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix,
const char *suffix)
@@ -2225,8 +2569,13 @@ crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix,
int randlen, rand_bytes_len;
size_t resultlen, prefixlen;
- tor_assert(max_rand_len >= min_rand_len);
+ if (max_rand_len > MAX_DNS_LABEL_SIZE)
+ max_rand_len = MAX_DNS_LABEL_SIZE;
+ if (min_rand_len > max_rand_len)
+ min_rand_len = max_rand_len;
+
randlen = min_rand_len + crypto_rand_int(max_rand_len - min_rand_len + 1);
+
prefixlen = strlen(prefix);
resultlen = prefixlen + strlen(suffix) + randlen + 16;
@@ -2737,5 +3086,44 @@ setup_openssl_threading(void)
return 0;
}
#endif
+
+/** Uninitialize the crypto library. Return 0 on success, -1 on failure.
+ */
+int
+crypto_global_cleanup(void)
+{
+ EVP_cleanup();
+ ERR_remove_state(0);
+ ERR_free_strings();
+
+ if (dh_param_p)
+ BN_free(dh_param_p);
+ if (dh_param_p_tls)
+ BN_free(dh_param_p_tls);
+ if (dh_param_g)
+ BN_free(dh_param_g);
+
+#ifndef DISABLE_ENGINES
+ ENGINE_cleanup();
+#endif
+
+ CONF_modules_unload(1);
+ CRYPTO_cleanup_all_ex_data();
+#ifdef TOR_IS_MULTITHREADED
+ if (_n_openssl_mutexes) {
+ int n = _n_openssl_mutexes;
+ tor_mutex_t **ms = _openssl_mutexes;
+ int i;
+ _openssl_mutexes = NULL;
+ _n_openssl_mutexes = 0;
+ for (i=0;i<n;++i) {
+ tor_mutex_free(ms[i]);
+ }
+ tor_free(ms);
+ }
+#endif
+ return 0;
+}
+
/** @} */
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 1a8c81f837..4783654445 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -16,6 +16,38 @@
#include <stdio.h>
#include "torint.h"
+/*
+ Macro to create an arbitrary OpenSSL version number as used by
+ OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard
+ to read.
+
+ Don't use this directly, instead use one of the other OPENSSL_V macros
+ below.
+
+ The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit
+ status.
+ */
+#define OPENSSL_VER(a,b,c,d,e) \
+ (((a)<<28) | \
+ ((b)<<20) | \
+ ((c)<<12) | \
+ ((d)<< 4) | \
+ (e))
+/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the
+ * version for the released version of 0.9.8j */
+#define OPENSSL_V(a,b,c,d) \
+ OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf)
+/** An openssl release number for the first release in the series. For
+ * example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL
+ * 1.0.0. */
+#define OPENSSL_V_NOPATCH(a,b,c) \
+ OPENSSL_VER((a),(b),(c),0,0xf)
+/** The first version that would occur for any alpha or beta in an openssl
+ * series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released
+ * 0.9.7, and less than any released 0.9.8. */
+#define OPENSSL_V_SERIES(a,b,c) \
+ OPENSSL_VER((a),(b),(c),0,0)
+
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
/** Length of the output of our second (improved) message digests. (For now
@@ -91,6 +123,8 @@ int crypto_global_cleanup(void);
crypto_pk_env_t *crypto_new_pk_env(void);
void crypto_free_pk_env(crypto_pk_env_t *env);
+void crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname);
+
/* convenience function: wraps crypto_create_crypto_env, set_key, and init. */
crypto_cipher_env_t *crypto_create_init_cipher(const char *key,
int encrypt_mode);
@@ -150,6 +184,7 @@ int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, char *to,
int crypto_pk_asn1_encode(crypto_pk_env_t *pk, char *dest, size_t dest_len);
crypto_pk_env_t *crypto_pk_asn1_decode(const char *str, size_t len);
int crypto_pk_get_digest(crypto_pk_env_t *pk, char *digest_out);
+int crypto_pk_get_all_digests(crypto_pk_env_t *pk, digests_t *digests_out);
int crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out,int add_space);
int crypto_pk_check_fingerprint_syntax(const char *s);
@@ -195,6 +230,9 @@ void crypto_digest_assign(crypto_digest_env_t *into,
void crypto_hmac_sha1(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len);
+void crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len);
/* Key negotiation */
#define DH_TYPE_CIRCUIT 1
@@ -245,7 +283,8 @@ void secret_to_key(char *key_out, size_t key_out_len, const char *secret,
size_t secret_len, const char *s2k_specifier);
#ifdef CRYPTO_PRIVATE
-/* Prototypes for private functions only used by tortls.c and crypto.c */
+/* Prototypes for private functions only used by tortls.c, crypto.c, and the
+ * unit tests. */
struct rsa_st;
struct evp_pkey_st;
struct dh_st;
diff --git a/src/common/log.c b/src/common/log.c
index ac98f13539..97400623e5 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -154,6 +154,17 @@ log_set_application_name(const char *name)
appname = name ? tor_strdup(name) : NULL;
}
+/** Log time granularity in milliseconds. */
+static int log_time_granularity = 1;
+
+/** Define log time granularity for all logs to be <b>granularity_msec</b>
+ * milliseconds. */
+void
+set_log_time_granularity(int granularity_msec)
+{
+ log_time_granularity = granularity_msec;
+}
+
/** Helper: Write the standard prefix for log lines to a
* <b>buf_len</b> character buffer in <b>buf</b>.
*/
@@ -164,14 +175,22 @@ _log_prefix(char *buf, size_t buf_len, int severity)
struct timeval now;
struct tm tm;
size_t n;
- int r;
+ int r, ms;
tor_gettimeofday(&now);
t = (time_t)now.tv_sec;
+ ms = (int)now.tv_usec / 1000;
+ if (log_time_granularity >= 1000) {
+ t -= t % (log_time_granularity / 1000);
+ ms = 0;
+ } else {
+ ms -= ((int)now.tv_usec / 1000) % log_time_granularity;
+ }
n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm));
- r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ",
- (int)now.tv_usec / 1000, sev_to_string(severity));
+ r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms,
+ sev_to_string(severity));
+
if (r<0)
return buf_len-1;
else
@@ -703,7 +722,7 @@ change_callback_log_severity(int loglevelMin, int loglevelMax,
UNLOCK_LOGS();
}
-/** If there are any log messages that were genered with LD_NOCB waiting to
+/** If there are any log messages that were generated with LD_NOCB waiting to
* be sent to callback-based loggers, send them now. */
void
flush_pending_log_callbacks(void)
@@ -803,7 +822,7 @@ add_file_log(const log_severity_list_t *severity, const char *filename)
int fd;
logfile_t *lf;
- fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
if (fd<0)
return -1;
if (tor_fd_seekend(fd)<0)
@@ -880,7 +899,7 @@ log_level_to_string(int level)
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
- "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", NULL
+ "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
diff --git a/src/common/mempool.c b/src/common/mempool.c
index c444923189..1462c5f8fe 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -62,7 +62,6 @@
#if 1
/* Tor dependencies */
-#include "orconfig.h"
#include "util.h"
#include "compat.h"
#include "torlog.h"
@@ -137,7 +136,7 @@ struct mp_chunk_t {
int capacity; /**< Number of items that can be fit into this chunk. */
size_t mem_size; /**< Number of usable bytes in mem. */
char *next_mem; /**< Pointer into part of <b>mem</b> not yet carved up. */
- char mem[1]; /**< Storage for this chunk. (Not actual size.) */
+ char mem[FLEXIBLE_ARRAY_MEMBER]; /**< Storage for this chunk. */
};
/** Number of extra bytes needed beyond mem_size to allocate a chunk. */
diff --git a/src/common/torgzip.c b/src/common/torgzip.c
index a26e5b21e5..62e4a07035 100644
--- a/src/common/torgzip.c
+++ b/src/common/torgzip.c
@@ -44,11 +44,7 @@
#define off64_t int64_t
#endif
-#ifdef _MSC_VER
-#include "..\..\contrib\zlib\zlib.h"
-#else
#include <zlib.h>
-#endif
/** Set to 1 if zlib is a version that supports gzip; set to 0 if it doesn't;
* set to -1 if we haven't checked yet. */
diff --git a/src/common/torint.h b/src/common/torint.h
index 0b5c29adc0..af975471f1 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -111,6 +111,15 @@ typedef signed int int32_t;
typedef unsigned int uint32_t;
#define HAVE_UINT32_T
#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX 0xffffu
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX 0x7fff
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-INT16_MAX-1)
+#endif
#ifndef UINT32_MAX
#define UINT32_MAX 0xffffffffu
#endif
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 541a0d1738..4c5729ef53 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -92,8 +92,10 @@
#define LD_HIST (1u<<18)
/** OR handshaking */
#define LD_HANDSHAKE (1u<<19)
+/** Heartbeat messages */
+#define LD_HEARTBEAT (1u<<20)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 20
+#define N_LOGGING_DOMAINS 21
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */
@@ -145,6 +147,7 @@ void change_callback_log_severity(int loglevelMin, int loglevelMax,
log_callback cb);
void flush_pending_log_callbacks(void);
void log_set_application_name(const char *name);
+void set_log_time_granularity(int granularity_msec);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4);
diff --git a/src/common/tortls.c b/src/common/tortls.c
index d766377dcb..908337f799 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -22,8 +22,12 @@
#include <assert.h>
#ifdef MS_WINDOWS /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
+ #ifndef WIN32_WINNT
#define WIN32_WINNT 0x400
+ #endif
+ #ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
+ #endif
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER) && (_MSC_VER < 1300)
#include <winsock.h>
@@ -40,20 +44,27 @@
#include <openssl/bio.h>
#include <openssl/opensslv.h>
-#if OPENSSL_VERSION_NUMBER < 0x00907000l
-#error "We require OpenSSL >= 0.9.7"
+#ifdef USE_BUFFEREVENTS
+#include <event2/bufferevent_ssl.h>
+#include <event2/buffer.h>
+#include <event2/event.h>
+#include "compat_libevent.h"
#endif
#define CRYPTO_PRIVATE /* to import prototypes from crypto.h */
+#define TORTLS_PRIVATE
#include "crypto.h"
#include "tortls.h"
#include "util.h"
#include "torlog.h"
#include "container.h"
-#include "ht.h"
#include <string.h>
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
+#error "We require OpenSSL >= 0.9.7"
+#endif
+
/* Enable the "v2" TLS handshake.
*/
#define V2_HANDSHAKE_SERVER
@@ -68,9 +79,9 @@
#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer")
-#if (OPENSSL_VERSION_NUMBER < 0x0090813fL || \
- (OPENSSL_VERSION_NUMBER >= 0x00909000L && \
- OPENSSL_VERSION_NUMBER < 0x1000006fL))
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_V(0,9,8,'s') || \
+ (OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,9) && \
+ OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f')))
/* This is a version of OpenSSL before 0.9.8s/1.0.0f. It does not have
* the CVE-2011-4657 fix, and as such it can't use RELEASE_BUFFERS and
* SSL3 safely at the same time.
@@ -96,22 +107,36 @@ static int use_unsafe_renegotiation_op = 0;
* SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION? */
static int use_unsafe_renegotiation_flag = 0;
+/** Structure that we use for a single certificate. */
+struct tor_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;
- X509 *my_cert;
- X509 *my_id_cert;
- crypto_pk_env_t *key;
+ tor_cert_t *my_link_cert;
+ tor_cert_t *my_id_cert;
+ tor_cert_t *my_auth_cert;
+ crypto_pk_env_t *link_key;
+ crypto_pk_env_t *auth_key;
} tor_tls_context_t;
+#define TOR_TLS_MAGIC 0x71571571
+
/** Holds a SSL object and its associated data. Members are only
* accessed from within tortls.c.
*/
struct tor_tls_t {
- HT_ENTRY(tor_tls_t) node;
+ 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. */
@@ -119,6 +144,7 @@ struct tor_tls_t {
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
} 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 */
@@ -127,8 +153,10 @@ struct tor_tls_t {
* 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. */
+ /** True iff we should call negotiated_callback when we're done reading. */
unsigned int got_renegotiate:1;
+ /** 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
@@ -153,42 +181,29 @@ static SSL_CIPHER *CLIENT_CIPHER_DUMMIES = NULL;
static STACK_OF(SSL_CIPHER) *CLIENT_CIPHER_STACK = NULL;
#endif
-/** Helper: compare tor_tls_t objects by its SSL. */
-static INLINE int
-tor_tls_entries_eq(const tor_tls_t *a, const tor_tls_t *b)
-{
- return a->ssl == b->ssl;
-}
+/** 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;
-/** Helper: return a hash value for a tor_tls_t by its SSL. */
-static INLINE unsigned int
-tor_tls_entry_hash(const tor_tls_t *a)
+/** Helper: Allocate tor_tls_object_ex_data_index. */
+static void
+tor_tls_allocate_tor_tls_object_ex_data_index(void)
{
-#if SIZEOF_INT == SIZEOF_VOID_P
- return ((unsigned int)(uintptr_t)a->ssl);
-#else
- return (unsigned int) ((((uint64_t)a->ssl)>>2) & UINT_MAX);
-#endif
+ if (tor_tls_object_ex_data_index == -1) {
+ tor_tls_object_ex_data_index =
+ SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ tor_assert(tor_tls_object_ex_data_index != -1);
+ }
}
-/** Map from SSL* pointers to tor_tls_t objects using those pointers.
- */
-static HT_HEAD(tlsmap, tor_tls_t) tlsmap_root = HT_INITIALIZER();
-
-HT_PROTOTYPE(tlsmap, tor_tls_t, node, tor_tls_entry_hash,
- tor_tls_entries_eq)
-HT_GENERATE(tlsmap, tor_tls_t, node, tor_tls_entry_hash,
- tor_tls_entries_eq, 0.6, malloc, realloc, free)
-
/** Helper: given a SSL* pointer, return the tor_tls_t object using that
* pointer. */
static INLINE tor_tls_t *
tor_tls_get_by_ssl(const SSL *ssl)
{
- tor_tls_t search, *result;
- memset(&search, 0, sizeof(search));
- search.ssl = (SSL*)ssl;
- result = HT_FIND(tlsmap, &tlsmap_root, &search);
+ tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index);
+ if (result)
+ tor_assert(result->magic == TOR_TLS_MAGIC);
return result;
}
@@ -199,7 +214,7 @@ static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
const char *cname,
const char *cname_sign,
unsigned int lifetime);
-static void tor_tls_unblock_renegotiation(tor_tls_t *tls);
+
static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
crypto_pk_env_t *identity,
unsigned int key_lifetime,
@@ -207,11 +222,14 @@ static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
static tor_tls_context_t *tor_tls_context_new(crypto_pk_env_t *identity,
unsigned int key_lifetime,
int is_client);
+static int check_cert_lifetime_internal(int severity, const X509 *cert,
+ int past_tolerance, int future_tolerance);
/** Global TLS contexts. We keep them here because nobody else needs
* to touch them. */
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. */
static int tls_library_is_initialized = 0;
@@ -219,20 +237,82 @@ static int tls_library_is_initialized = 0;
#define _TOR_TLS_SYSCALL (_MIN_TOR_TLS_ERROR_VAL - 2)
#define _TOR_TLS_ZERORETURN (_MIN_TOR_TLS_ERROR_VAL - 1)
-#include "tortls_states.h"
+/** Write a description of the current state of <b>tls</b> into the
+ * <b>sz</b>-byte buffer at <b>buf</b>. */
+void
+tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
+{
+ const char *ssl_state;
+ const char *tortls_state;
+
+ if (PREDICT_UNLIKELY(!tls || !tls->ssl)) {
+ strlcpy(buf, "(No SSL object)", sz);
+ return;
+ }
+
+ ssl_state = SSL_state_string_long(tls->ssl);
+ switch (tls->state) {
+#define CASE(st) case TOR_TLS_ST_##st: tortls_state = " in "#st ; break
+ CASE(HANDSHAKE);
+ CASE(OPEN);
+ CASE(GOTCLOSE);
+ CASE(SENTCLOSE);
+ CASE(CLOSED);
+ CASE(RENEGOTIATE);
+#undef CASE
+ case TOR_TLS_ST_BUFFEREVENT:
+ tortls_state = "";
+ break;
+ default:
+ tortls_state = " in unknown TLS state";
+ break;
+ }
+
+ tor_snprintf(buf, sz, "%s%s", ssl_state, tortls_state);
+}
-/** Return the symbolic name of an OpenSSL state. */
-static const char *
-ssl_state_to_string(int ssl_state)
+void
+tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
+ int severity, int domain, const char *doing)
{
- static char buf[40];
- int i;
- for (i = 0; state_map[i].name; ++i) {
- if (state_map[i].state == ssl_state)
- return state_map[i].name;
+ const char *state = NULL, *addr;
+ const char *msg, *lib, *func;
+
+ state = (tls && tls->ssl)?SSL_state_string_long(tls->ssl):"---";
+
+ addr = tls ? tls->address : NULL;
+
+ /* Some errors are known-benign, meaning they are the fault of the other
+ * side of the connection. The caller doesn't know this, so override the
+ * priority for those cases. */
+ switch (ERR_GET_REASON(err)) {
+ case SSL_R_HTTP_REQUEST:
+ case SSL_R_HTTPS_PROXY_REQUEST:
+ case SSL_R_RECORD_LENGTH_MISMATCH:
+ case SSL_R_RECORD_TOO_LARGE:
+ case SSL_R_UNKNOWN_PROTOCOL:
+ case SSL_R_UNSUPPORTED_PROTOCOL:
+ severity = LOG_INFO;
+ break;
+ default:
+ break;
+ }
+
+ msg = (const char*)ERR_reason_error_string(err);
+ lib = (const char*)ERR_lib_error_string(err);
+ func = (const char*)ERR_func_error_string(err);
+ if (!msg) msg = "(null)";
+ if (!lib) lib = "(null)";
+ if (!func) func = "(null)";
+ if (doing) {
+ log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
+ doing, addr?" with ":"", addr?addr:"",
+ msg, lib, func, state);
+ } else {
+ log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
+ addr?" with ":"", addr?addr:"",
+ msg, lib, func, state);
}
- tor_snprintf(buf, sizeof(buf), "Unknown state %d", ssl_state);
- return buf;
}
/** Log all pending tls errors at level <b>severity</b>. Use
@@ -241,30 +321,10 @@ ssl_state_to_string(int ssl_state)
static void
tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
{
- const char *state = NULL;
- int st;
unsigned long err;
- const char *msg, *lib, *func, *addr;
- addr = tls ? tls->address : NULL;
- st = (tls && tls->ssl) ? tls->ssl->state : -1;
+
while ((err = ERR_get_error()) != 0) {
- msg = (const char*)ERR_reason_error_string(err);
- lib = (const char*)ERR_lib_error_string(err);
- func = (const char*)ERR_func_error_string(err);
- if (!state)
- state = (st>=0)?ssl_state_to_string(st):"---";
- if (!msg) msg = "(null)";
- if (!lib) lib = "(null)";
- if (!func) func = "(null)";
- if (doing) {
- log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
- doing, addr?" with ":"", addr?addr:"",
- msg, lib, func, state);
- } else {
- log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
- addr?" with ":"", addr?addr:"",
- msg, lib, func, state);
- }
+ tor_tls_log_one_error(tls, err, severity, domain, doing);
}
}
@@ -355,14 +415,14 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
return _TOR_TLS_SYSCALL;
if (r == 0) {
log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
- doing, ssl_state_to_string(tls->ssl->state));
+ doing, SSL_state_string_long(tls->ssl));
tor_error = TOR_TLS_ERROR_IO;
} else {
int e = tor_socket_errno(tls->socket);
log(severity, LD_NET,
"TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
doing, e, tor_socket_strerror(e),
- ssl_state_to_string(tls->ssl->state));
+ SSL_state_string_long(tls->ssl));
tor_error = tor_errno_to_tls_error(e);
}
tls_log_errors(tls, severity, domain, doing);
@@ -371,7 +431,7 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
if (extra&CATCH_ZERO)
return _TOR_TLS_ZERORETURN;
log(severity, LD_NET, "TLS connection closed while %s in state %s",
- doing, ssl_state_to_string(tls->ssl->state));
+ doing, SSL_state_string_long(tls->ssl));
tls_log_errors(tls, severity, domain, doing);
return TOR_TLS_CLOSE;
default:
@@ -414,18 +474,20 @@ tor_tls_init(void)
* program should be allowed to use renegotiation unless it first passed
* a test of intelligence and determination.
*/
- if (version >= 0x009080c0L && version < 0x009080d0L) {
- log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l; "
- "I will try SSL3_FLAGS to enable renegotation.",
+ if (version > OPENSSL_V(0,9,8,'k') && version <= OPENSSL_V(0,9,8,'l')) {
+ log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
+ "some vendors have backported renegotiation code from "
+ "0.9.8m without updating the version number. "
+ "I will try SSL3_FLAGS and SSL_OP to enable renegotation.",
SSLeay_version(SSLEAY_VERSION));
use_unsafe_renegotiation_flag = 1;
use_unsafe_renegotiation_op = 1;
- } else if (version >= 0x009080d0L) {
+ } else if (version > OPENSSL_V(0,9,8,'l')) {
log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
"I will try SSL_OP to enable renegotiation",
SSLeay_version(SSLEAY_VERSION));
use_unsafe_renegotiation_op = 1;
- } else if (version < 0x009080c0L) {
+ } else if (version <= OPENSSL_V(0,9,8,'k')) {
log_notice(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
"0.9.8l, but some vendors have backported 0.9.8l's "
"renegotiation code to earlier versions, and some have "
@@ -435,10 +497,13 @@ tor_tls_init(void)
use_unsafe_renegotiation_flag = 1;
use_unsafe_renegotiation_op = 1;
} else {
+ /* this is dead code, yes? */
log_info(LD_GENERAL, "OpenSSL %s has version %lx",
SSLeay_version(SSLEAY_VERSION), version);
}
+ tor_tls_allocate_tor_tls_object_ex_data_index();
+
tls_library_is_initialized = 1;
}
}
@@ -457,10 +522,6 @@ tor_tls_free_all(void)
client_tls_context = NULL;
tor_tls_context_decref(ctx);
}
- if (!HT_EMPTY(&tlsmap_root)) {
- log_warn(LD_MM, "Still have entries in the tlsmap at shutdown.");
- }
- HT_CLEAR(tlsmap, &tlsmap_root);
#ifdef V2_HANDSHAKE_CLIENT
if (CLIENT_CIPHER_DUMMIES)
tor_free(CLIENT_CIPHER_DUMMIES);
@@ -514,7 +575,13 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
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. */
+#define SERIAL_NUMBER_SIZE 8
+
time_t start_time, end_time;
+ BIGNUM *serial_number = NULL;
+ unsigned char serial_tmp[SERIAL_NUMBER_SIZE];
EVP_PKEY *sign_pkey = NULL, *pkey=NULL;
X509 *x509 = NULL;
X509_NAME *name = NULL, *name_issuer=NULL;
@@ -535,8 +602,15 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
goto error;
if (!(X509_set_version(x509, 2)))
goto error;
- if (!(ASN1_INTEGER_set(X509_get_serialNumber(x509), (long)start_time)))
- goto error;
+
+ { /* our serial number is 8 random bytes. */
+ if (crypto_rand((char *)serial_tmp, sizeof(serial_tmp)) < 0)
+ goto error;
+ if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL)))
+ goto error;
+ if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509))))
+ goto error;
+ }
if (!(name = tor_x509_name_new(cname)))
goto error;
@@ -569,11 +643,15 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
EVP_PKEY_free(sign_pkey);
if (pkey)
EVP_PKEY_free(pkey);
+ if (serial_number)
+ BN_free(serial_number);
if (name)
X509_NAME_free(name);
if (name_issuer)
X509_NAME_free(name_issuer);
return x509;
+
+#undef SERIAL_NUMBER_SIZE
}
/** List of ciphers that servers should select from.*/
@@ -620,6 +698,137 @@ static const int N_CLIENT_CIPHERS =
SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
#endif
+/** Free all storage held in <b>cert</b> */
+void
+tor_cert_free(tor_cert_t *cert)
+{
+ if (! cert)
+ return;
+ if (cert->cert)
+ X509_free(cert->cert);
+ tor_free(cert->encoded);
+ memset(cert, 0x03, sizeof(*cert));
+ tor_free(cert);
+}
+
+/**
+ * Allocate a new tor_cert_t to hold the certificate "x509_cert".
+ *
+ * Steals a reference to x509_cert.
+ */
+static tor_cert_t *
+tor_cert_new(X509 *x509_cert)
+{
+ tor_cert_t *cert;
+ EVP_PKEY *pkey;
+ RSA *rsa;
+ int length, length2;
+ unsigned char *cp;
+
+ if (!x509_cert)
+ return NULL;
+
+ length = i2d_X509(x509_cert, NULL);
+ cert = tor_malloc_zero(sizeof(tor_cert_t));
+ if (length <= 0) {
+ tor_free(cert);
+ log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate");
+ X509_free(x509_cert);
+ return NULL;
+ }
+ cert->encoded_len = (size_t) length;
+ cp = cert->encoded = tor_malloc(length);
+ length2 = i2d_X509(x509_cert, &cp);
+ tor_assert(length2 == length);
+
+ cert->cert = x509_cert;
+
+ crypto_digest_all(&cert->cert_digests,
+ (char*)cert->encoded, cert->encoded_len);
+
+ if ((pkey = X509_get_pubkey(x509_cert)) &&
+ (rsa = EVP_PKEY_get1_RSA(pkey))) {
+ crypto_pk_env_t *pk = _crypto_new_pk_env_rsa(rsa);
+ crypto_pk_get_all_digests(pk, &cert->pkey_digests);
+ cert->pkey_digests_set = 1;
+ crypto_free_pk_env(pk);
+ EVP_PKEY_free(pkey);
+ }
+
+ return cert;
+}
+
+/** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>,
+ * from a <b>certificate</b>. Return a newly allocated tor_cert_t on success
+ * and NULL on failure. */
+tor_cert_t *
+tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
+{
+ X509 *x509;
+ const unsigned char *cp = (const unsigned char *)certificate;
+ tor_cert_t *newcert;
+ tor_assert(certificate);
+
+ if (certificate_len > INT_MAX)
+ return NULL;
+
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+ /* This ifdef suppresses a type warning. Take out this case once everybody
+ * is using OpenSSL 0.9.8 or later. */
+ x509 = d2i_X509(NULL, (unsigned char**)&cp, (int)certificate_len);
+#else
+ x509 = d2i_X509(NULL, &cp, (int)certificate_len);
+#endif
+ if (!x509)
+ return NULL; /* Couldn't decode */
+ if (cp - certificate != (int)certificate_len) {
+ X509_free(x509);
+ return NULL; /* Didn't use all the bytes */
+ }
+ newcert = tor_cert_new(x509);
+ if (!newcert) {
+ return NULL;
+ }
+ if (newcert->encoded_len != certificate_len ||
+ fast_memneq(newcert->encoded, certificate, certificate_len)) {
+ /* Cert wasn't in DER */
+ tor_cert_free(newcert);
+ return NULL;
+ }
+ return newcert;
+}
+
+/** Set *<b>encoded_out</b> and *<b>size_out/b> to <b>cert</b>'s encoded DER
+ * representation and length, respectively. */
+void
+tor_cert_get_der(const tor_cert_t *cert,
+ const uint8_t **encoded_out, size_t *size_out)
+{
+ tor_assert(cert);
+ tor_assert(encoded_out);
+ tor_assert(size_out);
+ *encoded_out = cert->encoded;
+ *size_out = cert->encoded_len;
+}
+
+/** Return a set of digests for the public key in <b>cert</b>, or NULL if this
+ * cert's public key is not one we know how to take the digest of. */
+const digests_t *
+tor_cert_get_id_digests(const tor_cert_t *cert)
+{
+ if (cert->pkey_digests_set)
+ return &cert->pkey_digests;
+ else
+ return NULL;
+}
+
+/** Return a set of digests for the public key in <b>cert</b>. */
+const digests_t *
+tor_cert_get_cert_digests(const tor_cert_t *cert)
+{
+ return &cert->cert_digests;
+}
+
/** Remove a reference to <b>ctx</b>, and free it if it has no more
* references. */
static void
@@ -628,13 +837,172 @@ tor_tls_context_decref(tor_tls_context_t *ctx)
tor_assert(ctx);
if (--ctx->refcnt == 0) {
SSL_CTX_free(ctx->ctx);
- X509_free(ctx->my_cert);
- X509_free(ctx->my_id_cert);
- crypto_free_pk_env(ctx->key);
+ tor_cert_free(ctx->my_link_cert);
+ tor_cert_free(ctx->my_id_cert);
+ tor_cert_free(ctx->my_auth_cert);
+ crypto_free_pk_env(ctx->link_key);
+ crypto_free_pk_env(ctx->auth_key);
tor_free(ctx);
}
}
+/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate
+ * and ID certificate that we're currently using for our V3 in-protocol
+ * handshake's certificate chain. If <b>server</b> is true, provide the certs
+ * that we use in server mode; otherwise, provide the certs that we use in
+ * client mode. */
+int
+tor_tls_get_my_certs(int server,
+ const tor_cert_t **link_cert_out,
+ const tor_cert_t **id_cert_out)
+{
+ tor_tls_context_t *ctx = server ? server_tls_context : client_tls_context;
+ if (! ctx)
+ return -1;
+ if (link_cert_out)
+ *link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert;
+ if (id_cert_out)
+ *id_cert_out = ctx->my_id_cert;
+ return 0;
+}
+
+/**
+ * Return the authentication key that we use to authenticate ourselves as a
+ * client in the V3 in-protocol handshake.
+ */
+crypto_pk_env_t *
+tor_tls_get_my_client_auth_key(void)
+{
+ if (! client_tls_context)
+ return NULL;
+ return client_tls_context->auth_key;
+}
+
+/**
+ * Return a newly allocated copy of the public key that a certificate
+ * certifies. Return NULL if the cert's key is not RSA.
+ */
+crypto_pk_env_t *
+tor_tls_cert_get_key(tor_cert_t *cert)
+{
+ crypto_pk_env_t *result = NULL;
+ EVP_PKEY *pkey = X509_get_pubkey(cert->cert);
+ RSA *rsa;
+ if (!pkey)
+ return NULL;
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ if (!rsa) {
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ result = _crypto_new_pk_env_rsa(rsa);
+ EVP_PKEY_free(pkey);
+ return result;
+}
+
+/** Return true iff <b>a</b> and <b>b</b> represent the same public key. */
+static int
+pkey_eq(EVP_PKEY *a, EVP_PKEY *b)
+{
+ /* We'd like to do this, but openssl 0.9.7 doesn't have it:
+ return EVP_PKEY_cmp(a,b) == 1;
+ */
+ unsigned char *a_enc=NULL, *b_enc=NULL, *a_ptr, *b_ptr;
+ int a_len1, b_len1, a_len2, b_len2, result;
+ a_len1 = i2d_PublicKey(a, NULL);
+ b_len1 = i2d_PublicKey(b, NULL);
+ if (a_len1 != b_len1)
+ return 0;
+ a_ptr = a_enc = tor_malloc(a_len1);
+ b_ptr = b_enc = tor_malloc(b_len1);
+ a_len2 = i2d_PublicKey(a, &a_ptr);
+ b_len2 = i2d_PublicKey(b, &b_ptr);
+ tor_assert(a_len2 == a_len1);
+ tor_assert(b_len2 == b_len1);
+ result = tor_memeq(a_enc, b_enc, a_len1);
+ tor_free(a_enc);
+ tor_free(b_enc);
+ return result;
+}
+
+/** Return true iff the other side of <b>tls</b> has authenticated to us, and
+ * the key certified in <b>cert</b> is the same as the key they used to do it.
+ */
+int
+tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert)
+{
+ X509 *peercert = SSL_get_peer_certificate(tls->ssl);
+ EVP_PKEY *link_key = NULL, *cert_key = NULL;
+ int result;
+
+ if (!peercert)
+ return 0;
+ link_key = X509_get_pubkey(peercert);
+ cert_key = X509_get_pubkey(cert->cert);
+
+ result = link_key && cert_key && pkey_eq(cert_key, link_key);
+
+ X509_free(peercert);
+ if (link_key)
+ EVP_PKEY_free(link_key);
+ if (cert_key)
+ EVP_PKEY_free(cert_key);
+
+ return result;
+}
+
+/** Check whether <b>cert</b> is well-formed, currently live, and correctly
+ * signed by the public key in <b>signing_cert</b>. If <b>check_rsa_1024</b>,
+ * make sure that it has an RSA key with 1024 bits; otherwise, just check that
+ * the key is long enough. Return 1 if the cert is good, and 0 if it's bad or
+ * we couldn't check it. */
+int
+tor_tls_cert_is_valid(int severity,
+ const tor_cert_t *cert,
+ const tor_cert_t *signing_cert,
+ int check_rsa_1024)
+{
+ EVP_PKEY *cert_key;
+ EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert);
+ int r, key_ok = 0;
+ if (!signing_key)
+ return 0;
+ r = X509_verify(cert->cert, signing_key);
+ EVP_PKEY_free(signing_key);
+ if (r <= 0)
+ return 0;
+
+ /* okay, the signature checked out right. Now let's check the check the
+ * lifetime. */
+ if (check_cert_lifetime_internal(severity, cert->cert,
+ 48*60*60, 30*24*60*60) < 0)
+ return 0;
+
+ cert_key = X509_get_pubkey(cert->cert);
+ if (check_rsa_1024 && cert_key) {
+ RSA *rsa = EVP_PKEY_get1_RSA(cert_key);
+ if (rsa && BN_num_bits(rsa->n) == 1024)
+ key_ok = 1;
+ if (rsa)
+ RSA_free(rsa);
+ } else if (cert_key) {
+ int min_bits = 1024;
+#ifdef EVP_PKEY_EC
+ if (EVP_PKEY_type(cert_key->type) == EVP_PKEY_EC)
+ min_bits = 128;
+#endif
+ if (EVP_PKEY_bits(cert_key) >= min_bits)
+ key_ok = 1;
+ }
+ EVP_PKEY_free(cert_key);
+ if (!key_ok)
+ return 0;
+
+ /* XXXX compare DNs or anything? */
+
+ return 1;
+}
+
/** Increase the reference count of <b>ctx</b>. */
static void
tor_tls_context_incref(tor_tls_context_t *ctx)
@@ -740,29 +1108,42 @@ static tor_tls_context_t *
tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
int is_client)
{
- crypto_pk_env_t *rsa = NULL;
+ crypto_pk_env_t *rsa = NULL, *rsa_auth = NULL;
EVP_PKEY *pkey = NULL;
tor_tls_context_t *result = NULL;
- X509 *cert = NULL, *idcert = NULL;
+ X509 *cert = NULL, *idcert = NULL, *authcert = NULL;
char *nickname = NULL, *nn2 = NULL;
tor_tls_init();
nickname = crypto_random_hostname(8, 20, "www.", ".net");
+#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
nn2 = crypto_random_hostname(8, 20, "www.", ".net");
+#else
+ nn2 = crypto_random_hostname(8, 20, "www.", ".com");
+#endif
- /* Generate short-term RSA key. */
+ /* Generate short-term RSA key for use with TLS. */
if (!(rsa = crypto_new_pk_env()))
goto error;
if (crypto_pk_generate_key(rsa)<0)
goto error;
if (!is_client) {
- /* Create certificate signed by identity key. */
+ /* Generate short-term RSA key for use in the in-protocol ("v3")
+ * authentication handshake. */
+ if (!(rsa_auth = crypto_new_pk_env()))
+ goto error;
+ if (crypto_pk_generate_key(rsa_auth)<0)
+ goto error;
+ /* Create a link certificate signed by identity key. */
cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
key_lifetime);
/* Create self-signed certificate for identity key. */
idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
IDENTITY_CERT_LIFETIME);
- if (!cert || !idcert) {
+ /* Create an authentication certificate signed by identity key. */
+ authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
+ key_lifetime);
+ if (!cert || !idcert || !authcert) {
log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
goto error;
}
@@ -771,9 +1152,13 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
result = tor_malloc_zero(sizeof(tor_tls_context_t));
result->refcnt = 1;
if (!is_client) {
- result->my_cert = X509_dup(cert);
- result->my_id_cert = X509_dup(idcert);
- result->key = crypto_pk_dup_key(rsa);
+ result->my_link_cert = tor_cert_new(X509_dup(cert));
+ result->my_id_cert = tor_cert_new(X509_dup(idcert));
+ result->my_auth_cert = tor_cert_new(X509_dup(authcert));
+ if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
+ goto error;
+ result->link_key = crypto_pk_dup_key(rsa);
+ result->auth_key = crypto_pk_dup_key(rsa_auth);
}
#if 0
@@ -794,9 +1179,9 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
#ifdef DISABLE_SSL3_HANDSHAKE
1 ||
#endif
- SSLeay() < 0x0090813fL ||
- (SSLeay() >= 0x00909000L &&
- SSLeay() < 0x1000006fL)) {
+ SSLeay() < OPENSSL_V(0,9,8,'s') ||
+ (SSLeay() >= OPENSSL_V_SERIES(0,9,9) &&
+ SSLeay() < OPENSSL_V(1,0,0,'f'))) {
/* And not SSL3 if it's subject to CVE-2011-4657. */
log_info(LD_NET, "Disabling SSLv3 because this OpenSSL version "
"might otherwise be vulnerable to CVE-2011-4657 "
@@ -865,6 +1250,9 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
if (rsa)
crypto_free_pk_env(rsa);
+ if (rsa_auth)
+ crypto_free_pk_env(rsa_auth);
+ X509_free(authcert);
tor_free(nickname);
tor_free(nn2);
return result;
@@ -877,12 +1265,16 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
EVP_PKEY_free(pkey);
if (rsa)
crypto_free_pk_env(rsa);
+ if (rsa_auth)
+ crypto_free_pk_env(rsa_auth);
if (result)
tor_tls_context_decref(result);
if (cert)
X509_free(cert);
if (idcert)
X509_free(idcert);
+ if (authcert)
+ X509_free(authcert);
return NULL;
}
@@ -938,6 +1330,13 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
return 1;
}
+static void
+tor_tls_debug_state_callback(const SSL *ssl, int type, int val)
+{
+ log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].",
+ ssl, SSL_state_string_long(ssl), type, val);
+}
+
/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection
* changes state. We use this:
* <ul><li>To alter the state of the handshake partway through, so we
@@ -949,6 +1348,9 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
{
tor_tls_t *tls;
(void) val;
+
+ tor_tls_debug_state_callback(ssl, type, val);
+
if (type != SSL_CB_ACCEPT_LOOP)
return;
if (ssl->state != SSL3_ST_SW_SRVR_HELLO_A)
@@ -959,8 +1361,11 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
/* Check whether we're watching for renegotiates. If so, this is one! */
if (tls->negotiated_callback)
tls->got_renegotiate = 1;
+ if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/
+ ++tls->server_handshake_count;
} else {
log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
+ return;
}
/* Now check the cipher list. */
@@ -977,6 +1382,10 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
if (tls) {
tls->wasV2Handshake = 1;
+#ifdef USE_BUFFEREVENTS
+ if (use_unsafe_renegotiation_flag)
+ tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+#endif
} else {
log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
}
@@ -1064,6 +1473,7 @@ tor_tls_new(int sock, int isServer)
tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t));
tor_tls_context_t *context = isServer ? server_tls_context :
client_tls_context;
+ result->magic = TOR_TLS_MAGIC;
tor_assert(context); /* make sure somebody made it first */
if (!(result->ssl = SSL_new(context->ctx))) {
@@ -1104,7 +1514,14 @@ tor_tls_new(int sock, int isServer)
tor_free(result);
return NULL;
}
- HT_INSERT(tlsmap, &tlsmap_root, result);
+ {
+ int set_worked =
+ SSL_set_ex_data(result->ssl, tor_tls_object_ex_data_index, result);
+ if (!set_worked) {
+ log_warn(LD_BUG,
+ "Couldn't set the tls for an SSL*; connection will fail");
+ }
+ }
SSL_set_bio(result->ssl, bio, bio);
tor_tls_context_incref(context);
result->context = context;
@@ -1120,8 +1537,11 @@ tor_tls_new(int sock, int isServer)
#ifdef V2_HANDSHAKE_SERVER
if (isServer) {
SSL_set_info_callback(result->ssl, tor_tls_server_info_callback);
- }
+ } else
#endif
+ {
+ SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
+ }
/* Not expected to get called. */
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
@@ -1155,7 +1575,7 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls,
if (cb) {
SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback);
} else {
- SSL_set_info_callback(tls->ssl, NULL);
+ SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback);
}
#endif
}
@@ -1163,7 +1583,7 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls,
/** If this version of openssl requires it, turn on renegotiation on
* <b>tls</b>.
*/
-static void
+void
tor_tls_unblock_renegotiation(tor_tls_t *tls)
{
/* Yes, we know what we are doing here. No, we do not treat a renegotiation
@@ -1187,6 +1607,19 @@ tor_tls_block_renegotiation(tor_tls_t *tls)
tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
}
+void
+tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
+{
+ if (use_unsafe_renegotiation_flag) {
+ tor_assert(0 != (tls->ssl->s3->flags &
+ SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
+ }
+ if (use_unsafe_renegotiation_op) {
+ long options = SSL_get_options(tls->ssl);
+ tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
+ }
+}
+
/** Return whether this tls initiated the connect (client) or
* received it (server). */
int
@@ -1202,14 +1635,9 @@ tor_tls_is_server(tor_tls_t *tls)
void
tor_tls_free(tor_tls_t *tls)
{
- tor_tls_t *removed;
if (!tls)
return;
tor_assert(tls->ssl);
- removed = HT_REMOVE(tlsmap, &tlsmap_root, tls);
- if (!removed) {
- log_warn(LD_BUG, "Freeing a TLS that was not in the ssl->tls map.");
- }
#ifdef SSL_set_tlsext_host_name
SSL_set_tlsext_host_name(tls->ssl, NULL);
#endif
@@ -1219,6 +1647,7 @@ tor_tls_free(tor_tls_t *tls)
if (tls->context)
tor_tls_context_decref(tls->context);
tor_free(tls->address);
+ tls->magic = 0x99999999;
tor_free(tls);
}
@@ -1310,16 +1739,16 @@ tor_tls_handshake(tor_tls_t *tls)
oldstate = tls->ssl->state;
if (tls->isServer) {
log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
- ssl_state_to_string(tls->ssl->state));
+ SSL_state_string_long(tls->ssl));
r = SSL_accept(tls->ssl);
} else {
log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls,
- ssl_state_to_string(tls->ssl->state));
+ SSL_state_string_long(tls->ssl));
r = SSL_connect(tls->ssl);
}
if (oldstate != tls->ssl->state)
log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
- tls, ssl_state_to_string(tls->ssl->state));
+ tls, SSL_state_string_long(tls->ssl));
/* We need to call this here and not earlier, since OpenSSL has a penchant
* for clearing its flags when you say accept or connect. */
tor_tls_unblock_renegotiation(tls);
@@ -1331,56 +1760,86 @@ tor_tls_handshake(tor_tls_t *tls)
}
if (r == TOR_TLS_DONE) {
tls->state = TOR_TLS_ST_OPEN;
- if (tls->isServer) {
- SSL_set_info_callback(tls->ssl, NULL);
- SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb);
- /* There doesn't seem to be a clear OpenSSL API to clear mode flags. */
- tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN;
+ return tor_tls_finish_handshake(tls);
+ }
+ return r;
+}
+
+/** Perform the final part of the intial TLS handshake on <b>tls</b>. This
+ * should be called for the first handshake only: it determines whether the v1
+ * or the v2 handshake was used, and adjusts things for the renegotiation
+ * handshake as appropriate.
+ *
+ * tor_tls_handshake() calls this on its own; you only need to call this if
+ * bufferevent is doing the handshake for you.
+ */
+int
+tor_tls_finish_handshake(tor_tls_t *tls)
+{
+ int r = TOR_TLS_DONE;
+ if (tls->isServer) {
+ SSL_set_info_callback(tls->ssl, NULL);
+ SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb);
+ /* There doesn't seem to be a clear OpenSSL API to clear mode flags. */
+ tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN;
#ifdef V2_HANDSHAKE_SERVER
- if (tor_tls_client_is_using_v2_ciphers(tls->ssl, ADDR(tls))) {
- /* 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
- * was buggy. Fixing that. */
- if (!tls->wasV2Handshake) {
- log_warn(LD_BUG, "For some reason, wasV2Handshake didn't"
- " get set. Fixing that.");
- }
- tls->wasV2Handshake = 1;
- log_debug(LD_HANDSHAKE,
- "Completed V2 TLS handshake with client; waiting "
- "for renegotiation.");
- } else {
- tls->wasV2Handshake = 0;
+ if (tor_tls_client_is_using_v2_ciphers(tls->ssl, ADDR(tls))) {
+ /* 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
+ * was buggy. Fixing that. */
+ if (!tls->wasV2Handshake) {
+ log_warn(LD_BUG, "For some reason, wasV2Handshake didn't"
+ " get set. Fixing that.");
}
-#endif
+ tls->wasV2Handshake = 1;
+ log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting"
+ " for renegotiation.");
} 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);
+ /* 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
- 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;
- }
+ 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;
}
}
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.
@@ -1486,9 +1945,21 @@ tor_tls_peer_has_cert(tor_tls_t *tls)
return 1;
}
+/** Return the peer certificate, or NULL if there isn't one. */
+tor_cert_t *
+tor_tls_get_peer_cert(tor_tls_t *tls)
+{
+ X509 *cert;
+ cert = SSL_get_peer_certificate(tls->ssl);
+ tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
+ if (!cert)
+ return NULL;
+ return tor_cert_new(cert);
+}
+
/** Warn that a certificate lifetime extends through a certain range. */
static void
-log_cert_lifetime(X509 *cert, const char *problem)
+log_cert_lifetime(int severity, const X509 *cert, const char *problem)
{
BIO *bio = NULL;
BUF_MEM *buf;
@@ -1498,9 +1969,10 @@ log_cert_lifetime(X509 *cert, const char *problem)
struct tm tm;
if (problem)
- log_warn(LD_GENERAL,
- "Certificate %s: is your system clock set incorrectly?",
- problem);
+ log(severity, LD_GENERAL,
+ "Certificate %s. Either their clock is set wrong, or your clock "
+ "is wrong.",
+ problem);
if (!(bio = BIO_new(BIO_s_mem()))) {
log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end;
@@ -1522,9 +1994,9 @@ log_cert_lifetime(X509 *cert, const char *problem)
strftime(mytime, 32, "%b %d %H:%M:%S %Y GMT", tor_gmtime_r(&now, &tm));
- log_warn(LD_GENERAL,
- "(certificate lifetime runs from %s through %s. Your time is %s.)",
- s1,s2,mytime);
+ log(severity, LD_GENERAL,
+ "(certificate lifetime runs from %s through %s. Your time is %s.)",
+ s1,s2,mytime);
end:
/* Not expected to get invoked */
@@ -1597,6 +2069,8 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found");
goto done;
}
+ tls_log_errors(tls, severity, LD_HANDSHAKE, "before verifying certificate");
+
if (!(id_pkey = X509_get_pubkey(id_cert)) ||
X509_verify(cert, id_pkey) <= 0) {
log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0");
@@ -1624,34 +2098,25 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
return r;
}
-/** Check whether the certificate set on the connection <b>tls</b> is
- * expired or not-yet-valid, give or take <b>tolerance</b>
- * seconds. Return 0 for valid, -1 for failure.
+/** Check whether the certificate set on the connection <b>tls</b> is expired
+ * give or take <b>past_tolerance</b> seconds, or not-yet-valid give or take
+ * <b>future_tolerance</b> seconds. Return 0 for valid, -1 for failure.
*
* NOTE: you should call tor_tls_verify before tor_tls_check_lifetime.
*/
int
-tor_tls_check_lifetime(tor_tls_t *tls, int tolerance)
+tor_tls_check_lifetime(int severity, tor_tls_t *tls,
+ int past_tolerance, int future_tolerance)
{
- time_t now, t;
X509 *cert;
int r = -1;
- now = time(NULL);
-
if (!(cert = SSL_get_peer_certificate(tls->ssl)))
goto done;
- t = now + tolerance;
- if (X509_cmp_time(X509_get_notBefore(cert), &t) > 0) {
- log_cert_lifetime(cert, "not yet valid");
+ if (check_cert_lifetime_internal(severity, cert,
+ past_tolerance, future_tolerance) < 0)
goto done;
- }
- t = now - tolerance;
- if (X509_cmp_time(X509_get_notAfter(cert), &t) < 0) {
- log_cert_lifetime(cert, "already expired");
- goto done;
- }
r = 0;
done:
@@ -1663,6 +2128,32 @@ tor_tls_check_lifetime(tor_tls_t *tls, int tolerance)
return r;
}
+/** Helper: check whether <b>cert</b> is expired give or take
+ * <b>past_tolerance</b> seconds, or not-yet-valid give or take
+ * <b>future_tolerance</b> seconds. If it is live, return 0. If it is not
+ * live, log a message and return -1. */
+static int
+check_cert_lifetime_internal(int severity, const X509 *cert,
+ int past_tolerance, int future_tolerance)
+{
+ time_t now, t;
+
+ now = time(NULL);
+
+ t = now + future_tolerance;
+ if (X509_cmp_time(X509_get_notBefore(cert), &t) > 0) {
+ log_cert_lifetime(severity, cert, "not yet valid");
+ return -1;
+ }
+ t = now - past_tolerance;
+ if (X509_cmp_time(X509_get_notAfter(cert), &t) < 0) {
+ log_cert_lifetime(severity, cert, "already expired");
+ return -1;
+ }
+
+ return 0;
+}
+
/** Return the number of bytes available for reading from <b>tls</b>.
*/
int
@@ -1746,6 +2237,138 @@ tor_tls_used_v1_handshake(tor_tls_t *tls)
return 1;
}
+/** 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;
+ 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)
+{
+ 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:
+ 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
+ * <b>tls</b>. */
+int
+tor_tls_get_num_server_handshakes(tor_tls_t *tls)
+{
+ return tls->server_handshake_count;
+}
+
+/** Return true iff the server TLS connection <b>tls</b> got the renegotiation
+ * request it was waiting for. */
+int
+tor_tls_server_got_renegotiate(tor_tls_t *tls)
+{
+ return tls->got_renegotiate;
+}
+
+/** Set the DIGEST256_LEN buffer at <b>secrets_out</b> to the value used in
+ * the v3 handshake to prove that the client knows the TLS secrets for the
+ * connection <b>tls</b>. Return 0 on success, -1 on failure.
+ */
+int
+tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
+{
+#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification"
+ char buf[128];
+ size_t len;
+ tor_assert(tls);
+ tor_assert(tls->ssl);
+ tor_assert(tls->ssl->s3);
+ tor_assert(tls->ssl->session);
+ /*
+ The value is an HMAC, using the TLS master key as the HMAC key, of
+ client_random | server_random | TLSSECRET_MAGIC
+ */
+ memcpy(buf + 0, tls->ssl->s3->client_random, 32);
+ memcpy(buf + 32, tls->ssl->s3->server_random, 32);
+ memcpy(buf + 64, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1);
+ len = 64 + strlen(TLSSECRET_MAGIC) + 1;
+ crypto_hmac_sha256((char*)secrets_out,
+ (char*)tls->ssl->session->master_key,
+ tls->ssl->session->master_key_length,
+ buf, len);
+ memset(buf, 0, sizeof(buf));
+ return 0;
+}
+
/** Examine the amount of memory used and available for buffers in <b>tls</b>.
* Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read
* buffer and *<b>rbuf_bytes</b> to the amount actually used.
@@ -1768,3 +2391,75 @@ tor_tls_get_buffer_sizes(tor_tls_t *tls,
*wbuf_bytes = tls->ssl->s3->wbuf.left;
}
+#ifdef USE_BUFFEREVENTS
+/** Construct and return an TLS-encrypting bufferevent to send data over
+ * <b>socket</b>, which must match the socket of the underlying bufferevent
+ * <b>bufev_in</b>. The TLS object <b>tls</b> is used for encryption.
+ *
+ * This function will either create a filtering bufferevent that wraps around
+ * <b>bufev_in</b>, or it will free bufev_in and return a new bufferevent that
+ * uses the <b>tls</b> to talk to the network directly. Do not use
+ * <b>bufev_in</b> after calling this function.
+ *
+ * The connection will start out doing a server handshake if <b>receiving</b>
+ * is strue, and a client handshake otherwise.
+ *
+ * Returns NULL on failure.
+ */
+struct bufferevent *
+tor_tls_init_bufferevent(tor_tls_t *tls, struct bufferevent *bufev_in,
+ evutil_socket_t socket, int receiving,
+ int filter)
+{
+ struct bufferevent *out;
+ const enum bufferevent_ssl_state state = receiving ?
+ BUFFEREVENT_SSL_ACCEPTING : BUFFEREVENT_SSL_CONNECTING;
+
+ if (filter || tor_libevent_using_iocp_bufferevents()) {
+ /* Grab an extra reference to the SSL, since BEV_OPT_CLOSE_ON_FREE
+ means that the SSL will get freed too.
+
+ This increment makes our SSL usage not-threadsafe, BTW. We should
+ see if we're allowed to use CRYPTO_add from outside openssl. */
+ tls->ssl->references += 1;
+ out = bufferevent_openssl_filter_new(tor_libevent_get_base(),
+ bufev_in,
+ tls->ssl,
+ state,
+ BEV_OPT_DEFER_CALLBACKS|
+ BEV_OPT_CLOSE_ON_FREE);
+ /* Tell the underlying bufferevent when to accept more data from the SSL
+ filter (only when it's got less than 32K to write), and when to notify
+ the SSL filter that it could write more (when it drops under 24K). */
+ bufferevent_setwatermark(bufev_in, EV_WRITE, 24*1024, 32*1024);
+ } else {
+ if (bufev_in) {
+ evutil_socket_t s = bufferevent_getfd(bufev_in);
+ tor_assert(s == -1 || s == socket);
+ tor_assert(evbuffer_get_length(bufferevent_get_input(bufev_in)) == 0);
+ tor_assert(evbuffer_get_length(bufferevent_get_output(bufev_in)) == 0);
+ tor_assert(BIO_number_read(SSL_get_rbio(tls->ssl)) == 0);
+ tor_assert(BIO_number_written(SSL_get_rbio(tls->ssl)) == 0);
+ bufferevent_free(bufev_in);
+ }
+
+ /* Current versions (as of 2.0.x) of Libevent need to defer
+ * bufferevent_openssl callbacks, or else our callback functions will
+ * get called reentrantly, which is bad for us.
+ */
+ out = bufferevent_openssl_socket_new(tor_libevent_get_base(),
+ socket,
+ tls->ssl,
+ state,
+ BEV_OPT_DEFER_CALLBACKS);
+ }
+ tls->state = TOR_TLS_ST_BUFFEREVENT;
+
+ /* Unblock _after_ creating the bufferevent, since accept/connect tend to
+ * clear flags. */
+ tor_tls_unblock_renegotiation(tls);
+
+ return out;
+}
+#endif
+
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 55fee81aea..673f18dfe8 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -17,6 +17,9 @@
/* Opaque structure to hold a TLS connection. */
typedef struct tor_tls_t tor_tls_t;
+/* Opaque structure to hold an X509 certificate. */
+typedef struct tor_cert_t tor_cert_t;
+
/* Possible return values for most tor_tls_* functions. */
#define _MIN_TOR_TLS_ERROR_VAL -9
#define TOR_TLS_ERROR_MISC -9
@@ -48,6 +51,7 @@ typedef struct tor_tls_t tor_tls_t;
#define TOR_TLS_IS_ERROR(rv) ((rv) < TOR_TLS_CLOSE)
const char *tor_tls_err_to_string(int err);
+void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz);
void tor_tls_free_all(void);
int tor_tls_context_init(int is_public_server,
@@ -62,13 +66,19 @@ void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
int tor_tls_is_server(tor_tls_t *tls);
void tor_tls_free(tor_tls_t *tls);
int tor_tls_peer_has_cert(tor_tls_t *tls);
+tor_cert_t *tor_tls_get_peer_cert(tor_tls_t *tls);
int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity);
-int tor_tls_check_lifetime(tor_tls_t *tls, int tolerance);
+int tor_tls_check_lifetime(int severity,
+ tor_tls_t *tls, int past_tolerance,
+ int future_tolerance);
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);
int tor_tls_shutdown(tor_tls_t *tls);
int tor_tls_get_pending_bytes(tor_tls_t *tls);
size_t tor_tls_get_forced_write_size(tor_tls_t *tls);
@@ -81,12 +91,44 @@ void tor_tls_get_buffer_sizes(tor_tls_t *tls,
size_t *wbuf_capacity, size_t *wbuf_bytes);
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);
+int tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out);
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
#define check_no_tls_errors() _check_no_tls_errors(__FILE__,__LINE__)
void _check_no_tls_errors(const char *fname, int line);
+void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
+ int severity, int domain, const char *doing);
+
+#ifdef USE_BUFFEREVENTS
+int tor_tls_start_renegotiating(tor_tls_t *tls);
+struct bufferevent *tor_tls_init_bufferevent(tor_tls_t *tls,
+ struct bufferevent *bufev_in,
+ evutil_socket_t socket, int receiving,
+ int filter);
+#endif
+
+void tor_cert_free(tor_cert_t *cert);
+tor_cert_t *tor_cert_decode(const uint8_t *certificate,
+ size_t certificate_len);
+void tor_cert_get_der(const tor_cert_t *cert,
+ const uint8_t **encoded_out, size_t *size_out);
+const digests_t *tor_cert_get_id_digests(const tor_cert_t *cert);
+const digests_t *tor_cert_get_cert_digests(const tor_cert_t *cert);
+int tor_tls_get_my_certs(int server,
+ const tor_cert_t **link_cert_out,
+ const tor_cert_t **id_cert_out);
+crypto_pk_env_t *tor_tls_get_my_client_auth_key(void);
+crypto_pk_env_t *tor_tls_cert_get_key(tor_cert_t *cert);
+int tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert);
+int tor_tls_cert_is_valid(int severity,
+ const tor_cert_t *cert,
+ const tor_cert_t *signing_cert,
+ int check_rsa_1024);
#endif
diff --git a/src/common/tortls_states.h b/src/common/tortls_states.h
deleted file mode 100644
index dcff2479f6..0000000000
--- a/src/common/tortls_states.h
+++ /dev/null
@@ -1,414 +0,0 @@
-/* Copyright (c) 2003, Roger Dingledine
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/* Helper file: included only in tortls.c */
-
-#ifndef _TORTLS_STATES_H
-#define _TORTLS_STATES_H
-
-/* The main body of this file was mechanically generated with this
- perl script:
-
- my %keys = ();
- for $fn (@ARGV) {
- open(F, $fn);
- while (<F>) {
- next unless /^#define ((?:SSL|DTLS)\w*_ST_\w*)/;
- $keys{$1} = 1;
- }
- close(F);
- }
- for $k (sort keys %keys) {
- print "#ifdef $k\n S($k),\n#endif\n"
- }
-*/
-
-/** Mapping from allowed value of SSL.state to the name of C macro for that
- * state. Used for debugging an openssl connection. */
-static const struct { int state; const char *name; } state_map[] = {
-#define S(state) { state, #state }
-#ifdef DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A
- S(DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A),
-#endif
-#ifdef DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B
- S(DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B),
-#endif
-#ifdef DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A
- S(DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A),
-#endif
-#ifdef DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B
- S(DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B),
-#endif
-#ifdef SSL23_ST_CR_SRVR_HELLO_A
- S(SSL23_ST_CR_SRVR_HELLO_A),
-#endif
-#ifdef SSL23_ST_CR_SRVR_HELLO_B
- S(SSL23_ST_CR_SRVR_HELLO_B),
-#endif
-#ifdef SSL23_ST_CW_CLNT_HELLO_A
- S(SSL23_ST_CW_CLNT_HELLO_A),
-#endif
-#ifdef SSL23_ST_CW_CLNT_HELLO_B
- S(SSL23_ST_CW_CLNT_HELLO_B),
-#endif
-#ifdef SSL23_ST_SR_CLNT_HELLO_A
- S(SSL23_ST_SR_CLNT_HELLO_A),
-#endif
-#ifdef SSL23_ST_SR_CLNT_HELLO_B
- S(SSL23_ST_SR_CLNT_HELLO_B),
-#endif
-#ifdef SSL2_ST_CLIENT_START_ENCRYPTION
- S(SSL2_ST_CLIENT_START_ENCRYPTION),
-#endif
-#ifdef SSL2_ST_GET_CLIENT_FINISHED_A
- S(SSL2_ST_GET_CLIENT_FINISHED_A),
-#endif
-#ifdef SSL2_ST_GET_CLIENT_FINISHED_B
- S(SSL2_ST_GET_CLIENT_FINISHED_B),
-#endif
-#ifdef SSL2_ST_GET_CLIENT_HELLO_A
- S(SSL2_ST_GET_CLIENT_HELLO_A),
-#endif
-#ifdef SSL2_ST_GET_CLIENT_HELLO_B
- S(SSL2_ST_GET_CLIENT_HELLO_B),
-#endif
-#ifdef SSL2_ST_GET_CLIENT_HELLO_C
- S(SSL2_ST_GET_CLIENT_HELLO_C),
-#endif
-#ifdef SSL2_ST_GET_CLIENT_MASTER_KEY_A
- S(SSL2_ST_GET_CLIENT_MASTER_KEY_A),
-#endif
-#ifdef SSL2_ST_GET_CLIENT_MASTER_KEY_B
- S(SSL2_ST_GET_CLIENT_MASTER_KEY_B),
-#endif
-#ifdef SSL2_ST_GET_SERVER_FINISHED_A
- S(SSL2_ST_GET_SERVER_FINISHED_A),
-#endif
-#ifdef SSL2_ST_GET_SERVER_FINISHED_B
- S(SSL2_ST_GET_SERVER_FINISHED_B),
-#endif
-#ifdef SSL2_ST_GET_SERVER_HELLO_A
- S(SSL2_ST_GET_SERVER_HELLO_A),
-#endif
-#ifdef SSL2_ST_GET_SERVER_HELLO_B
- S(SSL2_ST_GET_SERVER_HELLO_B),
-#endif
-#ifdef SSL2_ST_GET_SERVER_VERIFY_A
- S(SSL2_ST_GET_SERVER_VERIFY_A),
-#endif
-#ifdef SSL2_ST_GET_SERVER_VERIFY_B
- S(SSL2_ST_GET_SERVER_VERIFY_B),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_A
- S(SSL2_ST_SEND_CLIENT_CERTIFICATE_A),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_B
- S(SSL2_ST_SEND_CLIENT_CERTIFICATE_B),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_C
- S(SSL2_ST_SEND_CLIENT_CERTIFICATE_C),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_D
- S(SSL2_ST_SEND_CLIENT_CERTIFICATE_D),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_FINISHED_A
- S(SSL2_ST_SEND_CLIENT_FINISHED_A),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_FINISHED_B
- S(SSL2_ST_SEND_CLIENT_FINISHED_B),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_HELLO_A
- S(SSL2_ST_SEND_CLIENT_HELLO_A),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_HELLO_B
- S(SSL2_ST_SEND_CLIENT_HELLO_B),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_MASTER_KEY_A
- S(SSL2_ST_SEND_CLIENT_MASTER_KEY_A),
-#endif
-#ifdef SSL2_ST_SEND_CLIENT_MASTER_KEY_B
- S(SSL2_ST_SEND_CLIENT_MASTER_KEY_B),
-#endif
-#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_A
- S(SSL2_ST_SEND_REQUEST_CERTIFICATE_A),
-#endif
-#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_B
- S(SSL2_ST_SEND_REQUEST_CERTIFICATE_B),
-#endif
-#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_C
- S(SSL2_ST_SEND_REQUEST_CERTIFICATE_C),
-#endif
-#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_D
- S(SSL2_ST_SEND_REQUEST_CERTIFICATE_D),
-#endif
-#ifdef SSL2_ST_SEND_SERVER_FINISHED_A
- S(SSL2_ST_SEND_SERVER_FINISHED_A),
-#endif
-#ifdef SSL2_ST_SEND_SERVER_FINISHED_B
- S(SSL2_ST_SEND_SERVER_FINISHED_B),
-#endif
-#ifdef SSL2_ST_SEND_SERVER_HELLO_A
- S(SSL2_ST_SEND_SERVER_HELLO_A),
-#endif
-#ifdef SSL2_ST_SEND_SERVER_HELLO_B
- S(SSL2_ST_SEND_SERVER_HELLO_B),
-#endif
-#ifdef SSL2_ST_SEND_SERVER_VERIFY_A
- S(SSL2_ST_SEND_SERVER_VERIFY_A),
-#endif
-#ifdef SSL2_ST_SEND_SERVER_VERIFY_B
- S(SSL2_ST_SEND_SERVER_VERIFY_B),
-#endif
-#ifdef SSL2_ST_SEND_SERVER_VERIFY_C
- S(SSL2_ST_SEND_SERVER_VERIFY_C),
-#endif
-#ifdef SSL2_ST_SERVER_START_ENCRYPTION
- S(SSL2_ST_SERVER_START_ENCRYPTION),
-#endif
-#ifdef SSL2_ST_X509_GET_CLIENT_CERTIFICATE
- S(SSL2_ST_X509_GET_CLIENT_CERTIFICATE),
-#endif
-#ifdef SSL2_ST_X509_GET_SERVER_CERTIFICATE
- S(SSL2_ST_X509_GET_SERVER_CERTIFICATE),
-#endif
-#ifdef SSL3_ST_CR_CERT_A
- S(SSL3_ST_CR_CERT_A),
-#endif
-#ifdef SSL3_ST_CR_CERT_B
- S(SSL3_ST_CR_CERT_B),
-#endif
-#ifdef SSL3_ST_CR_CERT_REQ_A
- S(SSL3_ST_CR_CERT_REQ_A),
-#endif
-#ifdef SSL3_ST_CR_CERT_REQ_B
- S(SSL3_ST_CR_CERT_REQ_B),
-#endif
-#ifdef SSL3_ST_CR_CERT_STATUS_A
- S(SSL3_ST_CR_CERT_STATUS_A),
-#endif
-#ifdef SSL3_ST_CR_CERT_STATUS_B
- S(SSL3_ST_CR_CERT_STATUS_B),
-#endif
-#ifdef SSL3_ST_CR_CHANGE_A
- S(SSL3_ST_CR_CHANGE_A),
-#endif
-#ifdef SSL3_ST_CR_CHANGE_B
- S(SSL3_ST_CR_CHANGE_B),
-#endif
-#ifdef SSL3_ST_CR_FINISHED_A
- S(SSL3_ST_CR_FINISHED_A),
-#endif
-#ifdef SSL3_ST_CR_FINISHED_B
- S(SSL3_ST_CR_FINISHED_B),
-#endif
-#ifdef SSL3_ST_CR_KEY_EXCH_A
- S(SSL3_ST_CR_KEY_EXCH_A),
-#endif
-#ifdef SSL3_ST_CR_KEY_EXCH_B
- S(SSL3_ST_CR_KEY_EXCH_B),
-#endif
-#ifdef SSL3_ST_CR_SESSION_TICKET_A
- S(SSL3_ST_CR_SESSION_TICKET_A),
-#endif
-#ifdef SSL3_ST_CR_SESSION_TICKET_B
- S(SSL3_ST_CR_SESSION_TICKET_B),
-#endif
-#ifdef SSL3_ST_CR_SRVR_DONE_A
- S(SSL3_ST_CR_SRVR_DONE_A),
-#endif
-#ifdef SSL3_ST_CR_SRVR_DONE_B
- S(SSL3_ST_CR_SRVR_DONE_B),
-#endif
-#ifdef SSL3_ST_CR_SRVR_HELLO_A
- S(SSL3_ST_CR_SRVR_HELLO_A),
-#endif
-#ifdef SSL3_ST_CR_SRVR_HELLO_B
- S(SSL3_ST_CR_SRVR_HELLO_B),
-#endif
-#ifdef SSL3_ST_CW_CERT_A
- S(SSL3_ST_CW_CERT_A),
-#endif
-#ifdef SSL3_ST_CW_CERT_B
- S(SSL3_ST_CW_CERT_B),
-#endif
-#ifdef SSL3_ST_CW_CERT_C
- S(SSL3_ST_CW_CERT_C),
-#endif
-#ifdef SSL3_ST_CW_CERT_D
- S(SSL3_ST_CW_CERT_D),
-#endif
-#ifdef SSL3_ST_CW_CERT_VRFY_A
- S(SSL3_ST_CW_CERT_VRFY_A),
-#endif
-#ifdef SSL3_ST_CW_CERT_VRFY_B
- S(SSL3_ST_CW_CERT_VRFY_B),
-#endif
-#ifdef SSL3_ST_CW_CHANGE_A
- S(SSL3_ST_CW_CHANGE_A),
-#endif
-#ifdef SSL3_ST_CW_CHANGE_B
- S(SSL3_ST_CW_CHANGE_B),
-#endif
-#ifdef SSL3_ST_CW_CLNT_HELLO_A
- S(SSL3_ST_CW_CLNT_HELLO_A),
-#endif
-#ifdef SSL3_ST_CW_CLNT_HELLO_B
- S(SSL3_ST_CW_CLNT_HELLO_B),
-#endif
-#ifdef SSL3_ST_CW_FINISHED_A
- S(SSL3_ST_CW_FINISHED_A),
-#endif
-#ifdef SSL3_ST_CW_FINISHED_B
- S(SSL3_ST_CW_FINISHED_B),
-#endif
-#ifdef SSL3_ST_CW_FLUSH
- S(SSL3_ST_CW_FLUSH),
-#endif
-#ifdef SSL3_ST_CW_KEY_EXCH_A
- S(SSL3_ST_CW_KEY_EXCH_A),
-#endif
-#ifdef SSL3_ST_CW_KEY_EXCH_B
- S(SSL3_ST_CW_KEY_EXCH_B),
-#endif
-#ifdef SSL3_ST_SR_CERT_A
- S(SSL3_ST_SR_CERT_A),
-#endif
-#ifdef SSL3_ST_SR_CERT_B
- S(SSL3_ST_SR_CERT_B),
-#endif
-#ifdef SSL3_ST_SR_CERT_VRFY_A
- S(SSL3_ST_SR_CERT_VRFY_A),
-#endif
-#ifdef SSL3_ST_SR_CERT_VRFY_B
- S(SSL3_ST_SR_CERT_VRFY_B),
-#endif
-#ifdef SSL3_ST_SR_CHANGE_A
- S(SSL3_ST_SR_CHANGE_A),
-#endif
-#ifdef SSL3_ST_SR_CHANGE_B
- S(SSL3_ST_SR_CHANGE_B),
-#endif
-#ifdef SSL3_ST_SR_CLNT_HELLO_A
- S(SSL3_ST_SR_CLNT_HELLO_A),
-#endif
-#ifdef SSL3_ST_SR_CLNT_HELLO_B
- S(SSL3_ST_SR_CLNT_HELLO_B),
-#endif
-#ifdef SSL3_ST_SR_CLNT_HELLO_C
- S(SSL3_ST_SR_CLNT_HELLO_C),
-#endif
-#ifdef SSL3_ST_SR_FINISHED_A
- S(SSL3_ST_SR_FINISHED_A),
-#endif
-#ifdef SSL3_ST_SR_FINISHED_B
- S(SSL3_ST_SR_FINISHED_B),
-#endif
-#ifdef SSL3_ST_SR_KEY_EXCH_A
- S(SSL3_ST_SR_KEY_EXCH_A),
-#endif
-#ifdef SSL3_ST_SR_KEY_EXCH_B
- S(SSL3_ST_SR_KEY_EXCH_B),
-#endif
-#ifdef SSL3_ST_SW_CERT_A
- S(SSL3_ST_SW_CERT_A),
-#endif
-#ifdef SSL3_ST_SW_CERT_B
- S(SSL3_ST_SW_CERT_B),
-#endif
-#ifdef SSL3_ST_SW_CERT_REQ_A
- S(SSL3_ST_SW_CERT_REQ_A),
-#endif
-#ifdef SSL3_ST_SW_CERT_REQ_B
- S(SSL3_ST_SW_CERT_REQ_B),
-#endif
-#ifdef SSL3_ST_SW_CERT_STATUS_A
- S(SSL3_ST_SW_CERT_STATUS_A),
-#endif
-#ifdef SSL3_ST_SW_CERT_STATUS_B
- S(SSL3_ST_SW_CERT_STATUS_B),
-#endif
-#ifdef SSL3_ST_SW_CHANGE_A
- S(SSL3_ST_SW_CHANGE_A),
-#endif
-#ifdef SSL3_ST_SW_CHANGE_B
- S(SSL3_ST_SW_CHANGE_B),
-#endif
-#ifdef SSL3_ST_SW_FINISHED_A
- S(SSL3_ST_SW_FINISHED_A),
-#endif
-#ifdef SSL3_ST_SW_FINISHED_B
- S(SSL3_ST_SW_FINISHED_B),
-#endif
-#ifdef SSL3_ST_SW_FLUSH
- S(SSL3_ST_SW_FLUSH),
-#endif
-#ifdef SSL3_ST_SW_HELLO_REQ_A
- S(SSL3_ST_SW_HELLO_REQ_A),
-#endif
-#ifdef SSL3_ST_SW_HELLO_REQ_B
- S(SSL3_ST_SW_HELLO_REQ_B),
-#endif
-#ifdef SSL3_ST_SW_HELLO_REQ_C
- S(SSL3_ST_SW_HELLO_REQ_C),
-#endif
-#ifdef SSL3_ST_SW_KEY_EXCH_A
- S(SSL3_ST_SW_KEY_EXCH_A),
-#endif
-#ifdef SSL3_ST_SW_KEY_EXCH_B
- S(SSL3_ST_SW_KEY_EXCH_B),
-#endif
-#ifdef SSL3_ST_SW_SESSION_TICKET_A
- S(SSL3_ST_SW_SESSION_TICKET_A),
-#endif
-#ifdef SSL3_ST_SW_SESSION_TICKET_B
- S(SSL3_ST_SW_SESSION_TICKET_B),
-#endif
-#ifdef SSL3_ST_SW_SRVR_DONE_A
- S(SSL3_ST_SW_SRVR_DONE_A),
-#endif
-#ifdef SSL3_ST_SW_SRVR_DONE_B
- S(SSL3_ST_SW_SRVR_DONE_B),
-#endif
-#ifdef SSL3_ST_SW_SRVR_HELLO_A
- S(SSL3_ST_SW_SRVR_HELLO_A),
-#endif
-#ifdef SSL3_ST_SW_SRVR_HELLO_B
- S(SSL3_ST_SW_SRVR_HELLO_B),
-#endif
-#ifdef SSL_ST_ACCEPT
- S(SSL_ST_ACCEPT),
-#endif
-#ifdef SSL_ST_BEFORE
- S(SSL_ST_BEFORE),
-#endif
-#ifdef SSL_ST_CONNECT
- S(SSL_ST_CONNECT),
-#endif
-#ifdef SSL_ST_INIT
- S(SSL_ST_INIT),
-#endif
-#ifdef SSL_ST_MASK
- S(SSL_ST_MASK),
-#endif
-#ifdef SSL_ST_OK
- S(SSL_ST_OK),
-#endif
-#ifdef SSL_ST_READ_BODY
- S(SSL_ST_READ_BODY),
-#endif
-#ifdef SSL_ST_READ_DONE
- S(SSL_ST_READ_DONE),
-#endif
-#ifdef SSL_ST_READ_HEADER
- S(SSL_ST_READ_HEADER),
-#endif
-#ifdef SSL_ST_RENEGOTIATE
- S(SSL_ST_RENEGOTIATE),
-#endif
- { 0, NULL }
-};
-
-#endif
-
diff --git a/src/common/util.c b/src/common/util.c
index 7675ede433..3d8b7dabef 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -14,6 +14,10 @@
#define _GNU_SOURCE
#include "orconfig.h"
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#define UTIL_PRIVATE
#include "util.h"
#include "torlog.h"
#undef log
@@ -27,6 +31,7 @@
#include <direct.h>
#include <process.h>
#include <tchar.h>
+#include <Winbase.h>
#else
#include <dirent.h>
#include <pwd.h>
@@ -42,6 +47,7 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#include <signal.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -67,9 +73,6 @@
#ifdef HAVE_SYS_FCNTL_H
#include <sys/fcntl.h>
#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
@@ -87,6 +90,9 @@
#ifdef HAVE_MALLOC_NP_H
#include <malloc_np.h>
#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
/* =====
* Memory management
@@ -417,6 +423,32 @@ round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
return number;
}
+/** Return the number of bits set in <b>v</b>. */
+int
+n_bits_set_u8(uint8_t v)
+{
+ static const int nybble_table[] = {
+ 0, /* 0000 */
+ 1, /* 0001 */
+ 1, /* 0010 */
+ 2, /* 0011 */
+ 1, /* 0100 */
+ 2, /* 0101 */
+ 2, /* 0110 */
+ 3, /* 0111 */
+ 1, /* 1000 */
+ 2, /* 1001 */
+ 2, /* 1010 */
+ 3, /* 1011 */
+ 2, /* 1100 */
+ 3, /* 1101 */
+ 3, /* 1110 */
+ 4, /* 1111 */
+ };
+
+ return nybble_table[v & 15] + nybble_table[v>>4];
+}
+
/* =====
* String manipulation
* ===== */
@@ -500,6 +532,23 @@ tor_strisnonupper(const char *s)
return 1;
}
+/** As strcmp, except that either string may be NULL. The NULL string is
+ * considered to be before any non-NULL string. */
+int
+strcmp_opt(const char *s1, const char *s2)
+{
+ if (!s1) {
+ if (!s2)
+ return 0;
+ else
+ return -1;
+ } else if (!s2) {
+ return 1;
+ } else {
+ return strcmp(s1, s2);
+ }
+}
+
/** Compares the first strlen(s2) characters of s1 with s2. Returns as for
* strcmp.
*/
@@ -722,6 +771,34 @@ find_str_at_start_of_line(const char *haystack, const char *needle)
return NULL;
}
+/** Returns true if <b>string</b> could be a C identifier.
+ A C identifier must begin with a letter or an underscore and the
+ rest of its characters can be letters, numbers or underscores. No
+ length limit is imposed. */
+int
+string_is_C_identifier(const char *string)
+{
+ size_t iter;
+ size_t length = strlen(string);
+ if (!length)
+ return 0;
+
+ for (iter = 0; iter < length ; iter++) {
+ if (iter == 0) {
+ if (!(TOR_ISALPHA(string[iter]) ||
+ string[iter] == '_'))
+ return 0;
+ } else {
+ if (!(TOR_ISALPHA(string[iter]) ||
+ TOR_ISDIGIT(string[iter]) ||
+ string[iter] == '_'))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
/** Return true iff the 'len' bytes at 'mem' are all zero. */
int
tor_mem_is_zero(const char *mem, size_t len)
@@ -958,7 +1035,7 @@ esc_for_log(const char *s)
char *result, *outp;
size_t len = 3;
if (!s) {
- return tor_strdup("");
+ return tor_strdup("(null)");
}
for (cp = s; *cp; ++cp) {
@@ -1353,6 +1430,26 @@ format_iso_time(char *buf, time_t t)
strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_gmtime_r(&t, &tm));
}
+/** As format_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid
+ * embedding an internal space. */
+void
+format_iso_time_nospace(char *buf, time_t t)
+{
+ format_iso_time(buf, t);
+ buf[10] = 'T';
+}
+
+/** As format_iso_time_nospace, but include microseconds in decimal
+ * fixed-point format. Requires that buf be at least ISO_TIME_USEC_LEN+1
+ * bytes long. */
+void
+format_iso_time_nospace_usec(char *buf, const struct timeval *tv)
+{
+ tor_assert(tv);
+ format_iso_time_nospace(buf, tv->tv_sec);
+ tor_snprintf(buf+ISO_TIME_LEN, 8, ".%06d", (int)tv->tv_usec);
+}
+
/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>,
* parse it and store its value in *<b>t</b>. Return 0 on success, -1 on
* failure. Ignore extraneous stuff in <b>cp</b> separated by whitespace from
@@ -1867,7 +1964,6 @@ int
start_writing_to_file(const char *fname, int open_flags, int mode,
open_file_t **data_out)
{
- size_t tempname_len = strlen(fname)+16;
open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t));
const char *open_name;
int append = 0;
@@ -1878,7 +1974,6 @@ start_writing_to_file(const char *fname, int open_flags, int mode,
tor_assert((open_flags & (O_BINARY|O_TEXT)) != 0);
#endif
new_file->fd = -1;
- tor_assert(tempname_len > strlen(fname)); /*check for overflow*/
new_file->filename = tor_strdup(fname);
if (open_flags & O_APPEND) {
open_name = fname;
@@ -1886,11 +1981,8 @@ start_writing_to_file(const char *fname, int open_flags, int mode,
append = 1;
open_flags &= ~O_APPEND;
} else {
- open_name = new_file->tempname = tor_malloc(tempname_len);
- if (tor_snprintf(new_file->tempname, tempname_len, "%s.tmp", fname)<0) {
- log_warn(LD_GENERAL, "Failed to generate filename");
- goto err;
- }
+ tor_asprintf(&new_file->tempname, "%s.tmp", fname);
+ open_name = new_file->tempname;
/* We always replace an existing temporary file if there is one. */
open_flags |= O_CREAT|O_TRUNC;
open_flags &= ~O_EXCL;
@@ -1899,7 +1991,7 @@ start_writing_to_file(const char *fname, int open_flags, int mode,
if (open_flags & O_BINARY)
new_file->binary = 1;
- new_file->fd = open(open_name, open_flags, mode);
+ new_file->fd = tor_open_cloexec(open_name, open_flags, mode);
if (new_file->fd < 0) {
log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s",
open_name, fname, strerror(errno));
@@ -2060,13 +2152,12 @@ write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin)
return write_chunks_to_file_impl(fname, chunks, flags);
}
-/** As write_str_to_file, but does not assume a NUL-terminated
- * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */
-int
-write_bytes_to_file(const char *fname, const char *str, size_t len,
- int bin)
+/** Write <b>len</b> bytes, starting at <b>str</b>, to <b>fname</b>
+ using the open() flags passed in <b>flags</b>. */
+static int
+write_bytes_to_file_impl(const char *fname, const char *str, size_t len,
+ int flags)
{
- int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT);
int r;
sized_chunk_t c = { str, len };
smartlist_t *chunks = smartlist_create();
@@ -2076,20 +2167,35 @@ write_bytes_to_file(const char *fname, const char *str, size_t len,
return r;
}
+/** As write_str_to_file, but does not assume a NUL-terminated
+ * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */
+int
+write_bytes_to_file(const char *fname, const char *str, size_t len,
+ int bin)
+{
+ return write_bytes_to_file_impl(fname, str, len,
+ OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT));
+}
+
/** As write_bytes_to_file, but if the file already exists, append the bytes
* to the end of the file instead of overwriting it. */
int
append_bytes_to_file(const char *fname, const char *str, size_t len,
int bin)
{
- int flags = OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT);
- int r;
- sized_chunk_t c = { str, len };
- smartlist_t *chunks = smartlist_create();
- smartlist_add(chunks, &c);
- r = write_chunks_to_file_impl(fname, chunks, flags);
- smartlist_free(chunks);
- return r;
+ return write_bytes_to_file_impl(fname, str, len,
+ OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT));
+}
+
+/** Like write_str_to_file(), but also return -1 if there was a file
+ already residing in <b>fname</b>. */
+int
+write_bytes_to_new_file(const char *fname, const char *str, size_t len,
+ int bin)
+{
+ return write_bytes_to_file_impl(fname, str, len,
+ OPEN_FLAGS_DONT_REPLACE|
+ (bin?O_BINARY:O_TEXT));
}
/** Read the contents of <b>filename</b> into a newly allocated
@@ -2120,7 +2226,7 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out)
tor_assert(filename);
- fd = open(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0);
+ fd = tor_open_cloexec(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0);
if (fd<0) {
int severity = LOG_WARN;
int save_errno = errno;
@@ -2506,18 +2612,21 @@ digit_to_num(char d)
* success, store the result in <b>out</b>, advance bufp to the next
* character, and return 0. On failure, return -1. */
static int
-scan_unsigned(const char **bufp, unsigned *out, int width)
+scan_unsigned(const char **bufp, unsigned *out, int width, int base)
{
unsigned result = 0;
int scanned_so_far = 0;
+ const int hex = base==16;
+ tor_assert(base == 10 || base == 16);
if (!bufp || !*bufp || !out)
return -1;
if (width<0)
width=MAX_SCANF_WIDTH;
- while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
- int digit = digit_to_num(*(*bufp)++);
- unsigned new_result = result * 10 + digit;
+ while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
+ && scanned_so_far < width) {
+ int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
+ unsigned new_result = result * base + digit;
if (new_result > UINT32_MAX || new_result < result)
return -1; /* over/underflow. */
result = new_result;
@@ -2579,11 +2688,12 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
if (!width) /* No zero-width things. */
return -1;
}
- if (*pattern == 'u') {
+ if (*pattern == 'u' || *pattern == 'x') {
unsigned *u = va_arg(ap, unsigned *);
+ const int base = (*pattern == 'u') ? 10 : 16;
if (!*buf)
return n_matched;
- if (scan_unsigned(&buf, u, width)<0)
+ if (scan_unsigned(&buf, u, width, base)<0)
return n_matched;
++pattern;
++n_matched;
@@ -2620,9 +2730,9 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b>
* and store the results in the corresponding argument fields. Differs from
- * sscanf in that it: Only handles %u and %Ns. Does not handle arbitrarily
- * long widths. %u does not consume any space. Is locale-independent.
- * Returns -1 on malformed patterns.
+ * sscanf in that it: Only handles %u and %x and %Ns. Does not handle
+ * arbitrarily long widths. %u and %x do not consume any space. Is
+ * locale-independent. Returns -1 on malformed patterns.
*
* (As with other locale-independent functions, we need this to parse data that
* is in ASCII without worrying that the C library's locale-handling will make
@@ -2639,6 +2749,30 @@ tor_sscanf(const char *buf, const char *pattern, ...)
return r;
}
+/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>)
+ * to <b>sl</b>. */
+void
+smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...)
+{
+ va_list ap;
+ va_start(ap, pattern);
+ smartlist_add_vasprintf(sl, pattern, ap);
+ va_end(ap);
+}
+
+/** va_list-based backend of smartlist_add_asprintf. */
+void
+smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern,
+ va_list args)
+{
+ char *str = NULL;
+
+ tor_vasprintf(&str, pattern, args);
+ tor_assert(str != NULL);
+
+ smartlist_add(sl, str);
+}
+
/** Return a new list containing the filenames in the directory <b>dirname</b>.
* Return NULL on error or if <b>dirname</b> is not a directory.
*/
@@ -2647,14 +2781,12 @@ tor_listdir(const char *dirname)
{
smartlist_t *result;
#ifdef MS_WINDOWS
- char *pattern;
+ char *pattern=NULL;
TCHAR tpattern[MAX_PATH] = {0};
char name[MAX_PATH] = {0};
HANDLE handle;
WIN32_FIND_DATA findData;
- size_t pattern_len = strlen(dirname)+16;
- pattern = tor_malloc(pattern_len);
- tor_snprintf(pattern, pattern_len, "%s\\*", dirname);
+ tor_asprintf(&pattern, "%s\\*", dirname);
#ifdef UNICODE
mbstowcs(tpattern,pattern,MAX_PATH);
#else
@@ -2816,7 +2948,7 @@ finish_daemon(const char *desired_cwd)
exit(1);
}
- nullfd = open("/dev/null", O_RDWR);
+ nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0);
if (nullfd < 0) {
log_err(LD_GENERAL,"/dev/null can't be opened. Exiting.");
exit(1);
@@ -2887,3 +3019,1166 @@ load_windows_system_library(const TCHAR *library_name)
}
#endif
+/** Format a single argument for being put on a Windows command line.
+ * Returns a newly allocated string */
+static char *
+format_win_cmdline_argument(const char *arg)
+{
+ char *formatted_arg;
+ char need_quotes;
+ const char *c;
+ int i;
+ int bs_counter = 0;
+ /* Backslash we can point to when one is inserted into the string */
+ const char backslash = '\\';
+
+ /* Smartlist of *char */
+ smartlist_t *arg_chars;
+ arg_chars = smartlist_create();
+
+ /* Quote string if it contains whitespace or is empty */
+ need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]);
+
+ /* Build up smartlist of *chars */
+ for (c=arg; *c != '\0'; c++) {
+ if ('"' == *c) {
+ /* Double up backslashes preceding a quote */
+ for (i=0; i<(bs_counter*2); i++)
+ smartlist_add(arg_chars, (void*)&backslash);
+ bs_counter = 0;
+ /* Escape the quote */
+ smartlist_add(arg_chars, (void*)&backslash);
+ smartlist_add(arg_chars, (void*)c);
+ } else if ('\\' == *c) {
+ /* Count backslashes until we know whether to double up */
+ bs_counter++;
+ } else {
+ /* Don't double up slashes preceding a non-quote */
+ for (i=0; i<bs_counter; i++)
+ smartlist_add(arg_chars, (void*)&backslash);
+ bs_counter = 0;
+ smartlist_add(arg_chars, (void*)c);
+ }
+ }
+ /* Don't double up trailing backslashes */
+ for (i=0; i<bs_counter; i++)
+ smartlist_add(arg_chars, (void*)&backslash);
+
+ /* Allocate space for argument, quotes (if needed), and terminator */
+ formatted_arg = tor_malloc(sizeof(char) *
+ (smartlist_len(arg_chars) + (need_quotes?2:0) + 1));
+
+ /* Add leading quote */
+ i=0;
+ if (need_quotes)
+ formatted_arg[i++] = '"';
+
+ /* Add characters */
+ SMARTLIST_FOREACH(arg_chars, char*, c,
+ {
+ formatted_arg[i++] = *c;
+ });
+
+ /* Add trailing quote */
+ if (need_quotes)
+ formatted_arg[i++] = '"';
+ formatted_arg[i] = '\0';
+
+ smartlist_free(arg_chars);
+ return formatted_arg;
+}
+
+/** Format a command line for use on Windows, which takes the command as a
+ * string rather than string array. Follows the rules from "Parsing C++
+ * Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the
+ * Python subprocess module. Returns a newly allocated string */
+char *
+tor_join_win_cmdline(const char *argv[])
+{
+ smartlist_t *argv_list;
+ char *joined_argv;
+ int i;
+
+ /* Format each argument and put the result in a smartlist */
+ argv_list = smartlist_create();
+ for (i=0; argv[i] != NULL; i++) {
+ smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i]));
+ }
+
+ /* Join the arguments with whitespace */
+ joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL);
+
+ /* Free the newly allocated arguments, and the smartlist */
+ SMARTLIST_FOREACH(argv_list, char *, arg,
+ {
+ tor_free(arg);
+ });
+ smartlist_free(argv_list);
+
+ return joined_argv;
+}
+
+/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
+ * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
+ * safe.
+ *
+ * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE bytes available.
+ *
+ * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded
+ * with spaces. Note that there is no trailing \0. CHILD_STATE indicates where
+ * in the processs of starting the child process did the failure occur (see
+ * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of
+ * errno when the failure occurred.
+ */
+
+void
+format_helper_exit_status(unsigned char child_state, int saved_errno,
+ char *hex_errno)
+{
+ unsigned int unsigned_errno;
+ char *cur;
+ size_t i;
+
+ /* Fill hex_errno with spaces, and a trailing newline (memset may
+ not be signal handler safe, so we can't use it) */
+ for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++)
+ hex_errno[i] = ' ';
+ hex_errno[HEX_ERRNO_SIZE - 1] = '\n';
+
+ /* Convert errno to be unsigned for hex conversion */
+ if (saved_errno < 0) {
+ unsigned_errno = (unsigned int) -saved_errno;
+ } else {
+ unsigned_errno = (unsigned int) saved_errno;
+ }
+
+ /* Convert errno to hex (start before \n) */
+ cur = hex_errno + HEX_ERRNO_SIZE - 2;
+
+ /* Check for overflow on first iteration of the loop */
+ if (cur < hex_errno)
+ return;
+
+ do {
+ *cur-- = "0123456789ABCDEF"[unsigned_errno % 16];
+ unsigned_errno /= 16;
+ } while (unsigned_errno != 0 && cur >= hex_errno);
+
+ /* Prepend the minus sign if errno was negative */
+ if (saved_errno < 0 && cur >= hex_errno)
+ *cur-- = '-';
+
+ /* Leave a gap */
+ if (cur >= hex_errno)
+ *cur-- = '/';
+
+ /* Check for overflow on first iteration of the loop */
+ if (cur < hex_errno)
+ return;
+
+ /* Convert child_state to hex */
+ do {
+ *cur-- = "0123456789ABCDEF"[child_state % 16];
+ child_state /= 16;
+ } while (child_state != 0 && cur >= hex_errno);
+}
+
+/* Maximum number of file descriptors, if we cannot get it via sysconf() */
+#define DEFAULT_MAX_FD 256
+
+/** Terminate the process of <b>process_handle</b>.
+ * Code borrowed from Python's os.kill. */
+int
+tor_terminate_process(process_handle_t *process_handle)
+{
+#ifdef MS_WINDOWS
+ if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) {
+ HANDLE handle;
+ /* If the signal is outside of what GenerateConsoleCtrlEvent can use,
+ attempt to open and terminate the process. */
+ handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
+ process_handle->pid.dwProcessId);
+ if (!handle)
+ return -1;
+
+ if (!TerminateProcess(handle, 0))
+ return -1;
+ else
+ return 0;
+ }
+#else /* Unix */
+ return kill(process_handle->pid, SIGTERM);
+#endif
+
+ return -1;
+}
+
+/** Return the Process ID of <b>process_handle</b>. */
+int
+tor_process_get_pid(process_handle_t *process_handle)
+{
+#ifdef MS_WINDOWS
+ return (int) process_handle->pid.dwProcessId;
+#else
+ return (int) process_handle->pid;
+#endif
+}
+
+#ifdef MS_WINDOWS
+HANDLE
+tor_process_get_stdout_pipe(process_handle_t *process_handle)
+{
+ return process_handle->stdout_pipe;
+}
+#else
+FILE *
+tor_process_get_stdout_pipe(process_handle_t *process_handle)
+{
+ return process_handle->stdout_handle;
+}
+#endif
+
+static process_handle_t *
+process_handle_new(void)
+{
+ process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t));
+
+#ifndef MS_WINDOWS
+ out->stdout_pipe = -1;
+ out->stderr_pipe = -1;
+#endif
+
+ return out;
+}
+
+/*DOCDOC*/
+#define CHILD_STATE_INIT 0
+#define CHILD_STATE_PIPE 1
+#define CHILD_STATE_MAXFD 2
+#define CHILD_STATE_FORK 3
+#define CHILD_STATE_DUPOUT 4
+#define CHILD_STATE_DUPERR 5
+#define CHILD_STATE_REDIRECT 6
+#define CHILD_STATE_CLOSEFD 7
+#define CHILD_STATE_EXEC 8
+#define CHILD_STATE_FAILEXEC 9
+
+/** Start a program in the background. If <b>filename</b> contains a '/', then
+ * it will be treated as an absolute or relative path. Otherwise, on
+ * non-Windows systems, the system path will be searched for <b>filename</b>.
+ * On Windows, only the current directory will be searched. Here, to search the
+ * system path (as well as the application directory, current working
+ * directory, and system directories), set filename to NULL.
+ *
+ * The strings in <b>argv</b> will be passed as the command line arguments of
+ * the child program (following convention, argv[0] should normally be the
+ * filename of the executable, and this must be the case if <b>filename</b> is
+ * NULL). The last element of argv must be NULL. A handle to the child process
+ * will be returned in process_handle (which must be non-NULL). Read
+ * process_handle.status to find out if the process was successfully launched.
+ * For convenience, process_handle.status is returned by this function.
+ *
+ * Some parts of this code are based on the POSIX subprocess module from
+ * Python, and example code from
+ * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx.
+ */
+int
+tor_spawn_background(const char *const filename, const char **argv,
+#ifdef MS_WINDOWS
+ LPVOID envp,
+#else
+ const char **envp,
+#endif
+ process_handle_t **process_handle_out)
+{
+#ifdef MS_WINDOWS
+ HANDLE stdout_pipe_read = NULL;
+ HANDLE stdout_pipe_write = NULL;
+ HANDLE stderr_pipe_read = NULL;
+ HANDLE stderr_pipe_write = NULL;
+ process_handle_t *process_handle;
+ int status;
+
+ STARTUPINFO siStartInfo;
+ BOOL retval = FALSE;
+
+ SECURITY_ATTRIBUTES saAttr;
+ char *joined_argv;
+
+ (void)envp; // Unused on Windows
+
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ /* TODO: should we set explicit security attributes? (#2046, comment 5) */
+ saAttr.lpSecurityDescriptor = NULL;
+
+ /* Assume failure to start process */
+ status = PROCESS_STATUS_ERROR;
+
+ /* Set up pipe for stdout */
+ if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) {
+ log_warn(LD_GENERAL,
+ "Failed to create pipe for stdout communication with child process: %s",
+ format_win32_error(GetLastError()));
+ return status;
+ }
+ if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
+ log_warn(LD_GENERAL,
+ "Failed to configure pipe for stdout communication with child "
+ "process: %s", format_win32_error(GetLastError()));
+ return status;
+ }
+
+ /* Set up pipe for stderr */
+ if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) {
+ log_warn(LD_GENERAL,
+ "Failed to create pipe for stderr communication with child process: %s",
+ format_win32_error(GetLastError()));
+ return status;
+ }
+ if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
+ log_warn(LD_GENERAL,
+ "Failed to configure pipe for stderr communication with child "
+ "process: %s", format_win32_error(GetLastError()));
+ return status;
+ }
+
+ /* Create the child process */
+
+ /* Windows expects argv to be a whitespace delimited string, so join argv up
+ */
+ joined_argv = tor_join_win_cmdline(argv);
+
+ process_handle = process_handle_new();
+ process_handle->status = status;
+
+ ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION));
+ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
+ siStartInfo.cb = sizeof(STARTUPINFO);
+ siStartInfo.hStdError = stderr_pipe_write;
+ siStartInfo.hStdOutput = stdout_pipe_write;
+ siStartInfo.hStdInput = NULL;
+ siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ /* Create the child process */
+
+ retval = CreateProcess(filename, // module name
+ joined_argv, // command line
+ /* TODO: should we set explicit security attributes? (#2046, comment 5) */
+ NULL, // process security attributes
+ NULL, // primary thread security attributes
+ TRUE, // handles are inherited
+ /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess()
+ * work?) */
+ 0, // creation flags
+ envp, // use parent's environment
+ NULL, // use parent's current directory
+ &siStartInfo, // STARTUPINFO pointer
+ &(process_handle->pid)); // receives PROCESS_INFORMATION
+
+ tor_free(joined_argv);
+
+ if (!retval) {
+ log_warn(LD_GENERAL,
+ "Failed to create child process %s: %s", filename?filename:argv[0],
+ format_win32_error(GetLastError()));
+ tor_free(process_handle);
+ } else {
+ /* TODO: Close hProcess and hThread in process_handle->pid? */
+ process_handle->stdout_pipe = stdout_pipe_read;
+ process_handle->stderr_pipe = stderr_pipe_read;
+ status = process_handle->status = PROCESS_STATUS_RUNNING;
+ }
+
+ /* TODO: Close pipes on exit */
+ *process_handle_out = process_handle;
+ return status;
+#else // MS_WINDOWS
+ pid_t pid;
+ int stdout_pipe[2];
+ int stderr_pipe[2];
+ int fd, retval;
+ ssize_t nbytes;
+ process_handle_t *process_handle;
+ int status;
+
+ const char *error_message = SPAWN_ERROR_MESSAGE;
+ size_t error_message_length;
+
+ /* Represents where in the process of spawning the program is;
+ this is used for printing out the error message */
+ unsigned char child_state = CHILD_STATE_INIT;
+
+ char hex_errno[HEX_ERRNO_SIZE];
+
+ static int max_fd = -1;
+
+ status = PROCESS_STATUS_ERROR;
+
+ /* We do the strlen here because strlen() is not signal handler safe,
+ and we are not allowed to use unsafe functions between fork and exec */
+ error_message_length = strlen(error_message);
+
+ child_state = CHILD_STATE_PIPE;
+
+ /* Set up pipe for redirecting stdout and stderr of child */
+ retval = pipe(stdout_pipe);
+ if (-1 == retval) {
+ log_warn(LD_GENERAL,
+ "Failed to set up pipe for stdout communication with child process: %s",
+ strerror(errno));
+ return status;
+ }
+
+ retval = pipe(stderr_pipe);
+ if (-1 == retval) {
+ log_warn(LD_GENERAL,
+ "Failed to set up pipe for stderr communication with child process: %s",
+ strerror(errno));
+ return status;
+ }
+
+ child_state = CHILD_STATE_MAXFD;
+
+#ifdef _SC_OPEN_MAX
+ if (-1 != max_fd) {
+ max_fd = (int) sysconf(_SC_OPEN_MAX);
+ if (max_fd == -1)
+ max_fd = DEFAULT_MAX_FD;
+ log_warn(LD_GENERAL,
+ "Cannot find maximum file descriptor, assuming %d", max_fd);
+ }
+#else
+ max_fd = DEFAULT_MAX_FD;
+#endif
+
+ child_state = CHILD_STATE_FORK;
+
+ pid = fork();
+ if (0 == pid) {
+ /* In child */
+
+ child_state = CHILD_STATE_DUPOUT;
+
+ /* Link child stdout to the write end of the pipe */
+ retval = dup2(stdout_pipe[1], STDOUT_FILENO);
+ if (-1 == retval)
+ goto error;
+
+ child_state = CHILD_STATE_DUPERR;
+
+ /* Link child stderr to the write end of the pipe */
+ retval = dup2(stderr_pipe[1], STDERR_FILENO);
+ if (-1 == retval)
+ goto error;
+
+ child_state = CHILD_STATE_REDIRECT;
+
+ /* Link stdin to /dev/null */
+ fd = open("/dev/null", O_RDONLY); /* NOT cloexec, obviously. */
+ if (fd != -1)
+ dup2(fd, STDIN_FILENO);
+ else
+ goto error;
+
+ child_state = CHILD_STATE_CLOSEFD;
+
+ close(stderr_pipe[0]);
+ close(stderr_pipe[1]);
+ close(stdout_pipe[0]);
+ close(stdout_pipe[1]);
+ close(fd);
+
+ /* Close all other fds, including the read end of the pipe */
+ /* XXX: We should now be doing enough FD_CLOEXEC setting to make
+ * this needless. */
+ for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) {
+ close(fd);
+ }
+
+ child_state = CHILD_STATE_EXEC;
+
+ /* Call the requested program. We need the cast because
+ execvp doesn't define argv as const, even though it
+ does not modify the arguments */
+ if (envp)
+ execve(filename, (char *const *) argv, (char*const*)envp);
+ else
+ execvp(filename, (char *const *) argv);
+
+ /* If we got here, the exec or open(/dev/null) failed */
+
+ child_state = CHILD_STATE_FAILEXEC;
+
+ error:
+ /* XXX: are we leaking fds from the pipe? */
+
+ format_helper_exit_status(child_state, errno, hex_errno);
+
+ /* Write the error message. GCC requires that we check the return
+ value, but there is nothing we can do if it fails */
+ /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */
+ nbytes = write(STDOUT_FILENO, error_message, error_message_length);
+ nbytes = write(STDOUT_FILENO, hex_errno, sizeof(hex_errno));
+
+ (void) nbytes;
+
+ _exit(255);
+ /* Never reached, but avoids compiler warning */
+ return status;
+ }
+
+ /* In parent */
+
+ if (-1 == pid) {
+ log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno));
+ close(stdout_pipe[0]);
+ close(stdout_pipe[1]);
+ close(stderr_pipe[0]);
+ close(stderr_pipe[1]);
+ return status;
+ }
+
+ process_handle = process_handle_new();
+ process_handle->status = status;
+ process_handle->pid = pid;
+
+ /* TODO: If the child process forked but failed to exec, waitpid it */
+
+ /* Return read end of the pipes to caller, and close write end */
+ process_handle->stdout_pipe = stdout_pipe[0];
+ retval = close(stdout_pipe[1]);
+
+ if (-1 == retval) {
+ log_warn(LD_GENERAL,
+ "Failed to close write end of stdout pipe in parent process: %s",
+ strerror(errno));
+ }
+
+ process_handle->stderr_pipe = stderr_pipe[0];
+ retval = close(stderr_pipe[1]);
+
+ if (-1 == retval) {
+ log_warn(LD_GENERAL,
+ "Failed to close write end of stderr pipe in parent process: %s",
+ strerror(errno));
+ }
+
+ status = process_handle->status = PROCESS_STATUS_RUNNING;
+ /* Set stdout/stderr pipes to be non-blocking */
+ fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK);
+ fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK);
+ /* Open the buffered IO streams */
+ process_handle->stdout_handle = fdopen(process_handle->stdout_pipe, "r");
+ process_handle->stderr_handle = fdopen(process_handle->stderr_pipe, "r");
+
+ *process_handle_out = process_handle;
+ return process_handle->status;
+#endif // MS_WINDOWS
+}
+
+/** Destroy all resources allocated by the process handle in
+ * <b>process_handle</b>.
+ * If <b>also_terminate_process</b> is true, also terminate the
+ * process of the process handle. */
+void
+tor_process_handle_destroy(process_handle_t *process_handle,
+ int also_terminate_process)
+{
+ if (!process_handle)
+ return;
+
+ if (also_terminate_process) {
+ if (tor_terminate_process(process_handle) < 0) {
+ log_notice(LD_GENERAL, "Failed to terminate process with PID '%d'",
+ tor_process_get_pid(process_handle));
+ } else {
+ log_info(LD_GENERAL, "Terminated process with PID '%d'",
+ tor_process_get_pid(process_handle));
+ }
+ }
+
+ process_handle->status = PROCESS_STATUS_NOTRUNNING;
+
+#ifdef MS_WINDOWS
+ if (process_handle->stdout_pipe)
+ CloseHandle(process_handle->stdout_pipe);
+
+ if (process_handle->stderr_pipe)
+ CloseHandle(process_handle->stderr_pipe);
+#else
+ if (process_handle->stdout_handle)
+ fclose(process_handle->stdout_handle);
+
+ if (process_handle->stderr_handle)
+ fclose(process_handle->stderr_handle);
+#endif
+
+ memset(process_handle, 0x0f, sizeof(process_handle_t));
+ tor_free(process_handle);
+}
+
+/** Get the exit code of a process specified by <b>process_handle</b> and store
+ * it in <b>exit_code</b>, if set to a non-NULL value. If <b>block</b> is set
+ * to true, the call will block until the process has exited. Otherwise if
+ * the process is still running, the function will return
+ * PROCESS_EXIT_RUNNING, and exit_code will be left unchanged. Returns
+ * PROCESS_EXIT_EXITED if the process did exit. If there is a failure,
+ * PROCESS_EXIT_ERROR will be returned and the contents of exit_code (if
+ * non-NULL) will be undefined. N.B. Under *nix operating systems, this will
+ * probably not work in Tor, because waitpid() is called in main.c to reap any
+ * terminated child processes.*/
+int
+tor_get_exit_code(const process_handle_t *process_handle,
+ int block, int *exit_code)
+{
+#ifdef MS_WINDOWS
+ DWORD retval;
+ BOOL success;
+
+ if (block) {
+ /* Wait for the process to exit */
+ retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE);
+ if (retval != WAIT_OBJECT_0) {
+ log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s",
+ (int)retval, format_win32_error(GetLastError()));
+ return PROCESS_EXIT_ERROR;
+ }
+ } else {
+ retval = WaitForSingleObject(process_handle->pid.hProcess, 0);
+ if (WAIT_TIMEOUT == retval) {
+ /* Process has not exited */
+ return PROCESS_EXIT_RUNNING;
+ } else if (retval != WAIT_OBJECT_0) {
+ log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s",
+ (int)retval, format_win32_error(GetLastError()));
+ return PROCESS_EXIT_ERROR;
+ }
+ }
+
+ if (exit_code != NULL) {
+ success = GetExitCodeProcess(process_handle->pid.hProcess,
+ (PDWORD)exit_code);
+ if (!success) {
+ log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s",
+ format_win32_error(GetLastError()));
+ return PROCESS_EXIT_ERROR;
+ }
+ }
+#else
+ int stat_loc;
+ int retval;
+
+ retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG);
+ if (!block && 0 == retval) {
+ /* Process has not exited */
+ return PROCESS_EXIT_RUNNING;
+ } else if (retval != process_handle->pid) {
+ log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s",
+ process_handle->pid, strerror(errno));
+ return PROCESS_EXIT_ERROR;
+ }
+
+ if (!WIFEXITED(stat_loc)) {
+ log_warn(LD_GENERAL, "Process %d did not exit normally",
+ process_handle->pid);
+ return PROCESS_EXIT_ERROR;
+ }
+
+ if (exit_code != NULL)
+ *exit_code = WEXITSTATUS(stat_loc);
+#endif // MS_WINDOWS
+
+ return PROCESS_EXIT_EXITED;
+}
+
+#ifdef MS_WINDOWS
+/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If
+ * <b>hProcess</b> is NULL, the function will return immediately if there is
+ * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle
+ * to the process owning the <b>h</b>. In this case, the function will exit
+ * only once the process has exited, or <b>count</b> bytes are read. Returns
+ * the number of bytes read, or -1 on error. */
+ssize_t
+tor_read_all_handle(HANDLE h, char *buf, size_t count,
+ const process_handle_t *process)
+{
+ size_t numread = 0;
+ BOOL retval;
+ DWORD byte_count;
+ BOOL process_exited = FALSE;
+
+ if (count > SIZE_T_CEILING || count > SSIZE_T_MAX)
+ return -1;
+
+ while (numread != count) {
+ /* Check if there is anything to read */
+ retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL);
+ if (!retval) {
+ log_warn(LD_GENERAL,
+ "Failed to peek from handle: %s",
+ format_win32_error(GetLastError()));
+ return -1;
+ } else if (0 == byte_count) {
+ /* Nothing available: process exited or it is busy */
+
+ /* Exit if we don't know whether the process is running */
+ if (NULL == process)
+ break;
+
+ /* The process exited and there's nothing left to read from it */
+ if (process_exited)
+ break;
+
+ /* If process is not running, check for output one more time in case
+ it wrote something after the peek was performed. Otherwise keep on
+ waiting for output */
+ tor_assert(process != NULL);
+ byte_count = WaitForSingleObject(process->pid.hProcess, 0);
+ if (WAIT_TIMEOUT != byte_count)
+ process_exited = TRUE;
+
+ continue;
+ }
+
+ /* There is data to read; read it */
+ retval = ReadFile(h, buf+numread, count-numread, &byte_count, NULL);
+ tor_assert(byte_count + numread <= count);
+ if (!retval) {
+ log_warn(LD_GENERAL, "Failed to read from handle: %s",
+ format_win32_error(GetLastError()));
+ return -1;
+ } else if (0 == byte_count) {
+ /* End of file */
+ break;
+ }
+ numread += byte_count;
+ }
+ return (ssize_t)numread;
+}
+#else
+/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If
+ * <b>process</b> is NULL, the function will return immediately if there is
+ * nothing more to read. Otherwise data will be read until end of file, or
+ * <b>count</b> bytes are read. Returns the number of bytes read, or -1 on
+ * error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the
+ * file has been reached. */
+ssize_t
+tor_read_all_handle(FILE *h, char *buf, size_t count,
+ const process_handle_t *process,
+ int *eof)
+{
+ size_t numread = 0;
+ char *retval;
+
+ if (eof)
+ *eof = 0;
+
+ if (count > SIZE_T_CEILING || count > SSIZE_T_MAX)
+ return -1;
+
+ while (numread != count) {
+ /* Use fgets because that is what we use in log_from_pipe() */
+ retval = fgets(buf+numread, (int)(count-numread), h);
+ if (NULL == retval) {
+ if (feof(h)) {
+ log_debug(LD_GENERAL, "fgets() reached end of file");
+ if (eof)
+ *eof = 1;
+ break;
+ } else {
+ if (EAGAIN == errno) {
+ if (process)
+ continue;
+ else
+ break;
+ } else {
+ log_warn(LD_GENERAL, "fgets() from handle failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ }
+ }
+ tor_assert(retval != NULL);
+ tor_assert(strlen(retval) + numread <= count);
+ numread += strlen(retval);
+ }
+
+ log_debug(LD_GENERAL, "fgets() read %d bytes from handle", (int)numread);
+ return (ssize_t)numread;
+}
+#endif
+
+/** Read from stdout of a process until the process exits. */
+ssize_t
+tor_read_all_from_process_stdout(const process_handle_t *process_handle,
+ char *buf, size_t count)
+{
+#ifdef MS_WINDOWS
+ return tor_read_all_handle(process_handle->stdout_pipe, buf, count,
+ process_handle);
+#else
+ return tor_read_all_handle(process_handle->stdout_handle, buf, count,
+ process_handle, NULL);
+#endif
+}
+
+/** Read from stdout of a process until the process exits. */
+ssize_t
+tor_read_all_from_process_stderr(const process_handle_t *process_handle,
+ char *buf, size_t count)
+{
+#ifdef MS_WINDOWS
+ return tor_read_all_handle(process_handle->stderr_pipe, buf, count,
+ process_handle);
+#else
+ return tor_read_all_handle(process_handle->stderr_handle, buf, count,
+ process_handle, NULL);
+#endif
+}
+
+/** Split buf into lines, and add to smartlist. The buffer <b>buf</b> will be
+ * modified. The resulting smartlist will consist of pointers to buf, so there
+ * is no need to free the contents of sl. <b>buf</b> must be a NUL-terminated
+ * string. <b>len</b> should be set to the length of the buffer excluding the
+ * NUL. Non-printable characters (including NUL) will be replaced with "." */
+int
+tor_split_lines(smartlist_t *sl, char *buf, int len)
+{
+ /* Index in buf of the start of the current line */
+ int start = 0;
+ /* Index in buf of the current character being processed */
+ int cur = 0;
+ /* Are we currently in a line */
+ char in_line = 0;
+
+ /* Loop over string */
+ while (cur < len) {
+ /* Loop until end of line or end of string */
+ for (; cur < len; cur++) {
+ if (in_line) {
+ if ('\r' == buf[cur] || '\n' == buf[cur]) {
+ /* End of line */
+ buf[cur] = '\0';
+ /* Point cur to the next line */
+ cur++;
+ /* Line starts at start and ends with a nul */
+ break;
+ } else {
+ if (!TOR_ISPRINT(buf[cur]))
+ buf[cur] = '.';
+ }
+ } else {
+ if ('\r' == buf[cur] || '\n' == buf[cur]) {
+ /* Skip leading vertical space */
+ ;
+ } else {
+ in_line = 1;
+ start = cur;
+ if (!TOR_ISPRINT(buf[cur]))
+ buf[cur] = '.';
+ }
+ }
+ }
+ /* We are at the end of the line or end of string. If in_line is true there
+ * is a line which starts at buf+start and ends at a NUL. cur points to
+ * the character after the NUL. */
+ if (in_line)
+ smartlist_add(sl, (void *)(buf+start));
+ in_line = 0;
+ }
+ return smartlist_len(sl);
+}
+
+#ifdef MS_WINDOWS
+/** Read from stream, and send lines to log at the specified log level.
+ * Returns -1 if there is a error reading, and 0 otherwise.
+ * If the generated stream is flushed more often than on new lines, or
+ * a read exceeds 256 bytes, lines will be truncated. This should be fixed,
+ * along with the corresponding problem on *nix (see bug #2045).
+ */
+static int
+log_from_handle(HANDLE *pipe, int severity)
+{
+ char buf[256];
+ int pos;
+ smartlist_t *lines;
+
+ pos = tor_read_all_handle(pipe, buf, sizeof(buf) - 1, NULL);
+ if (pos < 0) {
+ /* Error */
+ log_warn(LD_GENERAL, "Failed to read data from subprocess");
+ return -1;
+ }
+
+ if (0 == pos) {
+ /* There's nothing to read (process is busy or has exited) */
+ log_debug(LD_GENERAL, "Subprocess had nothing to say");
+ return 0;
+ }
+
+ /* End with a null even if there isn't a \r\n at the end */
+ /* TODO: What if this is a partial line? */
+ buf[pos] = '\0';
+ log_debug(LD_GENERAL, "Subprocess had %d bytes to say", pos);
+
+ /* Split up the buffer */
+ lines = smartlist_create();
+ tor_split_lines(lines, buf, pos);
+
+ /* Log each line */
+ SMARTLIST_FOREACH(lines, char *, line,
+ {
+ log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", line);
+ });
+ smartlist_free(lines);
+
+ return 0;
+}
+
+#else
+
+/** Read from stream, and send lines to log at the specified log level.
+ * Returns 1 if stream is closed normally, -1 if there is a error reading, and
+ * 0 otherwise. Handles lines from tor-fw-helper and
+ * tor_spawn_background() specially.
+ */
+static int
+log_from_pipe(FILE *stream, int severity, const char *executable,
+ int *child_status)
+{
+ char buf[256];
+ enum stream_status r;
+
+ for (;;) {
+ r = get_string_from_pipe(stream, buf, sizeof(buf) - 1);
+
+ if (r == IO_STREAM_CLOSED) {
+ return 1;
+ } else if (r == IO_STREAM_EAGAIN) {
+ return 0;
+ } else if (r == IO_STREAM_TERM) {
+ return -1;
+ }
+
+ tor_assert(r == IO_STREAM_OKAY);
+
+ /* Check if buf starts with SPAWN_ERROR_MESSAGE */
+ if (strcmpstart(buf, SPAWN_ERROR_MESSAGE) == 0) {
+ /* Parse error message */
+ int retval, child_state, saved_errno;
+ retval = tor_sscanf(buf, SPAWN_ERROR_MESSAGE "%x/%x",
+ &child_state, &saved_errno);
+ if (retval == 2) {
+ log_warn(LD_GENERAL,
+ "Failed to start child process \"%s\" in state %d: %s",
+ executable, child_state, strerror(saved_errno));
+ if (child_status)
+ *child_status = 1;
+ } else {
+ /* Failed to parse message from child process, log it as a
+ warning */
+ log_warn(LD_GENERAL,
+ "Unexpected message from port forwarding helper \"%s\": %s",
+ executable, buf);
+ }
+ } else {
+ log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", buf);
+ }
+ }
+
+ /* We should never get here */
+ return -1;
+}
+#endif
+
+/** Reads from <b>stream</b> and stores input in <b>buf_out</b> making
+ * sure it's below <b>count</b> bytes.
+ * If the string has a trailing newline, we strip it off.
+ *
+ * This function is specifically created to handle input from managed
+ * proxies, according to the pluggable transports spec. Make sure it
+ * fits your needs before using it.
+ *
+ * Returns:
+ * IO_STREAM_CLOSED: If the stream is closed.
+ * IO_STREAM_EAGAIN: If there is nothing to read and we should check back
+ * later.
+ * IO_STREAM_TERM: If something is wrong with the stream.
+ * IO_STREAM_OKAY: If everything went okay and we got a string
+ * in <b>buf_out</b>. */
+enum stream_status
+get_string_from_pipe(FILE *stream, char *buf_out, size_t count)
+{
+ char *retval;
+ size_t len;
+
+ tor_assert(count <= INT_MAX);
+
+ retval = fgets(buf_out, (int)count, stream);
+
+ if (!retval) {
+ if (feof(stream)) {
+ /* Program has closed stream (probably it exited) */
+ /* TODO: check error */
+ return IO_STREAM_CLOSED;
+ } else {
+ if (EAGAIN == errno) {
+ /* Nothing more to read, try again next time */
+ return IO_STREAM_EAGAIN;
+ } else {
+ /* There was a problem, abandon this child process */
+ return IO_STREAM_TERM;
+ }
+ }
+ } else {
+ len = strlen(buf_out);
+ tor_assert(len>0);
+
+ if (buf_out[len - 1] == '\n') {
+ /* Remove the trailing newline */
+ buf_out[len - 1] = '\0';
+ } else {
+ /* No newline; check whether we overflowed the buffer */
+ if (!feof(stream))
+ log_info(LD_GENERAL,
+ "Line from stream was truncated: %s", buf_out);
+ /* TODO: What to do with this error? */
+ }
+
+ return IO_STREAM_OKAY;
+ }
+
+ /* We should never get here */
+ return IO_STREAM_TERM;
+}
+
+void
+tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
+ time_t now)
+{
+/* When fw-helper succeeds, how long do we wait until running it again */
+#define TIME_TO_EXEC_FWHELPER_SUCCESS 300
+/* When fw-helper failed to start, how long do we wait until running it again
+ */
+#define TIME_TO_EXEC_FWHELPER_FAIL 60
+
+ /* Static variables are initialized to zero, so child_handle.status=0
+ * which corresponds to it not running on startup */
+ static process_handle_t *child_handle=NULL;
+
+ static time_t time_to_run_helper = 0;
+ int stdout_status, stderr_status, retval;
+ const char *argv[10];
+ char s_dirport[6], s_orport[6];
+
+ tor_assert(filename);
+
+ /* Set up command line for tor-fw-helper */
+ snprintf(s_dirport, sizeof s_dirport, "%d", dir_port);
+ snprintf(s_orport, sizeof s_orport, "%d", or_port);
+
+ /* TODO: Allow different internal and external ports */
+ argv[0] = filename;
+ argv[1] = "--internal-or-port";
+ argv[2] = s_orport;
+ argv[3] = "--external-or-port";
+ argv[4] = s_orport;
+ argv[5] = "--internal-dir-port";
+ argv[6] = s_dirport;
+ argv[7] = "--external-dir-port";
+ argv[8] = s_dirport;
+ argv[9] = NULL;
+
+ /* Start the child, if it is not already running */
+ if ((!child_handle || child_handle->status != PROCESS_STATUS_RUNNING) &&
+ time_to_run_helper < now) {
+ int status;
+
+ /* Assume tor-fw-helper will succeed, start it later*/
+ time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS;
+
+ if (child_handle) {
+ tor_process_handle_destroy(child_handle, 1);
+ child_handle = NULL;
+ }
+
+#ifdef MS_WINDOWS
+ /* Passing NULL as lpApplicationName makes Windows search for the .exe */
+ status = tor_spawn_background(NULL, argv, NULL, &child_handle);
+#else
+ status = tor_spawn_background(filename, argv, NULL, &child_handle);
+#endif
+
+ if (PROCESS_STATUS_ERROR == status) {
+ log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",
+ filename);
+ time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
+ return;
+ }
+
+ log_info(LD_GENERAL,
+ "Started port forwarding helper (%s) with pid '%d'",
+ filename, tor_process_get_pid(child_handle));
+ }
+
+ /* If child is running, read from its stdout and stderr) */
+ if (child_handle && PROCESS_STATUS_RUNNING == child_handle->status) {
+ /* Read from stdout/stderr and log result */
+ retval = 0;
+#ifdef MS_WINDOWS
+ stdout_status = log_from_handle(child_handle->stdout_pipe, LOG_INFO);
+ stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_WARN);
+ /* If we got this far (on Windows), the process started */
+ retval = 0;
+#else
+ stdout_status = log_from_pipe(child_handle->stdout_handle,
+ LOG_INFO, filename, &retval);
+ stderr_status = log_from_pipe(child_handle->stderr_handle,
+ LOG_WARN, filename, &retval);
+#endif
+ if (retval) {
+ /* There was a problem in the child process */
+ time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
+ }
+
+ /* Combine the two statuses in order of severity */
+ if (-1 == stdout_status || -1 == stderr_status)
+ /* There was a failure */
+ retval = -1;
+#ifdef MS_WINDOWS
+ else if (!child_handle || tor_get_exit_code(child_handle, 0, NULL) !=
+ PROCESS_EXIT_RUNNING) {
+ /* process has exited or there was an error */
+ /* TODO: Do something with the process return value */
+ /* TODO: What if the process output something since
+ * between log_from_handle and tor_get_exit_code? */
+ retval = 1;
+ }
+#else
+ else if (1 == stdout_status || 1 == stderr_status)
+ /* stdout or stderr was closed, the process probably
+ * exited. It will be reaped by waitpid() in main.c */
+ /* TODO: Do something with the process return value */
+ retval = 1;
+#endif
+ else
+ /* Both are fine */
+ retval = 0;
+
+ /* If either pipe indicates a failure, act on it */
+ if (0 != retval) {
+ if (1 == retval) {
+ log_info(LD_GENERAL, "Port forwarding helper terminated");
+ child_handle->status = PROCESS_STATUS_NOTRUNNING;
+ } else {
+ log_warn(LD_GENERAL, "Failed to read from port forwarding helper");
+ child_handle->status = PROCESS_STATUS_ERROR;
+ }
+
+ /* TODO: The child might not actually be finished (maybe it failed or
+ closed stdout/stderr), so maybe we shouldn't start another? */
+ }
+ }
+}
+
diff --git a/src/common/util.h b/src/common/util.h
index b9db25ca73..b15b1ea56a 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -160,6 +160,7 @@ uint64_t round_to_power_of_2(uint64_t u64);
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
+int n_bits_set_u8(uint8_t v);
/* 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
@@ -172,18 +173,15 @@ uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
#define HEX_CHARACTERS "0123456789ABCDEFabcdef"
void tor_strlower(char *s) ATTR_NONNULL((1));
void tor_strupper(char *s) ATTR_NONNULL((1));
-int tor_strisprint(const char *s) ATTR_PURE ATTR_NONNULL((1));
-int tor_strisnonupper(const char *s) ATTR_PURE ATTR_NONNULL((1));
-int strcmpstart(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
-int strcmp_len(const char *s1, const char *s2, size_t len)
- ATTR_PURE ATTR_NONNULL((1,2));
-int strcasecmpstart(const char *s1, const char *s2)
- ATTR_PURE ATTR_NONNULL((1,2));
-int strcmpend(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
-int strcasecmpend(const char *s1, const char *s2)
- ATTR_PURE ATTR_NONNULL((1,2));
-int fast_memcmpstart(const void *mem, size_t memlen,
- const char *prefix) ATTR_PURE;
+int tor_strisprint(const char *s) ATTR_NONNULL((1));
+int tor_strisnonupper(const char *s) ATTR_NONNULL((1));
+int strcmp_opt(const char *s1, const char *s2);
+int strcmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int strcmp_len(const char *s1, const char *s2, size_t len) ATTR_NONNULL((1,2));
+int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix);
void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2));
long tor_parse_long(const char *s, int base, long min,
@@ -195,17 +193,19 @@ double tor_parse_double(const char *s, double min, double max, int *ok,
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
uint64_t max, int *ok, char **next);
const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1));
-const char *eat_whitespace(const char *s) ATTR_PURE;
-const char *eat_whitespace_eos(const char *s, const char *eos) ATTR_PURE;
-const char *eat_whitespace_no_nl(const char *s) ATTR_PURE;
-const char *eat_whitespace_eos_no_nl(const char *s, const char *eos) ATTR_PURE;
-const char *find_whitespace(const char *s) ATTR_PURE;
-const char *find_whitespace_eos(const char *s, const char *eos) ATTR_PURE;
-const char *find_str_at_start_of_line(const char *haystack, const char *needle)
- ATTR_PURE;
-int tor_mem_is_zero(const char *mem, size_t len) ATTR_PURE;
-int tor_digest_is_zero(const char *digest) ATTR_PURE;
-int tor_digest256_is_zero(const char *digest) ATTR_PURE;
+const char *eat_whitespace(const char *s);
+const char *eat_whitespace_eos(const char *s, const char *eos);
+const char *eat_whitespace_no_nl(const char *s);
+const char *eat_whitespace_eos_no_nl(const char *s, const char *eos);
+const char *find_whitespace(const char *s);
+const char *find_whitespace_eos(const char *s, const char *eos);
+const char *find_str_at_start_of_line(const char *haystack,
+ const char *needle);
+int string_is_C_identifier(const char *string);
+
+int tor_mem_is_zero(const char *mem, size_t len);
+int tor_digest_is_zero(const char *digest);
+int tor_digest256_is_zero(const char *digest);
char *esc_for_log(const char *string) ATTR_MALLOC;
const char *escaped(const char *string);
struct smartlist_t;
@@ -218,6 +218,11 @@ int tor_sscanf(const char *buf, const char *pattern, ...)
#endif
;
+void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...)
+ CHECK_PRINTF(2, 3);
+void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern,
+ va_list args);
+
int hex_decode_digit(char c);
void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
@@ -233,8 +238,11 @@ time_t tor_timegm(struct tm *tm);
void format_rfc1123_time(char *buf, time_t t);
int parse_rfc1123_time(const char *buf, time_t *t);
#define ISO_TIME_LEN 19
+#define ISO_TIME_USEC_LEN (ISO_TIME_LEN+7)
void format_local_iso_time(char *buf, time_t t);
void format_iso_time(char *buf, time_t t);
+void format_iso_time_nospace(char *buf, time_t t);
+void format_iso_time_nospace_usec(char *buf, const struct timeval *tv);
int parse_iso_time(const char *buf, time_t *t);
int parse_http_time(const char *buf, struct tm *tm);
int format_time_interval(char *out, size_t out_len, long interval);
@@ -279,6 +287,16 @@ char *rate_limit_log(ratelim_t *lim, time_t now);
ssize_t write_all(tor_socket_t fd, const char *buf, size_t count,int isSocket);
ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket);
+/** Status of an I/O stream. */
+enum stream_status {
+ IO_STREAM_OKAY,
+ IO_STREAM_EAGAIN,
+ IO_STREAM_TERM,
+ IO_STREAM_CLOSED
+};
+
+enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
+
/** Return values from file_status(); see that function's documentation
* for details. */
typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR } file_status_t;
@@ -296,6 +314,7 @@ int check_private_dir(const char *dirname, cpd_check_t check,
const char *effective_user);
#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC)
#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND)
+#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY)
typedef struct open_file_t open_file_t;
int start_writing_to_file(const char *fname, int open_flags, int mode,
open_file_t **data_out);
@@ -317,6 +336,8 @@ int write_chunks_to_file(const char *fname, const struct smartlist_t *chunks,
int bin);
int append_bytes_to_file(const char *fname, const char *str, size_t len,
int bin);
+int write_bytes_to_new_file(const char *fname, const char *str, size_t len,
+ int bin);
/** Flag for read_file_to_str: open the file in binary mode. */
#define RFTS_BIN 1
@@ -330,17 +351,101 @@ const char *parse_config_line_from_str(const char *line,
char **key_out, char **value_out);
char *expand_filename(const char *filename);
struct smartlist_t *tor_listdir(const char *dirname);
-int path_is_relative(const char *filename) ATTR_PURE;
+int path_is_relative(const char *filename);
/* Process helpers */
void start_daemon(void);
void finish_daemon(const char *desired_cwd);
void write_pidfile(char *filename);
+/* Port forwarding */
+void tor_check_port_forwarding(const char *filename,
+ int dir_port, int or_port, time_t now);
+
+typedef struct process_handle_t process_handle_t;
+int tor_spawn_background(const char *const filename, const char **argv,
+#ifdef MS_WINDOWS
+ LPVOID envp,
+#else
+ const char **envp,
+#endif
+ process_handle_t **process_handle_out);
+
+#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code "
+
#ifdef MS_WINDOWS
HANDLE load_windows_system_library(const TCHAR *library_name);
#endif
+/* Values of process_handle_t.status. PROCESS_STATUS_NOTRUNNING must be
+ * 0 because tor_check_port_forwarding depends on this being the initial
+ * statue of the static instance of process_handle_t */
+#define PROCESS_STATUS_NOTRUNNING 0
+#define PROCESS_STATUS_RUNNING 1
+#define PROCESS_STATUS_ERROR -1
+
+#ifdef UTIL_PRIVATE
+/*DOCDOC*/
+struct process_handle_t {
+ int status;
+#ifdef MS_WINDOWS
+ HANDLE stdout_pipe;
+ HANDLE stderr_pipe;
+ PROCESS_INFORMATION pid;
+#else
+ int stdout_pipe;
+ int stderr_pipe;
+ FILE *stdout_handle;
+ FILE *stderr_handle;
+ pid_t pid;
+#endif // MS_WINDOWS
+};
+#endif
+
+/* Return values of tor_get_exit_code() */
+#define PROCESS_EXIT_RUNNING 1
+#define PROCESS_EXIT_EXITED 0
+#define PROCESS_EXIT_ERROR -1
+int tor_get_exit_code(const process_handle_t *process_handle,
+ int block, int *exit_code);
+int tor_split_lines(struct smartlist_t *sl, char *buf, int len);
+#ifdef MS_WINDOWS
+ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count,
+ const process_handle_t *process);
+#else
+ssize_t tor_read_all_handle(FILE *h, char *buf, size_t count,
+ const process_handle_t *process,
+ int *eof);
+#endif
+ssize_t tor_read_all_from_process_stdout(
+ const process_handle_t *process_handle, char *buf, size_t count);
+ssize_t tor_read_all_from_process_stderr(
+ const process_handle_t *process_handle, char *buf, size_t count);
+char *tor_join_win_cmdline(const char *argv[]);
+
+int tor_process_get_pid(process_handle_t *process_handle);
+#ifdef MS_WINDOWS
+HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle);
+#else
+FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle);
+#endif
+
+int tor_terminate_process(process_handle_t *process_handle);
+void tor_process_handle_destroy(process_handle_t *process_handle,
+ int also_terminate_process);
+
+#ifdef UTIL_PRIVATE
+/* Prototypes for private functions only used by util.c (and unit tests) */
+
+void format_helper_exit_status(unsigned char child_state,
+ int saved_errno, char *hex_errno);
+
+/* Space for hex values of child state, a slash, saved_errno (with
+ leading minus) and newline (no null) */
+#define HEX_ERRNO_SIZE (sizeof(char) * 2 + 1 + \
+ 1 + sizeof(int) * 2 + 1)
+#endif
+
const char *libor_get_digests(void);
#endif