aboutsummaryrefslogtreecommitdiff
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/OpenBSD_malloc_Linux.c40
-rw-r--r--src/common/address.c326
-rw-r--r--src/common/address.h44
-rw-r--r--src/common/aes.c1257
-rw-r--r--src/common/aes.h13
-rw-r--r--src/common/ciphers.inc47
-rw-r--r--src/common/compat.c685
-rw-r--r--src/common/compat.h72
-rw-r--r--src/common/compat_libevent.c181
-rw-r--r--src/common/compat_libevent.h33
-rw-r--r--src/common/container.c13
-rw-r--r--src/common/container.h56
-rw-r--r--src/common/crypto.c957
-rw-r--r--src/common/crypto.h178
-rw-r--r--src/common/di_ops.c2
-rw-r--r--src/common/di_ops.h2
-rw-r--r--src/common/get_mozilla_ciphers.py192
-rw-r--r--src/common/ht.h101
-rw-r--r--src/common/log.c45
-rw-r--r--src/common/memarea.c2
-rw-r--r--src/common/memarea.h2
-rw-r--r--src/common/mempool.c8
-rw-r--r--src/common/mempool.h4
-rw-r--r--src/common/procmon.c15
-rw-r--r--src/common/procmon.h3
-rw-r--r--src/common/sha256.c2
-rw-r--r--src/common/torgzip.c6
-rw-r--r--src/common/torgzip.h2
-rw-r--r--src/common/torint.h21
-rw-r--r--src/common/torlog.h9
-rw-r--r--src/common/tortls.c1187
-rw-r--r--src/common/tortls.h52
-rw-r--r--src/common/tortls_states.h414
-rw-r--r--src/common/util.c1768
-rw-r--r--src/common/util.h189
-rw-r--r--src/common/util_codedigest.c2
38 files changed, 5556 insertions, 2443 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 6da1782c8..5e7684259 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 000000000..e54827367
--- /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/OpenBSD_malloc_Linux.c b/src/common/OpenBSD_malloc_Linux.c
index 92ca9c006..da8272981 100644
--- a/src/common/OpenBSD_malloc_Linux.c
+++ b/src/common/OpenBSD_malloc_Linux.c
@@ -14,6 +14,10 @@
* ----------------------------------------------------------------------------
*/
+/* We use this macro to remove some code that we don't actually want,
+ * rather than to fix its warnings. */
+#define BUILDING_FOR_TOR
+
/*
* Defining MALLOC_EXTRA_SANITY will enable extra checks which are
* related to internal conditions and consistency in malloc.c. This has
@@ -79,6 +83,7 @@ static size_t g_alignment = 0;
extern int __libc_enable_secure;
+#ifndef HAVE_ISSETUGID
static int issetugid(void)
{
if (__libc_enable_secure) return 1;
@@ -86,8 +91,10 @@ static int issetugid(void)
if (getgid() != getegid()) return 1;
return 0;
}
+#endif
#define PGSHIFT 12
+#undef MADV_FREE
#define MADV_FREE MADV_DONTNEED
#include <pthread.h>
static pthread_mutex_t gen_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -443,6 +450,7 @@ extern char *__progname;
static void
wrterror(const char *p)
{
+#ifndef BUILDING_FOR_TOR
const char *q = " error: ";
struct iovec iov[5];
@@ -457,7 +465,9 @@ wrterror(const char *p)
iov[4].iov_base = (char*)"\n";
iov[4].iov_len = 1;
writev(STDERR_FILENO, iov, 5);
-
+#else
+ (void)p;
+#endif
suicide = 1;
#ifdef MALLOC_STATS
if (malloc_stats)
@@ -471,14 +481,17 @@ wrterror(const char *p)
static void
wrtwarning(const char *p)
{
+#ifndef BUILDING_FOR_TOR
const char *q = " warning: ";
struct iovec iov[5];
+#endif
if (malloc_abort)
wrterror(p);
else if (malloc_silent)
return;
+#ifndef BUILDING_FOR_TOR
iov[0].iov_base = __progname;
iov[0].iov_len = strlen(__progname);
iov[1].iov_base = (char*)malloc_func;
@@ -489,8 +502,11 @@ wrtwarning(const char *p)
iov[3].iov_len = strlen(p);
iov[4].iov_base = (char*)"\n";
iov[4].iov_len = 1;
-
- writev(STDERR_FILENO, iov, 5);
+
+ (void) writev(STDERR_FILENO, iov, 5);
+#else
+ (void)p;
+#endif
}
#ifdef MALLOC_STATS
@@ -665,7 +681,7 @@ malloc_init(void)
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
- j = readlink("/etc/malloc.conf", b, sizeof b - 1);
+ j = (int) readlink("/etc/malloc.conf", b, sizeof b - 1);
if (j <= 0)
continue;
b[j] = '\0';
@@ -1145,9 +1161,10 @@ malloc_bytes(size_t size)
if (size == 0)
j = 0;
else {
+ size_t ii;
j = 1;
- i = size - 1;
- while (i >>= 1)
+ ii = size - 1;
+ while (ii >>= 1)
j++;
}
@@ -1971,6 +1988,7 @@ calloc(size_t num, size_t size)
return(p);
}
+#ifndef BUILDING_FOR_TOR
static int ispowerof2 (size_t a) {
size_t b;
for (b = 1ULL << (sizeof(size_t)*NBBY - 1); b > 1; b >>= 1)
@@ -1978,7 +1996,9 @@ static int ispowerof2 (size_t a) {
return 1;
return 0;
}
+#endif
+#ifndef BUILDING_FOR_TOR
int posix_memalign(void **memptr, size_t alignment, size_t size)
{
void *r;
@@ -2015,18 +2035,20 @@ void *valloc(size_t size)
posix_memalign(&r, malloc_pagesize, size);
return r;
}
+#endif
size_t malloc_good_size(size_t size)
{
if (size == 0) {
return 1;
} else if (size <= malloc_maxsize) {
- int i, j;
+ int j;
+ size_t ii;
/* round up to the nearest power of 2, with same approach
* as malloc_bytes() uses. */
j = 1;
- i = size - 1;
- while (i >>= 1)
+ ii = size - 1;
+ while (ii >>= 1)
j++;
return ((size_t)1) << j;
} else {
diff --git a/src/common/address.c b/src/common/address.c
index 17bdea923..df26f61f8 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,10 +13,16 @@
#include "util.h"
#include "address.h"
#include "torlog.h"
+#include "container.h"
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#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
@@ -253,7 +275,7 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
ent = err ? NULL : &hent;
#else
ent = gethostbyname(name);
-#ifdef MS_WINDOWS
+#ifdef _WIN32
err = WSAGetLastError();
#else
err = h_errno;
@@ -269,7 +291,7 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
}
return 0;
}
-#ifdef MS_WINDOWS
+#ifdef _WIN32
return (err == WSATRY_AGAIN) ? 1 : -1;
#else
return (err == TRY_AGAIN) ? 1 : -1;
@@ -333,7 +355,9 @@ tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
/* unknown address family... assume it's not safe for external use */
/* rather than tor_assert(0) */
- log_warn(LD_BUG, "tor_addr_is_internal() called with a non-IP address.");
+ log_warn(LD_BUG, "tor_addr_is_internal() called with a non-IP address of "
+ "type %d", (int)v_family);
+ tor_fragile_assert();
return 1;
}
@@ -343,22 +367,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 +414,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 +485,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 +500,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 +533,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;
}
@@ -745,7 +779,8 @@ tor_addr_is_loopback(const tor_addr_t *addr)
case AF_INET6: {
/* ::1 */
uint32_t *a32 = tor_addr_to_in6_addr32(addr);
- return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) && (a32[3] == 1);
+ return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) &&
+ (ntohl(a32[3]) == 1);
}
case AF_INET:
/* 127.0.0.1 */
@@ -952,21 +987,39 @@ tor_dup_addr(const tor_addr_t *addr)
}
}
-/** Return a string representing the address <b>addr</b>. This string is
- * statically allocated, and must not be freed. Each call to
- * <b>fmt_addr</b> invalidates the last result of the function. This
- * function is not thread-safe. */
+/** Return a string representing the address <b>addr</b>. This string
+ * is statically allocated, and must not be freed. Each call to
+ * <b>fmt_addr_impl</b> invalidates the last result of the function.
+ * This function is not thread-safe. If <b>decorate</b> is set, add
+ * brackets to IPv6 addresses.
+ *
+ * It's better to use the wrapper macros of this function:
+ * <b>fmt_addr()</b> and <b>fmt_and_decorate_addr()</b>.
+ */
const char *
-fmt_addr(const tor_addr_t *addr)
+fmt_addr_impl(const tor_addr_t *addr, int decorate)
{
static char buf[TOR_ADDR_BUF_LEN];
if (!addr) return "<null>";
- if (tor_addr_to_str(buf, addr, sizeof(buf), 0))
+ if (tor_addr_to_str(buf, addr, sizeof(buf), decorate))
return buf;
else
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 +1027,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 +1055,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 +1109,169 @@ tor_addr_port_parse(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
return -1;
}
+#ifdef _WIN32
+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_new();
+ 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(_WIN32)
+ /* 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_new();
+ 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_new();
+ 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 +1279,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
@@ -1122,7 +1364,7 @@ get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr)
/* ======
* IPv4 helpers
- * XXXX023 IPv6 deprecate some of these.
+ * XXXX024 IPv6 deprecate some of these.
*/
/** Return true iff <b>ip</b> (in host order) is an IP reserved to localhost,
@@ -1138,6 +1380,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 +1405,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 +1415,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);
@@ -1271,7 +1527,7 @@ parse_port_range(const char *port, uint16_t *port_min_out,
} else if (endptr && *endptr == '-') {
port = endptr+1;
endptr = NULL;
- port_max = (int)tor_parse_long(port, 10, 1, 65536, &ok, &endptr);
+ port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr);
if (!ok) {
log_warn(LD_GENERAL,
"Malformed port %s on address range; rejecting.",
@@ -1432,3 +1688,13 @@ get_interface_address(int severity, uint32_t *addr)
return r;
}
+/** Return true if we can tell that <b>name</b> is a canonical name for the
+ * loopback address. */
+int
+tor_addr_hostname_is_local(const char *name)
+{
+ return !strcasecmp(name, "localhost") ||
+ !strcasecmp(name, "local") ||
+ !strcasecmpend(name, ".local");
+}
+
diff --git a/src/common/address.h b/src/common/address.h
index 9a7656f69..c6c126862 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,11 +26,22 @@ typedef struct tor_addr_t
{
sa_family_t family;
union {
+ uint32_t dummy_; /* This field is here so we have something to initialize
+ * with a reliable cross-platform type. */
struct in_addr in_addr;
struct in6_addr in6_addr;
} 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;
+
+#define TOR_ADDR_NULL {AF_UNSPEC, {0}};
+
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);
@@ -126,7 +137,15 @@ 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);
+
+/** Wrapper function of fmt_addr_impl(). It does not decorate IPv6
+ * addresses. */
+#define fmt_addr(a) fmt_addr_impl((a), 0)
+/** Wrapper function of fmt_addr_impl(). It decorates IPv6
+ * addresses. */
+#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1)
+const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
+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 +167,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 +199,14 @@ 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);
+
+int tor_addr_hostname_is_local(const char *name);
+
/* 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 c2fdeb594..295a90749 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -1,137 +1,149 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \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"
+
+#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
+ #ifndef _WIN32_WINNT
+ #define _WIN32_WINNT 0x0501
+ #endif
+ #define WIN32_LEAN_AND_MEAN
+ #if defined(_MSC_VER) && (_MSC_VER < 1300)
+ #include <winsock.h>
+ #else
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #endif
+#endif
+
#include <openssl/opensslv.h>
#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
+#ifdef ANDROID
+/* Android's OpenSSL seems to have removed all of its Engine support. */
+#define DISABLE_ENGINES
+#endif
-/* Figure out our CPU type. We use this to pick an AES implementation.
- * Macros are as listed at http://predef.sourceforge.net/prearch.html
+/* We have five strategies for implementing AES counter mode.
+ *
+ * Best with x86 and x86_64: Use EVP_aes_ctr128() and EVP_EncryptUpdate().
+ * This is possible with OpenSSL 1.0.1, where the counter-mode implementation
+ * can use bit-sliced or vectorized AES or AESNI as appropriate.
+ *
+ * Otherwise: Pick the best possible AES block implementation that OpenSSL
+ * gives us, and the best possible counter-mode implementation, and combine
+ * them.
*/
-#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
-#endif
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,0,1) && \
+ (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || \
+ defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__)) \
-/* 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))
+#define USE_EVP_AES_CTR
-/* 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
+#endif
+
+/* We have 2 strategies for getting the AES block cipher: Via OpenSSL's
+ * AES_encrypt function, or 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 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.
+ */
-# 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
+/* We have 2 strategies for getting a plug-in 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.)
+ */
-/* Otherwise, use the built-in implementation below. */
-# ifndef USE_OPENSSL_AES
-# define USE_BUILTIN_AES
-# endif
-#endif /* endif need to pick a method */
+#ifdef USE_EVP_AES_CTR
-/* Include OpenSSL headers as needed. */
-#ifdef USE_OPENSSL_AES
-# include <openssl/aes.h>
-#endif
-#ifdef USE_OPENSSL_EVP
-# include <openssl/evp.h>
-#endif
+struct aes_cnt_cipher {
+ EVP_CIPHER_CTX evp;
+};
-/* 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
+aes_cnt_cipher_t *
+aes_new_cipher(const char *key, const char *iv)
+{
+ aes_cnt_cipher_t *cipher;
+ cipher = tor_malloc_zero(sizeof(aes_cnt_cipher_t));
+ EVP_EncryptInit(&cipher->evp, EVP_aes_128_ctr(),
+ (const unsigned char*)key, (const unsigned char *)iv);
+ return cipher;
+}
+void
+aes_cipher_free(aes_cnt_cipher_t *cipher)
+{
+ if (!cipher)
+ return;
+ EVP_CIPHER_CTX_cleanup(&cipher->evp);
+ memwipe(cipher, 0, sizeof(aes_cnt_cipher_t));
+ tor_free(cipher);
+}
+void
+aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
+ char *output)
+{
+ int outl;
-/*======================================================================*/
-/* From rijndael-alg-fst.h */
+ tor_assert(len < INT_MAX);
-typedef uint64_t u64;
-typedef uint32_t u32;
-typedef uint8_t u8;
+ EVP_EncryptUpdate(&cipher->evp, (unsigned char*)output,
+ &outl, (const unsigned char *)input, (int)len);
+}
+void
+aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
+{
+ int outl;
-#ifdef USE_BUILTIN_AES
-#define MAXNR 14
+ tor_assert(len < INT_MAX);
-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]);
+ EVP_EncryptUpdate(&cipher->evp, (unsigned char*)data,
+ &outl, (unsigned char*)data, (int)len);
+}
+int
+evaluate_evp_for_aes(int force_val)
+{
+ (void) force_val;
+ log_notice(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
+ "counter-mode implementation. Using it.");
+ return 0;
+}
+int
+evaluate_ctr_for_aes(void)
+{
+ return 0;
+}
#else
-static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr,
- const u8 pt[16], u8 ct[16]);
-#endif
-#endif
/*======================================================================*/
/* Interface to AES code, and counter implementation */
@@ -139,42 +151,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,34 +293,32 @@ _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
}
+static void aes_set_key(aes_cnt_cipher_t *cipher, const char *key,
+ int key_bits);
+static void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv);
+
/**
- * Return a newly allocated counter-mode AES128 cipher implementation.
+ * Return a newly allocated counter-mode AES128 cipher implementation,
+ * using the 128-bit key <b>key</b> and the 128-bit IV <b>iv</b>.
*/
aes_cnt_cipher_t*
-aes_new_cipher(void)
+aes_new_cipher(const char *key, const char *iv)
{
aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t));
+ aes_set_key(result, key, 128);
+ aes_set_iv(result, iv);
+
return result;
}
@@ -229,53 +326,58 @@ aes_new_cipher(void)
* <b>key_bits</b> bits long (must be 128, 192, or 256). Also resets
* the counter to 0.
*/
-void
+static 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>
*/
void
-aes_free_cipher(aes_cnt_cipher_t *cipher)
+aes_cipher_free(aes_cnt_cipher_t *cipher)
{
if (!cipher)
return;
-#ifdef USE_OPENSSL_EVP
- EVP_CIPHER_CTX_cleanup(&cipher->key);
-#endif
- memset(cipher, 0, sizeof(aes_cnt_cipher_t));
+ if (cipher->using_evp) {
+ EVP_CIPHER_CTX_cleanup(&cipher->key.evp);
+ }
+ memwipe(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 +385,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 +405,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,38 +465,42 @@ 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);
}
}
/** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value
* in <b>iv</b>. */
-void
+static void
aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
{
#ifdef USING_COUNTER_VARS
@@ -368,705 +510,12 @@ 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);
+ _aes_fill_buf(cipher);
}
-#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;
-}
#endif
-
diff --git a/src/common/aes.h b/src/common/aes.h
index eb633dbcc..bde567f87 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Implements a minimal interface to counter-mode AES. */
@@ -13,18 +13,17 @@
* \brief Headers for aes.c
*/
-#include "torint.h"
-
struct aes_cnt_cipher;
typedef struct aes_cnt_cipher aes_cnt_cipher_t;
-aes_cnt_cipher_t* aes_new_cipher(void);
-void aes_free_cipher(aes_cnt_cipher_t *cipher);
-void aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits);
+aes_cnt_cipher_t* aes_new_cipher(const char *key, const char *iv);
+void aes_cipher_free(aes_cnt_cipher_t *cipher);
void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
char *output);
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/ciphers.inc b/src/common/ciphers.inc
index c84620d49..137d78b11 100644
--- a/src/common/ciphers.inc
+++ b/src/common/ciphers.inc
@@ -1,6 +1,9 @@
/* This is an include file used to define the list of ciphers clients should
* advertise. Before including it, you should define the CIPHER and XCIPHER
- * macros. */
+ * macros.
+ *
+ * This file was automatically generated by get_mozilla_ciphers.py.
+ */
#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
#else
@@ -11,6 +14,16 @@
#else
XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA)
#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ CIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
+#else
+ XCIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
+#endif
+#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
+ CIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA)
+#else
+ XCIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA)
+#endif
#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA
CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA)
#else
@@ -31,6 +44,11 @@
#else
XCIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA)
#endif
+#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA
+ CIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
+#else
+ XCIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
+#endif
#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA
CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA)
#else
@@ -56,6 +74,16 @@
#else
XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA)
#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ CIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
+#else
+ XCIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
+#endif
+#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
+ CIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA)
+#else
+ XCIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA)
+#endif
#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA
CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA)
#else
@@ -86,6 +114,16 @@
#else
XCIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA)
#endif
+#ifdef TLS1_TXT_RSA_WITH_SEED_SHA
+ CIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA)
+#else
+ XCIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA)
+#endif
+#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA
+ CIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
+#else
+ XCIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
+#endif
#ifdef SSL3_TXT_RSA_RC4_128_MD5
CIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5)
#else
@@ -131,10 +169,11 @@
#else
XCIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA)
#endif
-#ifdef SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
- CIPHER(0xfeff, SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
+/* No openssl macro found for 0xfeff */
+#ifdef SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
+ CIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
#else
- XCIPHER(0xfeff, SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
+ XCIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
#endif
#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA
CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA)
diff --git a/src/common/compat.c b/src/common/compat.c
index a4e50747c..59e3898de 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,13 +15,17 @@
/* This is required on rh7 to make strptime not complain.
* We also need it to make memmem get defined (where available)
*/
-/* XXXX023 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf,
- * and get this (and other important stuff!) automatically */
+/* XXXX024 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf,
+ * and get this (and other important stuff!) automatically. Once we do that,
+ * make sure to also change the extern char **environ detection in
+ * configure.in, because whether that is declared or not depends on whether
+ * we have _GNU_SOURCE defined! Maybe that means that once we take this out,
+ * we can also take out the configure check. */
#define _GNU_SOURCE
#include "compat.h"
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#include <process.h>
#include <windows.h>
#include <sys/locking.h>
@@ -51,6 +55,9 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h>
+#endif
#ifndef HAVE_GETTIMEOFDAY
#ifdef HAVE_FTIME
@@ -58,6 +65,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,7 +118,45 @@
#include "strlcat.c"
#endif
-#ifdef HAVE_SYS_MMAN_H
+/** 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)
+{
+ int fd;
+#ifdef O_CLOEXEC
+ fd = open(path, flags|O_CLOEXEC, mode);
+ if (fd >= 0)
+ return fd;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with O_CLOEXEC support, we
+ * are running on one without. */
+ if (errno != EINVAL)
+ return -1;
+#endif
+
+ fd = open(path, flags, mode);
+#ifdef FD_CLOEXEC
+ if (fd >= 0)
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+ return fd;
+}
+
+/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the
+ * underlying file handle. */
+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;
+}
+
+#if defined(HAVE_SYS_MMAN_H) || defined(RUNNING_DOXYGEN)
/** Try to create a memory mapping for <b>filename</b> and return it. On
* failure, return NULL. Sets errno properly, using ERANGE to mean
* "empty file". */
@@ -118,7 +171,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;
@@ -168,47 +221,55 @@ tor_munmap_file(tor_mmap_t *handle)
munmap((char*)handle->data, handle->mapping_size);
tor_free(handle);
}
-#elif defined(MS_WINDOWS)
+#elif defined(_WIN32)
tor_mmap_t *
tor_mmap_file(const char *filename)
{
TCHAR tfilename[MAX_PATH]= {0};
tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t));
int empty = 0;
- res->file_handle = INVALID_HANDLE_VALUE;
+ HANDLE file_handle = INVALID_HANDLE_VALUE;
+ DWORD size_low, size_high;
+ uint64_t real_size;
res->mmap_handle = NULL;
#ifdef UNICODE
mbstowcs(tfilename,filename,MAX_PATH);
#else
strlcpy(tfilename,filename,MAX_PATH);
#endif
- res->file_handle = CreateFile(tfilename,
- GENERIC_READ, FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- 0);
+ file_handle = CreateFile(tfilename,
+ GENERIC_READ, FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ 0);
- if (res->file_handle == INVALID_HANDLE_VALUE)
+ if (file_handle == INVALID_HANDLE_VALUE)
goto win_err;
- res->size = GetFileSize(res->file_handle, NULL);
+ size_low = GetFileSize(file_handle, &size_high);
- if (res->size == 0) {
+ if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) {
+ log_warn(LD_FS,"Error getting size of \"%s\".",filename);
+ goto win_err;
+ }
+ if (size_low == 0 && size_high == 0) {
log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename);
empty = 1;
goto err;
}
+ real_size = (((uint64_t)size_high)<<32) | size_low;
+ if (real_size > SIZE_MAX) {
+ log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename);
+ goto err;
+ }
+ res->size = real_size;
- res->mmap_handle = CreateFileMapping(res->file_handle,
+ res->mmap_handle = CreateFileMapping(file_handle,
NULL,
PAGE_READONLY,
-#if SIZEOF_SIZE_T > 4
- (res->base.size >> 32),
-#else
- 0,
-#endif
- (res->size & 0xfffffffful),
+ size_high,
+ size_low,
NULL);
if (res->mmap_handle == NULL)
goto win_err;
@@ -218,6 +279,7 @@ tor_mmap_file(const char *filename)
if (!res->data)
goto win_err;
+ CloseHandle(file_handle);
return res;
win_err: {
DWORD e = GetLastError();
@@ -234,6 +296,8 @@ tor_mmap_file(const char *filename)
err:
if (empty)
errno = ERANGE;
+ if (file_handle != INVALID_HANDLE_VALUE)
+ CloseHandle(file_handle);
tor_munmap_file(res);
return NULL;
}
@@ -247,8 +311,6 @@ tor_munmap_file(tor_mmap_t *handle)
if (handle->mmap_handle != NULL)
CloseHandle(handle->mmap_handle);
- if (handle->file_handle != INVALID_HANDLE_VALUE)
- CloseHandle(handle->file_handle);
tor_free(handle);
}
#else
@@ -270,7 +332,7 @@ tor_munmap_file(tor_mmap_t *handle)
{
char *d = (char*)handle->data;
tor_free(d);
- memset(handle, 0, sizeof(tor_mmap_t));
+ memwipe(handle, 0, sizeof(tor_mmap_t));
tor_free(handle);
}
#endif
@@ -304,7 +366,7 @@ tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
return -1; /* no place for the NUL */
if (size > SIZE_T_CEILING)
return -1;
-#ifdef MS_WINDOWS
+#ifdef _WIN32
r = _vsnprintf(str, size, format, args);
#else
r = vsnprintf(str, size, format, args);
@@ -447,10 +509,13 @@ tor_memmem(const void *_haystack, size_t hlen,
#endif
}
-/* Tables to implement ctypes-replacement TOR_IS*() functions. Each table
+/**
+ * Tables to implement ctypes-replacement TOR_IS*() functions. Each table
* has 256 bits to look up whether a character is in some set or not. This
* fails on non-ASCII platforms, but it is hard to find a platform whose
* character set is not a superset of ASCII nowadays. */
+
+/**@{*/
const uint32_t TOR_ISALPHA_TABLE[8] =
{ 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 };
const uint32_t TOR_ISALNUM_TABLE[8] =
@@ -463,8 +528,10 @@ const uint32_t TOR_ISPRINT_TABLE[8] =
{ 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 };
const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 };
const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 };
-/* Upper-casing and lowercasing tables to map characters to upper/lowercase
- * equivalents. */
+
+/** Upper-casing and lowercasing tables to map characters to upper/lowercase
+ * equivalents. Used by tor_toupper() and tor_tolower(). */
+/**@{*/
const char TOR_TOUPPER_TABLE[256] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
@@ -501,6 +568,22 @@ const char TOR_TOLOWER_TABLE[256] = {
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
};
+/**@}*/
+
+/** Helper for tor_strtok_r_impl: Advances cp past all characters in
+ * <b>sep</b>, and returns its new value. */
+static char *
+strtok_helper(char *cp, const char *sep)
+{
+ if (sep[1]) {
+ while (*cp && strchr(sep, *cp))
+ ++cp;
+ } else {
+ while (*cp && *cp == *sep)
+ ++cp;
+ }
+ return cp;
+}
/** Implementation of strtok_r for platforms whose coders haven't figured out
* how to write one. Hey guys! You can use this code here for free! */
@@ -508,19 +591,22 @@ char *
tor_strtok_r_impl(char *str, const char *sep, char **lasts)
{
char *cp, *start;
- if (str)
+ tor_assert(*sep);
+ if (str) {
+ str = strtok_helper(str, sep);
+ if (!*str)
+ return NULL;
start = cp = *lasts = str;
- else if (!*lasts)
+ } else if (!*lasts || !**lasts) {
return NULL;
- else
+ } else {
start = cp = *lasts;
+ }
- tor_assert(*sep);
if (sep[1]) {
while (*cp && !strchr(sep, *cp))
++cp;
} else {
- tor_assert(strlen(sep) == 1);
cp = strchr(cp, *sep);
}
@@ -528,12 +614,12 @@ tor_strtok_r_impl(char *str, const char *sep, char **lasts)
*lasts = NULL;
} else {
*cp++ = '\0';
- *lasts = cp;
+ *lasts = strtok_helper(cp, sep);
}
return start;
}
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/** Take a filename and return a pointer to its final element. This
* function is called on __FILE__ to fix a MSVC nit where __FILE__
* contains the full path to the file. This is bad, because it
@@ -633,7 +719,7 @@ set_uint64(void *cp, uint64_t v)
int
replace_file(const char *from, const char *to)
{
-#ifndef MS_WINDOWS
+#ifndef _WIN32
return rename(from,to);
#else
switch (file_status(to))
@@ -695,14 +781,14 @@ 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));
return NULL;
}
-#ifdef WIN32
+#ifdef _WIN32
_lseek(fd, 0, SEEK_SET);
if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) {
if (errno != EACCES && errno != EDEADLOCK)
@@ -751,7 +837,7 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
tor_assert(lockfile);
log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename);
-#ifdef WIN32
+#ifdef _WIN32
_lseek(lockfile->fd, 0, SEEK_SET);
if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) {
log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename,
@@ -787,7 +873,7 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
off_t
tor_fd_getpos(int fd)
{
-#ifdef WIN32
+#ifdef _WIN32
return (off_t) _lseek(fd, 0, SEEK_CUR);
#else
return (off_t) lseek(fd, 0, SEEK_CUR);
@@ -798,7 +884,7 @@ tor_fd_getpos(int fd)
int
tor_fd_seekend(int fd)
{
-#ifdef WIN32
+#ifdef _WIN32
return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0;
#else
return lseek(fd, 0, SEEK_END) < 0 ? -1 : 0;
@@ -851,7 +937,7 @@ tor_close_socket(tor_socket_t s)
* tor_close_socket to close sockets, and always using close() on
* files.
*/
-#if defined(MS_WINDOWS)
+#if defined(_WIN32)
r = closesocket(s);
#else
r = close(s);
@@ -872,7 +958,7 @@ tor_close_socket(tor_socket_t s)
} else {
int err = tor_socket_errno(-1);
log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err));
-#ifdef WIN32
+#ifdef _WIN32
if (err != WSAENOTSOCK)
--n_sockets_open;
#else
@@ -922,13 +1008,33 @@ 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);
- if (SOCKET_OK(s)) {
- socket_accounting_lock();
- ++n_sockets_open;
- mark_socket_open(s);
- socket_accounting_unlock();
- }
+ tor_socket_t s;
+#ifdef SOCK_CLOEXEC
+ s = socket(domain, type|SOCK_CLOEXEC, protocol);
+ if (SOCKET_OK(s))
+ goto socket_ok;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with SOCK_CLOEXEC support, we
+ * are running on one without. */
+ if (errno != EINVAL)
+ return s;
+#endif /* SOCK_CLOEXEC */
+
+ s = socket(domain, type, protocol);
+ if (! SOCKET_OK(s))
+ return s;
+
+#if defined(FD_CLOEXEC)
+ fcntl(s, F_SETFD, FD_CLOEXEC);
+#endif
+
+ goto socket_ok; /* So that socket_ok will not be unused. */
+
+ socket_ok:
+ socket_accounting_lock();
+ ++n_sockets_open;
+ mark_socket_open(s);
+ socket_accounting_unlock();
return s;
}
@@ -936,13 +1042,34 @@ 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);
- if (SOCKET_OK(s)) {
- socket_accounting_lock();
- ++n_sockets_open;
- mark_socket_open(s);
- socket_accounting_unlock();
- }
+ tor_socket_t s;
+#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
+ s = accept4(sockfd, addr, len, SOCK_CLOEXEC);
+ if (SOCKET_OK(s))
+ goto socket_ok;
+ /* If we got an error, see if it is ENOSYS. ENOSYS indicates that,
+ * even though we were built on a system with accept4 support, we
+ * are running on one without. Also, check for EINVAL, which indicates that
+ * we are missing SOCK_CLOEXEC support. */
+ if (errno != EINVAL && errno != ENOSYS)
+ return s;
+#endif
+
+ s = accept(sockfd, addr, len);
+ if (!SOCKET_OK(s))
+ return s;
+
+#if defined(FD_CLOEXEC)
+ fcntl(s, F_SETFD, FD_CLOEXEC);
+#endif
+
+ goto socket_ok; /* So that socket_ok will not be unused. */
+
+ socket_ok:
+ socket_accounting_lock();
+ ++n_sockets_open;
+ mark_socket_open(s);
+ socket_accounting_unlock();
return s;
}
@@ -962,7 +1089,7 @@ get_n_open_sockets(void)
void
set_socket_nonblocking(tor_socket_t socket)
{
-#if defined(MS_WINDOWS)
+#if defined(_WIN32)
unsigned long nonblocking = 1;
ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
#else
@@ -991,22 +1118,45 @@ int
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)
+#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32)
int r;
+
+#ifdef SOCK_CLOEXEC
+ r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd);
+ if (r == 0)
+ goto sockets_ok;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with SOCK_CLOEXEC support, we
+ * are running on one without. */
+ if (errno != EINVAL)
+ return -errno;
+#endif
+
r = socketpair(family, type, protocol, fd);
- if (r == 0) {
- socket_accounting_lock();
- if (fd[0] >= 0) {
- ++n_sockets_open;
- mark_socket_open(fd[0]);
- }
- if (fd[1] >= 0) {
- ++n_sockets_open;
- mark_socket_open(fd[1]);
- }
- socket_accounting_unlock();
+ if (r < 0)
+ return -errno;
+
+#if defined(FD_CLOEXEC)
+ if (SOCKET_OK(fd[0]))
+ fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ if (SOCKET_OK(fd[1]))
+ fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+#endif
+ goto sockets_ok; /* So that sockets_ok will not be unused. */
+
+ sockets_ok:
+ socket_accounting_lock();
+ if (SOCKET_OK(fd[0])) {
+ ++n_sockets_open;
+ mark_socket_open(fd[0]);
}
- return r < 0 ? -errno : r;
+ if (SOCKET_OK(fd[1])) {
+ ++n_sockets_open;
+ mark_socket_open(fd[1]);
+ }
+ socket_accounting_unlock();
+
+ return 0;
#else
/* This socketpair does not work when localhost is down. So
* it's really not the same thing at all. But it's close enough
@@ -1026,7 +1176,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
|| family != AF_UNIX
#endif
) {
-#ifdef MS_WINDOWS
+#ifdef _WIN32
return -WSAEAFNOSUPPORT;
#else
return -EAFNOSUPPORT;
@@ -1037,7 +1187,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
}
listener = tor_open_socket(AF_INET, type, 0);
- if (listener < 0)
+ if (!SOCKET_OK(listener))
return -tor_socket_errno(-1);
memset(&listen_addr, 0, sizeof(listen_addr));
listen_addr.sin_family = AF_INET;
@@ -1050,7 +1200,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
goto tidy_up_and_fail;
connector = tor_open_socket(AF_INET, type, 0);
- if (connector < 0)
+ if (!SOCKET_OK(connector))
goto tidy_up_and_fail;
/* We want to find out the port number to connect to. */
size = sizeof(connect_addr);
@@ -1065,7 +1215,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
size = sizeof(listen_addr);
acceptor = tor_accept_socket(listener,
(struct sockaddr *) &listen_addr, &size);
- if (acceptor < 0)
+ if (!SOCKET_OK(acceptor))
goto tidy_up_and_fail;
if (size != sizeof(listen_addr))
goto abort_tidy_up_and_fail;
@@ -1086,7 +1236,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
return 0;
abort_tidy_up_and_fail:
-#ifdef MS_WINDOWS
+#ifdef _WIN32
saved_errno = WSAECONNABORTED;
#else
saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */
@@ -1108,13 +1258,16 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
* tell Tor it's allowed to use. */
#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond _ConnLimit */
-/** Learn the maximum allowed number of file descriptors. (Some systems
- * have a low soft limit.
+/** Learn the maximum allowed number of file descriptors, and tell the system
+ * we want to use up to that number. (Some systems have a low soft limit, and
+ * let us set it higher.)
*
* We compute this by finding the largest number that we can use.
* If we can't find a number greater than or equal to <b>limit</b>,
* then we fail: return -1.
*
+ * If <b>limit</b> is 0, then do not adjust the current maximum.
+ *
* Otherwise, return 0 and store the maximum we found inside <b>max_out</b>.*/
int
set_max_file_descriptors(rlim_t limit, int *max_out)
@@ -1128,7 +1281,7 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
#if defined(CYGWIN) || defined(__CYGWIN__)
const char *platform = "Cygwin";
const unsigned long MAX_CONNECTIONS = 3200;
-#elif defined(MS_WINDOWS)
+#elif defined(_WIN32)
const char *platform = "Windows";
const unsigned long MAX_CONNECTIONS = 15000;
#else
@@ -1147,14 +1300,20 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
limit = MAX_CONNECTIONS;
#else /* HAVE_GETRLIMIT */
struct rlimit rlim;
- tor_assert(limit > 0);
if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
log_warn(LD_NET, "Could not get maximum number of file descriptors: %s",
strerror(errno));
return -1;
}
-
+ if (limit == 0) {
+ /* If limit == 0, return the maximum value without setting it. */
+ limit = rlim.rlim_max;
+ if (limit > INT_MAX)
+ limit = INT_MAX;
+ *max_out = (int)limit - ULIMIT_BUFFER;
+ return 0;
+ }
if (rlim.rlim_max < limit) {
log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're "
"limited to %lu. Please change your ulimit -n.",
@@ -1211,7 +1370,7 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
return 0;
}
-#ifndef MS_WINDOWS
+#ifndef _WIN32
/** Log details of current user and group credentials. Return 0 on
* success. Logs and return -1 on failure.
*/
@@ -1288,31 +1447,19 @@ log_credential_status(void)
return -1;
} else {
int i, retval = 0;
- char *strgid;
char *s = NULL;
- smartlist_t *elts = smartlist_create();
+ smartlist_t *elts = smartlist_new();
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);
@@ -1329,7 +1476,7 @@ log_credential_status(void)
int
switch_id(const char *user)
{
-#ifndef MS_WINDOWS
+#ifndef _WIN32
struct passwd *pw = NULL;
uid_t old_uid;
gid_t old_gid;
@@ -1464,6 +1611,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. */
@@ -1481,14 +1680,18 @@ get_user_homedir(const char *username)
}
#endif
-/** Modify <b>fname</b> to contain the name of the directory */
+/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't
+ * actually examine the filesystem; does a purely syntactic modification.
+ *
+ * The parent of the root director is considered to be iteself.
+ * */
int
get_parent_directory(char *fname)
{
char *cp;
int at_end = 1;
tor_assert(fname);
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/* If we start with, say, c:, then don't consider that the start of the path
*/
if (fname[0] && fname[1] == ':') {
@@ -1503,13 +1706,18 @@ get_parent_directory(char *fname)
*/
cp = fname + strlen(fname);
at_end = 1;
- while (--cp > fname) {
+ while (--cp >= fname) {
int is_sep = (*cp == '/'
-#ifdef MS_WINDOWS
+#ifdef _WIN32
|| *cp == '\\'
#endif
);
if (is_sep) {
+ if (cp == fname) {
+ /* This is the first separator in the file name; don't remove it! */
+ cp[1] = '\0';
+ return 0;
+ }
*cp = '\0';
if (! at_end)
return 0;
@@ -1520,6 +1728,101 @@ get_parent_directory(char *fname)
return -1;
}
+#ifndef _WIN32
+/** Return a newly allocated string containing the output of getcwd(). Return
+ * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since
+ * Hurd hasn't got a PATH_MAX.)
+ */
+static char *
+alloc_getcwd(void)
+{
+ int saved_errno = errno;
+/* We use this as a starting path length. Not too large seems sane. */
+#define START_PATH_LENGTH 128
+/* Nobody has a maxpath longer than this, as far as I know. And if they
+ * do, they shouldn't. */
+#define MAX_SANE_PATH_LENGTH 4096
+ size_t path_length = START_PATH_LENGTH;
+ char *path = tor_malloc(path_length);
+
+ errno = 0;
+ while (getcwd(path, path_length) == NULL) {
+ if (errno == ERANGE && path_length < MAX_SANE_PATH_LENGTH) {
+ path_length*=2;
+ path = tor_realloc(path, path_length);
+ } else {
+ tor_free(path);
+ path = NULL;
+ break;
+ }
+ }
+ errno = saved_errno;
+ return path;
+}
+#endif
+
+/** 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 _WIN32
+ 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 *absfname = NULL, *path = NULL;
+
+ tor_assert(fname);
+
+ if (fname[0] == '/') {
+ absfname = tor_strdup(fname);
+ } else {
+ path = alloc_getcwd();
+ if (path) {
+ tor_asprintf(&absfname, "%s/%s", path, fname);
+ tor_free(path);
+ } else {
+ /* If getcwd failed, the best we can do here is keep using the
+ * relative path. (Perhaps / isn't readable by this UID/GID.) */
+ log_warn(LD_GENERAL, "Unable to find current working directory: %s",
+ strerror(errno));
+ absfname = tor_strdup(fname);
+ }
+ }
+ return absfname;
+#endif
+}
+
+#ifndef HAVE__NSGETENVIRON
+#ifndef HAVE_EXTERN_ENVIRON_DECLARED
+/* Some platforms declare environ under some circumstances, others don't. */
+#ifndef RUNNING_DOXYGEN
+extern char **environ;
+#endif
+#endif
+#endif
+
+/** Return the current environment. This is a portable replacement for
+ * 'environ'. */
+char **
+get_environment(void)
+{
+#ifdef HAVE__NSGETENVIRON
+ /* This is for compatibility between OSX versions. Otherwise (for example)
+ * when we do a mostly-static build on OSX 10.7, the resulting binary won't
+ * work on OSX 10.6. */
+ return *_NSGetEnviron();
+#else
+ return environ;
+#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 +1880,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 +1921,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 +1981,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 {
@@ -1755,7 +2064,7 @@ tor_lookup_hostname(const char *name, uint32_t *addr)
void
tor_init_weak_random(unsigned seed)
{
-#ifdef MS_WINDOWS
+#ifdef _WIN32
srand(seed);
#else
srandom(seed);
@@ -1768,7 +2077,7 @@ tor_init_weak_random(unsigned seed)
long
tor_weak_random(void)
{
-#ifdef MS_WINDOWS
+#ifdef _WIN32
return rand();
#else
return random();
@@ -1792,17 +2101,14 @@ get_uname(void)
#ifdef HAVE_UNAME
if (uname(&u) != -1) {
/* (Linux says 0 is success, Solaris says 1 is success) */
- tor_snprintf(uname_result, sizeof(uname_result), "%s %s",
- u.sysname, u.machine);
+ strlcpy(uname_result, u.sysname, sizeof(uname_result));
} else
#endif
{
-#ifdef MS_WINDOWS
+#ifdef _WIN32
OSVERSIONINFOEX info;
int i;
const char *plat = NULL;
- const char *extra = NULL;
- char acsd[MAX_PATH] = {0};
static struct {
unsigned major; unsigned minor; const char *version;
} win_version_table[] = {
@@ -1827,20 +2133,11 @@ get_uname(void)
uname_result_is_set = 1;
return uname_result;
}
-#ifdef UNICODE
- wcstombs(acsd, info.szCSDVersion, MAX_PATH);
-#else
- strlcpy(acsd, info.szCSDVersion, sizeof(acsd));
-#endif
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
plat = "Windows NT 4.0";
else
plat = "Windows 95";
- if (acsd[1] == 'B')
- extra = "OSR2 (B)";
- else if (acsd[1] == 'C')
- extra = "OSR2 (C)";
} else {
for (i=0; win_version_table[i].major>0; ++i) {
if (win_version_table[i].major == info.dwMajorVersion &&
@@ -1850,39 +2147,25 @@ get_uname(void)
}
}
}
- if (plat && !strcmp(plat, "Windows 98")) {
- if (acsd[1] == 'A')
- extra = "SE (A)";
- else if (acsd[1] == 'B')
- extra = "SE (B)";
- }
if (plat) {
- if (!extra)
- extra = acsd;
- tor_snprintf(uname_result, sizeof(uname_result), "%s %s",
- plat, extra);
+ strlcpy(uname_result, plat, sizeof(uname_result));
} else {
if (info.dwMajorVersion > 6 ||
(info.dwMajorVersion==6 && info.dwMinorVersion>2))
tor_snprintf(uname_result, sizeof(uname_result),
- "Very recent version of Windows [major=%d,minor=%d] %s",
- (int)info.dwMajorVersion,(int)info.dwMinorVersion,
- acsd);
+ "Very recent version of Windows [major=%d,minor=%d]",
+ (int)info.dwMajorVersion,(int)info.dwMinorVersion);
else
tor_snprintf(uname_result, sizeof(uname_result),
- "Unrecognized version of Windows [major=%d,minor=%d] %s",
- (int)info.dwMajorVersion,(int)info.dwMinorVersion,
- acsd);
+ "Unrecognized version of Windows [major=%d,minor=%d]",
+ (int)info.dwMajorVersion,(int)info.dwMinorVersion);
}
#if !defined (WINCE)
-#ifdef VER_SUITE_BACKOFFICE
- if (info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
- strlcat(uname_result, " [domain controller]", sizeof(uname_result));
- } else if (info.wProductType == VER_NT_SERVER) {
- strlcat(uname_result, " [server]", sizeof(uname_result));
- } else if (info.wProductType == VER_NT_WORKSTATION) {
- strlcat(uname_result, " [workstation]", sizeof(uname_result));
- }
+#ifdef VER_NT_SERVER
+ if (info.wProductType == VER_NT_SERVER ||
+ info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
+ strlcat(uname_result, " [server]", sizeof(uname_result));
+ }
#endif
#endif
#else
@@ -1995,13 +2278,59 @@ spawn_exit(void)
#endif
}
+/** Implementation logic for compute_num_cpus(). */
+static int
+compute_num_cpus_impl(void)
+{
+#ifdef _WIN32
+ 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.)
*/
void
tor_gettimeofday(struct timeval *timeval)
{
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/* Epoch bias copied from perl: number of units between windows epoch and
* Unix epoch. */
#define EPOCH_BIAS U64_LITERAL(116444736000000000)
@@ -2046,12 +2375,18 @@ tor_gettimeofday(struct timeval *timeval)
return;
}
-#if defined(TOR_IS_MULTITHREADED) && !defined(MS_WINDOWS)
+#if defined(TOR_IS_MULTITHREADED) && !defined(_WIN32)
/** Defined iff we need to add locks when defining fake versions of reentrant
* versions of time-related functions. */
#define TIME_FNS_NEED_LOCKS
#endif
+/** Helper: Deal with confused or out-of-bounds values from localtime_r and
+ * friends. (On some platforms, they can give out-of-bounds values or can
+ * return NULL.) If <b>islocal</b>, this is a localtime result; otherwise
+ * it's from gmtime. The function returned <b>r</b>, when given <b>timep</b>
+ * as its input. If we need to store new results, store them in
+ * <b>resultbuf</b>. */
static struct tm *
correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
struct tm *r)
@@ -2396,7 +2731,7 @@ tor_cond_new(void)
{
tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
InitializeCriticalSection(&cond->mutex);
- cond->events = smartlist_create();
+ cond->events = smartlist_new();
return cond;
}
void
@@ -2590,7 +2925,7 @@ in_main_thread(void)
* should call tor_socket_errno <em>at most once</em> on the failing
* socket to get the error.
*/
-#if defined(MS_WINDOWS)
+#if defined(_WIN32)
int
tor_socket_errno(tor_socket_t sock)
{
@@ -2606,7 +2941,7 @@ tor_socket_errno(tor_socket_t sock)
}
#endif
-#if defined(MS_WINDOWS)
+#if defined(_WIN32)
#define E(code, s) { code, (s " [" #code " ]") }
struct { int code; const char *msg; } windows_socket_errors[] = {
E(WSAEINTR, "Interrupted function call"),
@@ -2688,7 +3023,7 @@ tor_socket_strerror(int e)
int
network_init(void)
{
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/* This silly exercise is necessary before windows will allow
* gethostbyname to work. */
WSADATA WSAData;
@@ -2698,6 +3033,11 @@ network_init(void)
log_warn(LD_NET,"Error initializing windows network layer: code was %d",r);
return -1;
}
+ if (sizeof(SOCKET) != sizeof(tor_socket_t)) {
+ log_warn(LD_BUG,"The tor_socket_t type does not match SOCKET in size; Tor "
+ "might not work. (Sizes are %d and %d respectively.)",
+ (int)sizeof(tor_socket_t), (int)sizeof(SOCKET));
+ }
/* WSAData.iMaxSockets might show the max sockets we're allowed to use.
* We might use it to complain if we're trying to be a server but have
* too few sockets available. */
@@ -2705,7 +3045,7 @@ network_init(void)
return 0;
}
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/** Return a newly allocated string describing the windows system error code
* <b>err</b>. Note that error codes are different from errno. Error codes
* come from GetLastError() when a winapi call fails. errno is set only when
@@ -2715,28 +3055,37 @@ format_win32_error(DWORD err)
{
TCHAR *str = NULL;
char *result;
+ DWORD n;
/* Somebody once decided that this interface was better than strerror(). */
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPVOID)&str,
+ (LPVOID)&str,
0, NULL);
- if (str) {
+ if (str && n) {
#ifdef UNICODE
- char abuf[1024] = {0};
- wcstombs(abuf,str,1024);
- result = tor_strdup(abuf);
+ size_t len;
+ if (n > 128*1024)
+ len = (128 * 1024) * 2 + 1; /* This shouldn't be possible, but let's
+ * make sure. */
+ else
+ len = n * 2 + 1;
+ result = tor_malloc(len);
+ wcstombs(result,str,len);
+ result[len-1] = '\0';
#else
result = tor_strdup(str);
#endif
- LocalFree(str); /* LocalFree != free() */
} else {
result = tor_strdup("<unformattable error>");
}
+ if (str) {
+ LocalFree(str); /* LocalFree != free() */
+ }
return result;
}
#endif
diff --git a/src/common/compat.h b/src/common/compat.h
index fc70caf50..42648bb04 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_COMPAT_H
@@ -8,9 +8,10 @@
#include "orconfig.h"
#include "torint.h"
-#ifdef MS_WINDOWS
-#define WIN32_WINNT 0x400
-#define _WIN32_WINNT 0x400
+#ifdef _WIN32
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER) && (_MSC_VER < 1300)
#include <winsock.h>
@@ -19,6 +20,9 @@
#include <ws2tcpip.h>
#endif
#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -31,7 +35,7 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-#if defined(HAVE_PTHREAD_H) && !defined(MS_WINDOWS)
+#if defined(HAVE_PTHREAD_H) && !defined(_WIN32)
#include <pthread.h>
#endif
#include <stdarg.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>
@@ -86,7 +89,7 @@
#endif
/* inline is __inline on windows. */
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#define INLINE __inline
#else
#define INLINE inline
@@ -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
@@ -195,7 +196,7 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#endif
/* ===== String compatibility */
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/* Windows names string functions differently from most other platforms. */
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
@@ -248,8 +249,7 @@ typedef struct tor_mmap_t {
#ifdef HAVE_SYS_MMAN_H
size_t mapping_size; /**< Size of the actual mapping. (This is this file
* size, rounded up to the nearest page.) */
-#elif defined MS_WINDOWS
- HANDLE file_handle;
+#elif defined _WIN32
HANDLE mmap_handle;
#endif
@@ -269,9 +269,9 @@ int tor_vasprintf(char **strp, const char *fmt, va_list args)
CHECK_PRINTF(2,0);
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)
{
@@ -307,7 +307,7 @@ char *tor_strtok_r_impl(char *str, const char *sep, char **lasts);
#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts)
#endif
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#define _SHORT_FILE_ (tor_fix_source_file(__FILE__))
const char *tor_fix_source_file(const char *fname);
#else
@@ -372,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);
@@ -383,7 +386,7 @@ void tor_lockfile_unlock(tor_lockfile_t *lockfile);
off_t tor_fd_getpos(int fd);
int tor_fd_seekend(int fd);
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#define PATH_SEPARATOR "\\"
#else
#define PATH_SEPARATOR "/"
@@ -395,12 +398,20 @@ int tor_fd_seekend(int fd);
typedef int socklen_t;
#endif
-#ifdef MS_WINDOWS
+#ifdef _WIN32
+/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that
+ * any inadvertant checks for the socket being <= 0 or > 0 will probably
+ * still work. */
#define tor_socket_t intptr_t
#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET)
+#define TOR_INVALID_SOCKET INVALID_SOCKET
#else
+/** Type used for a network socket. */
#define tor_socket_t int
+/** Macro: true iff 's' is a possible value for a valid initialized socket. */
#define SOCKET_OK(s) ((s) >= 0)
+/** Error/uninitialized value for a tor_socket_t. */
+#define TOR_INVALID_SOCKET (-1)
#endif
int tor_close_socket(tor_socket_t s);
@@ -488,7 +499,9 @@ int network_init(void);
* errnos against expected values, and use tor_socket_errno to find
* the actual errno after a socket operation fails.
*/
-#if defined(MS_WINDOWS)
+#if defined(_WIN32)
+/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */
+#define SOCK_ERRNO(e) WSA##e
/** Return true if e is EAGAIN or the local equivalent. */
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
/** Return true if e is EINPROGRESS or the local equivalent. */
@@ -509,6 +522,7 @@ int network_init(void);
int tor_socket_errno(tor_socket_t sock);
const char *tor_socket_strerror(int e);
#else
+#define SOCK_ERRNO(e) e
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN)
#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS)
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
@@ -541,9 +555,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));
@@ -561,17 +575,21 @@ 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);
+
+char **get_environment(void);
int spawn_func(void (*func)(void *), void *data);
void spawn_exit(void) ATTR_NORETURN;
-#if defined(ENABLE_THREADS) && defined(MS_WINDOWS)
+#if defined(ENABLE_THREADS) && defined(_WIN32)
#define USE_WIN32_THREADS
#define TOR_IS_MULTITHREADED 1
#elif (defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H) && \
@@ -582,6 +600,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. */
@@ -651,14 +671,14 @@ void tor_cond_signal_all(tor_cond_t *cond);
#endif
/* Platform-specific helpers. */
-#ifdef MS_WINDOWS
+#ifdef _WIN32
char *format_win32_error(DWORD err);
#endif
/*for some reason my compiler doesn't have these version flags defined
a nice homework assignment for someone one day is to define the rest*/
//these are the values as given on MSDN
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#ifndef VER_SUITE_EMBEDDEDNT
#define VER_SUITE_EMBEDDEDNT 0x00000040
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index ddb2da68a..6655ca87d 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, The Tor Project, Inc. */
+/* Copyright (c) 2009-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,9 +6,8 @@
* \brief Wrappers to handle porting between different versions of libevent.
*
* In an ideal world, we'd just use Libevent 2.0 from now on. But as of June
- * 2009, Libevent 2.0 is still in alpha, and we will have old versions of
- * Libevent for the forseeable future.
- **/
+ * 2012, Libevent 1.4 is still all over, and some poor souls are stuck on
+ * Libevent 1.3e. */
#include "orconfig.h"
#include "compat.h"
@@ -19,6 +18,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
@@ -53,7 +56,7 @@ typedef uint32_t le_version_t;
static le_version_t tor_get_libevent_version(const char **v_out);
-#ifdef HAVE_EVENT_SET_LOG_CALLBACK
+#if defined(HAVE_EVENT_SET_LOG_CALLBACK) || defined(RUNNING_DOXYGEN)
/** A string which, if it appears in a libevent log, should be ignored. */
static const char *suppress_msg = NULL;
/** Callback function passed to event_set_log() so we can intercept
@@ -163,11 +166,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 +194,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(_WIN32) && 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(_WIN32) && 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 +276,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 +325,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 +333,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 +637,90 @@ 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
+
+#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,1,1)
+void
+tor_gettimeofday_cached(struct timeval *tv)
+{
+ event_base_gettimeofday_cached(the_event_base, tv);
+}
+void
+tor_gettimeofday_cache_clear(void)
+{
+ event_base_update_cache_time(the_event_base);
+}
+#else
+/** Cache the current hi-res time; the cache gets reset when libevent
+ * calls us. */
+static struct timeval cached_time_hires = {0, 0};
+
+/** Return a fairly recent view of the current time. */
+void
+tor_gettimeofday_cached(struct timeval *tv)
+{
+ if (cached_time_hires.tv_sec == 0) {
+ tor_gettimeofday(&cached_time_hires);
+ }
+ *tv = cached_time_hires;
+}
+
+/** Reset the cached view of the current time, so that the next time we try
+ * to learn it, we will get an up-to-date value. */
+void
+tor_gettimeofday_cache_clear(void)
+{
+ cached_time_hires.tv_sec = 0;
+}
+#endif
+
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 89b256396..56285ef80 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Tor Project, Inc. */
+/* Copyright (c) 2009-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_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,19 @@ struct timeval;
int tor_event_base_loopexit(struct event_base *base, struct timeval *tv);
#endif
-void tor_libevent_initialize(void);
+/** Defines a configuration for using libevent with Tor: passed as an argument
+ * to tor_libevent_initialize() to describe how we want to set up. */
+typedef struct tor_libevent_cfg {
+ /** Flag: if true, disable IOCP (assuming that it could be enabled). */
+ int disable_iocp;
+ /** How many CPUs should we use (relevant only with IOCP). */
+ int num_cpus;
+ /** How many milliseconds should we allow between updating bandwidth limits?
+ * (relevant only with bufferevents). */
+ 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 +79,17 @@ 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
+
+void tor_gettimeofday_cached(struct timeval *tv);
+void tor_gettimeofday_cache_clear(void);
+
#endif
diff --git a/src/common/container.c b/src/common/container.c
index c047562cd..ede98eca5 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,7 +29,7 @@
/** Allocate and return an empty smartlist.
*/
smartlist_t *
-smartlist_create(void)
+smartlist_new(void)
{
smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
sl->num_used = 0;
@@ -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)
@@ -1049,7 +1048,7 @@ digestmap_set(digestmap_t *map, const char *key, void *val)
* the hash table that we do in the unoptimized code above. (Each of
* HT_INSERT and HT_FIND calls HT_SET_HASH and HT_FIND_P.)
*/
- _HT_FIND_OR_INSERT(digestmap_impl, node, digestmap_entry_hash, &(map->head),
+ HT_FIND_OR_INSERT_(digestmap_impl, node, digestmap_entry_hash, &(map->head),
digestmap_entry_t, &search, ptr,
{
/* we found an entry. */
@@ -1063,7 +1062,7 @@ digestmap_set(digestmap_t *map, const char *key, void *val)
tor_malloc_zero(sizeof(digestmap_entry_t));
memcpy(newent->key, key, DIGEST_LEN);
newent->val = val;
- _HT_FOI_INSERT(node, &(map->head), &search, newent, ptr);
+ HT_FOI_INSERT_(node, &(map->head), &search, newent, ptr);
return NULL;
});
#endif
@@ -1376,14 +1375,14 @@ digestmap_free(digestmap_t *map, void (*free_val)(void*))
void
strmap_assert_ok(const strmap_t *map)
{
- tor_assert(!_strmap_impl_HT_REP_IS_BAD(&map->head));
+ tor_assert(!strmap_impl_HT_REP_IS_BAD_(&map->head));
}
/** Fail with an assertion error if anything has gone wrong with the internal
* representation of <b>map</b>. */
void
digestmap_assert_ok(const digestmap_t *map)
{
- tor_assert(!_digestmap_impl_HT_REP_IS_BAD(&map->head));
+ tor_assert(!digestmap_impl_HT_REP_IS_BAD_(&map->head));
}
/** Return true iff <b>map</b> has no entries. */
diff --git a/src/common/container.h b/src/common/container.h
index 4a6eba789..dab3b83f3 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_CONTAINER_H
@@ -26,7 +26,7 @@ typedef struct smartlist_t {
/** @} */
} smartlist_t;
-smartlist_t *smartlist_create(void);
+smartlist_t *smartlist_new(void);
void smartlist_free(smartlist_t *sl);
void smartlist_clear(smartlist_t *sl);
void smartlist_add(smartlist_t *sl, void *element);
@@ -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);
@@ -148,9 +142,9 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item,
* assign it to a new local variable of type <b>type</b> named <b>var</b>, and
- * execute the statement <b>cmd</b>. Inside the loop, the loop index can
- * be accessed as <b>var</b>_sl_idx and the length of the list can be accessed
- * as <b>var</b>_sl_len.
+ * execute the statements inside the loop body. Inside the loop, the loop
+ * index can be accessed as <b>var</b>_sl_idx and the length of the list can
+ * be accessed as <b>var</b>_sl_len.
*
* NOTE: Do not change the length of the list while the loop is in progress,
* unless you adjust the _sl_len variable correspondingly. See second example
@@ -159,23 +153,21 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
* Example use:
* <pre>
* smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
- * SMARTLIST_FOREACH(list, char *, cp,
- * {
+ * SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
* printf("%d: %s\n", cp_sl_idx, cp);
* tor_free(cp);
- * });
+ * } SMARTLIST_FOREACH_END(cp);
* smartlist_free(list);
* </pre>
*
* Example use (advanced):
* <pre>
- * SMARTLIST_FOREACH(list, char *, cp,
- * {
+ * SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
* if (!strcmp(cp, "junk")) {
* tor_free(cp);
* SMARTLIST_DEL_CURRENT(list, cp);
* }
- * });
+ * } SMARTLIST_FOREACH_END(cp);
* </pre>
*/
/* Note: these macros use token pasting, and reach into smartlist internals.
@@ -224,6 +216,14 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
var = NULL; \
} STMT_END
+/**
+ * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using
+ * <b>cmd</b> as the loop body. This wrapper is here for convenience with
+ * very short loops.
+ *
+ * By convention, we do not use this for loops which nest, or for loops over
+ * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those.
+ */
#define SMARTLIST_FOREACH(sl, type, var, cmd) \
SMARTLIST_FOREACH_BEGIN(sl,type,var) { \
cmd; \
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 88e48ef84..30990ecc8 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,9 +12,10 @@
#include "orconfig.h"
-#ifdef MS_WINDOWS
-#define WIN32_WINNT 0x400
-#define _WIN32_WINNT 0x400
+#ifdef _WIN32
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>
@@ -56,18 +57,20 @@
#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) && \
+ !defined(RUNNING_DOXYGEN)
/** @{ */
/** 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
@@ -104,23 +107,24 @@ static int _n_openssl_mutexes = 0;
#endif
/** A public key, or a public/private key-pair. */
-struct crypto_pk_env_t
+struct crypto_pk_t
{
int refs; /**< reference count, so we don't have to copy keys */
RSA *key; /**< The key itself */
};
/** Key and stream information for a stream cipher. */
-struct crypto_cipher_env_t
+struct crypto_cipher_t
{
char key[CIPHER_KEY_LEN]; /**< The raw key. */
+ char iv[CIPHER_IV_LEN]; /**< The initial IV. */
aes_cnt_cipher_t *cipher; /**< The key in format usable for counter-mode AES
* encryption */
};
/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake
* while we're waiting for the second.*/
-struct crypto_dh_env_t {
+struct crypto_dh_t {
DH *dh; /**< The openssl DH object */
};
@@ -134,7 +138,6 @@ crypto_get_rsa_padding_overhead(int padding)
{
switch (padding)
{
- case RSA_NO_PADDING: return 0;
case RSA_PKCS1_OAEP_PADDING: return 42;
case RSA_PKCS1_PADDING: return 11;
default: tor_assert(0); return -1;
@@ -148,7 +151,6 @@ crypto_get_rsa_padding(int padding)
{
switch (padding)
{
- case PK_NO_PADDING: return RSA_NO_PADDING;
case PK_PKCS1_PADDING: return RSA_PKCS1_PADDING;
case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING;
default: tor_assert(0); return -1;
@@ -274,6 +276,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,61 +292,30 @@ 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)
+/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
+crypto_pk_t *
+_crypto_new_pk_from_rsa(RSA *rsa)
{
- crypto_pk_env_t *env;
+ crypto_pk_t *env;
tor_assert(rsa);
- env = tor_malloc(sizeof(crypto_pk_env_t));
+ env = tor_malloc(sizeof(crypto_pk_t));
env->refs = 1;
env->key = rsa;
return env;
}
/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a
- * crypto_pk_env_t. */
+ * crypto_pk_t. */
RSA *
-_crypto_pk_env_get_rsa(crypto_pk_env_t *env)
+_crypto_pk_get_rsa(crypto_pk_t *env)
{
return env->key;
}
-/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_env_t. Iff
+/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
* private is set, include the private-key portion of the key. */
EVP_PKEY *
-_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env, int private)
+_crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
{
RSA *key = NULL;
EVP_PKEY *pkey = NULL;
@@ -365,10 +340,10 @@ _crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env, int private)
return NULL;
}
-/** Used by tortls.c: Get the DH* from a crypto_dh_env_t.
+/** Used by tortls.c: Get the DH* from a crypto_dh_t.
*/
DH *
-_crypto_dh_env_get_dh(crypto_dh_env_t *dh)
+_crypto_dh_get_dh(crypto_dh_t *dh)
{
return dh->dh;
}
@@ -376,21 +351,21 @@ _crypto_dh_env_get_dh(crypto_dh_env_t *dh)
/** Allocate and return storage for a public key. The key itself will not yet
* be set.
*/
-crypto_pk_env_t *
-crypto_new_pk_env(void)
+crypto_pk_t *
+crypto_pk_new(void)
{
RSA *rsa;
rsa = RSA_new();
tor_assert(rsa);
- return _crypto_new_pk_env_rsa(rsa);
+ return _crypto_new_pk_from_rsa(rsa);
}
/** Release a reference to an asymmetric key; when all the references
* are released, free the key.
*/
void
-crypto_free_pk_env(crypto_pk_env_t *env)
+crypto_pk_free(crypto_pk_t *env)
{
if (!env)
return;
@@ -405,61 +380,52 @@ crypto_free_pk_env(crypto_pk_env_t *env)
tor_free(env);
}
-/** Create a new symmetric cipher for a given key and encryption flag
- * (1=encrypt, 0=decrypt). Return the crypto object on success; NULL
- * on failure.
+/** Allocate and return a new symmetric cipher using the provided key and iv.
+ * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. If you
+ * provide NULL in place of either one, it is generated at random.
*/
-crypto_cipher_env_t *
-crypto_create_init_cipher(const char *key, int encrypt_mode)
+crypto_cipher_t *
+crypto_cipher_new_with_iv(const char *key, const char *iv)
{
- int r;
- crypto_cipher_env_t *crypto = NULL;
+ crypto_cipher_t *env;
- if (! (crypto = crypto_new_cipher_env())) {
- log_warn(LD_CRYPTO, "Unable to allocate crypto object");
- return NULL;
- }
+ env = tor_malloc_zero(sizeof(crypto_cipher_t));
- crypto_cipher_set_key(crypto, key);
-
- if (encrypt_mode)
- r = crypto_cipher_encrypt_init_cipher(crypto);
+ if (key == NULL)
+ crypto_rand(env->key, CIPHER_KEY_LEN);
+ else
+ memcpy(env->key, key, CIPHER_KEY_LEN);
+ if (iv == NULL)
+ crypto_rand(env->iv, CIPHER_IV_LEN);
else
- r = crypto_cipher_decrypt_init_cipher(crypto);
+ memcpy(env->iv, iv, CIPHER_IV_LEN);
- if (r)
- goto error;
- return crypto;
+ env->cipher = aes_new_cipher(env->key, env->iv);
- error:
- if (crypto)
- crypto_free_cipher_env(crypto);
- return NULL;
+ return env;
}
-/** Allocate and return a new symmetric cipher.
- */
-crypto_cipher_env_t *
-crypto_new_cipher_env(void)
+/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all
+ * zero bytes. */
+crypto_cipher_t *
+crypto_cipher_new(const char *key)
{
- crypto_cipher_env_t *env;
-
- env = tor_malloc_zero(sizeof(crypto_cipher_env_t));
- env->cipher = aes_new_cipher();
- return env;
+ char zeroiv[CIPHER_IV_LEN];
+ memset(zeroiv, 0, sizeof(zeroiv));
+ return crypto_cipher_new_with_iv(key, zeroiv);
}
/** Free a symmetric cipher.
*/
void
-crypto_free_cipher_env(crypto_cipher_env_t *env)
+crypto_cipher_free(crypto_cipher_t *env)
{
if (!env)
return;
tor_assert(env->cipher);
- aes_free_cipher(env->cipher);
- memset(env, 0, sizeof(crypto_cipher_env_t));
+ aes_cipher_free(env->cipher);
+ memwipe(env, 0, sizeof(crypto_cipher_t));
tor_free(env);
}
@@ -469,13 +435,13 @@ crypto_free_cipher_env(crypto_cipher_env_t *env)
* Return 0 on success, -1 on failure.
*/
int
-crypto_pk_generate_key_with_bits(crypto_pk_env_t *env, int bits)
+crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
{
tor_assert(env);
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
@@ -516,7 +482,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_env_t *env, int bits)
*/
/* Used here, and used for testing. */
int
-crypto_pk_read_private_key_from_string(crypto_pk_env_t *env,
+crypto_pk_read_private_key_from_string(crypto_pk_t *env,
const char *s, ssize_t len)
{
BIO *b;
@@ -548,7 +514,7 @@ crypto_pk_read_private_key_from_string(crypto_pk_env_t *env,
* <b>keyfile</b> into <b>env</b>. Return 0 on success, -1 on failure.
*/
int
-crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env,
+crypto_pk_read_private_key_from_filename(crypto_pk_t *env,
const char *keyfile)
{
char *contents;
@@ -563,7 +529,7 @@ crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env,
/* Try to parse it. */
r = crypto_pk_read_private_key_from_string(env, contents, -1);
- memset(contents, 0, strlen(contents));
+ memwipe(contents, 0, strlen(contents));
tor_free(contents);
if (r)
return -1; /* read_private_key_from_string already warned, so we don't.*/
@@ -577,7 +543,7 @@ crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env,
/** Helper function to implement crypto_pk_write_*_key_to_string. */
static int
-crypto_pk_write_key_to_string_impl(crypto_pk_env_t *env, char **dest,
+crypto_pk_write_key_to_string_impl(crypto_pk_t *env, char **dest,
size_t *len, int is_public)
{
BUF_MEM *buf;
@@ -625,7 +591,7 @@ crypto_pk_write_key_to_string_impl(crypto_pk_env_t *env, char **dest,
* failure, return -1.
*/
int
-crypto_pk_write_public_key_to_string(crypto_pk_env_t *env, char **dest,
+crypto_pk_write_public_key_to_string(crypto_pk_t *env, char **dest,
size_t *len)
{
return crypto_pk_write_key_to_string_impl(env, dest, len, 1);
@@ -637,7 +603,7 @@ crypto_pk_write_public_key_to_string(crypto_pk_env_t *env, char **dest,
* failure, return -1.
*/
int
-crypto_pk_write_private_key_to_string(crypto_pk_env_t *env, char **dest,
+crypto_pk_write_private_key_to_string(crypto_pk_t *env, char **dest,
size_t *len)
{
return crypto_pk_write_key_to_string_impl(env, dest, len, 0);
@@ -648,7 +614,7 @@ crypto_pk_write_private_key_to_string(crypto_pk_env_t *env, char **dest,
* failure.
*/
int
-crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, const char *src,
+crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src,
size_t len)
{
BIO *b;
@@ -679,7 +645,7 @@ crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, const char *src,
* PEM-encoded. Return 0 on success, -1 on failure.
*/
int
-crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env,
+crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
const char *fname)
{
BIO *bio;
@@ -705,7 +671,7 @@ crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env,
s[len]='\0';
r = write_str_to_file(fname, s, 0);
BIO_free(bio);
- memset(s, 0, strlen(s));
+ memwipe(s, 0, strlen(s));
tor_free(s);
return r;
}
@@ -713,7 +679,7 @@ crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env,
/** Return true iff <b>env</b> has a valid key.
*/
int
-crypto_pk_check_key(crypto_pk_env_t *env)
+crypto_pk_check_key(crypto_pk_t *env)
{
int r;
tor_assert(env);
@@ -727,7 +693,7 @@ crypto_pk_check_key(crypto_pk_env_t *env)
/** Return true iff <b>key</b> contains the private-key portion of the RSA
* key. */
int
-crypto_pk_key_is_private(const crypto_pk_env_t *key)
+crypto_pk_key_is_private(const crypto_pk_t *key)
{
tor_assert(key);
return PRIVATE_KEY_OK(key);
@@ -737,7 +703,7 @@ crypto_pk_key_is_private(const crypto_pk_env_t *key)
* equals 65537.
*/
int
-crypto_pk_public_exponent_ok(crypto_pk_env_t *env)
+crypto_pk_public_exponent_ok(crypto_pk_t *env)
{
tor_assert(env);
tor_assert(env->key);
@@ -749,7 +715,7 @@ crypto_pk_public_exponent_ok(crypto_pk_env_t *env)
* if a==b, and 1 if a\>b.
*/
int
-crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b)
+crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
{
int result;
@@ -769,7 +735,7 @@ crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b)
/** Return the size of the public key modulus in <b>env</b>, in bytes. */
size_t
-crypto_pk_keysize(crypto_pk_env_t *env)
+crypto_pk_keysize(crypto_pk_t *env)
{
tor_assert(env);
tor_assert(env->key);
@@ -779,7 +745,7 @@ crypto_pk_keysize(crypto_pk_env_t *env)
/** Return the size of the public key modulus of <b>env</b>, in bits. */
int
-crypto_pk_num_bits(crypto_pk_env_t *env)
+crypto_pk_num_bits(crypto_pk_t *env)
{
tor_assert(env);
tor_assert(env->key);
@@ -790,8 +756,8 @@ crypto_pk_num_bits(crypto_pk_env_t *env)
/** Increase the reference count of <b>env</b>, and return it.
*/
-crypto_pk_env_t *
-crypto_pk_dup_key(crypto_pk_env_t *env)
+crypto_pk_t *
+crypto_pk_dup_key(crypto_pk_t *env)
{
tor_assert(env);
tor_assert(env->key);
@@ -801,8 +767,8 @@ crypto_pk_dup_key(crypto_pk_env_t *env)
}
/** Make a real honest-to-goodness copy of <b>env</b>, and return it. */
-crypto_pk_env_t *
-crypto_pk_copy_full(crypto_pk_env_t *env)
+crypto_pk_t *
+crypto_pk_copy_full(crypto_pk_t *env)
{
RSA *new_key;
int privatekey = 0;
@@ -825,7 +791,7 @@ crypto_pk_copy_full(crypto_pk_env_t *env)
return NULL;
}
- return _crypto_new_pk_env_rsa(new_key);
+ return _crypto_new_pk_from_rsa(new_key);
}
/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
@@ -837,7 +803,7 @@ crypto_pk_copy_full(crypto_pk_env_t *env)
* at least the length of the modulus of <b>env</b>.
*/
int
-crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, size_t tolen,
+crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen, int padding)
{
int r;
@@ -866,7 +832,7 @@ crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, size_t tolen,
* at least the length of the modulus of <b>env</b>.
*/
int
-crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to,
+crypto_pk_private_decrypt(crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen,
int padding, int warnOnFailure)
@@ -903,7 +869,7 @@ crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to,
* at least the length of the modulus of <b>env</b>.
*/
int
-crypto_pk_public_checksig(crypto_pk_env_t *env, char *to,
+crypto_pk_public_checksig(crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen)
{
@@ -930,7 +896,7 @@ crypto_pk_public_checksig(crypto_pk_env_t *env, char *to,
* SHA1(data). Else return -1.
*/
int
-crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
+crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data,
size_t datalen, const char *sig, size_t siglen)
{
char digest[DIGEST_LEN];
@@ -948,7 +914,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) {
@@ -975,7 +941,7 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
* at least the length of the modulus of <b>env</b>.
*/
int
-crypto_pk_private_sign(crypto_pk_env_t *env, char *to, size_t tolen,
+crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen)
{
int r;
@@ -1007,7 +973,7 @@ crypto_pk_private_sign(crypto_pk_env_t *env, char *to, size_t tolen,
* at least the length of the modulus of <b>env</b>.
*/
int
-crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, size_t tolen,
+crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen)
{
int r;
@@ -1015,7 +981,7 @@ crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, size_t tolen,
if (crypto_digest(digest,from,fromlen)<0)
return -1;
r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN);
- memset(digest, 0, sizeof(digest));
+ memwipe(digest, 0, sizeof(digest));
return r;
}
@@ -1023,9 +989,6 @@ crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, size_t tolen,
* bytes of data from <b>from</b>, with padding type 'padding',
* storing the results on <b>to</b>.
*
- * If no padding is used, the public key must be at least as large as
- * <b>from</b>.
- *
* Returns the number of bytes written on success, -1 on failure.
*
* The encrypted data consists of:
@@ -1037,7 +1000,7 @@ crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, size_t tolen,
* the source data encrypted in AES-CTR mode with the symmetric key.
*/
int
-crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
+crypto_pk_public_hybrid_encrypt(crypto_pk_t *env,
char *to, size_t tolen,
const char *from,
size_t fromlen,
@@ -1045,7 +1008,7 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
{
int overhead, outlen, r;
size_t pkeylen, symlen;
- crypto_cipher_env_t *cipher = NULL;
+ crypto_cipher_t *cipher = NULL;
char *buf = NULL;
tor_assert(env);
@@ -1056,9 +1019,6 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding));
pkeylen = crypto_pk_keysize(env);
- if (padding == PK_NO_PADDING && fromlen < pkeylen)
- return -1;
-
if (!force && fromlen+overhead <= pkeylen) {
/* It all fits in a single encrypt. */
return crypto_pk_public_encrypt(env,to,
@@ -1068,20 +1028,8 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN);
tor_assert(tolen >= pkeylen);
- cipher = crypto_new_cipher_env();
- if (!cipher) return -1;
- if (crypto_cipher_generate_key(cipher)<0)
- goto err;
- /* You can't just run around RSA-encrypting any bitstream: if it's
- * greater than the RSA key, then OpenSSL will happily encrypt, and
- * later decrypt to the wrong value. So we set the first bit of
- * 'cipher->key' to 0 if we aren't padding. This means that our
- * symmetric key is really only 127 bits.
- */
- if (padding == PK_NO_PADDING)
- cipher->key[0] &= 0x7f;
- if (crypto_cipher_encrypt_init_cipher(cipher)<0)
- goto err;
+ cipher = crypto_cipher_new(NULL); /* generate a new key. */
+
buf = tor_malloc(pkeylen+1);
memcpy(buf, cipher->key, CIPHER_KEY_LEN);
memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN);
@@ -1097,23 +1045,22 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
from+pkeylen-overhead-CIPHER_KEY_LEN, symlen);
if (r<0) goto err;
- memset(buf, 0, pkeylen);
+ memwipe(buf, 0, pkeylen);
tor_free(buf);
- crypto_free_cipher_env(cipher);
+ crypto_cipher_free(cipher);
tor_assert(outlen+symlen < INT_MAX);
return (int)(outlen + symlen);
err:
- if (buf) {
- memset(buf, 0, pkeylen);
- tor_free(buf);
- }
- if (cipher) crypto_free_cipher_env(cipher);
+
+ memwipe(buf, 0, pkeylen);
+ tor_free(buf);
+ crypto_cipher_free(cipher);
return -1;
}
/** Invert crypto_pk_public_hybrid_encrypt. */
int
-crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
+crypto_pk_private_hybrid_decrypt(crypto_pk_t *env,
char *to,
size_t tolen,
const char *from,
@@ -1122,7 +1069,7 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
{
int outlen, r;
size_t pkeylen;
- crypto_cipher_env_t *cipher = NULL;
+ crypto_cipher_t *cipher = NULL;
char *buf = NULL;
tor_assert(fromlen < SIZE_T_CEILING);
@@ -1133,8 +1080,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,
@@ -1146,7 +1093,7 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
"No room for a symmetric key");
goto err;
}
- cipher = crypto_create_init_cipher(buf, 0);
+ cipher = crypto_cipher_new(buf);
if (!cipher) {
goto err;
}
@@ -1156,15 +1103,15 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen);
if (r<0)
goto err;
- memset(buf,0,pkeylen);
+ memwipe(buf,0,pkeylen);
tor_free(buf);
- crypto_free_cipher_env(cipher);
+ crypto_cipher_free(cipher);
tor_assert(outlen + fromlen < INT_MAX);
return (int)(outlen + (fromlen-pkeylen));
err:
- memset(buf,0,pkeylen);
+ memwipe(buf,0,pkeylen);
tor_free(buf);
- if (cipher) crypto_free_cipher_env(cipher);
+ crypto_cipher_free(cipher);
return -1;
}
@@ -1172,7 +1119,7 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
* Return -1 on error, or the number of characters used on success.
*/
int
-crypto_pk_asn1_encode(crypto_pk_env_t *pk, char *dest, size_t dest_len)
+crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len)
{
int len;
unsigned char *buf, *cp;
@@ -1197,14 +1144,11 @@ crypto_pk_asn1_encode(crypto_pk_env_t *pk, char *dest, size_t dest_len)
/** Decode an ASN.1-encoded public key from <b>str</b>; return the result on
* success and NULL on failure.
*/
-crypto_pk_env_t *
+crypto_pk_t *
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);
@@ -1214,7 +1158,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
crypto_log_errors(LOG_WARN,"decoding public key");
return NULL;
}
- return _crypto_new_pk_env_rsa(rsa);
+ return _crypto_new_pk_from_rsa(rsa);
}
/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
@@ -1222,7 +1166,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
* Return 0 on success, -1 on failure.
*/
int
-crypto_pk_get_digest(crypto_pk_env_t *pk, char *digest_out)
+crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out)
{
unsigned char *buf, *bufp;
int len;
@@ -1245,6 +1189,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_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
@@ -1276,7 +1246,7 @@ add_spaces_to_fp(char *out, size_t outlen, const char *in)
* If <b>add_space</b> is false, omit the spaces.
*/
int
-crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out, int add_space)
+crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
{
char digest[DIGEST_LEN];
char hexdigest[HEX_DIGEST_LEN+1];
@@ -1311,87 +1281,20 @@ crypto_pk_check_fingerprint_syntax(const char *s)
/* symmetric crypto */
-/** Generate a new random key for the symmetric cipher in <b>env</b>.
- * Return 0 on success, -1 on failure. Does not initialize the cipher.
- */
-int
-crypto_cipher_generate_key(crypto_cipher_env_t *env)
-{
- tor_assert(env);
-
- return crypto_rand(env->key, CIPHER_KEY_LEN);
-}
-
-/** Set the symmetric key for the cipher in <b>env</b> to the first
- * CIPHER_KEY_LEN bytes of <b>key</b>. Does not initialize the cipher.
- */
-void
-crypto_cipher_set_key(crypto_cipher_env_t *env, const char *key)
-{
- tor_assert(env);
- tor_assert(key);
-
- memcpy(env->key, key, CIPHER_KEY_LEN);
-}
-
-/** Generate an initialization vector for our AES-CTR cipher; store it
- * in the first CIPHER_IV_LEN bytes of <b>iv_out</b>. */
-void
-crypto_cipher_generate_iv(char *iv_out)
-{
- crypto_rand(iv_out, CIPHER_IV_LEN);
-}
-
-/** Adjust the counter of <b>env</b> to point to the first byte of the block
- * corresponding to the encryption of the CIPHER_IV_LEN bytes at
- * <b>iv</b>. */
-int
-crypto_cipher_set_iv(crypto_cipher_env_t *env, const char *iv)
-{
- tor_assert(env);
- tor_assert(iv);
- aes_set_iv(env->cipher, iv);
- return 0;
-}
-
/** Return a pointer to the key set for the cipher in <b>env</b>.
*/
const char *
-crypto_cipher_get_key(crypto_cipher_env_t *env)
+crypto_cipher_get_key(crypto_cipher_t *env)
{
return env->key;
}
-/** Initialize the cipher in <b>env</b> for encryption. Return 0 on
- * success, -1 on failure.
- */
-int
-crypto_cipher_encrypt_init_cipher(crypto_cipher_env_t *env)
-{
- tor_assert(env);
-
- aes_set_key(env->cipher, env->key, CIPHER_KEY_LEN*8);
- return 0;
-}
-
-/** Initialize the cipher in <b>env</b> for decryption. Return 0 on
- * success, -1 on failure.
- */
-int
-crypto_cipher_decrypt_init_cipher(crypto_cipher_env_t *env)
-{
- tor_assert(env);
-
- aes_set_key(env->cipher, env->key, CIPHER_KEY_LEN*8);
- return 0;
-}
-
/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher
* <b>env</b>; on success, store the result to <b>to</b> and return 0.
* On failure, return -1.
*/
int
-crypto_cipher_encrypt(crypto_cipher_env_t *env, char *to,
+crypto_cipher_encrypt(crypto_cipher_t *env, char *to,
const char *from, size_t fromlen)
{
tor_assert(env);
@@ -1410,7 +1313,7 @@ crypto_cipher_encrypt(crypto_cipher_env_t *env, char *to,
* On failure, return -1.
*/
int
-crypto_cipher_decrypt(crypto_cipher_env_t *env, char *to,
+crypto_cipher_decrypt(crypto_cipher_t *env, char *to,
const char *from, size_t fromlen)
{
tor_assert(env);
@@ -1426,7 +1329,7 @@ crypto_cipher_decrypt(crypto_cipher_env_t *env, char *to,
* on success, return 0. On failure, return -1.
*/
int
-crypto_cipher_crypt_inplace(crypto_cipher_env_t *env, char *buf, size_t len)
+crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len)
{
tor_assert(len < SIZE_T_CEILING);
aes_crypt_inplace(env->cipher, buf, len);
@@ -1434,20 +1337,17 @@ crypto_cipher_crypt_inplace(crypto_cipher_env_t *env, char *buf, size_t len)
}
/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in
- * <b>cipher</b> to the buffer in <b>to</b> of length
+ * <b>key</b> to the buffer in <b>to</b> of length
* <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus
* CIPHER_IV_LEN bytes for the initialization vector. On success, return the
* number of bytes written, on failure, return -1.
- *
- * This function adjusts the current position of the counter in <b>cipher</b>
- * to immediately after the encrypted data.
*/
int
-crypto_cipher_encrypt_with_iv(crypto_cipher_env_t *cipher,
+crypto_cipher_encrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen)
{
- tor_assert(cipher);
+ crypto_cipher_t *cipher;
tor_assert(from);
tor_assert(to);
tor_assert(fromlen < INT_MAX);
@@ -1457,28 +1357,27 @@ crypto_cipher_encrypt_with_iv(crypto_cipher_env_t *cipher,
if (tolen < fromlen + CIPHER_IV_LEN)
return -1;
- crypto_cipher_generate_iv(to);
- if (crypto_cipher_set_iv(cipher, to)<0)
- return -1;
+ cipher = crypto_cipher_new_with_iv(key, NULL);
+
+ memcpy(to, cipher->iv, CIPHER_IV_LEN);
crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen);
+ crypto_cipher_free(cipher);
return (int)(fromlen + CIPHER_IV_LEN);
}
/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b>
- * with the key in <b>cipher</b> to the buffer in <b>to</b> of length
+ * with the key in <b>key</b> to the buffer in <b>to</b> of length
* <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus
* CIPHER_IV_LEN bytes for the initialization vector. On success, return the
* number of bytes written, on failure, return -1.
- *
- * This function adjusts the current position of the counter in <b>cipher</b>
- * to immediately after the decrypted data.
*/
int
-crypto_cipher_decrypt_with_iv(crypto_cipher_env_t *cipher,
+crypto_cipher_decrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen)
{
- tor_assert(cipher);
+ crypto_cipher_t *cipher;
+ tor_assert(key);
tor_assert(from);
tor_assert(to);
tor_assert(fromlen < INT_MAX);
@@ -1488,9 +1387,10 @@ crypto_cipher_decrypt_with_iv(crypto_cipher_env_t *cipher,
if (tolen < fromlen - CIPHER_IV_LEN)
return -1;
- if (crypto_cipher_set_iv(cipher, from)<0)
- return -1;
+ cipher = crypto_cipher_new_with_iv(key, from);
+
crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN);
+ crypto_cipher_free(cipher);
return (int)(fromlen - CIPHER_IV_LEN);
}
@@ -1568,7 +1468,7 @@ crypto_digest_algorithm_parse_name(const char *name)
}
/** Intermediate information about the digest of a stream of data. */
-struct crypto_digest_env_t {
+struct crypto_digest_t {
union {
SHA_CTX sha1; /**< state for SHA1 */
SHA256_CTX sha2; /**< state for SHA256 */
@@ -1579,11 +1479,11 @@ struct crypto_digest_env_t {
/** Allocate and return a new digest object to compute SHA1 digests.
*/
-crypto_digest_env_t *
-crypto_new_digest_env(void)
+crypto_digest_t *
+crypto_digest_new(void)
{
- crypto_digest_env_t *r;
- r = tor_malloc(sizeof(crypto_digest_env_t));
+ crypto_digest_t *r;
+ r = tor_malloc(sizeof(crypto_digest_t));
SHA1_Init(&r->d.sha1);
r->algorithm = DIGEST_SHA1;
return r;
@@ -1591,12 +1491,12 @@ crypto_new_digest_env(void)
/** Allocate and return a new digest object to compute 256-bit digests
* using <b>algorithm</b>. */
-crypto_digest_env_t *
-crypto_new_digest256_env(digest_algorithm_t algorithm)
+crypto_digest_t *
+crypto_digest256_new(digest_algorithm_t algorithm)
{
- crypto_digest_env_t *r;
+ crypto_digest_t *r;
tor_assert(algorithm == DIGEST_SHA256);
- r = tor_malloc(sizeof(crypto_digest_env_t));
+ r = tor_malloc(sizeof(crypto_digest_t));
SHA256_Init(&r->d.sha2);
r->algorithm = algorithm;
return r;
@@ -1605,18 +1505,18 @@ crypto_new_digest256_env(digest_algorithm_t algorithm)
/** Deallocate a digest object.
*/
void
-crypto_free_digest_env(crypto_digest_env_t *digest)
+crypto_digest_free(crypto_digest_t *digest)
{
if (!digest)
return;
- memset(digest, 0, sizeof(crypto_digest_env_t));
+ memwipe(digest, 0, sizeof(crypto_digest_t));
tor_free(digest);
}
/** Add <b>len</b> bytes from <b>data</b> to the digest object.
*/
void
-crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
+crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
size_t len)
{
tor_assert(digest);
@@ -1644,15 +1544,15 @@ crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
* <b>out_len</b> must be \<= DIGEST256_LEN.
*/
void
-crypto_digest_get_digest(crypto_digest_env_t *digest,
+crypto_digest_get_digest(crypto_digest_t *digest,
char *out, size_t out_len)
{
unsigned char r[DIGEST256_LEN];
- crypto_digest_env_t tmpenv;
+ crypto_digest_t tmpenv;
tor_assert(digest);
tor_assert(out);
/* memcpy into a temporary ctx, since SHA*_Final clears the context */
- memcpy(&tmpenv, digest, sizeof(crypto_digest_env_t));
+ memcpy(&tmpenv, digest, sizeof(crypto_digest_t));
switch (digest->algorithm) {
case DIGEST_SHA1:
tor_assert(out_len <= DIGEST_LEN);
@@ -1671,19 +1571,19 @@ crypto_digest_get_digest(crypto_digest_env_t *digest,
break;
}
memcpy(out, r, out_len);
- memset(r, 0, sizeof(r));
+ memwipe(r, 0, sizeof(r));
}
/** Allocate and return a new digest object with the same state as
* <b>digest</b>
*/
-crypto_digest_env_t *
-crypto_digest_dup(const crypto_digest_env_t *digest)
+crypto_digest_t *
+crypto_digest_dup(const crypto_digest_t *digest)
{
- crypto_digest_env_t *r;
+ crypto_digest_t *r;
tor_assert(digest);
- r = tor_malloc(sizeof(crypto_digest_env_t));
- memcpy(r,digest,sizeof(crypto_digest_env_t));
+ r = tor_malloc(sizeof(crypto_digest_t));
+ memcpy(r,digest,sizeof(crypto_digest_t));
return r;
}
@@ -1691,12 +1591,12 @@ crypto_digest_dup(const crypto_digest_env_t *digest)
* of the digest object <b>from</b>.
*/
void
-crypto_digest_assign(crypto_digest_env_t *into,
- const crypto_digest_env_t *from)
+crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from)
{
tor_assert(into);
tor_assert(from);
- memcpy(into,from,sizeof(crypto_digest_env_t));
+ memcpy(into,from,sizeof(crypto_digest_t));
}
/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using
@@ -1715,15 +1615,15 @@ crypto_hmac_sha1(char *hmac_out,
}
/** 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>.
+ * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_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 >= 0x00908000l)
+#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);
@@ -1773,10 +1673,10 @@ crypto_hmac_sha256(char *hmac_out,
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));
+ memwipe(k, 0, sizeof(k));
+ memwipe(pad, 0, sizeof(pad));
+ memwipe(d, 0, sizeof(d));
+ memwipe(&st, 0, sizeof(st));
#undef BLOCKSIZE
#undef DIGESTSIZE
#endif
@@ -1784,6 +1684,9 @@ crypto_hmac_sha256(char *hmac_out,
/* 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. */
@@ -1791,49 +1694,324 @@ 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;
+ 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 */
+ char *fname_new=NULL;
+ tor_asprintf(&fname_new, "%s.broken", fname);
+
+ 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
@@ -1844,10 +2022,10 @@ init_dh_param(void)
/** Allocate and return a new DH object for a key exchange.
*/
-crypto_dh_env_t *
+crypto_dh_t *
crypto_dh_new(int dh_type)
{
- crypto_dh_env_t *res = tor_malloc_zero(sizeof(crypto_dh_env_t));
+ crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t));
tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS ||
dh_type == DH_TYPE_REND);
@@ -1882,7 +2060,7 @@ crypto_dh_new(int dh_type)
/** Return the length of the DH key in <b>dh</b>, in bytes.
*/
int
-crypto_dh_get_bytes(crypto_dh_env_t *dh)
+crypto_dh_get_bytes(crypto_dh_t *dh)
{
tor_assert(dh);
return DH_size(dh->dh);
@@ -1892,7 +2070,7 @@ crypto_dh_get_bytes(crypto_dh_env_t *dh)
* success, -1 on failure.
*/
int
-crypto_dh_generate_public(crypto_dh_env_t *dh)
+crypto_dh_generate_public(crypto_dh_t *dh)
{
again:
if (!DH_generate_key(dh->dh)) {
@@ -1916,7 +2094,7 @@ crypto_dh_generate_public(crypto_dh_env_t *dh)
* success, -1 on failure. <b>pubkey_len</b> must be \>= DH_BYTES.
*/
int
-crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey, size_t pubkey_len)
+crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len)
{
int bytes;
tor_assert(dh);
@@ -1989,7 +2167,7 @@ tor_check_dh_key(int severity, BIGNUM *bn)
* where || is concatenation.)
*/
ssize_t
-crypto_dh_compute_secret(int severity, crypto_dh_env_t *dh,
+crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_bytes_out)
{
@@ -2030,7 +2208,7 @@ crypto_dh_compute_secret(int severity, crypto_dh_env_t *dh,
if (pubkey_bn)
BN_free(pubkey_bn);
if (secret_tmp) {
- memset(secret_tmp, 0, secret_tmp_len);
+ memwipe(secret_tmp, 0, secret_tmp_len);
tor_free(secret_tmp);
}
if (result < 0)
@@ -2065,22 +2243,22 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
goto err;
memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out)));
}
- memset(tmp, 0, key_in_len+1);
+ memwipe(tmp, 0, key_in_len+1);
tor_free(tmp);
- memset(digest, 0, sizeof(digest));
+ memwipe(digest, 0, sizeof(digest));
return 0;
err:
- memset(tmp, 0, key_in_len+1);
+ memwipe(tmp, 0, key_in_len+1);
tor_free(tmp);
- memset(digest, 0, sizeof(digest));
+ memwipe(digest, 0, sizeof(digest));
return -1;
}
/** Free a DH key exchange object.
*/
void
-crypto_dh_free(crypto_dh_env_t *dh)
+crypto_dh_free(crypto_dh_t *dh)
{
if (!dh)
return;
@@ -2097,13 +2275,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
@@ -2111,9 +2282,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
@@ -2134,7 +2305,7 @@ crypto_seed_rng(int startup)
int rand_poll_status = 0;
/* local variables */
-#ifdef MS_WINDOWS
+#ifdef _WIN32
unsigned char buf[ADD_ENTROPY];
static int provider_set = 0;
static HCRYPTPROV provider;
@@ -2147,8 +2318,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) {
@@ -2156,9 +2326,8 @@ crypto_seed_rng(int startup)
if (rand_poll_status == 0)
log_warn(LD_CRYPTO, "RAND_poll() failed.");
}
-#endif
-#ifdef MS_WINDOWS
+#ifdef _WIN32
if (!provider_set) {
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
@@ -2174,7 +2343,7 @@ crypto_seed_rng(int startup)
return rand_poll_status ? 0 : -1;
}
RAND_seed(buf, sizeof(buf));
- memset(buf, 0, sizeof(buf));
+ memwipe(buf, 0, sizeof(buf));
seed_weak_rng();
return 0;
#else
@@ -2191,7 +2360,7 @@ crypto_seed_rng(int startup)
return -1;
}
RAND_seed(buf, (int)sizeof(buf));
- memset(buf, 0, sizeof(buf));
+ memwipe(buf, 0, sizeof(buf));
seed_weak_rng();
return 0;
}
@@ -2282,9 +2451,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)
@@ -2293,8 +2465,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;
@@ -2666,7 +2843,7 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
}
}
- memset(tmp, 0, srclen);
+ memwipe(tmp, 0, srclen);
tor_free(tmp);
tmp = NULL;
return 0;
@@ -2682,7 +2859,7 @@ void
secret_to_key(char *key_out, size_t key_out_len, const char *secret,
size_t secret_len, const char *s2k_specifier)
{
- crypto_digest_env_t *d;
+ crypto_digest_t *d;
uint8_t c;
size_t count, tmplen;
char *tmp;
@@ -2695,7 +2872,7 @@ secret_to_key(char *key_out, size_t key_out_len, const char *secret,
tor_assert(key_out_len <= DIGEST_LEN);
- d = crypto_new_digest_env();
+ d = crypto_digest_new();
tmplen = 8+secret_len;
tmp = tor_malloc(tmplen);
memcpy(tmp,s2k_specifier,8);
@@ -2711,9 +2888,52 @@ secret_to_key(char *key_out, size_t key_out_len, const char *secret,
}
}
crypto_digest_get_digest(d, key_out, key_out_len);
- memset(tmp, 0, tmplen);
+ memwipe(tmp, 0, tmplen);
tor_free(tmp);
- crypto_free_digest_env(d);
+ crypto_digest_free(d);
+}
+
+/**
+ * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
+ * the value <b>byte</b>.
+ *
+ * This function is preferable to memset, since many compilers will happily
+ * optimize out memset() when they can convince themselves that the data being
+ * cleared will never be read.
+ *
+ * Right now, our convention is to use this function when we are wiping data
+ * that's about to become inaccessible, such as stack buffers that are about
+ * to go out of scope or structures that are about to get freed. (In
+ * practice, it appears that the compilers we're currently using will optimize
+ * out the memset()s for stack-allocated buffers, but not those for
+ * about-to-be-freed structures. That could change, though, so we're being
+ * wary.) If there are live reads for the data, then you can just use
+ * memset().
+ */
+void
+memwipe(void *mem, uint8_t byte, size_t sz)
+{
+ /* Because whole-program-optimization exists, we may not be able to just
+ * have this function call "memset". A smart compiler could inline it, then
+ * eliminate dead memsets, and declare itself to be clever. */
+
+ /* This is a slow and ugly function from OpenSSL that fills 'mem' with junk
+ * based on the pointer value, then uses that junk to update a global
+ * variable. It's an elaborate ruse to trick the compiler into not
+ * optimizing out the "wipe this memory" code. Read it if you like zany
+ * programming tricks! In later versions of Tor, we should look for better
+ * not-optimized-out memory wiping stuff. */
+ OPENSSL_cleanse(mem, sz);
+ /* Just in case some caller of memwipe() is relying on getting a buffer
+ * filled with a particular value, fill the buffer.
+ *
+ * If this function gets inlined, this memset might get eliminated, but
+ * that's okay: We only care about this particular memset in the case where
+ * the caller should have been using memset(), and the memset() wouldn't get
+ * eliminated. In other words, this is here so that we won't break anything
+ * if somebody accidentally calls memwipe() instead of memset().
+ **/
+ memset(mem, byte, sz);
}
#ifdef TOR_IS_MULTITHREADED
@@ -2805,5 +3025,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 a0ee075ba..7d5627178 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -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
@@ -37,11 +69,9 @@
* signs removed. */
#define BASE64_DIGEST256_LEN 43
-/** Constants used to indicate no padding for public-key encryption */
-#define PK_NO_PADDING 60000
-/** Constants used to indicate PKCS1 padding for public-key encryption */
+/** Constant used to indicate PKCS1 padding for public-key encryption */
#define PK_PKCS1_PADDING 60001
-/** Constants used to indicate OAEP padding for public-key encryption */
+/** Constant used to indicate OAEP padding for public-key encryption */
#define PK_PKCS1_OAEP_PADDING 60002
/** Number of bytes added for PKCS1 padding. */
@@ -75,10 +105,10 @@ typedef struct {
char d[N_DIGEST_ALGORITHMS][DIGEST256_LEN];
} digests_t;
-typedef struct crypto_pk_env_t crypto_pk_env_t;
-typedef struct crypto_cipher_env_t crypto_cipher_env_t;
-typedef struct crypto_digest_env_t crypto_digest_env_t;
-typedef struct crypto_dh_env_t crypto_dh_env_t;
+typedef struct crypto_pk_t crypto_pk_t;
+typedef struct crypto_cipher_t crypto_cipher_t;
+typedef struct crypto_digest_t crypto_digest_t;
+typedef struct crypto_dh_t crypto_dh_t;
/* global state */
int crypto_global_init(int hardwareAccel,
@@ -88,90 +118,84 @@ void crypto_thread_cleanup(void);
int crypto_global_cleanup(void);
/* environment setup */
-crypto_pk_env_t *crypto_new_pk_env(void);
-void crypto_free_pk_env(crypto_pk_env_t *env);
+crypto_pk_t *crypto_pk_new(void);
+void crypto_pk_free(crypto_pk_t *env);
-/* 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);
+void crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname);
-crypto_cipher_env_t *crypto_new_cipher_env(void);
-void crypto_free_cipher_env(crypto_cipher_env_t *env);
+crypto_cipher_t *crypto_cipher_new(const char *key);
+crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv);
+void crypto_cipher_free(crypto_cipher_t *env);
/* public key crypto */
-int crypto_pk_generate_key_with_bits(crypto_pk_env_t *env, int bits);
+int crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits);
#define crypto_pk_generate_key(env) \
crypto_pk_generate_key_with_bits((env), (PK_BYTES*8))
-int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env,
+int crypto_pk_read_private_key_from_filename(crypto_pk_t *env,
const char *keyfile);
-int crypto_pk_write_public_key_to_string(crypto_pk_env_t *env,
+int crypto_pk_write_public_key_to_string(crypto_pk_t *env,
char **dest, size_t *len);
-int crypto_pk_write_private_key_to_string(crypto_pk_env_t *env,
+int crypto_pk_write_private_key_to_string(crypto_pk_t *env,
char **dest, size_t *len);
-int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env,
+int crypto_pk_read_public_key_from_string(crypto_pk_t *env,
const char *src, size_t len);
-int crypto_pk_read_private_key_from_string(crypto_pk_env_t *env,
+int crypto_pk_read_private_key_from_string(crypto_pk_t *env,
const char *s, ssize_t len);
-int crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env,
+int crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
const char *fname);
-int crypto_pk_check_key(crypto_pk_env_t *env);
-int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b);
-size_t crypto_pk_keysize(crypto_pk_env_t *env);
-int crypto_pk_num_bits(crypto_pk_env_t *env);
-crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *orig);
-crypto_pk_env_t *crypto_pk_copy_full(crypto_pk_env_t *orig);
-int crypto_pk_key_is_private(const crypto_pk_env_t *key);
-int crypto_pk_public_exponent_ok(crypto_pk_env_t *env);
+int crypto_pk_check_key(crypto_pk_t *env);
+int crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b);
+size_t crypto_pk_keysize(crypto_pk_t *env);
+int crypto_pk_num_bits(crypto_pk_t *env);
+crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig);
+crypto_pk_t *crypto_pk_copy_full(crypto_pk_t *orig);
+int crypto_pk_key_is_private(const crypto_pk_t *key);
+int crypto_pk_public_exponent_ok(crypto_pk_t *env);
-int crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, size_t tolen,
+int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen, int padding);
-int crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to, size_t tolen,
+int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen,
int padding, int warnOnFailure);
-int crypto_pk_public_checksig(crypto_pk_env_t *env, char *to, size_t tolen,
+int crypto_pk_public_checksig(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen);
-int crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
+int crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data,
size_t datalen, const char *sig, size_t siglen);
-int crypto_pk_private_sign(crypto_pk_env_t *env, char *to, size_t tolen,
+int crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen);
-int crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, size_t tolen,
+int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen);
-int crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, char *to,
+int crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen,
int padding, int force);
-int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, char *to,
+int crypto_pk_private_hybrid_decrypt(crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen,
int padding, int warnOnFailure);
-int crypto_pk_asn1_encode(crypto_pk_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_fingerprint(crypto_pk_env_t *pk, char *fp_out,int add_space);
+int crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len);
+crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
+int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out);
+int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out);
+int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
int crypto_pk_check_fingerprint_syntax(const char *s);
/* symmetric crypto */
-int crypto_cipher_generate_key(crypto_cipher_env_t *env);
-void crypto_cipher_set_key(crypto_cipher_env_t *env, const char *key);
-void crypto_cipher_generate_iv(char *iv_out);
-int crypto_cipher_set_iv(crypto_cipher_env_t *env, const char *iv);
-const char *crypto_cipher_get_key(crypto_cipher_env_t *env);
-int crypto_cipher_encrypt_init_cipher(crypto_cipher_env_t *env);
-int crypto_cipher_decrypt_init_cipher(crypto_cipher_env_t *env);
-
-int crypto_cipher_encrypt(crypto_cipher_env_t *env, char *to,
+const char *crypto_cipher_get_key(crypto_cipher_t *env);
+
+int crypto_cipher_encrypt(crypto_cipher_t *env, char *to,
const char *from, size_t fromlen);
-int crypto_cipher_decrypt(crypto_cipher_env_t *env, char *to,
+int crypto_cipher_decrypt(crypto_cipher_t *env, char *to,
const char *from, size_t fromlen);
-int crypto_cipher_crypt_inplace(crypto_cipher_env_t *env, char *d, size_t len);
+int crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *d, size_t len);
-int crypto_cipher_encrypt_with_iv(crypto_cipher_env_t *env,
+int crypto_cipher_encrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen);
-int crypto_cipher_decrypt_with_iv(crypto_cipher_env_t *env,
+int crypto_cipher_decrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen);
@@ -182,16 +206,16 @@ int crypto_digest256(char *digest, const char *m, size_t len,
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
int crypto_digest_algorithm_parse_name(const char *name);
-crypto_digest_env_t *crypto_new_digest_env(void);
-crypto_digest_env_t *crypto_new_digest256_env(digest_algorithm_t algorithm);
-void crypto_free_digest_env(crypto_digest_env_t *digest);
-void crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
+crypto_digest_t *crypto_digest_new(void);
+crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
+void crypto_digest_free(crypto_digest_t *digest);
+void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
size_t len);
-void crypto_digest_get_digest(crypto_digest_env_t *digest,
+void crypto_digest_get_digest(crypto_digest_t *digest,
char *out, size_t out_len);
-crypto_digest_env_t *crypto_digest_dup(const crypto_digest_env_t *digest);
-void crypto_digest_assign(crypto_digest_env_t *into,
- const crypto_digest_env_t *from);
+crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest);
+void crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from);
void crypto_hmac_sha1(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len);
@@ -203,15 +227,15 @@ void crypto_hmac_sha256(char *hmac_out,
#define DH_TYPE_CIRCUIT 1
#define DH_TYPE_REND 2
#define DH_TYPE_TLS 3
-crypto_dh_env_t *crypto_dh_new(int dh_type);
-int crypto_dh_get_bytes(crypto_dh_env_t *dh);
-int crypto_dh_generate_public(crypto_dh_env_t *dh);
-int crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey_out,
+crypto_dh_t *crypto_dh_new(int dh_type);
+int crypto_dh_get_bytes(crypto_dh_t *dh);
+int crypto_dh_generate_public(crypto_dh_t *dh);
+int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out,
size_t pubkey_out_len);
-ssize_t crypto_dh_compute_secret(int severity, crypto_dh_env_t *dh,
+ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_out_len);
-void crypto_dh_free(crypto_dh_env_t *dh);
+void crypto_dh_free(crypto_dh_t *dh);
int crypto_expand_key_material(const char *key_in, size_t in_len,
char *key_out, size_t key_out_len);
@@ -247,16 +271,20 @@ int digest256_from_base64(char *digest, const char *d64);
void secret_to_key(char *key_out, size_t key_out_len, const char *secret,
size_t secret_len, const char *s2k_specifier);
+/** OpenSSL-based utility functions. */
+void memwipe(void *mem, uint8_t byte, size_t sz);
+
#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;
-struct rsa_st *_crypto_pk_env_get_rsa(crypto_pk_env_t *env);
-crypto_pk_env_t *_crypto_new_pk_env_rsa(struct rsa_st *rsa);
-struct evp_pkey_st *_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env,
+struct rsa_st *_crypto_pk_get_rsa(crypto_pk_t *env);
+crypto_pk_t *_crypto_new_pk_from_rsa(struct rsa_st *rsa);
+struct evp_pkey_st *_crypto_pk_get_evp_pkey(crypto_pk_t *env,
int private);
-struct dh_st *_crypto_dh_env_get_dh(crypto_dh_env_t *dh);
+struct dh_st *_crypto_dh_get_dh(crypto_dh_t *dh);
/* Prototypes for private functions only used by crypto.c and test.c*/
void add_spaces_to_fp(char *out, size_t outlen, const char *in);
#endif
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index b22a58d1b..7683c59de 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Tor Project, Inc. */
+/* Copyright (c) 2011-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/di_ops.h b/src/common/di_ops.h
index fa7d86806..8f0bb698f 100644
--- a/src/common/di_ops.h
+++ b/src/common/di_ops.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/get_mozilla_ciphers.py b/src/common/get_mozilla_ciphers.py
new file mode 100644
index 000000000..c7e9a84a0
--- /dev/null
+++ b/src/common/get_mozilla_ciphers.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+# coding=utf-8
+# Copyright 2011, The Tor Project, Inc
+# original version by Arturo Filastò
+# See LICENSE for licensing information
+
+# This script parses Firefox and OpenSSL sources, and uses this information
+# to generate a ciphers.inc file.
+#
+# It takes two arguments: the location of a firefox source directory, and the
+# location of an openssl source directory.
+
+import os
+import re
+import sys
+
+if len(sys.argv) != 3:
+ print >>sys.stderr, "Syntax: get_mozilla_ciphers.py <firefox-source-dir> <openssl-source-dir>"
+ sys.exit(1)
+
+ff_root = sys.argv[1]
+ossl_root = sys.argv[2]
+
+def ff(s):
+ return os.path.join(ff_root, s)
+def ossl(s):
+ return os.path.join(ossl_root, s)
+
+#####
+# Read the cpp file to understand what Ciphers map to what name :
+# Make "ciphers" a map from name used in the javascript to a cipher macro name
+fileA = open(ff('security/manager/ssl/src/nsNSSComponent.cpp'),'r')
+
+# The input format is a file containing exactly one section of the form:
+# static CipherPref CipherPrefs[] = {
+# {"name", MACRO_NAME}, // comment
+# ...
+# {NULL, 0}
+# }
+
+inCipherSection = False
+cipherLines = []
+for line in fileA:
+ if line.startswith('static CipherPref CipherPrefs'):
+ # Get the starting boundary of the Cipher Preferences
+ inCipherSection = True
+ elif inCipherSection:
+ line = line.strip()
+ if line.startswith('{NULL, 0}'):
+ # At the ending boundary of the Cipher Prefs
+ break
+ else:
+ cipherLines.append(line)
+fileA.close()
+
+# Parse the lines and put them into a dict
+ciphers = {}
+cipher_pref = {}
+for line in cipherLines:
+ m = re.search(r'^{\s*\"([^\"]+)\",\s*(\S*)\s*}', line)
+ if m:
+ key,value = m.groups()
+ ciphers[key] = value
+ cipher_pref[value] = key
+
+####
+# Now find the correct order for the ciphers
+fileC = open(ff('security/nss/lib/ssl/ssl3con.c'), 'r')
+firefox_ciphers = []
+inEnum=False
+for line in fileC:
+ if not inEnum:
+ if "ssl3CipherSuiteCfg cipherSuites[" in line:
+ inEnum = True
+ continue
+
+ if line.startswith("};"):
+ break
+
+ m = re.match(r'^\s*\{\s*([A-Z_0-9]+),', line)
+ if m:
+ firefox_ciphers.append(m.group(1))
+
+fileC.close()
+
+#####
+# Read the JS file to understand what ciphers are enabled. The format is
+# pref("name", true/false);
+# Build a map enabled_ciphers from javascript name to "true" or "false",
+# and an (unordered!) list of the macro names for those ciphers that are
+# enabled.
+fileB = open(ff('netwerk/base/public/security-prefs.js'), 'r')
+
+enabled_ciphers = {}
+for line in fileB:
+ m = re.match(r'pref\(\"([^\"]+)\"\s*,\s*(\S*)\s*\)', line)
+ if not m:
+ continue
+ key, val = m.groups()
+ if key.startswith("security.ssl3"):
+ enabled_ciphers[key] = val
+fileB.close()
+
+used_ciphers = []
+for k, v in enabled_ciphers.items():
+ if v == "true":
+ used_ciphers.append(ciphers[k])
+
+#oSSLinclude = ('/usr/include/openssl/ssl3.h', '/usr/include/openssl/ssl.h',
+# '/usr/include/openssl/ssl2.h', '/usr/include/openssl/ssl23.h',
+# '/usr/include/openssl/tls1.h')
+oSSLinclude = ('ssl/ssl3.h', 'ssl/ssl.h',
+ 'ssl/ssl2.h', 'ssl/ssl23.h',
+ 'ssl/tls1.h')
+
+#####
+# This reads the hex code for the ciphers that are used by firefox.
+# sslProtoD is set to a map from macro name to macro value in sslproto.h;
+# cipher_codes is set to an (unordered!) list of these hex values.
+sslProto = open(ff('security/nss/lib/ssl/sslproto.h'), 'r')
+sslProtoD = {}
+
+for line in sslProto:
+ m = re.match('#define\s+(\S+)\s+(\S+)', line)
+ if m:
+ key, value = m.groups()
+ sslProtoD[key] = value
+sslProto.close()
+
+cipher_codes = []
+for x in used_ciphers:
+ cipher_codes.append(sslProtoD[x].lower())
+
+####
+# Now read through all the openssl include files, and try to find the openssl
+# macro names for those files.
+openssl_macro_by_hex = {}
+all_openssl_macros = {}
+for fl in oSSLinclude:
+ fp = open(ossl(fl), 'r')
+ for line in fp.readlines():
+ m = re.match('#define\s+(\S+)\s+(\S+)', line)
+ if m:
+ value,key = m.groups()
+ if key.startswith('0x') and "_CK_" in value:
+ key = key.replace('0x0300','0x').lower()
+ #print "%s %s" % (key, value)
+ openssl_macro_by_hex[key] = value
+ all_openssl_macros[value]=key
+ fp.close()
+
+# Now generate the output.
+print """\
+/* This is an include file used to define the list of ciphers clients should
+ * advertise. Before including it, you should define the CIPHER and XCIPHER
+ * macros.
+ *
+ * This file was automatically generated by get_mozilla_ciphers.py.
+ */"""
+# Go in order by the order in CipherPrefs
+for firefox_macro in firefox_ciphers:
+
+ try:
+ js_cipher_name = cipher_pref[firefox_macro]
+ except KeyError:
+ # This one has no javascript preference.
+ continue
+
+ # The cipher needs to be enabled in security-prefs.js
+ if enabled_ciphers.get(js_cipher_name, 'false') != 'true':
+ continue
+
+ hexval = sslProtoD[firefox_macro].lower()
+
+ try:
+ openssl_macro = openssl_macro_by_hex[hexval.lower()]
+ openssl_macro = openssl_macro.replace("_CK_", "_TXT_")
+ if openssl_macro not in all_openssl_macros:
+ raise KeyError()
+ format = {'hex':hexval, 'macro':openssl_macro, 'note':""}
+ except KeyError:
+ # openssl doesn't have a macro for this.
+ format = {'hex':hexval, 'macro':firefox_macro,
+ 'note':"/* No openssl macro found for "+hexval+" */\n"}
+
+ res = """\
+%(note)s#ifdef %(macro)s
+ CIPHER(%(hex)s, %(macro)s)
+#else
+ XCIPHER(%(hex)s, %(macro)s)
+#endif""" % format
+ print res
diff --git a/src/common/ht.h b/src/common/ht.h
index 0850c0709..25156c416 100644
--- a/src/common/ht.h
+++ b/src/common/ht.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2002, Christopher Clark.
* Copyright (c) 2005-2006, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See license at end. */
/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
@@ -25,19 +25,22 @@
#define HT_INITIALIZER() \
{ NULL, 0, 0, 0, -1 }
+#ifdef HT_NO_CACHE_HASH_VALUES
+#define HT_ENTRY(type) \
+ struct { \
+ struct type *hte_next; \
+ }
+#else
#define HT_ENTRY(type) \
struct { \
struct type *hte_next; \
unsigned hte_hash; \
}
+#endif
#define HT_EMPTY(head) \
((head)->hth_n_entries == 0)
-/* Helper: alias for the bucket containing 'elm'. */
-#define _HT_BUCKET(head, field, elm) \
- ((head)->hth_table[elm->field.hte_hash % head->hth_table_length])
-
/* How many elements in 'head'? */
#define HT_SIZE(head) \
((head)->hth_n_entries)
@@ -98,8 +101,26 @@ ht_string_hash(const char *s)
return h;
}
-#define _HT_SET_HASH(elm, field, hashfn) \
- (elm)->field.hte_hash = hashfn(elm)
+#ifndef HT_NO_CACHE_HASH_VALUES
+#define HT_SET_HASH_(elm, field, hashfn) \
+ do { (elm)->field.hte_hash = hashfn(elm); } while (0)
+#define HT_SET_HASHVAL_(elm, field, val) \
+ do { (elm)->field.hte_hash = (val); } while (0)
+#define HT_ELT_HASH_(elm, field, hashfn) \
+ ((elm)->field.hte_hash)
+#else
+#define HT_SET_HASH_(elm, field, hashfn) \
+ ((void)0)
+#define HT_ELT_HASH_(elm, field, hashfn) \
+ (hashfn(elm))
+#define HT_SET_HASHVAL_(elm, field, val) \
+ ((void)0)
+#endif
+
+/* Helper: alias for the bucket containing 'elm'. */
+#define HT_BUCKET_(head, field, elm, hashfn) \
+ ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn) \
+ % head->hth_table_length])
#define HT_FOREACH(x, name, head) \
for ((x) = HT_START(name, head); \
@@ -109,7 +130,7 @@ ht_string_hash(const char *s)
#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
void name##_HT_CLEAR(struct name *ht); \
- int _##name##_HT_REP_IS_BAD(const struct name *ht); \
+ int name##_HT_REP_IS_BAD_(const struct name *ht); \
static INLINE void \
name##_HT_INIT(struct name *head) { \
head->hth_table_length = 0; \
@@ -121,12 +142,12 @@ ht_string_hash(const char *s)
/* Helper: returns a pointer to the right location in the table \
* 'head' to find or insert the element 'elm'. */ \
static INLINE struct type ** \
- _##name##_HT_FIND_P(struct name *head, struct type *elm) \
+ name##_HT_FIND_P_(struct name *head, struct type *elm) \
{ \
struct type **p; \
if (!head->hth_table) \
return NULL; \
- p = &_HT_BUCKET(head, field, elm); \
+ p = &HT_BUCKET_(head, field, elm, hashfn); \
while (*p) { \
if (eqfn(*p, elm)) \
return p; \
@@ -141,8 +162,8 @@ ht_string_hash(const char *s)
{ \
struct type **p; \
struct name *h = (struct name *) head; \
- _HT_SET_HASH(elm, field, hashfn); \
- p = _##name##_HT_FIND_P(h, elm); \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = name##_HT_FIND_P_(h, elm); \
return p ? *p : NULL; \
} \
/* Insert the element 'elm' into the table 'head'. Do not call this \
@@ -154,8 +175,8 @@ ht_string_hash(const char *s)
if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
name##_HT_GROW(head, head->hth_n_entries+1); \
++head->hth_n_entries; \
- _HT_SET_HASH(elm, field, hashfn); \
- p = &_HT_BUCKET(head, field, elm); \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = &HT_BUCKET_(head, field, elm, hashfn); \
elm->field.hte_next = *p; \
*p = elm; \
} \
@@ -168,8 +189,8 @@ ht_string_hash(const char *s)
struct type **p, *r; \
if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
name##_HT_GROW(head, head->hth_n_entries+1); \
- _HT_SET_HASH(elm, field, hashfn); \
- p = _##name##_HT_FIND_P(head, elm); \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = name##_HT_FIND_P_(head, elm); \
r = *p; \
*p = elm; \
if (r && (r!=elm)) { \
@@ -187,8 +208,8 @@ ht_string_hash(const char *s)
name##_HT_REMOVE(struct name *head, struct type *elm) \
{ \
struct type **p, *r; \
- _HT_SET_HASH(elm, field, hashfn); \
- p = _##name##_HT_FIND_P(head,elm); \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = name##_HT_FIND_P_(head,elm); \
if (!p || !*p) \
return NULL; \
r = *p; \
@@ -207,7 +228,6 @@ ht_string_hash(const char *s)
void *data) \
{ \
unsigned idx; \
- int remove; \
struct type **p, **nextp, *next; \
if (!head->hth_table) \
return; \
@@ -216,8 +236,7 @@ ht_string_hash(const char *s)
while (*p) { \
nextp = &(*p)->field.hte_next; \
next = *nextp; \
- remove = fn(*p, data); \
- if (remove) { \
+ if (fn(*p, data)) { \
--head->hth_n_entries; \
*p = next; \
} else { \
@@ -251,7 +270,8 @@ ht_string_hash(const char *s)
if ((*elm)->field.hte_next) { \
return &(*elm)->field.hte_next; \
} else { \
- unsigned b = ((*elm)->field.hte_hash % head->hth_table_length)+1; \
+ unsigned b = (HT_ELT_HASH_(*elm, field, hashfn) \
+ % head->hth_table_length)+1; \
while (b < head->hth_table_length) { \
if (head->hth_table[b]) \
return &head->hth_table[b]; \
@@ -263,7 +283,7 @@ ht_string_hash(const char *s)
static INLINE struct type ** \
name##_HT_NEXT_RMV(struct name *head, struct type **elm) \
{ \
- unsigned h = (*elm)->field.hte_hash; \
+ unsigned h = HT_ELT_HASH_(*elm, field, hashfn); \
*elm = (*elm)->field.hte_next; \
--head->hth_n_entries; \
if (*elm) { \
@@ -320,7 +340,7 @@ ht_string_hash(const char *s)
elm = head->hth_table[b]; \
while (elm) { \
next = elm->field.hte_next; \
- b2 = elm->field.hte_hash % new_len; \
+ b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len; \
elm->field.hte_next = new_table[b2]; \
new_table[b2] = elm; \
elm = next; \
@@ -338,7 +358,7 @@ ht_string_hash(const char *s)
for (b=0; b < head->hth_table_length; ++b) { \
struct type *e, **pE; \
for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) { \
- b2 = e->field.hte_hash % new_len; \
+ b2 = HT_ELT_HASH_(e, field, hashfn) % new_len; \
if (b2 == b) { \
pE = &e->field.hte_next; \
} else { \
@@ -368,7 +388,7 @@ ht_string_hash(const char *s)
/* Debugging helper: return false iff the representation of 'head' is \
* internally consistent. */ \
int \
- _##name##_HT_REP_IS_BAD(const struct name *head) \
+ name##_HT_REP_IS_BAD_(const struct name *head) \
{ \
unsigned n, i; \
struct type *elm; \
@@ -390,9 +410,9 @@ ht_string_hash(const char *s)
return 5; \
for (n = i = 0; i < head->hth_table_length; ++i) { \
for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) { \
- if (elm->field.hte_hash != hashfn(elm)) \
+ if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm)) \
return 1000 + i; \
- if ((elm->field.hte_hash % head->hth_table_length) != i) \
+ if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \
return 10000 + i; \
++n; \
} \
@@ -405,24 +425,24 @@ ht_string_hash(const char *s)
/** Implements an over-optimized "find and insert if absent" block;
* not meant for direct usage by typical code, or usage outside the critical
* path.*/
-#define _HT_FIND_OR_INSERT(name, field, hashfn, head, eltype, elm, var, y, n) \
+#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \
{ \
- struct name *_##var##_head = head; \
- eltype **var; \
- if (!_##var##_head->hth_table || \
- _##var##_head->hth_n_entries >= _##var##_head->hth_load_limit) \
- name##_HT_GROW(_##var##_head, _##var##_head->hth_n_entries+1); \
- _HT_SET_HASH((elm), field, hashfn); \
- var = _##name##_HT_FIND_P(_##var##_head, (elm)); \
+ struct name *var##_head_ = head; \
+ struct eltype **var; \
+ if (!var##_head_->hth_table || \
+ var##_head_->hth_n_entries >= var##_head_->hth_load_limit) \
+ name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1); \
+ HT_SET_HASH_((elm), field, hashfn); \
+ var = name##_HT_FIND_P_(var##_head_, (elm)); \
if (*var) { \
y; \
} else { \
n; \
} \
}
-#define _HT_FOI_INSERT(field, head, elm, newent, var) \
+#define HT_FOI_INSERT_(field, head, elm, newent, var) \
{ \
- newent->field.hte_hash = (elm)->field.hte_hash; \
+ HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash); \
newent->field.hte_next = NULL; \
*var = newent; \
++((head)->hth_n_entries); \
@@ -431,9 +451,8 @@ ht_string_hash(const char *s)
/*
* Copyright 2005, Nick Mathewson. Implementation logic is adapted from code
* by Christopher Clark, retrofit to allow drop-in memory management, and to
- * use the same interface as Niels Provos's HT_H. I'm not sure whether this
- * is a derived work any more, but whether it is or not, the license below
- * applies.
+ * use the same interface as Niels Provos's tree.h. This is probably still
+ * a derived work, so the original license below still applies.
*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
diff --git a/src/common/log.c b/src/common/log.c
index f2999f4e6..5e2e6b5b5 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -97,6 +97,7 @@ should_log_function_name(log_domain_mask_t domain, int severity)
/** A mutex to guard changes to logfiles and logging. */
static tor_mutex_t log_mutex;
+/** True iff we have initialized log_mutex */
static int log_mutex_initialized = 0;
/** Linked list of logfile_t. */
@@ -161,6 +162,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>.
*/
@@ -171,14 +183,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
@@ -641,7 +661,7 @@ init_logging(void)
log_mutex_initialized = 1;
}
if (pending_cb_messages == NULL)
- pending_cb_messages = smartlist_create();
+ pending_cb_messages = smartlist_new();
}
/** Set whether we report logging domains as a part of our log messages.
@@ -710,7 +730,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)
@@ -725,7 +745,7 @@ flush_pending_log_callbacks(void)
}
messages = pending_cb_messages;
- pending_cb_messages = smartlist_create();
+ pending_cb_messages = smartlist_new();
do {
SMARTLIST_FOREACH_BEGIN(messages, pending_cb_message_t *, msg) {
const int severity = msg->severity;
@@ -810,7 +830,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)
@@ -887,7 +907,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,
@@ -981,12 +1001,11 @@ parse_log_severity_config(const char **cfg_ptr,
return -1;
domains = 0;
domains_str = tor_strndup(cfg+1, closebracket-cfg-1);
- domains_list = smartlist_create();
+ domains_list = smartlist_new();
smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE,
-1);
tor_free(domains_str);
- SMARTLIST_FOREACH(domains_list, const char *, domain,
- {
+ SMARTLIST_FOREACH_BEGIN(domains_list, const char *, domain) {
if (!strcmp(domain, "*")) {
domains = ~0u;
} else {
@@ -1007,7 +1026,7 @@ parse_log_severity_config(const char **cfg_ptr,
domains |= d;
}
}
- });
+ } SMARTLIST_FOREACH_END(domain);
SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d));
smartlist_free(domains_list);
if (err)
diff --git a/src/common/memarea.c b/src/common/memarea.c
index a6b8c4ee9..07bd593cc 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, The Tor Project, Inc. */
+/* Copyright (c) 2008-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** \file memarea.c
diff --git a/src/common/memarea.h b/src/common/memarea.h
index 4d31dc95a..b3c76d8d0 100644
--- a/src/common/memarea.h
+++ b/src/common/memarea.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, The Tor Project, Inc. */
+/* Copyright (c) 2008-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Tor dependencies */
diff --git a/src/common/mempool.c b/src/common/mempool.c
index c44492318..637f081c8 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2011, The Tor Project, Inc. */
+/* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#if 1
/* Tor dependencies */
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include "torint.h"
+#include "crypto.h"
#define MEMPOOL_PRIVATE
#include "mempool.h"
@@ -62,7 +63,6 @@
#if 1
/* Tor dependencies */
-#include "orconfig.h"
#include "util.h"
#include "compat.h"
#include "torlog.h"
@@ -137,7 +137,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. */
@@ -520,7 +520,7 @@ mp_pool_destroy(mp_pool_t *pool)
destroy_chunks(pool->empty_chunks);
destroy_chunks(pool->used_chunks);
destroy_chunks(pool->full_chunks);
- memset(pool, 0xe0, sizeof(mp_pool_t));
+ memwipe(pool, 0xe0, sizeof(mp_pool_t));
FREE(pool);
}
diff --git a/src/common/mempool.h b/src/common/mempool.h
index fb1e9e8b4..bc424acde 100644
--- a/src/common/mempool.h
+++ b/src/common/mempool.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2011, The Tor Project, Inc. */
+/* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,6 +22,8 @@ void mp_pool_destroy(mp_pool_t *pool);
void mp_pool_assert_ok(mp_pool_t *pool);
void mp_pool_log_status(mp_pool_t *pool, int severity);
+#define MP_POOL_ITEM_OVERHEAD (sizeof(void*))
+
#define MEMPOOL_STATS
#ifdef MEMPOOL_PRIVATE
diff --git a/src/common/procmon.c b/src/common/procmon.c
index 5c10e9a22..36b1a4855 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -1,3 +1,5 @@
+/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
/**
* \file procmon.c
@@ -21,7 +23,7 @@
#include <errno.h>
#endif
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#include <windows.h>
/* Windows does not define pid_t, but _getpid() returns an int. */
@@ -41,6 +43,7 @@ static void tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
/* This struct may contain pointers into the original process
* specifier string, but it should *never* contain anything which
* needs to be freed. */
+/* DOCDOC parsed_process_specifier_t */
struct parsed_process_specifier_t {
pid_t pid;
};
@@ -81,6 +84,7 @@ parse_process_specifier(const char *process_spec,
return -1;
}
+/* DOCDOC tor_process_monitor_t */
struct tor_process_monitor_t {
/** Log domain for warning messages. */
log_domain_mask_t log_domain;
@@ -91,7 +95,7 @@ struct tor_process_monitor_t {
* polls. */
pid_t pid;
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/** Windows-only: Should we poll hproc? If false, poll pid
* instead. */
int poll_hproc;
@@ -152,6 +156,7 @@ tor_validate_process_specifier(const char *process_spec,
#define PERIODIC_TIMER_FLAGS (0)
#endif
+/* DOCDOC poll_interval_tv */
static struct timeval poll_interval_tv = {15, 0};
/* Note: If you port this file to plain Libevent 2, you can make
* poll_interval_tv const. It has to be non-const here because in
@@ -192,7 +197,7 @@ tor_process_monitor_new(struct event_base *base,
procmon->pid = ppspec.pid;
-#ifdef MS_WINDOWS
+#ifdef _WIN32
procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
FALSE,
procmon->pid);
@@ -246,7 +251,7 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
tor_assert(procmon != NULL);
-#ifdef MS_WINDOWS
+#ifdef _WIN32
if (procmon->poll_hproc) {
DWORD exit_code;
if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
@@ -323,7 +328,7 @@ tor_process_monitor_free(tor_process_monitor_t *procmon)
if (procmon == NULL)
return;
-#ifdef MS_WINDOWS
+#ifdef _WIN32
if (procmon->hproc != NULL)
CloseHandle(procmon->hproc);
#endif
diff --git a/src/common/procmon.h b/src/common/procmon.h
index 02eb2da61..88d64d6a1 100644
--- a/src/common/procmon.h
+++ b/src/common/procmon.h
@@ -1,3 +1,5 @@
+/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
/**
* \file procmon.h
@@ -14,6 +16,7 @@
typedef struct tor_process_monitor_t tor_process_monitor_t;
+/* DOCDOC tor_procmon_callback_t */
typedef void (*tor_procmon_callback_t)(void *);
int tor_validate_process_specifier(const char *process_spec,
diff --git a/src/common/sha256.c b/src/common/sha256.c
index 258b7e062..813c68d2a 100644
--- a/src/common/sha256.c
+++ b/src/common/sha256.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, The Tor Project, Inc. */
+/* Copyright (c) 2009-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* This SHA256 implementation is adapted from the public domain one in
LibTomCrypt, version 1.6. Tor uses it on platforms where OpenSSL doesn't
diff --git a/src/common/torgzip.c b/src/common/torgzip.c
index a26e5b21e..da4136228 100644
--- a/src/common/torgzip.c
+++ b/src/common/torgzip.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -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/torgzip.h b/src/common/torgzip.h
index 15e09eb70..d3ded81f9 100644
--- a/src/common/torgzip.h
+++ b/src/common/torgzip.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/torint.h b/src/common/torint.h
index 0b5c29adc..8771802d7 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -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
@@ -182,6 +191,16 @@ typedef unsigned __int64 uint64_t;
#endif
#endif
+#ifndef SIZE_MAX
+#if SIZEOF_SIZE_T == 8
+#define SIZE_MAX UINT64_MAX
+#elif SIZEOF_SIZE_T == 4
+#define SIZE_MAX UINT32_MAX
+#else
+#error "Can't define SIZE_MAX"
+#endif
+#endif
+
#ifndef HAVE_SSIZE_T
#if SIZEOF_SIZE_T == 8
typedef int64_t ssize_t;
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 541a0d173..28890a44a 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -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,12 +147,13 @@ 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);
#define log tor_log /* hack it so we don't conflict with log() as much */
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(RUNNING_DOXYGEN)
extern int _log_global_min_severity;
void _log_fn(int severity, log_domain_mask_t domain,
diff --git a/src/common/tortls.c b/src/common/tortls.c
index fc0bcb952..60aac6492 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,9 +21,10 @@
#endif
#include <assert.h>
-#ifdef MS_WINDOWS /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
- #define WIN32_WINNT 0x400
- #define _WIN32_WINNT 0x400
+#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
+ #ifndef _WIN32_WINNT
+ #define _WIN32_WINNT 0x0501
+ #endif
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER) && (_MSC_VER < 1300)
#include <winsock.h>
@@ -40,20 +41,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 +76,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-4576 fix, and as such it can't use RELEASE_BUFFERS and
* SSL3 safely at the same time.
@@ -96,22 +104,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_t *link_key;
+ crypto_pk_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 +141,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 +150,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,65 +178,58 @@ 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;
}
static void tor_tls_context_decref(tor_tls_context_t *ctx);
static void tor_tls_context_incref(tor_tls_context_t *ctx);
-static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
- crypto_pk_env_t *rsa_sign,
+static X509* tor_tls_create_certificate(crypto_pk_t *rsa,
+ crypto_pk_t *rsa_sign,
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,
+ crypto_pk_t *identity,
unsigned int key_lifetime,
int is_client);
-static tor_tls_context_t *tor_tls_context_new(crypto_pk_env_t *identity,
+static tor_tls_context_t *tor_tls_context_new(crypto_pk_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. */
+ * 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,52 +237,97 @@ 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;
+ }
-/** Return the symbolic name of an OpenSSL state. */
-static const char *
-ssl_state_to_string(int ssl_state)
+ 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);
+}
+
+/** Log a single error <b>err</b> as returned by ERR_get_error(), which was
+ * received while performing an operation <b>doing</b> on <b>tls</b>. Log
+ * the message at <b>severity</b>, in log domain <b>domain</b>. */
+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
- * <b>doing</b> to describe our current activities.
+/** Log all pending tls errors at level <b>severity</b> in log domain
+ * <b>domain</b>. Use <b>doing</b> to describe our current activities.
*/
static void
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);
}
}
@@ -273,7 +336,7 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
static int
tor_errno_to_tls_error(int e)
{
-#if defined(MS_WINDOWS)
+#if defined(_WIN32)
switch (e) {
case WSAECONNRESET: // most common
return TOR_TLS_ERROR_CONNRESET;
@@ -355,14 +418,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 +434,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 +477,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 +500,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 +525,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);
@@ -508,13 +572,19 @@ tor_x509_name_new(const char *cname)
* failure.
*/
static X509 *
-tor_tls_create_certificate(crypto_pk_env_t *rsa,
- crypto_pk_env_t *rsa_sign,
+tor_tls_create_certificate(crypto_pk_t *rsa,
+ crypto_pk_t *rsa_sign,
const char *cname,
const char *cname_sign,
unsigned int cert_lifetime)
{
+ /* OpenSSL generates self-signed certificates with random 64-bit serial
+ * numbers, so let's do that too. */
+#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;
@@ -527,16 +597,23 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
tor_assert(cname);
tor_assert(rsa_sign);
tor_assert(cname_sign);
- if (!(sign_pkey = _crypto_pk_env_get_evp_pkey(rsa_sign,1)))
+ if (!(sign_pkey = _crypto_pk_get_evp_pkey(rsa_sign,1)))
goto error;
- if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,0)))
+ if (!(pkey = _crypto_pk_get_evp_pkey(rsa,0)))
goto error;
if (!(x509 = X509_new()))
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 +646,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.*/
@@ -593,6 +674,9 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
* our OpenSSL doesn't know about. */
static const char CLIENT_CIPHER_LIST[] =
#include "./ciphers.inc"
+ /* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version
+ * of any cipher we say. */
+ "!SSLv2"
;
#undef CIPHER
#undef XCIPHER
@@ -620,6 +704,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);
+ memwipe(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_t *pk = _crypto_new_pk_from_rsa(rsa);
+ crypto_pk_get_all_digests(pk, &cert->pkey_digests);
+ cert->pkey_digests_set = 1;
+ crypto_pk_free(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 +843,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_pk_free(ctx->link_key);
+ crypto_pk_free(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_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_t *
+tor_tls_cert_get_key(tor_cert_t *cert)
+{
+ crypto_pk_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_from_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)
@@ -650,8 +1024,8 @@ tor_tls_context_incref(tor_tls_context_t *ctx)
* ignore <b>client_identity</b>. */
int
tor_tls_context_init(int is_public_server,
- crypto_pk_env_t *client_identity,
- crypto_pk_env_t *server_identity,
+ crypto_pk_t *client_identity,
+ crypto_pk_t *server_identity,
unsigned int key_lifetime)
{
int rv1 = 0;
@@ -709,7 +1083,7 @@ tor_tls_context_init(int is_public_server,
*/
static int
tor_tls_context_init_one(tor_tls_context_t **ppcontext,
- crypto_pk_env_t *identity,
+ crypto_pk_t *identity,
unsigned int key_lifetime,
int is_client)
{
@@ -737,32 +1111,45 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
* certificate.
*/
static tor_tls_context_t *
-tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
+tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
int is_client)
{
- crypto_pk_env_t *rsa = NULL;
+ crypto_pk_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. */
- if (!(rsa = crypto_new_pk_env()))
+ /* Generate short-term RSA key for use with TLS. */
+ if (!(rsa = crypto_pk_new()))
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_pk_new()))
+ 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 +1158,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
@@ -817,9 +1208,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-4576. */
log_info(LD_NET, "Disabling SSLv3 because this OpenSSL version "
"might otherwise be vulnerable to CVE-2011-4576 "
@@ -866,7 +1257,7 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
if (!is_client) {
tor_assert(rsa);
- if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1)))
+ if (!(pkey = _crypto_pk_get_evp_pkey(rsa,1)))
goto error;
if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
goto error;
@@ -876,9 +1267,9 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
goto error;
}
{
- crypto_dh_env_t *dh = crypto_dh_new(DH_TYPE_TLS);
+ crypto_dh_t *dh = crypto_dh_new(DH_TYPE_TLS);
tor_assert(dh);
- SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_env_get_dh(dh));
+ SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_get_dh(dh));
crypto_dh_free(dh);
}
SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
@@ -887,7 +1278,10 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
if (rsa)
- crypto_free_pk_env(rsa);
+ crypto_pk_free(rsa);
+ if (rsa_auth)
+ crypto_pk_free(rsa_auth);
+ X509_free(authcert);
tor_free(nickname);
tor_free(nn2);
return result;
@@ -899,13 +1293,17 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime,
if (pkey)
EVP_PKEY_free(pkey);
if (rsa)
- crypto_free_pk_env(rsa);
+ crypto_pk_free(rsa);
+ if (rsa_auth)
+ crypto_pk_free(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;
}
@@ -945,7 +1343,7 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
return 0;
dump_list:
{
- smartlist_t *elts = smartlist_create();
+ smartlist_t *elts = smartlist_new();
char *s;
for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
@@ -961,6 +1359,14 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
return 1;
}
+/** Invoked when a TLS state changes: log the change at severity 'debug' */
+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
@@ -972,9 +1378,13 @@ 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)
+ if ((ssl->state != SSL3_ST_SW_SRVR_HELLO_A) &&
+ (ssl->state != SSL3_ST_SW_SRVR_HELLO_B))
return;
tls = tor_tls_get_by_ssl(ssl);
@@ -982,13 +1392,18 @@ 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. */
if (tor_tls_client_is_using_v2_ciphers(ssl, ADDR(tls))) {
- /*XXXX_TLS keep this from happening more than once! */
+ if (tls->wasV2Handshake)
+ return; /* We already turned this stuff off for the first handshake;
+ * This is a renegotiation. */
/* Yes, we're casting away the const from ssl. This is very naughty of us.
* Let's hope openssl doesn't notice! */
@@ -1000,6 +1415,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!");
}
@@ -1007,11 +1426,35 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
}
#endif
+/** Explain which ciphers we're missing. */
+static void
+log_unsupported_ciphers(smartlist_t *unsupported)
+{
+ char *joined;
+
+ log_notice(LD_NET, "We weren't able to find support for all of the "
+ "TLS ciphersuites that we wanted to advertise. This won't "
+ "hurt security, but it might make your Tor (if run as a client) "
+ "more easy for censors to block.");
+
+ if (SSLeay() < 0x10000000L) {
+ log_notice(LD_NET, "To correct this, use a more recent OpenSSL, "
+ "built without disabling any secure ciphers or features.");
+ } else {
+ log_notice(LD_NET, "To correct this, use a version of OpenSSL "
+ "built with none of its ciphers disabled.");
+ }
+
+ joined = smartlist_join_strings(unsupported, ":", 0, NULL);
+ log_info(LD_NET, "The unsupported ciphers were: %s", joined);
+ tor_free(joined);
+}
+
/** Replace *<b>ciphers</b> with a new list of SSL ciphersuites: specifically,
- * a list designed to mimic a common web browser. Some of the ciphers in the
- * list won't actually be implemented by OpenSSL: that's okay so long as the
- * server doesn't select them, and the server won't select anything besides
- * what's in SERVER_CIPHER_LIST.
+ * a list designed to mimic a common web browser. We might not be able to do
+ * that if OpenSSL doesn't support all the ciphers we want. Some of the
+ * ciphers in the list won't actually be implemented by OpenSSL: that's okay
+ * so long as the server doesn't select them.
*
* [If the server <b>does</b> select a bogus cipher, we won't crash or
* anything; we'll just fail later when we try to look up the cipher in
@@ -1023,14 +1466,17 @@ rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
#ifdef V2_HANDSHAKE_CLIENT
if (PREDICT_UNLIKELY(!CLIENT_CIPHER_STACK)) {
/* We need to set CLIENT_CIPHER_STACK to an array of the ciphers
- * we want.*/
+ * we want to use/advertise. */
int i = 0, j = 0;
+ smartlist_t *unsupported = smartlist_new();
/* First, create a dummy SSL_CIPHER for every cipher. */
CLIENT_CIPHER_DUMMIES =
tor_malloc_zero(sizeof(SSL_CIPHER)*N_CLIENT_CIPHERS);
for (i=0; i < N_CLIENT_CIPHERS; ++i) {
CLIENT_CIPHER_DUMMIES[i].valid = 1;
+ /* The "3<<24" here signifies that the cipher is supposed to work with
+ * SSL3 and TLS1. */
CLIENT_CIPHER_DUMMIES[i].id = CLIENT_CIPHER_INFO_LIST[i].id | (3<<24);
CLIENT_CIPHER_DUMMIES[i].name = CLIENT_CIPHER_INFO_LIST[i].name;
}
@@ -1045,27 +1491,49 @@ rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
}
/* Then copy as many ciphers as we can from the good list, inserting
- * dummies as needed. */
- j=0;
- for (i = 0; i < N_CLIENT_CIPHERS; ) {
+ * dummies as needed. Let j be an index into list of ciphers we have
+ * (*ciphers) and let i be an index into the ciphers we want
+ * (CLIENT_INFO_CIPHER_LIST). We are building a list of ciphers in
+ * CLIENT_CIPHER_STACK.
+ */
+ for (i = j = 0; i < N_CLIENT_CIPHERS; ) {
SSL_CIPHER *cipher = NULL;
if (j < sk_SSL_CIPHER_num(*ciphers))
cipher = sk_SSL_CIPHER_value(*ciphers, j);
if (cipher && ((cipher->id >> 24) & 0xff) != 3) {
- log_debug(LD_NET, "Skipping v2 cipher %s", cipher->name);
+ /* Skip over non-v3 ciphers entirely. (This should no longer be
+ * needed, thanks to saying !SSLv2 above.) */
+ log_debug(LD_NET, "Skipping v%d cipher %s",
+ (int)((cipher->id>>24) & 0xff),
+ cipher->name);
++j;
} else if (cipher &&
(cipher->id & 0xffff) == CLIENT_CIPHER_INFO_LIST[i].id) {
+ /* "cipher" is the cipher we expect. Put it on the list. */
log_debug(LD_NET, "Found cipher %s", cipher->name);
sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, cipher);
++j;
++i;
- } else {
+ } else if (!strcmp(CLIENT_CIPHER_DUMMIES[i].name,
+ "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA")) {
+ /* We found bogus cipher 0xfeff, which OpenSSL doesn't support and
+ * never has. For this one, we need a dummy. */
log_debug(LD_NET, "Inserting fake %s", CLIENT_CIPHER_DUMMIES[i].name);
sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, &CLIENT_CIPHER_DUMMIES[i]);
++i;
+ } else {
+ /* OpenSSL doesn't have this one. */
+ log_debug(LD_NET, "Completely omitting unsupported cipher %s",
+ CLIENT_CIPHER_INFO_LIST[i].name);
+ smartlist_add(unsupported, (char*) CLIENT_CIPHER_INFO_LIST[i].name);
+ ++i;
}
}
+
+ if (smartlist_len(unsupported))
+ log_unsupported_ciphers(unsupported);
+
+ smartlist_free(unsupported);
}
sk_SSL_CIPHER_free(*ciphers);
@@ -1087,6 +1555,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))) {
@@ -1127,7 +1596,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;
@@ -1143,8 +1619,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");
@@ -1178,7 +1657,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
}
@@ -1186,7 +1665,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
@@ -1210,6 +1689,20 @@ tor_tls_block_renegotiation(tor_tls_t *tls)
tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
}
+/** Assert that the flags that allow legacy renegotiation are still set */
+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
@@ -1225,14 +1718,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
@@ -1242,6 +1730,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);
}
@@ -1333,16 +1822,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);
@@ -1354,56 +1843,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.
@@ -1509,9 +2028,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;
@@ -1521,9 +2052,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;
@@ -1545,9 +2077,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 */
@@ -1604,7 +2136,7 @@ try_to_extract_certs_from_tls(int severity, tor_tls_t *tls,
* 0. Else, return -1 and log complaints with log-level <b>severity</b>.
*/
int
-tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
+tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
{
X509 *cert = NULL, *id_cert = NULL;
EVP_PKEY *id_pkey = NULL;
@@ -1620,6 +2152,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");
@@ -1630,7 +2164,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
rsa = EVP_PKEY_get1_RSA(id_pkey);
if (!rsa)
goto done;
- *identity_key = _crypto_new_pk_env_rsa(rsa);
+ *identity_key = _crypto_new_pk_from_rsa(rsa);
r = 0;
@@ -1647,34 +2181,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:
@@ -1686,6 +2211,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
@@ -1769,6 +2320,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);
+ memwipe(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.
@@ -1791,3 +2474,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 55fee81ae..491a5419d 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_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,11 +51,12 @@ 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,
- crypto_pk_env_t *client_identity,
- crypto_pk_env_t *server_identity,
+ crypto_pk_t *client_identity,
+ crypto_pk_t *server_identity,
unsigned int key_lifetime);
tor_tls_t *tor_tls_new(int sock, int is_server);
void tor_tls_set_logged_address(tor_tls_t *tls, const char *address);
@@ -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);
-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);
+tor_cert_t *tor_tls_get_peer_cert(tor_tls_t *tls);
+int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity);
+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_t *tor_tls_get_my_client_auth_key(void);
+crypto_pk_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 dcff2479f..000000000
--- 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 698f989ec..6fb597a3a 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -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
@@ -22,11 +26,12 @@
#include "container.h"
#include "address.h"
-#ifdef MS_WINDOWS
+#ifdef _WIN32
#include <io.h>
#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
@@ -77,7 +80,7 @@
#include <malloc/malloc.h>
#endif
#ifdef HAVE_MALLOC_H
-#ifndef OPENBSD
+#if !defined(OPENBSD) && !defined(__FreeBSD__)
/* OpenBSD has a malloc.h, but for our purposes, it only exists in order to
* scold us for being so stupid as to autodetect its presence. To be fair,
* they've done this since 1996, when autoconf was only 5 years old. */
@@ -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
@@ -166,6 +172,35 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
return result;
}
+/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill
+ * the memory with zero bytes, and return a pointer to the result.
+ * Log and terminate the process on error. (Same as
+ * calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.)
+ *
+ * XXXX This implementation probably asserts in cases where it could
+ * work, because it only tries dividing SIZE_MAX by size (according to
+ * the calloc(3) man page, the size of an element of the nmemb-element
+ * array to be allocated), not by nmemb (which could in theory be
+ * smaller than size). Don't do that then.
+ */
+void *
+_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
+{
+ /* You may ask yourself, "wouldn't it be smart to use calloc instead of
+ * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
+ * we don't!" Indeed it does, but its optimizations are only a big win when
+ * we're allocating something very big (it knows if it just got the memory
+ * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero
+ * for big stuff, so we don't bother with calloc. */
+ void *result;
+ size_t max_nmemb = (size == 0) ? SIZE_MAX : SIZE_MAX/size;
+
+ tor_assert(nmemb < max_nmemb);
+
+ result = _tor_malloc_zero((nmemb * size) DMALLOC_FN_ARGS);
+ return result;
+}
+
/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b>
* bytes long; return the new memory block. On error, log and
* terminate. (Like realloc(ptr,size), but never returns NULL.)
@@ -417,6 +452,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 +561,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 +800,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)
@@ -803,6 +909,12 @@ tor_parse_long(const char *s, int base, long min, long max,
char *endptr;
long r;
+ if (base < 0) {
+ if (ok)
+ *ok = 0;
+ return 0;
+ }
+
errno = 0;
r = strtol(s, &endptr, base);
CHECK_STRTOX_RESULT();
@@ -816,6 +928,12 @@ tor_parse_ulong(const char *s, int base, unsigned long min,
char *endptr;
unsigned long r;
+ if (base < 0) {
+ if (ok)
+ *ok = 0;
+ return 0;
+ }
+
errno = 0;
r = strtoul(s, &endptr, base);
CHECK_STRTOX_RESULT();
@@ -842,10 +960,16 @@ tor_parse_uint64(const char *s, int base, uint64_t min,
char *endptr;
uint64_t r;
+ if (base < 0) {
+ if (ok)
+ *ok = 0;
+ return 0;
+ }
+
errno = 0;
#ifdef HAVE_STRTOULL
r = (uint64_t)strtoull(s, &endptr, base);
-#elif defined(MS_WINDOWS)
+#elif defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER < 1300
tor_assert(base <= 10);
r = (uint64_t)_atoi64(s);
@@ -965,7 +1089,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) {
@@ -1361,6 +1485,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
@@ -1646,7 +1790,7 @@ read_all(tor_socket_t fd, char *buf, size_t count, int isSocket)
static void
clean_name_for_stat(char *name)
{
-#ifdef MS_WINDOWS
+#ifdef _WIN32
size_t len = strlen(name);
if (!len)
return;
@@ -1705,7 +1849,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
int r;
struct stat st;
char *f;
-#ifndef MS_WINDOWS
+#ifndef _WIN32
int mask;
struct passwd *pw = NULL;
uid_t running_uid;
@@ -1727,7 +1871,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
}
if (check & CPD_CREATE) {
log_info(LD_GENERAL, "Creating directory %s", dirname);
-#if defined (MS_WINDOWS) && !defined (WINCE)
+#if defined (_WIN32) && !defined (WINCE)
r = mkdir(dirname);
#else
r = mkdir(dirname, 0700);
@@ -1749,7 +1893,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
log_warn(LD_FS, "%s is not a directory", dirname);
return -1;
}
-#ifndef MS_WINDOWS
+#ifndef _WIN32
if (effective_user) {
/* Look up the user and group information.
* If we have a problem, bail out. */
@@ -1836,7 +1980,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
int
write_str_to_file(const char *fname, const char *str, int bin)
{
-#ifdef MS_WINDOWS
+#ifdef _WIN32
if (!bin && strchr(str, '\r')) {
log_warn(LD_BUG,
"We're writing a text string that already contains a CR.");
@@ -1879,7 +2023,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;
@@ -1890,7 +2033,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;
@@ -1898,11 +2040,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;
@@ -1911,7 +2050,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));
@@ -2072,36 +2211,50 @@ 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();
+ smartlist_t *chunks = smartlist_new();
smartlist_add(chunks, &c);
r = write_chunks_to_file_impl(fname, chunks, flags);
smartlist_free(chunks);
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
@@ -2132,7 +2285,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;
@@ -2169,7 +2322,7 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out)
}
string[r] = '\0'; /* NUL-terminate the result. */
-#ifdef MS_WINDOWS
+#if defined(_WIN32) || defined(__CYGWIN__)
if (!bin && strchr(string, '\r')) {
log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped "
"when reading %s. Coping.",
@@ -2334,7 +2487,7 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
KEYCHAR = Any character except ' ', '\r', '\n', '\t', '#', "\"
VALUES = QUOTEDVALUE | NORMALVALUE
- QUOTEDVALUE = QUOTE QVITEM* QUOTE EOLSPACE?
+ QUOTEDVALUE = QUOTE QVCHAR* QUOTE EOLSPACE?
QUOTE = '"'
QVCHAR = KEYCHAR | ESC ('n' | 't' | 'r' | '"' | ESC |'\'' | OCTAL | HEX)
ESC = "\\"
@@ -2462,7 +2615,7 @@ char *
expand_filename(const char *filename)
{
tor_assert(filename);
-#ifdef MS_WINDOWS
+#ifdef _WIN32
return tor_strdup(filename);
#else
if (*filename == '~') {
@@ -2530,18 +2683,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;
@@ -2603,11 +2759,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;
@@ -2630,7 +2787,7 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
++n_matched;
} else if (*pattern == '%') {
if (*buf != '%')
- return -1;
+ return n_matched;
++buf;
++pattern;
} else {
@@ -2644,9 +2801,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, %x, %c 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
@@ -2663,6 +2820,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.
*/
@@ -2670,15 +2851,13 @@ smartlist_t *
tor_listdir(const char *dirname)
{
smartlist_t *result;
-#ifdef MS_WINDOWS
- char *pattern;
+#ifdef _WIN32
+ char *pattern=NULL;
TCHAR tpattern[MAX_PATH] = {0};
- char name[MAX_PATH] = {0};
+ char name[MAX_PATH*2+1] = {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
@@ -2688,10 +2867,11 @@ tor_listdir(const char *dirname)
tor_free(pattern);
return NULL;
}
- result = smartlist_create();
+ result = smartlist_new();
while (1) {
#ifdef UNICODE
wcstombs(name,findData.cFileName,MAX_PATH);
+ name[sizeof(name)-1] = '\0';
#else
strlcpy(name,findData.cFileName,sizeof(name));
#endif
@@ -2717,7 +2897,7 @@ tor_listdir(const char *dirname)
if (!(d = opendir(dirname)))
return NULL;
- result = smartlist_create();
+ result = smartlist_new();
while ((de = readdir(d))) {
if (!strcmp(de->d_name, ".") ||
!strcmp(de->d_name, ".."))
@@ -2735,7 +2915,7 @@ path_is_relative(const char *filename)
{
if (filename && filename[0] == '/')
return 0;
-#ifdef MS_WINDOWS
+#ifdef _WIN32
else if (filename && filename[0] == '\\')
return 0;
else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) &&
@@ -2750,7 +2930,7 @@ path_is_relative(const char *filename)
* Process helpers
* ===== */
-#ifndef MS_WINDOWS
+#ifndef _WIN32
/* Based on code contributed by christian grothoff */
/** True iff we've called start_daemon(). */
static int start_daemon_called = 0;
@@ -2840,7 +3020,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);
@@ -2864,7 +3044,7 @@ finish_daemon(const char *desired_cwd)
close(daemon_filedes[1]);
}
#else
-/* defined(MS_WINDOWS) */
+/* defined(_WIN32) */
void
start_daemon(void)
{
@@ -2887,7 +3067,7 @@ write_pidfile(char *filename)
log_warn(LD_FS, "Unable to open \"%s\" for writing: %s", filename,
strerror(errno));
} else {
-#ifdef MS_WINDOWS
+#ifdef _WIN32
fprintf(pidfile, "%d\n", (int)_getpid());
#else
fprintf(pidfile, "%d\n", (int)getpid());
@@ -2896,7 +3076,7 @@ write_pidfile(char *filename)
}
}
-#ifdef MS_WINDOWS
+#ifdef _WIN32
HANDLE
load_windows_system_library(const TCHAR *library_name)
{
@@ -2911,3 +3091,1463 @@ 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_new();
+
+ /* 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_new();
+ 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;
+}
+
+/**
+ * Helper function to output hex numbers, called by
+ * format_helper_exit_status(). This writes the hexadecimal digits of x into
+ * buf, up to max_len digits, and returns the actual number of digits written.
+ * If there is insufficient space, it will write nothing and return 0.
+ *
+ * This function DOES NOT add a terminating NUL character to its output: be
+ * careful!
+ *
+ * This accepts an unsigned int because format_helper_exit_status() needs to
+ * call it with a signed int and an unsigned char, and since the C standard
+ * does not guarantee that an int is wider than a char (an int must be at
+ * least 16 bits but it is permitted for a char to be that wide as well), we
+ * can't assume a signed int is sufficient to accomodate an unsigned char.
+ * Thus, format_helper_exit_status() will still need to emit any require '-'
+ * on its own.
+ *
+ * For most purposes, you'd want to use tor_snprintf("%x") instead of this
+ * function; it's designed to be used in code paths where you can't call
+ * arbitrary C functions.
+ */
+int
+format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
+ int max_len)
+{
+ int len;
+ unsigned int tmp;
+ char *cur;
+
+ /* Sanity check */
+ if (!buf || max_len <= 0)
+ return 0;
+
+ /* How many chars do we need for x? */
+ if (x > 0) {
+ len = 0;
+ tmp = x;
+ while (tmp > 0) {
+ tmp >>= 4;
+ ++len;
+ }
+ } else {
+ len = 1;
+ }
+
+ /* Bail if we would go past the end of the buffer */
+ if (len > max_len)
+ return 0;
+
+ /* Point to last one */
+ cur = buf + len - 1;
+
+ /* Convert x to hex */
+ do {
+ *cur-- = "0123456789ABCDEF"[x & 0xf];
+ x >>= 4;
+ } while (x != 0 && cur >= buf);
+
+ /* Return len */
+ return len;
+}
+
+/** 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.
+ *
+ * On success return the number of characters added to hex_errno, not counting
+ * the terminating NUL; return -1 on error.
+ */
+int
+format_helper_exit_status(unsigned char child_state, int saved_errno,
+ char *hex_errno)
+{
+ unsigned int unsigned_errno;
+ int written, left;
+ char *cur;
+ size_t i;
+ int res = -1;
+
+ /* 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;
+ }
+
+ /*
+ * Count how many chars of space we have left, and keep a pointer into the
+ * current point in the buffer.
+ */
+ left = HEX_ERRNO_SIZE;
+ cur = hex_errno;
+
+ /* Emit child_state */
+ written = format_hex_number_for_helper_exit_status(child_state,
+ cur, left);
+ if (written <= 0)
+ goto err;
+
+ /* Adjust left and cur */
+ left -= written;
+ cur += written;
+ if (left <= 0)
+ goto err;
+
+ /* Now the '/' */
+ *cur = '/';
+
+ /* Adjust left and cur */
+ ++cur;
+ --left;
+ if (left <= 0)
+ goto err;
+
+ /* Need minus? */
+ if (saved_errno < 0) {
+ *cur = '-';
+ ++cur;
+ --left;
+ if (left <= 0)
+ goto err;
+ }
+
+ /* Emit unsigned_errno */
+ written = format_hex_number_for_helper_exit_status(unsigned_errno,
+ cur, left);
+
+ if (written <= 0)
+ goto err;
+
+ /* Adjust left and cur */
+ left -= written;
+ cur += written;
+
+ /* Check that we have enough space left for a newline */
+ if (left <= 0)
+ goto err;
+
+ /* Emit the newline and NUL */
+ *cur++ = '\n';
+ *cur++ = '\0';
+
+ res = (int)(cur - hex_errno - 1);
+
+ goto done;
+
+ err:
+ /*
+ * In error exit, just write a '\0' in the first char so whatever called
+ * this at least won't fall off the end.
+ */
+ *hex_errno = '\0';
+
+ done:
+ return res;
+}
+
+/* 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 _WIN32
+ 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 _WIN32
+ return (int) process_handle->pid.dwProcessId;
+#else
+ return (int) process_handle->pid;
+#endif
+}
+
+#ifdef _WIN32
+HANDLE
+tor_process_get_stdout_pipe(process_handle_t *process_handle)
+{
+ return process_handle->stdout_pipe;
+}
+#else
+/* DOCDOC tor_process_get_stdout_pipe */
+FILE *
+tor_process_get_stdout_pipe(process_handle_t *process_handle)
+{
+ return process_handle->stdout_handle;
+}
+#endif
+
+/* DOCDOC process_handle_new */
+static process_handle_t *
+process_handle_new(void)
+{
+ process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t));
+
+#ifdef _WIN32
+ out->stdout_pipe = INVALID_HANDLE_VALUE;
+ out->stderr_pipe = INVALID_HANDLE_VALUE;
+#else
+ out->stdout_pipe = -1;
+ out->stderr_pipe = -1;
+#endif
+
+ return out;
+}
+
+/**
+ * @name child-process states
+ *
+ * Each of these values represents a possible state that a child process can
+ * be in. They're used to determine what to say when telling the parent how
+ * far along we were before failure.
+ *
+ * @{
+ */
+#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,
+ process_environment_t *env,
+ process_handle_t **process_handle_out)
+{
+#ifdef _WIN32
+ 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;
+
+ STARTUPINFOA siStartInfo;
+ BOOL retval = FALSE;
+
+ SECURITY_ATTRIBUTES saAttr;
+ char *joined_argv;
+
+ 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 = CreateProcessA(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
+ (env==NULL) ? NULL : env->windows_environment_block,
+ 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 // _WIN32
+ 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));
+
+ close(stdout_pipe[0]);
+ close(stdout_pipe[1]);
+
+ 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 (env)
+ execve(filename, (char *const *) argv, env->unixoid_environment_block);
+ 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? */
+ int n;
+
+ n = format_helper_exit_status(child_state, errno, hex_errno);
+
+ if (n >= 0) {
+ /* 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, n);
+ }
+ }
+
+ (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 // _WIN32
+}
+
+/** 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 _WIN32
+ 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 _WIN32
+ 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 // _WIN32
+
+ return PROCESS_EXIT_EXITED;
+}
+
+/** Helper: return the number of characters in <b>s</b> preceding the first
+ * occurrence of <b>ch</b>. If <b>ch</b> does not occur in <b>s</b>, return
+ * the length of <b>s</b>. Should be equivalent to strspn(s, "ch"). */
+static INLINE size_t
+str_num_before(const char *s, char ch)
+{
+ const char *cp = strchr(s, ch);
+ if (cp)
+ return cp - s;
+ else
+ return strlen(s);
+}
+
+/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b>
+ * to have the same name as strings in a process's environment. */
+int
+environment_variable_names_equal(const char *s1, const char *s2)
+{
+ size_t s1_name_len = str_num_before(s1, '=');
+ size_t s2_name_len = str_num_before(s2, '=');
+
+ return (s1_name_len == s2_name_len &&
+ tor_memeq(s1, s2, s1_name_len));
+}
+
+/** Free <b>env</b> (assuming it was produced by
+ * process_environment_make). */
+void
+process_environment_free(process_environment_t *env)
+{
+ if (env == NULL) return;
+
+ /* As both an optimization hack to reduce consing on Unixoid systems
+ * and a nice way to ensure that some otherwise-Windows-specific
+ * code will always get tested before changes to it get merged, the
+ * strings which env->unixoid_environment_block points to are packed
+ * into env->windows_environment_block. */
+ tor_free(env->unixoid_environment_block);
+ tor_free(env->windows_environment_block);
+
+ tor_free(env);
+}
+
+/** Make a process_environment_t containing the environment variables
+ * specified in <b>env_vars</b> (as C strings of the form
+ * "NAME=VALUE"). */
+process_environment_t *
+process_environment_make(struct smartlist_t *env_vars)
+{
+ process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t));
+ size_t n_env_vars = smartlist_len(env_vars);
+ size_t i;
+ size_t total_env_length;
+ smartlist_t *env_vars_sorted;
+
+ tor_assert(n_env_vars + 1 != 0);
+ env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *));
+ /* env->unixoid_environment_block is already NULL-terminated,
+ * because we assume that NULL == 0 (and check that during compilation). */
+
+ total_env_length = 1; /* terminating NUL of terminating empty string */
+ for (i = 0; i < n_env_vars; ++i) {
+ const char *s = smartlist_get(env_vars, i);
+ size_t slen = strlen(s);
+
+ tor_assert(slen + 1 != 0);
+ tor_assert(slen + 1 < SIZE_MAX - total_env_length);
+ total_env_length += slen + 1;
+ }
+
+ env->windows_environment_block = tor_malloc_zero(total_env_length);
+ /* env->windows_environment_block is already
+ * (NUL-terminated-empty-string)-terminated. */
+
+ /* Some versions of Windows supposedly require that environment
+ * blocks be sorted. Or maybe some Windows programs (or their
+ * runtime libraries) fail to look up strings in non-sorted
+ * environment blocks.
+ *
+ * Also, sorting strings makes it easy to find duplicate environment
+ * variables and environment-variable strings without an '=' on all
+ * OSes, and they can cause badness. Let's complain about those. */
+ env_vars_sorted = smartlist_new();
+ smartlist_add_all(env_vars_sorted, env_vars);
+ smartlist_sort_strings(env_vars_sorted);
+
+ /* Now copy the strings into the environment blocks. */
+ {
+ char *cp = env->windows_environment_block;
+ const char *prev_env_var = NULL;
+
+ for (i = 0; i < n_env_vars; ++i) {
+ const char *s = smartlist_get(env_vars_sorted, i);
+ size_t slen = strlen(s);
+ size_t s_name_len = str_num_before(s, '=');
+
+ if (s_name_len == slen) {
+ log_warn(LD_GENERAL,
+ "Preparing an environment containing a variable "
+ "without a value: %s",
+ s);
+ }
+ if (prev_env_var != NULL &&
+ environment_variable_names_equal(s, prev_env_var)) {
+ log_warn(LD_GENERAL,
+ "Preparing an environment containing two variables "
+ "with the same name: %s and %s",
+ prev_env_var, s);
+ }
+
+ prev_env_var = s;
+
+ /* Actually copy the string into the environment. */
+ memcpy(cp, s, slen+1);
+ env->unixoid_environment_block[i] = cp;
+ cp += slen+1;
+ }
+
+ tor_assert(cp == env->windows_environment_block + total_env_length - 1);
+ }
+
+ smartlist_free(env_vars_sorted);
+
+ return env;
+}
+
+/** Return a newly allocated smartlist containing every variable in
+ * this process's environment, as a NUL-terminated string of the form
+ * "NAME=VALUE". Note that on some/many/most/all OSes, the parent
+ * process can put strings not of that form in our environment;
+ * callers should try to not get crashed by that.
+ *
+ * The returned strings are heap-allocated, and must be freed by the
+ * caller. */
+struct smartlist_t *
+get_current_process_environment_variables(void)
+{
+ smartlist_t *sl = smartlist_new();
+
+ char **environ_tmp; /* Not const char ** ? Really? */
+ for (environ_tmp = get_environment(); *environ_tmp; ++environ_tmp) {
+ smartlist_add(sl, tor_strdup(*environ_tmp));
+ }
+
+ return sl;
+}
+
+/** For each string s in <b>env_vars</b> such that
+ * environment_variable_names_equal(s, <b>new_var</b>), remove it; if
+ * <b>free_p</b> is non-zero, call <b>free_old</b>(s). If
+ * <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */
+void
+set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
+ const char *new_var,
+ void (*free_old)(void*),
+ int free_p)
+{
+ SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) {
+ if (environment_variable_names_equal(s, new_var)) {
+ SMARTLIST_DEL_CURRENT(env_vars, s);
+ if (free_p) {
+ free_old((void *)s);
+ }
+ }
+ } SMARTLIST_FOREACH_END(s);
+
+ if (strchr(new_var, '=') != NULL) {
+ smartlist_add(env_vars, (void *)new_var);
+ }
+}
+
+#ifdef _WIN32
+/** 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 _WIN32
+ 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 _WIN32
+ 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 _WIN32
+/** 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_new();
+ 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);
+ if (len == 0) {
+ /* this probably means we got a NUL at the start of the string. */
+ return IO_STREAM_EAGAIN;
+ }
+
+ 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;
+}
+
+/* DOCDOC tor_check_port_forwarding */
+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 _WIN32
+ /* 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 _WIN32
+ 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 _WIN32
+ 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 75de3422d..8977d273c 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,6 +17,10 @@
#include "di_ops.h"
#include <stdio.h>
#include <stdlib.h>
+#ifdef _WIN32
+/* for the correct alias to struct stat */
+#include <sys/stat.h>
+#endif
#ifndef O_BINARY
#define O_BINARY 0
@@ -73,6 +77,7 @@
void *_tor_malloc(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *_tor_malloc_zero(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *_tor_malloc_roundup(size_t *size DMALLOC_PARAMS) ATTR_MALLOC;
+void *_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS);
char *_tor_strdup(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
char *_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
@@ -107,6 +112,7 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
#define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS)
#define tor_malloc_zero(size) _tor_malloc_zero(size DMALLOC_ARGS)
+#define tor_calloc(nmemb,size) _tor_calloc(nmemb, size DMALLOC_ARGS)
#define tor_malloc_roundup(szp) _tor_malloc_roundup(szp DMALLOC_ARGS)
#define tor_realloc(ptr, size) _tor_realloc(ptr, size DMALLOC_ARGS)
#define tor_strdup(s) _tor_strdup(s DMALLOC_ARGS)
@@ -160,6 +166,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 +179,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 +199,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;
@@ -222,6 +228,12 @@ 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)
+ CHECK_PRINTF(2, 0);
+
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);
@@ -237,8 +249,11 @@ int tor_timegm(const struct tm *tm, time_t *time_out);
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);
@@ -283,6 +298,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;
@@ -300,6 +325,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);
@@ -321,30 +347,141 @@ 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
/** Flag for read_file_to_str: it's okay if the file doesn't exist. */
#define RFTS_IGNORE_MISSING 2
+#ifndef _WIN32
struct stat;
+#endif
char *read_file_to_str(const char *filename, int flags, struct stat *stat_out)
ATTR_MALLOC;
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);
-#ifdef MS_WINDOWS
+/* 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;
+typedef struct process_environment_t process_environment_t;
+int tor_spawn_background(const char *const filename, const char **argv,
+ process_environment_t *env,
+ process_handle_t **process_handle_out);
+
+#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code "
+
+#ifdef _WIN32
HANDLE load_windows_system_library(const TCHAR *library_name);
#endif
+int environment_variable_names_equal(const char *s1, const char *s2);
+
+/* DOCDOC process_environment_t */
+struct process_environment_t {
+ /** A pointer to a sorted empty-string-terminated sequence of
+ * NUL-terminated strings of the form "NAME=VALUE". */
+ char *windows_environment_block;
+ /** A pointer to a NULL-terminated array of pointers to
+ * NUL-terminated strings of the form "NAME=VALUE". */
+ char **unixoid_environment_block;
+};
+
+process_environment_t *process_environment_make(struct smartlist_t *env_vars);
+void process_environment_free(process_environment_t *env);
+
+struct smartlist_t *get_current_process_environment_variables(void);
+
+void set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
+ const char *new_var,
+ void (*free_old)(void*),
+ int free_p);
+
+/* 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
+/** Structure to represent the state of a process with which Tor is
+ * communicating. The contents of this structure are private to util.c */
+struct process_handle_t {
+ /** One of the PROCESS_STATUS_* values */
+ int status;
+#ifdef _WIN32
+ 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 // _WIN32
+};
+#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 _WIN32
+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 _WIN32
+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) */
+
+int format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
+ int max_len);
+int 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
diff --git a/src/common/util_codedigest.c b/src/common/util_codedigest.c
index 88fe508b9..7384f7dc1 100644
--- a/src/common/util_codedigest.c
+++ b/src/common/util_codedigest.c
@@ -1,6 +1,8 @@
#include "util.h"
+/** Return a string describing the digest of the source files in src/common/
+ */
const char *
libor_get_digests(void)
{