diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/address.c | 82 | ||||
-rw-r--r-- | src/common/address.h | 7 | ||||
-rw-r--r-- | src/common/aes.c | 4 | ||||
-rw-r--r-- | src/common/compat.c | 2 | ||||
-rw-r--r-- | src/common/crypto.c | 85 | ||||
-rw-r--r-- | src/common/crypto.h | 3 | ||||
-rw-r--r-- | src/common/mempool.c | 3 | ||||
-rw-r--r-- | src/common/tortls.c | 6 | ||||
-rw-r--r-- | src/common/util.c | 33 | ||||
-rw-r--r-- | src/common/util.h | 2 |
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 |