diff options
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r-- | src/common/crypto.c | 232 |
1 files changed, 105 insertions, 127 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index 30990ecc8f..6c3dd8d4a4 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -57,8 +57,8 @@ #include "container.h" #include "compat.h" -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7) -#error "We require OpenSSL >= 0.9.7" +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) +#error "We require OpenSSL >= 0.9.8" #endif #ifdef ANDROID @@ -69,31 +69,6 @@ /** 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 - * to our needs. These macros make it usable by us. */ -#define SHA256_CTX sha256_state -#define SHA256_Init sha256_init -#define SHA256_Update sha256_process -#define LTC_ARGCHK(x) tor_assert(x) -/** @} */ -#include "sha256.c" -#define SHA256_Final(a,b) sha256_done(b,a) - -static unsigned char * -SHA256(const unsigned char *m, size_t len, unsigned char *d) -{ - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, m, len); - SHA256_Final(d, &ctx); - return d; -} -#endif - /** Macro: is k a valid RSA public or private key? */ #define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n) /** Macro: is k a valid RSA private key? */ @@ -101,9 +76,9 @@ SHA256(const unsigned char *m, size_t len, unsigned char *d) #ifdef TOR_IS_MULTITHREADED /** A number of preallocated mutexes for use by OpenSSL. */ -static tor_mutex_t **_openssl_mutexes = NULL; +static tor_mutex_t **openssl_mutexes_ = NULL; /** How many mutexes have we allocated for use by OpenSSL? */ -static int _n_openssl_mutexes = 0; +static int n_openssl_mutexes_ = 0; #endif /** A public key, or a public/private key-pair. */ @@ -158,7 +133,7 @@ crypto_get_rsa_padding(int padding) } /** Boolean: has OpenSSL's crypto been initialized? */ -static int _crypto_global_initialized = 0; +static int crypto_global_initialized_ = 0; /** Log all pending crypto errors at level <b>severity</b>. Use * <b>doing</b> to describe our current activities. @@ -221,16 +196,60 @@ try_load_engine(const char *path, const char *engine) } #endif +static char *crypto_openssl_version_str = NULL; +/* Return a human-readable version of the run-time openssl version number. */ +const char * +crypto_openssl_get_version_str(void) +{ + if (crypto_openssl_version_str == NULL) { + const char *raw_version = SSLeay_version(SSLEAY_VERSION); + const char *end_of_version = NULL; + /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's + trim that down. */ + if (!strcmpstart(raw_version, "OpenSSL ")) { + raw_version += strlen("OpenSSL "); + end_of_version = strchr(raw_version, ' '); + } + + if (end_of_version) + crypto_openssl_version_str = tor_strndup(raw_version, + end_of_version-raw_version); + else + crypto_openssl_version_str = tor_strdup(raw_version); + } + return crypto_openssl_version_str; +} + /** Initialize the crypto library. Return 0 on success, -1 on failure. */ int crypto_global_init(int useAccel, const char *accelName, const char *accelDir) { - if (!_crypto_global_initialized) { + if (!crypto_global_initialized_) { ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); - _crypto_global_initialized = 1; + crypto_global_initialized_ = 1; setup_openssl_threading(); + + if (SSLeay() == OPENSSL_VERSION_NUMBER && + !strcmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT)) { + log_info(LD_CRYPTO, "OpenSSL version matches version from headers " + "(%lx: %s).", SSLeay(), SSLeay_version(SSLEAY_VERSION)); + } else { + log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " + "version we're running with. If you get weird crashes, that " + "might be why. (Compiled with %lx: %s; running with %lx: %s).", + (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, + 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()); + } + if (useAccel > 0) { #ifdef DISABLE_ENGINES (void)accelName; @@ -294,7 +313,7 @@ crypto_thread_cleanup(void) /** used by tortls.c: wrap an RSA* in a crypto_pk_t. */ crypto_pk_t * -_crypto_new_pk_from_rsa(RSA *rsa) +crypto_new_pk_from_rsa_(RSA *rsa) { crypto_pk_t *env; tor_assert(rsa); @@ -307,7 +326,7 @@ _crypto_new_pk_from_rsa(RSA *rsa) /** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a * crypto_pk_t. */ RSA * -_crypto_pk_get_rsa(crypto_pk_t *env) +crypto_pk_get_rsa_(crypto_pk_t *env) { return env->key; } @@ -315,7 +334,7 @@ _crypto_pk_get_rsa(crypto_pk_t *env) /** 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_get_evp_pkey(crypto_pk_t *env, int private) +crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private) { RSA *key = NULL; EVP_PKEY *pkey = NULL; @@ -343,7 +362,7 @@ _crypto_pk_get_evp_pkey(crypto_pk_t *env, int private) /** Used by tortls.c: Get the DH* from a crypto_dh_t. */ DH * -_crypto_dh_get_dh(crypto_dh_t *dh) +crypto_dh_get_dh_(crypto_dh_t *dh) { return dh->dh; } @@ -358,7 +377,7 @@ crypto_pk_new(void) rsa = RSA_new(); tor_assert(rsa); - return _crypto_new_pk_from_rsa(rsa); + return crypto_new_pk_from_rsa_(rsa); } /** Release a reference to an asymmetric key; when all the references @@ -441,11 +460,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits) if (env->key) RSA_free(env->key); -#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 - /* In OpenSSL 0.9.8, RSA_generate_key is deprecated. */ + { BIGNUM *e = BN_new(); RSA *r = NULL; @@ -466,8 +481,8 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits) BN_free(e); if (r) RSA_free(r); - } -#endif + } + if (!env->key) { crypto_log_errors(LOG_WARN, "generating RSA key"); return -1; @@ -711,19 +726,23 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env) return BN_is_word(env->key->e, 65537); } -/** Compare the public-key components of a and b. Return -1 if a\<b, 0 - * if a==b, and 1 if a\>b. +/** Compare the public-key components of a and b. Return less than 0 + * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is + * considered to be less than all non-NULL keys, and equal to itself. + * + * Note that this may leak information about the keys through timing. */ int crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b) { int result; + char a_is_non_null = (a != NULL) && (a->key != NULL); + char b_is_non_null = (b != NULL) && (b->key != NULL); + char an_argument_is_null = !a_is_non_null | !b_is_non_null; - if (!a || !b) - return -1; - - if (!a->key || !b->key) - return -1; + result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null)); + if (an_argument_is_null) + return result; tor_assert(PUBLIC_KEY_OK(a)); tor_assert(PUBLIC_KEY_OK(b)); @@ -733,6 +752,18 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b) return BN_cmp((a->key)->e, (b->key)->e); } +/** Compare the public-key components of a and b. Return non-zero iff + * a==b. A NULL key is considered to be distinct from all non-NULL + * keys, and equal to itself. + * + * Note that this may leak information about the keys through timing. + */ +int +crypto_pk_eq_keys(crypto_pk_t *a, 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) @@ -791,7 +822,7 @@ crypto_pk_copy_full(crypto_pk_t *env) return NULL; } - return _crypto_new_pk_from_rsa(new_key); + return crypto_new_pk_from_rsa_(new_key); } /** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key @@ -1158,7 +1189,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_from_rsa(rsa); + return crypto_new_pk_from_rsa_(rsa); } /** Given a private or public key <b>pk</b>, put a SHA1 hash of the @@ -1623,63 +1654,11 @@ crypto_hmac_sha256(char *hmac_out, const char *key, size_t key_len, const char *msg, size_t msg_len) { -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,8) /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ tor_assert(key_len < INT_MAX); tor_assert(msg_len < INT_MAX); HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, (unsigned char*)hmac_out, NULL); -#else - /* OpenSSL doesn't have an EVP implementation for SHA256. We'll need - to do HMAC on our own. - - HMAC isn't so hard: To compute HMAC(key, msg): - 1. If len(key) > blocksize, key = H(key). - 2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes. - 3. let ipad = key xor 0x363636363636....36 - let opad = key xor 0x5c5c5c5c5c5c....5c - The result is H(opad | H( ipad | msg ) ) - */ -#define BLOCKSIZE 64 -#define DIGESTSIZE 32 - uint8_t k[BLOCKSIZE]; - uint8_t pad[BLOCKSIZE]; - uint8_t d[DIGESTSIZE]; - int i; - SHA256_CTX st; - - tor_assert(key_len < INT_MAX); - tor_assert(msg_len < INT_MAX); - - if (key_len <= BLOCKSIZE) { - memset(k, 0, sizeof(k)); - memcpy(k, key, key_len); /* not time invariant in key_len */ - } else { - SHA256((const uint8_t *)key, key_len, k); - memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE); - } - for (i = 0; i < BLOCKSIZE; ++i) - pad[i] = k[i] ^ 0x36; - SHA256_Init(&st); - SHA256_Update(&st, pad, BLOCKSIZE); - SHA256_Update(&st, (uint8_t*)msg, msg_len); - SHA256_Final(d, &st); - - for (i = 0; i < BLOCKSIZE; ++i) - pad[i] = k[i] ^ 0x5c; - SHA256_Init(&st); - SHA256_Update(&st, pad, BLOCKSIZE); - SHA256_Update(&st, d, DIGESTSIZE); - SHA256_Final((uint8_t*)hmac_out, &st); - - /* Now clear everything. */ - 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 } /* DH */ @@ -2282,9 +2261,7 @@ crypto_dh_free(crypto_dh_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 >= OPENSSL_V(0,9,7,'j') && \ - OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)) || \ - OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c')) + (OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c')) /** Set the seed of the weak RNG to a random value. */ static void @@ -2939,19 +2916,19 @@ memwipe(void *mem, uint8_t byte, size_t sz) #ifdef TOR_IS_MULTITHREADED /** Helper: OpenSSL uses this callback to manipulate mutexes. */ static void -_openssl_locking_cb(int mode, int n, const char *file, int line) +openssl_locking_cb_(int mode, int n, const char *file, int line) { (void)file; (void)line; - if (!_openssl_mutexes) + if (!openssl_mutexes_) /* This is not a really good fix for the * "release-freed-lock-from-separate-thread-on-shutdown" problem, but * it can't hurt. */ return; if (mode & CRYPTO_LOCK) - tor_mutex_acquire(_openssl_mutexes[n]); + tor_mutex_acquire(openssl_mutexes_[n]); else - tor_mutex_release(_openssl_mutexes[n]); + tor_mutex_release(openssl_mutexes_[n]); } /** OpenSSL helper type: wraps a Tor mutex so that OpenSSL can use it @@ -2963,7 +2940,7 @@ struct CRYPTO_dynlock_value { /** OpenSSL callback function to allocate a lock: see CRYPTO_set_dynlock_* * documentation in OpenSSL's docs for more info. */ static struct CRYPTO_dynlock_value * -_openssl_dynlock_create_cb(const char *file, int line) +openssl_dynlock_create_cb_(const char *file, int line) { struct CRYPTO_dynlock_value *v; (void)file; @@ -2976,7 +2953,7 @@ _openssl_dynlock_create_cb(const char *file, int line) /** OpenSSL callback function to acquire or release a lock: see * CRYPTO_set_dynlock_* documentation in OpenSSL's docs for more info. */ static void -_openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v, +openssl_dynlock_lock_cb_(int mode, struct CRYPTO_dynlock_value *v, const char *file, int line) { (void)file; @@ -2990,7 +2967,7 @@ _openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v, /** OpenSSL callback function to free a lock: see CRYPTO_set_dynlock_* * documentation in OpenSSL's docs for more info. */ static void -_openssl_dynlock_destroy_cb(struct CRYPTO_dynlock_value *v, +openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v, const char *file, int line) { (void)file; @@ -3007,15 +2984,15 @@ setup_openssl_threading(void) { int i; int n = CRYPTO_num_locks(); - _n_openssl_mutexes = n; - _openssl_mutexes = tor_malloc(n*sizeof(tor_mutex_t *)); + n_openssl_mutexes_ = n; + openssl_mutexes_ = tor_malloc(n*sizeof(tor_mutex_t *)); for (i=0; i < n; ++i) - _openssl_mutexes[i] = tor_mutex_new(); - CRYPTO_set_locking_callback(_openssl_locking_cb); + openssl_mutexes_[i] = tor_mutex_new(); + CRYPTO_set_locking_callback(openssl_locking_cb_); CRYPTO_set_id_callback(tor_get_thread_id); - 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); + 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_); return 0; } #else @@ -3049,18 +3026,19 @@ crypto_global_cleanup(void) 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; + if (n_openssl_mutexes_) { + int n = n_openssl_mutexes_; + tor_mutex_t **ms = openssl_mutexes_; int i; - _openssl_mutexes = NULL; - _n_openssl_mutexes = 0; + openssl_mutexes_ = NULL; + n_openssl_mutexes_ = 0; for (i=0;i<n;++i) { tor_mutex_free(ms[i]); } tor_free(ms); } #endif + tor_free(crypto_openssl_version_str); return 0; } |