diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/address.c | 4 | ||||
-rw-r--r-- | src/common/aes.c | 158 | ||||
-rw-r--r-- | src/common/aes.h | 2 | ||||
-rw-r--r-- | src/common/crypto.c | 90 | ||||
-rw-r--r-- | src/common/crypto.h | 2 | ||||
-rw-r--r-- | src/common/torint.h | 28 |
6 files changed, 106 insertions, 178 deletions
diff --git a/src/common/address.c b/src/common/address.c index 86c32efdd9..70675c0a7a 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -148,7 +148,9 @@ tor_addr_make_af_unix(tor_addr_t *a) } /** Set the tor_addr_t in <b>a</b> to contain the socket address contained in - * <b>sa</b>. Return 0 on success and -1 on failure. */ + * <b>sa</b>. IF <b>port_out</b> is non-NULL and <b>sa</b> contains a port, + * set *<b>port_out</b> to that port. Return 0 on success and -1 on + * failure. */ int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, uint16_t *port_out) diff --git a/src/common/aes.c b/src/common/aes.c index 89c99c150a..fd2043372e 100644 --- a/src/common/aes.c +++ b/src/common/aes.c @@ -101,18 +101,6 @@ aes_cipher_free(aes_cnt_cipher_t *cipher_) EVP_CIPHER_CTX_free(cipher); } void -aes_crypt(aes_cnt_cipher_t *cipher_, const char *input, size_t len, - char *output) -{ - int outl; - EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; - - tor_assert(len < INT_MAX); - - EVP_EncryptUpdate(cipher, (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; @@ -181,10 +169,6 @@ struct aes_cnt_cipher { * we're testing it or because we have hardware acceleration configured */ static int should_use_EVP = 0; -/** 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; - /** 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. */ @@ -249,13 +233,9 @@ evaluate_ctr_for_aes(void) if (fast_memneq(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_info(LD_CRYPTO, "This OpenSSL has a good implementation of counter " - "mode; using it."); - should_use_openssl_CTR = 1; + log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " + "quitting tor."); + exit(1); } return 0; } @@ -266,29 +246,6 @@ evaluate_ctr_for_aes(void) #define COUNTER(c, n) ((c)->counter ## n) #endif -/** - * Helper function: set <b>cipher</b>'s internal buffer to the encrypted - * value of the current counter. - */ -static inline void -aes_fill_buf_(aes_cnt_cipher_t *cipher) -{ - /* We don't currently use OpenSSL's counter mode implementation because: - * 1) some versions have known bugs - * 2) its attitude towards IVs is not our own - * 3) changing the counter position was not trivial, last time I looked. - * None of these issues are insurmountable in principle. - */ - - if (cipher->using_evp) { - int outl=16, inl=16; - 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); - } -} - 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); @@ -341,10 +298,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits) cipher->pos = 0; - if (should_use_openssl_CTR) - memset(cipher->buf, 0, sizeof(cipher->buf)); - else - aes_fill_buf_(cipher); + memset(cipher->buf, 0, sizeof(cipher->buf)); } /** Release storage held by <b>cipher</b> @@ -380,63 +334,6 @@ evp_block128_fn(const uint8_t in[16], EVP_EncryptUpdate(ctx, out, &outl, in, inl); } -/** 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. - */ -void -aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, - char *output) -{ - 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 { - 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, 1); - } - UPDATE_CTR_BUF(cipher, 0); - aes_fill_buf_(cipher); - } - } -} - /** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place. * Uses the key in <b>cipher</b>, and advances the counter by <b>len</b> bytes * as it encrypts. @@ -444,32 +341,26 @@ 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) { - if (should_use_openssl_CTR) { - aes_crypt(cipher, data, len, data); - return; + 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 *)data, + (unsigned char *)data, + len, + &cipher->key.evp, + cipher->ctr_buf.buf, + cipher->buf, + &cipher->pos, + evp_block128_fn); } else { - 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, 1); - } - UPDATE_CTR_BUF(cipher, 0); - aes_fill_buf_(cipher); - } + AES_ctr128_encrypt((const unsigned char *)data, + (unsigned char *)data, + len, + &cipher->key.aes, + cipher->ctr_buf.buf, + cipher->buf, + &cipher->pos); } } @@ -486,9 +377,6 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv) #endif cipher->pos = 0; memcpy(cipher->ctr_buf.buf, iv, 16); - - if (!should_use_openssl_CTR) - aes_fill_buf_(cipher); } #endif diff --git a/src/common/aes.h b/src/common/aes.h index 5500db7d0c..bd0456511b 100644 --- a/src/common/aes.h +++ b/src/common/aes.h @@ -17,8 +17,6 @@ typedef struct aes_cnt_cipher aes_cnt_cipher_t; 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); int evaluate_evp_for_aes(int force_value); diff --git a/src/common/crypto.c b/src/common/crypto.c index bc659b1935..06446ba050 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1509,7 +1509,8 @@ crypto_cipher_encrypt(crypto_cipher_t *env, char *to, tor_assert(to); tor_assert(fromlen < SIZE_T_CEILING); - aes_crypt(env->cipher, from, fromlen, to); + memcpy(to, from, fromlen); + aes_crypt_inplace(env->cipher, to, fromlen); return 0; } @@ -1526,19 +1527,19 @@ crypto_cipher_decrypt(crypto_cipher_t *env, char *to, tor_assert(to); tor_assert(fromlen < SIZE_T_CEILING); - aes_crypt(env->cipher, from, fromlen, to); + memcpy(to, from, fromlen); + aes_crypt_inplace(env->cipher, to, fromlen); return 0; } /** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; - * on success, return 0. Does not check for failure. + * on success. Does not check for failure. */ -int +void 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); - return 0; } /** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in @@ -2088,6 +2089,71 @@ static BIGNUM *dh_param_p_tls = NULL; /** Shared G parameter for our DH key exchanges. */ static BIGNUM *dh_param_g = NULL; +/** Validate a given set of Diffie-Hellman parameters. This is moderately + * computationally expensive (milliseconds), so should only be called when + * the DH parameters change. Returns 0 on success, * -1 on failure. + */ +static int +crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) +{ + DH *dh = NULL; + int ret = -1; + + /* Copy into a temporary DH object. */ + if (!(dh = DH_new())) + goto out; + if (!(dh->p = BN_dup(p))) + goto out; + if (!(dh->g = BN_dup(g))) + goto out; + + /* Perform the validation. */ + int codes = 0; + if (!DH_check(dh, &codes)) + goto out; + if (BN_is_word(dh->g, DH_GENERATOR_2)) { + /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters + * + * OpenSSL checks the prime is congruent to 11 when g = 2; while the + * IETF's primes are congruent to 23 when g = 2. + */ + BN_ULONG residue = BN_mod_word(dh->p, 24); + if (residue == 11 || residue == 23) + codes &= ~DH_NOT_SUITABLE_GENERATOR; + } + if (codes != 0) /* Specifics on why the params suck is irrelevant. */ + goto out; + + /* Things are probably not evil. */ + ret = 0; + + out: + if (dh) + DH_free(dh); + return ret; +} + +/** Set the global Diffie-Hellman generator, used for both TLS and internal + * DH stuff. + */ +static void +crypto_set_dh_generator(void) +{ + BIGNUM *generator; + int r; + + if (dh_param_g) + return; + + generator = BN_new(); + tor_assert(generator); + + r = BN_set_word(generator, DH_GENERATOR); + tor_assert(r); + + dh_param_g = generator; +} + /** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH * modulus. */ void @@ -2120,6 +2186,8 @@ crypto_set_tls_dh_prime(void) tor_assert(tls_prime); dh_param_p_tls = tls_prime; + crypto_set_dh_generator(); + tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g)); } /** Initialize dh_param_p and dh_param_g if they are not already @@ -2127,18 +2195,13 @@ crypto_set_tls_dh_prime(void) static void init_dh_param(void) { - BIGNUM *circuit_dh_prime, *generator; + BIGNUM *circuit_dh_prime; int r; if (dh_param_p && dh_param_g) return; 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); + tor_assert(circuit_dh_prime); /* This is from rfc2409, section 6.2. It's a safe prime, and supposedly it equals: @@ -2154,7 +2217,8 @@ init_dh_param(void) /* Set the new values as the global DH parameters. */ dh_param_p = circuit_dh_prime; - dh_param_g = generator; + crypto_set_dh_generator(); + tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g)); if (!dh_param_p_tls) { crypto_set_tls_dh_prime(); diff --git a/src/common/crypto.h b/src/common/crypto.h index fa2ed610c7..74b88bcd4a 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -205,7 +205,7 @@ int crypto_cipher_encrypt(crypto_cipher_t *env, char *to, const char *from, size_t fromlen); int crypto_cipher_decrypt(crypto_cipher_t *env, char *to, const char *from, size_t fromlen); -int crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *d, size_t len); +void crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *d, size_t len); int crypto_cipher_encrypt_with_iv(const char *key, char *to, size_t tolen, diff --git a/src/common/torint.h b/src/common/torint.h index 418fe0fabf..480ba1a596 100644 --- a/src/common/torint.h +++ b/src/common/torint.h @@ -312,8 +312,6 @@ typedef uint32_t uintptr_t; #ifndef TIME_MAX -#ifdef TIME_T_IS_SIGNED - #if (SIZEOF_TIME_T == SIZEOF_INT) #define TIME_MAX ((time_t)INT_MAX) #elif (SIZEOF_TIME_T == SIZEOF_LONG) @@ -321,25 +319,13 @@ typedef uint32_t uintptr_t; #elif (SIZEOF_TIME_T == 8) #define TIME_MAX ((time_t)INT64_MAX) #else -#error "Can't define (signed) TIME_MAX" +#error "Can't define TIME_MAX" #endif -#else -/* Unsigned case */ -#if (SIZEOF_TIME_T == 4) -#define TIME_MAX ((time_t)UINT32_MAX) -#elif (SIZEOF_TIME_T == 8) -#define TIME_MAX ((time_t)UINT64_MAX) -#else -#error "Can't define (unsigned) TIME_MAX" -#endif -#endif /* time_t_is_signed */ #endif /* ifndef(TIME_MAX) */ #ifndef TIME_MIN -#ifdef TIME_T_IS_SIGNED - #if (SIZEOF_TIME_T == SIZEOF_INT) #define TIME_MIN ((time_t)INT_MIN) #elif (SIZEOF_TIME_T == SIZEOF_LONG) @@ -347,19 +333,9 @@ typedef uint32_t uintptr_t; #elif (SIZEOF_TIME_T == 8) #define TIME_MIN ((time_t)INT64_MIN) #else -#error "Can't define (signed) TIME_MIN" +#error "Can't define TIME_MIN" #endif -#else -/* Unsigned case */ -#if (SIZEOF_TIME_T == 4) -#define TIME_MIN ((time_t)UINT32_MIN) -#elif (SIZEOF_TIME_T == 8) -#define TIME_MIN ((time_t)UINT64_MIN) -#else -#error "Can't define (unsigned) TIME_MIN" -#endif -#endif /* time_t_is_signed */ #endif /* ifndef(TIME_MIN) */ #ifndef SIZE_MAX |