diff options
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r-- | src/common/crypto.c | 850 |
1 files changed, 196 insertions, 654 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index 8402ca079a..57981f9a00 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -13,10 +13,7 @@ #include "orconfig.h" #ifdef _WIN32 -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif -#define WIN32_LEAN_AND_MEAN +#include <winsock2.h> #include <windows.h> #include <wincrypt.h> /* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually @@ -24,13 +21,24 @@ #undef OCSP_RESPONSE #endif +#include <openssl/opensslv.h> + +#define CRYPTO_PRIVATE +#include "crypto.h" +#include "crypto_curve25519.h" +#include "crypto_ed25519.h" +#include "crypto_format.h" + +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) +#error "We require OpenSSL >= 1.0.0" +#endif + #include <openssl/err.h> #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/evp.h> #include <openssl/engine.h> #include <openssl/rand.h> -#include <openssl/opensslv.h> #include <openssl/bn.h> #include <openssl/dh.h> #include <openssl/conf.h> @@ -49,18 +57,13 @@ #include <sys/fcntl.h> #endif -#define CRYPTO_PRIVATE -#include "crypto.h" -#include "../common/torlog.h" +#include "torlog.h" #include "aes.h" -#include "../common/util.h" +#include "util.h" #include "container.h" #include "compat.h" #include "sandbox.h" - -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) -#error "We require OpenSSL >= 0.9.8" -#endif +#include "util_format.h" #ifdef ANDROID /* Android's OpenSSL seems to have removed all of its Engine support. */ @@ -300,19 +303,15 @@ crypto_early_init(void) SSLeay(), SSLeay_version(SSLEAY_VERSION)); } - if (SSLeay() < OPENSSL_V_SERIES(1,0,0)) { - log_notice(LD_CRYPTO, - "Your OpenSSL version seems to be %s. We recommend 1.0.0 " - "or later.", - crypto_openssl_get_version_str()); - } - crypto_force_rand_ssleay(); - if (crypto_seed_rng(1) < 0) + if (crypto_seed_rng() < 0) return -1; if (crypto_init_siphash_key() < 0) return -1; + + curve25519_init(); + ed25519_init(); } return 0; } @@ -391,7 +390,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir) } if (crypto_force_rand_ssleay()) { - if (crypto_seed_rng(1) < 0) + if (crypto_seed_rng() < 0) return -1; } @@ -405,7 +404,11 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir) void crypto_thread_cleanup(void) { +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + ERR_remove_thread_state(NULL); +#else ERR_remove_state(0); +#endif } /** used by tortls.c: wrap an RSA* in a crypto_pk_t. */ @@ -830,7 +833,7 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env) * Note that this may leak information about the keys through timing. */ int -crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b) +crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b) { int result; char a_is_non_null = (a != NULL) && (a->key != NULL); @@ -856,19 +859,19 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b) * Note that this may leak information about the keys through timing. */ int -crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b) +crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b) { return (crypto_pk_cmp_keys(a, b) == 0); } /** Return the size of the public key modulus in <b>env</b>, in bytes. */ size_t -crypto_pk_keysize(crypto_pk_t *env) +crypto_pk_keysize(const crypto_pk_t *env) { tor_assert(env); tor_assert(env->key); - return (size_t) RSA_size(env->key); + return (size_t) RSA_size((RSA*)env->key); } /** Return the size of the public key modulus of <b>env</b>, in bits. */ @@ -997,7 +1000,7 @@ crypto_pk_private_decrypt(crypto_pk_t *env, char *to, * at least the length of the modulus of <b>env</b>. */ int -crypto_pk_public_checksig(crypto_pk_t *env, char *to, +crypto_pk_public_checksig(const crypto_pk_t *env, char *to, size_t tolen, const char *from, size_t fromlen) { @@ -1069,7 +1072,7 @@ crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data, * at least the length of the modulus of <b>env</b>. */ int -crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen, +crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen, const char *from, size_t fromlen) { int r; @@ -1084,7 +1087,7 @@ crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen, r = RSA_private_encrypt((int)fromlen, (unsigned char*)from, (unsigned char*)to, - env->key, RSA_PKCS1_PADDING); + (RSA*)env->key, RSA_PKCS1_PADDING); if (r<0) { crypto_log_errors(LOG_WARN, "generating RSA signature"); return -1; @@ -1298,7 +1301,7 @@ crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out) unsigned char *buf = NULL; int len; - len = i2d_RSAPublicKey(pk->key, &buf); + len = i2d_RSAPublicKey((RSA*)pk->key, &buf); if (len < 0 || buf == NULL) return -1; if (crypto_digest(digest_out, (char*)buf, len) < 0) { @@ -1397,6 +1400,78 @@ crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out) return 0; } +/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the + * Base64 encoding of the DER representation of the private key as a NUL + * terminated string, and return it via <b>priv_out</b>. Return 0 on + * sucess, -1 on failure. + * + * It is the caller's responsibility to sanitize and free the resulting buffer. + */ +int +crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out) +{ + unsigned char *der = NULL; + int der_len; + int ret = -1; + + *priv_out = NULL; + + der_len = i2d_RSAPrivateKey(pk->key, &der); + if (der_len < 0 || der == NULL) + return ret; + + size_t priv_len = base64_encode_size(der_len, 0) + 1; + char *priv = tor_malloc_zero(priv_len); + if (base64_encode(priv, priv_len, (char *)der, der_len, 0) >= 0) { + *priv_out = priv; + ret = 0; + } else { + tor_free(priv); + } + + memwipe(der, 0, der_len); + OPENSSL_free(der); + return ret; +} + +/** Given a string containing the Base64 encoded DER representation of the + * private key <b>str</b>, decode and return the result on success, or NULL + * on failure. + */ +crypto_pk_t * +crypto_pk_base64_decode(const char *str, size_t len) +{ + crypto_pk_t *pk = NULL; + + char *der = tor_malloc_zero(len + 1); + int der_len = base64_decode(der, len, str, len); + if (der_len <= 0) { + log_warn(LD_CRYPTO, "Stored RSA private key seems corrupted (base64)."); + goto out; + } + + const unsigned char *dp = (unsigned char*)der; /* Shut the compiler up. */ + RSA *rsa = d2i_RSAPrivateKey(NULL, &dp, der_len); + if (!rsa) { + crypto_log_errors(LOG_WARN, "decoding private key"); + goto out; + } + + pk = crypto_new_pk_from_rsa_(rsa); + + /* Make sure it's valid. */ + if (crypto_pk_check_key(pk) <= 0) { + crypto_pk_free(pk); + pk = NULL; + goto out; + } + + out: + memwipe(der, 0, len + 1); + tor_free(der); + return pk; +} + /* symmetric crypto */ /** Return a pointer to the key set for the cipher in <b>env</b>. @@ -1724,7 +1799,24 @@ crypto_digest_assign(crypto_digest_t *into, * <b>out_len</b> must be \<= DIGEST256_LEN. */ void crypto_digest_smartlist(char *digest_out, size_t len_out, - const smartlist_t *lst, const char *append, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); +} + +/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest + * at <b>digest_out</b> to the hash of the concatenation of: the + * optional string <b>prepend</b>, those strings, + * and the optional string <b>append</b>, computed with the algorithm + * <b>alg</b>. + * <b>out_len</b> must be \<= DIGEST256_LEN. */ +void +crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, + const char *prepend, + const smartlist_t *lst, + const char *append, digest_algorithm_t alg) { crypto_digest_t *d; @@ -1732,6 +1824,8 @@ crypto_digest_smartlist(char *digest_out, size_t len_out, d = crypto_digest_new(); else d = crypto_digest256_new(alg); + if (prepend) + crypto_digest_add_bytes(d, prepend, strlen(prepend)); SMARTLIST_FOREACH(lst, const char *, cp, crypto_digest_add_bytes(d, cp, strlen(cp))); if (append) @@ -1768,235 +1862,12 @@ 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_new(); - tor_assert(dh_parameters); - - r = DH_generate_parameters_ex(dh_parameters, - DH_BYTES*8, DH_GENERATOR, NULL); - tor_assert(r == 0); - - 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; - 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, &dh_string_repr); - if ((len < 0) || (dh_string_repr == NULL)) { - log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2)."); - goto done; - } - - base64_encoded_dh = tor_calloc(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); - if (dh_string_repr) - OPENSSL_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 +/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH * modulus. */ void -crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) +crypto_set_tls_dh_prime(void) { BIGNUM *tls_prime = NULL; - int store_dh_prime_afterwards = 0; int r; /* If the space is occupied, free the previous TLS DH prime */ @@ -2005,44 +1876,24 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) 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(); + tls_prime = BN_new(); + tor_assert(tls_prime); - 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); - } + /* 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 @@ -2079,10 +1930,8 @@ init_dh_param(void) 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); + crypto_set_tls_dh_prime(); } } @@ -2134,6 +1983,8 @@ crypto_dh_t * crypto_dh_dup(const crypto_dh_t *dh) { crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); + tor_assert(dh); + tor_assert(dh->dh); dh_new->dh = dh->dh; DH_up_ref(dh->dh); return dh_new; @@ -2419,15 +2270,6 @@ crypto_dh_free(crypto_dh_t *dh) * work for us too. */ #define ADD_ENTROPY 32 -/** 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 - * would allocate an fd_set on the stack, open a new file, and try to FD_SET - * 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 >= OPENSSL_V(0,9,8,'c')) - /** Set the seed of the weak RNG to a random value. */ void crypto_seed_weak_rng(tor_weak_rng_t *rng) @@ -2497,7 +2339,7 @@ crypto_strongest_rand(uint8_t *out, size_t out_len) * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure. */ int -crypto_seed_rng(int startup) +crypto_seed_rng(void) { int rand_poll_ok = 0, load_entropy_ok = 0; uint8_t buf[ADD_ENTROPY]; @@ -2505,11 +2347,9 @@ crypto_seed_rng(int startup) /* 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) { - rand_poll_ok = RAND_poll(); - if (rand_poll_ok == 0) - log_warn(LD_CRYPTO, "RAND_poll() failed."); - } + rand_poll_ok = RAND_poll(); + if (rand_poll_ok == 0) + log_warn(LD_CRYPTO, "RAND_poll() failed."); load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf)); if (load_entropy_ok) { @@ -2525,11 +2365,20 @@ crypto_seed_rng(int startup) } /** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on - * success, -1 on failure. + * success, -1 on failure, with support for mocking for unit tests. */ MOCK_IMPL(int, crypto_rand, (char *to, size_t n)) { + return crypto_rand_unmocked(to, n); +} + +/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on + * success, -1 on failure. Most callers will want crypto_rand instead. + */ +int +crypto_rand_unmocked(char *to, size_t n) +{ int r; tor_assert(n < INT_MAX); tor_assert(to); @@ -2562,8 +2411,41 @@ crypto_rand_int(unsigned int max) } } +/** Return a pseudorandom integer, chosen uniformly from the values <i>i</i> + * such that <b>min</b> <= <i>i</i> < <b>max</b>. + * + * <b>min</b> MUST be in range [0, <b>max</b>). + * <b>max</b> MUST be in range (min, INT_MAX]. + */ +int +crypto_rand_int_range(unsigned int min, unsigned int max) +{ + tor_assert(min < max); + tor_assert(max <= INT_MAX); + + /* The overflow is avoided here because crypto_rand_int() returns a value + * between 0 and (max - min) inclusive. */ + return min + crypto_rand_int(max - min); +} + +/** As crypto_rand_int_range, but supports uint64_t. */ +uint64_t +crypto_rand_uint64_range(uint64_t min, uint64_t max) +{ + tor_assert(min < max); + return min + crypto_rand_uint64(max - min); +} + +/** As crypto_rand_int_range, but supports time_t. */ +time_t +crypto_rand_time_range(time_t min, time_t max) +{ + tor_assert(min < max); + return min + (time_t)crypto_rand_uint64(max - min); +} + /** Return a pseudorandom 64-bit integer, chosen uniformly from the values - * between 0 and <b>max</b>-1. */ + * between 0 and <b>max</b>-1 inclusive. */ uint64_t crypto_rand_uint64(uint64_t max) { @@ -2624,7 +2506,7 @@ crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix, 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); + randlen = crypto_rand_int_range(min_rand_len, max_rand_len+1); prefixlen = strlen(prefix); resultlen = prefixlen + strlen(suffix) + randlen + 16; @@ -2671,344 +2553,6 @@ smartlist_shuffle(smartlist_t *sl) } } -/** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write - * the result into <b>dest</b>, if it will fit within <b>destlen</b> - * bytes. Return the number of bytes written on success; -1 if - * destlen is too short, or other failure. - */ -int -base64_encode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - /* FFFF we might want to rewrite this along the lines of base64_decode, if - * it ever shows up in the profile. */ - EVP_ENCODE_CTX ctx; - int len, ret; - tor_assert(srclen < INT_MAX); - - /* 48 bytes of input -> 64 bytes of output plus newline. - Plus one more byte, in case I'm wrong. - */ - if (destlen < ((srclen/48)+1)*66) - return -1; - if (destlen > SIZE_T_CEILING) - return -1; - - EVP_EncodeInit(&ctx); - EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len, - (unsigned char*)src, (int)srclen); - EVP_EncodeFinal(&ctx, (unsigned char*)(dest+len), &ret); - ret += len; - return ret; -} - -/** @{ */ -/** Special values used for the base64_decode_table */ -#define X 255 -#define SP 64 -#define PAD 65 -/** @} */ -/** Internal table mapping byte values to what they represent in base64. - * Numbers 0..63 are 6-bit integers. SPs are spaces, and should be - * skipped. Xs are invalid and must not appear in base64. PAD indicates - * end-of-string. */ -static const uint8_t base64_decode_table[256] = { - X, X, X, X, X, X, X, X, X, SP, SP, SP, X, SP, X, X, /* */ - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - SP, X, X, X, X, X, X, X, X, X, X, 62, X, X, X, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, PAD, X, X, - X, 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, X, X, X, X, X, - X, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, -}; - -/** Base64 decode <b>srclen</b> bytes of data from <b>src</b>. Write - * the result into <b>dest</b>, if it will fit within <b>destlen</b> - * bytes. Return the number of bytes written on success; -1 if - * destlen is too short, or other failure. - * - * NOTE 1: destlen is checked conservatively, as though srclen contained no - * spaces or padding. - * - * NOTE 2: This implementation does not check for the correct number of - * padding "=" characters at the end of the string, and does not check - * for internal padding characters. - */ -int -base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) -{ -#ifdef USE_OPENSSL_BASE64 - EVP_ENCODE_CTX ctx; - int len, ret; - /* 64 bytes of input -> *up to* 48 bytes of output. - Plus one more byte, in case I'm wrong. - */ - if (destlen < ((srclen/64)+1)*49) - return -1; - if (destlen > SIZE_T_CEILING) - return -1; - - memset(dest, 0, destlen); - - EVP_DecodeInit(&ctx); - EVP_DecodeUpdate(&ctx, (unsigned char*)dest, &len, - (unsigned char*)src, srclen); - EVP_DecodeFinal(&ctx, (unsigned char*)dest, &ret); - ret += len; - return ret; -#else - const char *eos = src+srclen; - uint32_t n=0; - int n_idx=0; - char *dest_orig = dest; - - /* Max number of bits == srclen*6. - * Number of bytes required to hold all bits == (srclen*6)/8. - * Yes, we want to round down: anything that hangs over the end of a - * byte is padding. */ - if (destlen < (srclen*3)/4) - return -1; - if (destlen > SIZE_T_CEILING) - return -1; - - memset(dest, 0, destlen); - - /* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the - * value we're decoding. Accumulate bits in <b>n</b>, and whenever we have - * 24 bits, batch them into 3 bytes and flush those bytes to dest. - */ - for ( ; src < eos; ++src) { - unsigned char c = (unsigned char) *src; - uint8_t v = base64_decode_table[c]; - switch (v) { - case X: - /* This character isn't allowed in base64. */ - return -1; - case SP: - /* This character is whitespace, and has no effect. */ - continue; - case PAD: - /* We've hit an = character: the data is over. */ - goto end_of_loop; - default: - /* We have an actual 6-bit value. Append it to the bits in n. */ - n = (n<<6) | v; - if ((++n_idx) == 4) { - /* We've accumulated 24 bits in n. Flush them. */ - *dest++ = (n>>16); - *dest++ = (n>>8) & 0xff; - *dest++ = (n) & 0xff; - n_idx = 0; - n = 0; - } - } - } - end_of_loop: - /* If we have leftover bits, we need to cope. */ - switch (n_idx) { - case 0: - default: - /* No leftover bits. We win. */ - break; - case 1: - /* 6 leftover bits. That's invalid; we can't form a byte out of that. */ - return -1; - case 2: - /* 12 leftover bits: The last 4 are padding and the first 8 are data. */ - *dest++ = n >> 4; - break; - case 3: - /* 18 leftover bits: The last 2 are padding and the first 16 are data. */ - *dest++ = n >> 10; - *dest++ = n >> 2; - } - - tor_assert((dest-dest_orig) <= (ssize_t)destlen); - tor_assert((dest-dest_orig) <= INT_MAX); - - return (int)(dest-dest_orig); -#endif -} -#undef X -#undef SP -#undef PAD - -/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing = - * and newline characters, and store the nul-terminated result in the first - * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */ -int -digest_to_base64(char *d64, const char *digest) -{ - char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST_LEN); - buf[BASE64_DIGEST_LEN] = '\0'; - memcpy(d64, buf, BASE64_DIGEST_LEN+1); - return 0; -} - -/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without - * trailing newline or = characters), decode it and store the result in the - * first DIGEST_LEN bytes at <b>digest</b>. */ -int -digest_from_base64(char *digest, const char *d64) -{ -#ifdef USE_OPENSSL_BASE64 - char buf_in[BASE64_DIGEST_LEN+3]; - char buf[256]; - if (strlen(d64) != BASE64_DIGEST_LEN) - return -1; - memcpy(buf_in, d64, BASE64_DIGEST_LEN); - memcpy(buf_in+BASE64_DIGEST_LEN, "=\n\0", 3); - if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST_LEN) - return -1; - memcpy(digest, buf, DIGEST_LEN); - return 0; -#else - if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN) - return 0; - else - return -1; -#endif -} - -/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the - * trailing = and newline characters, and store the nul-terminated result in - * the first BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */ -int -digest256_to_base64(char *d64, const char *digest) -{ - char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN); - buf[BASE64_DIGEST256_LEN] = '\0'; - memcpy(d64, buf, BASE64_DIGEST256_LEN+1); - return 0; -} - -/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without - * trailing newline or = characters), decode it and store the result in the - * first DIGEST256_LEN bytes at <b>digest</b>. */ -int -digest256_from_base64(char *digest, const char *d64) -{ -#ifdef USE_OPENSSL_BASE64 - char buf_in[BASE64_DIGEST256_LEN+3]; - char buf[256]; - if (strlen(d64) != BASE64_DIGEST256_LEN) - return -1; - memcpy(buf_in, d64, BASE64_DIGEST256_LEN); - memcpy(buf_in+BASE64_DIGEST256_LEN, "=\n\0", 3); - if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST256_LEN) - return -1; - memcpy(digest, buf, DIGEST256_LEN); - return 0; -#else - if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN) - return 0; - else - return -1; -#endif -} - -/** Implements base32 encoding as in RFC 4648. Limitation: Requires - * that srclen*8 is a multiple of 5. - */ -void -base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - unsigned int i, v, u; - size_t nbits = srclen * 8, bit; - - tor_assert(srclen < SIZE_T_CEILING/8); - tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */ - tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */ - tor_assert(destlen < SIZE_T_CEILING); - - for (i=0,bit=0; bit < nbits; ++i, bit+=5) { - /* set v to the 16-bit value starting at src[bits/8], 0-padded. */ - v = ((uint8_t)src[bit/8]) << 8; - if (bit+5<nbits) v += (uint8_t)src[(bit/8)+1]; - /* set u to the 5-bit value at the bit'th bit of src. */ - u = (v >> (11-(bit%8))) & 0x1F; - dest[i] = BASE32_CHARS[u]; - } - dest[i] = '\0'; -} - -/** Implements base32 decoding as in RFC 4648. Limitation: Requires - * that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise. - */ -int -base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - /* XXXX we might want to rewrite this along the lines of base64_decode, if - * it ever shows up in the profile. */ - unsigned int i; - size_t nbits, j, bit; - char *tmp; - nbits = srclen * 5; - - tor_assert(srclen < SIZE_T_CEILING / 5); - tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */ - tor_assert((nbits/8) <= destlen); /* We need enough space. */ - tor_assert(destlen < SIZE_T_CEILING); - - memset(dest, 0, destlen); - - /* Convert base32 encoded chars to the 5-bit values that they represent. */ - tmp = tor_malloc_zero(srclen); - for (j = 0; j < srclen; ++j) { - if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61; - else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18; - else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41; - else { - log_warn(LD_BUG, "illegal character in base32 encoded string"); - tor_free(tmp); - return -1; - } - } - - /* Assemble result byte-wise by applying five possible cases. */ - for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) { - switch (bit % 40) { - case 0: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) + - (((uint8_t)tmp[(bit/5)+1]) >> 2); - break; - case 8: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) + - (((uint8_t)tmp[(bit/5)+1]) << 1) + - (((uint8_t)tmp[(bit/5)+2]) >> 4); - break; - case 16: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) + - (((uint8_t)tmp[(bit/5)+1]) >> 1); - break; - case 24: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) + - (((uint8_t)tmp[(bit/5)+1]) << 2) + - (((uint8_t)tmp[(bit/5)+2]) >> 3); - break; - case 32: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) + - ((uint8_t)tmp[(bit/5)+1]); - break; - } - } - - memwipe(tmp, 0, srclen); - tor_free(tmp); - tmp = NULL; - return 0; -} - /** * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to * the value <b>byte</b>. @@ -3129,13 +2673,11 @@ openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v, tor_free(v); } -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0) static void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid) { CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id()); } -#endif /** @{ */ /** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being @@ -3150,11 +2692,7 @@ setup_openssl_threading(void) for (i=0; i < n; ++i) openssl_mutexes_[i] = tor_mutex_new(); CRYPTO_set_locking_callback(openssl_locking_cb_); -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) - CRYPTO_set_id_callback(tor_get_thread_id); -#else CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id); -#endif CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_); CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_); CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_); @@ -3167,7 +2705,11 @@ int crypto_global_cleanup(void) { EVP_cleanup(); +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + ERR_remove_thread_state(NULL); +#else ERR_remove_state(0); +#endif ERR_free_strings(); if (dh_param_p) |