summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/address.c82
-rw-r--r--src/common/address.h7
-rw-r--r--src/common/aes.c4
-rw-r--r--src/common/compat.c2
-rw-r--r--src/common/crypto.c85
-rw-r--r--src/common/crypto.h3
-rw-r--r--src/common/mempool.c3
-rw-r--r--src/common/tortls.c6
-rw-r--r--src/common/util.c33
-rw-r--r--src/common/util.h2
10 files changed, 190 insertions, 37 deletions
diff --git a/src/common/address.c b/src/common/address.c
index a714ead5e6..3b844f7993 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -181,6 +181,16 @@ tor_addr_make_unspec(tor_addr_t *a)
a->family = AF_UNSPEC;
}
+/** Set address <a>a</b> to the null address in address family <b>family</b>.
+ * The null address for AF_INET is 0.0.0.0. The null address for AF_INET6 is
+ * [::]. AF_UNSPEC is all null. */
+void
+tor_addr_make_null(tor_addr_t *a, sa_family_t family)
+{
+ memset(a, 0, sizeof(*a));
+ a->family = family;
+}
+
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* *<b>addr</b> to the proper IP address and family. The <b>family</b>
* argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a
@@ -559,9 +569,22 @@ tor_addr_to_PTR_name(char *out, size_t outlen,
*
* Return an address family on success, or -1 if an invalid address string is
* provided.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is false, then the wildcard address '*'
+ * yield an IPv4 wildcard.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is true, then the wildcard address '*'
+ * yields an AF_UNSPEC wildcard address, and the following change is made
+ * in the grammar above:
+ * Address ::= IPv4Address / "[" IPv6Address "]" / "*" / "*4" / "*6"
+ * with the new "*4" and "*6" productions creating a wildcard to match
+ * IPv4 or IPv6 addresses.
+ *
*/
int
-tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
+tor_addr_parse_mask_ports(const char *s,
+ unsigned flags,
+ tor_addr_t *addr_out,
maskbits_t *maskbits_out,
uint16_t *port_min_out, uint16_t *port_max_out)
{
@@ -618,9 +641,23 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
memset(addr_out, 0, sizeof(tor_addr_t));
if (!strcmp(address, "*")) {
- family = AF_INET; /* AF_UNSPEC ???? XXXX_IP6 */
+ if (flags & TAPMP_EXTENDED_STAR) {
+ family = AF_UNSPEC;
+ tor_addr_make_unspec(addr_out);
+ } else {
+ family = AF_INET;
+ tor_addr_from_ipv4h(addr_out, 0);
+ }
+ any_flag = 1;
+ } else if (!strcmp(address, "*4") && (flags & TAPMP_EXTENDED_STAR)) {
+ family = AF_INET;
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
+ } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
+ static char nil_bytes[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ family = AF_INET6;
+ tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
+ any_flag = 1;
} else if (tor_inet_pton(AF_INET6, address, &in6_tmp) > 0) {
family = AF_INET6;
tor_addr_from_in6(addr_out, &in6_tmp);
@@ -1393,7 +1430,46 @@ 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
+/** Given an address of the form "ip:port", try to divide it into its
+ * ip and port portions, setting *<b>address_out</b> to a newly
+ * allocated string holding the address portion and *<b>port_out</b>
+ * to the port.
+ *
+ * Don't do DNS lookups and don't allow domain names in the <ip> field.
+ * Don't accept <b>addrport</b> of the form "<ip>" or "<ip>:0".
+ *
+ * Return 0 on success, -1 on failure. */
+int
+tor_addr_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out)
+{
+ int retval = -1;
+ int r;
+ char *addr_tmp = NULL;
+
+ tor_assert(addrport);
+ tor_assert(address_out);
+ tor_assert(port_out);
+
+ r = tor_addr_port_split(severity, addrport, &addr_tmp, port_out);
+ if (r < 0)
+ goto done;
+
+ if (!*port_out)
+ goto done;
+
+ /* make sure that address_out is an IP address */
+ if (tor_addr_parse(address_out, addr_tmp) < 0)
+ goto done;
+
+ retval = 0;
+
+ done:
+ tor_free(addr_tmp);
+ return retval;
+}
+
+/** 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. */
diff --git a/src/common/address.h b/src/common/address.h
index 067b7a0ca6..0e2bbdcf88 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -55,6 +55,7 @@ socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port,
int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
+void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
@@ -183,7 +184,8 @@ int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
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,
+#define TAPMP_EXTENDED_STAR 1
+int tor_addr_parse_mask_ports(const char *s, unsigned flags,
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, size_t len,
@@ -206,6 +208,9 @@ 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_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out);
+
int tor_addr_hostname_is_local(const char *name);
/* IPv4 helpers */
diff --git a/src/common/aes.c b/src/common/aes.c
index 8e489baae1..2d64b85944 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -106,7 +106,7 @@ aes_cipher_free(aes_cnt_cipher_t *cipher)
if (!cipher)
return;
EVP_CIPHER_CTX_cleanup(&cipher->evp);
- memset(cipher, 0, sizeof(aes_cnt_cipher_t));
+ memwipe(cipher, 0, sizeof(aes_cnt_cipher_t));
tor_free(cipher);
}
void
@@ -373,7 +373,7 @@ aes_cipher_free(aes_cnt_cipher_t *cipher)
if (cipher->using_evp) {
EVP_CIPHER_CTX_cleanup(&cipher->key.evp);
}
- memset(cipher, 0, sizeof(aes_cnt_cipher_t));
+ memwipe(cipher, 0, sizeof(aes_cnt_cipher_t));
tor_free(cipher);
}
diff --git a/src/common/compat.c b/src/common/compat.c
index 2a4763c0fc..d0e516c2ce 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -332,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
diff --git a/src/common/crypto.c b/src/common/crypto.c
index c5844046e8..39f5a4a642 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -444,7 +444,7 @@ crypto_cipher_free(crypto_cipher_t *env)
tor_assert(env->cipher);
aes_cipher_free(env->cipher);
- memset(env, 0, sizeof(crypto_cipher_t));
+ memwipe(env, 0, sizeof(crypto_cipher_t));
tor_free(env);
}
@@ -544,7 +544,7 @@ crypto_pk_read_private_key_from_filename(crypto_pk_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.*/
@@ -686,7 +686,7 @@ crypto_pk_write_private_key_to_filename(crypto_pk_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;
}
@@ -1012,7 +1012,7 @@ crypto_pk_private_sign_digest(crypto_pk_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;
}
@@ -1076,14 +1076,14 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_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_cipher_free(cipher);
tor_assert(outlen+symlen < INT_MAX);
return (int)(outlen + symlen);
err:
- memset(buf, 0, pkeylen);
+ memwipe(buf, 0, pkeylen);
tor_free(buf);
crypto_cipher_free(cipher);
return -1;
@@ -1134,13 +1134,13 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_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_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);
crypto_cipher_free(cipher);
return -1;
@@ -1540,7 +1540,7 @@ crypto_digest_free(crypto_digest_t *digest)
{
if (!digest)
return;
- memset(digest, 0, sizeof(crypto_digest_t));
+ memwipe(digest, 0, sizeof(crypto_digest_t));
tor_free(digest);
}
@@ -1602,7 +1602,7 @@ crypto_digest_get_digest(crypto_digest_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
@@ -2187,7 +2187,7 @@ crypto_dh_compute_secret(int severity, crypto_dh_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)
@@ -2222,15 +2222,15 @@ 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;
}
@@ -2320,7 +2320,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
@@ -2337,7 +2337,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;
}
@@ -2736,7 +2736,7 @@ digest256_from_base64(char *digest, const char *d64)
#endif
}
-/** Implements base32 encoding as in rfc3548. Limitation: Requires
+/** Implements base32 encoding as in RFC 4648. Limitation: Requires
* that srclen*8 is a multiple of 5.
*/
void
@@ -2761,7 +2761,7 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
dest[i] = '\0';
}
-/** Implements base32 decoding as in rfc3548. Limitation: Requires
+/** Implements base32 decoding as in RFC 4648. Limitation: Requires
* that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
*/
int
@@ -2820,7 +2820,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;
@@ -2865,11 +2865,54 @@ 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_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
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
static void
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 0782ee57f1..4c5fa6ad97 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -273,6 +273,9 @@ 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, crypto.c, and the
* unit tests. */
diff --git a/src/common/mempool.c b/src/common/mempool.c
index 0d2580dcaf..78d4da6f76 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include "torint.h"
+#include "crypto.h"
#define MEMPOOL_PRIVATE
#include "mempool.h"
@@ -509,7 +510,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/tortls.c b/src/common/tortls.c
index d4f02d3d38..af3059a02d 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -713,7 +713,7 @@ tor_cert_free(tor_cert_t *cert)
if (cert->cert)
X509_free(cert->cert);
tor_free(cert->encoded);
- memset(cert, 0x03, sizeof(*cert));
+ memwipe(cert, 0x03, sizeof(*cert));
tor_free(cert);
}
@@ -2077,7 +2077,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem)
BIO_get_mem_ptr(bio, &buf);
s2 = tor_strndup(buf->data, buf->length);
- strftime(mytime, 32, "%b %d %H:%M:%S %Y GMT", tor_gmtime_r(&now, &tm));
+ strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm));
log(severity, LD_GENERAL,
"(certificate lifetime runs from %s through %s. Your time is %s.)",
@@ -2450,7 +2450,7 @@ tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
(char*)tls->ssl->session->master_key,
tls->ssl->session->master_key_length,
buf, len);
- memset(buf, 0, sizeof(buf));
+ memwipe(buf, 0, sizeof(buf));
return 0;
}
diff --git a/src/common/util.c b/src/common/util.c
index 75eb233bef..61d09aa4a8 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1342,7 +1342,7 @@ n_leapdays(int y1, int y2)
static const int days_per_month[] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-/** Compute a time_t given a struct tm. The result is given in GMT, and
+/** Compute a time_t given a struct tm. The result is given in UTC, and
* does not account for leap seconds. Return 0 on success, -1 on failure.
*/
int
@@ -1383,10 +1383,11 @@ static const char *MONTH_NAMES[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-/** Set <b>buf</b> to the RFC1123 encoding of the GMT value of <b>t</b>.
+/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>.
* The buffer must be at least RFC1123_TIME_LEN+1 bytes long.
*
- * (RFC1123 format is Fri, 29 Sep 2006 15:54:20 GMT)
+ * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT"
+ * rather than "UTC".)
*/
void
format_rfc1123_time(char *buf, time_t t)
@@ -1404,8 +1405,11 @@ format_rfc1123_time(char *buf, time_t t)
memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
}
-/** Parse the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
- * and store the result in *<b>t</b>.
+/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from
+ * <b>buf</b>, and store the result in *<b>t</b>.
+ *
+ * Note that we only accept the subset generated by format_rfc1123_time above,
+ * not the full range of formats suggested by RFC 1123.
*
* Return 0 on success, -1 on failure.
*/
@@ -4461,6 +4465,25 @@ tor_split_lines(smartlist_t *sl, char *buf, int len)
return smartlist_len(sl);
}
+/** Return a string corresponding to <b>stream_status</b>. */
+const char *
+stream_status_to_string(enum stream_status stream_status)
+{
+ switch (stream_status) {
+ case IO_STREAM_OKAY:
+ return "okay";
+ case IO_STREAM_EAGAIN:
+ return "temporarily unavailable";
+ case IO_STREAM_TERM:
+ return "terminated";
+ case IO_STREAM_CLOSED:
+ return "closed";
+ default:
+ tor_fragile_assert();
+ return "unknown";
+ }
+}
+
#ifdef _WIN32
/** Return a smartlist containing lines outputted from
diff --git a/src/common/util.h b/src/common/util.h
index aa2087b013..fabfdb19fd 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -307,6 +307,8 @@ enum stream_status {
IO_STREAM_CLOSED
};
+const char *stream_status_to_string(enum stream_status stream_status);
+
enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
/** Return values from file_status(); see that function's documentation