From edec9409e85ba4a8b5d0575b23046d83d7562b87 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 24 Nov 2011 22:06:50 +0100 Subject: [PATCH 01/26] Copy/Paste Jake's stuff. This commit copies parts of Jake's f3bb6846975193d9a6649c31f94bda47e4014070 commit verbatim to the current master. --- src/common/crypto.c | 60 ++++++++++++++++++++++++++++++++++++++++++--- src/common/crypto.h | 4 +++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index f2ef833522..aeaabafb0c 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1816,23 +1816,71 @@ 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 *generate_rakshasa_prime(void) +{ + BIGNUM *rakshasa_prime, *misc; + DH *dh_parameters; + int r; + int dh_codes; + int rakshasa_bits = RAKSHASA_BITS; + int generator = DH_GENERATOR; + + dh_parameters = DH_new(); + rakshasa_prime = BN_new(); + misc = BN_new(); + + /** XXX - do we want to cache the result in a file? Or perhaps load from a file? */ + /* This implements the prime number strategy outlined in prop 179 */ + tor_assert(rakshasa_prime); + log_notice(LD_OR, "Generating Rakshasa prime; this will take a while..."); + dh_parameters = DH_generate_parameters(rakshasa_bits, generator, NULL, NULL); // XXX Do we want a pretty call back? + tor_assert(dh_parameters); + log_notice(LD_OR, "Rakshasa prime generated!"); + log_notice(LD_OR, "Testing our Rakshasa prime; this will take a while..."); + r = DH_check(dh_parameters, &dh_codes); + tor_assert(r); + log_notice(LD_OR, "Rakshasa prime seems probabilistically reasonable!"); + misc = BN_copy(rakshasa_prime, dh_parameters->p); + tor_assert(misc); + DH_free(dh_parameters); + + return rakshasa_prime; +} + /** Initialize dh_param_p and dh_param_g if they are not already * set. */ static void init_dh_param(void) { - BIGNUM *p, *p2, *g; + BIGNUM *rakshasa_prime, *p, *p2, *g; int r; if (dh_param_p && dh_param_g && dh_param_p_tls) return; + rakshasa_prime = BN_new(); p = BN_new(); p2 = BN_new(); g = BN_new(); + tor_assert(rakshasa_prime); tor_assert(p); tor_assert(p2); tor_assert(g); + /* Set our generator for all DH parameters */ + r = BN_set_word(g, generator); + tor_assert(r); + + /* Are we generating a random DH parameter?*/ + log_notice(LD_OR, "Do we want to generate a Rakshasa prime?"); + rakshasa = get_rakshasa(); + log_notice(LD_OR, "We think: %i?", rakshasa); + + /* This implements the prime number strategy outlined in prop 179 */ + if (rakshasa == 1) { + rakshasa_prime = generate_rakshasa_prime(); + } + /* This is from rfc2409, section 6.2. It's a safe prime, and supposedly it equals: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. @@ -1845,7 +1893,9 @@ init_dh_param(void) "49286651ECE65381FFFFFFFFFFFFFFFF"); tor_assert(r); /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see - * modules/ssl/ssl_engine_dh.c */ + * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this + * prime. + */ r = BN_hex2bn(&p2, "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" @@ -1857,7 +1907,11 @@ init_dh_param(void) r = BN_set_word(g, 2); tor_assert(r); dh_param_p = p; - dh_param_p_tls = p2; + if (rakshasa) { + dh_param_p_tls = rakshasa_prime; + } else { + dh_param_p_tls = p2; + } dh_param_g = g; } diff --git a/src/common/crypto.h b/src/common/crypto.h index 80c10296a3..2929a2effb 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -29,6 +29,10 @@ #define PK_BYTES (1024/8) /** Length of our DH keys. */ #define DH_BYTES (1024/8) +/** Our DH 'g' parameter */ +#define DH_GENERATOR 2 +/** Length of our Rakshasa DH parameter prime 'p' */ +#define RAKSHASA_BITS 1024 /** Length of a sha1 message digest when encoded in base64 with trailing = * signs removed. */ From 659381e00dc09deb4fb342d9f45cfae0b65aa33f Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 22 Nov 2011 04:53:43 +0100 Subject: [PATCH 02/26] Introduce the DynamicPrimes configuration option. --- src/common/crypto.c | 13 ++++++------- src/common/crypto.h | 3 ++- src/or/config.c | 1 + src/or/main.c | 3 ++- src/or/or.h | 2 ++ src/or/router.c | 3 ++- src/test/test.c | 2 +- src/tools/tor-checkkey.c | 2 +- src/tools/tor-gencert.c | 2 +- 9 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index aeaabafb0c..790ea1646c 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -224,13 +224,15 @@ try_load_engine(const char *path, const char *engine) /** Initialize the crypto library. Return 0 on success, -1 on failure. */ int -crypto_global_init(int useAccel, const char *accelName, const char *accelDir) +crypto_global_init(int useAccel, const char *accelName, const char *accelDir, + int DynamicPrimes) { if (!_crypto_global_initialized) { ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); _crypto_global_initialized = 1; setup_openssl_threading(); + use_dynamic_primes = DynamicPrimes; if (useAccel > 0) { #ifdef DISABLE_ENGINES (void)accelName; @@ -1815,6 +1817,8 @@ static BIGNUM *dh_param_p = NULL; static BIGNUM *dh_param_p_tls = NULL; /** Shared G parameter for our DH key exchanges. */ static BIGNUM *dh_param_g = NULL; +/** True if we use dynamic primes. */ +static int use_dynamic_primes = 0; /** Generate and return a reasonable and safe DH parameter p. */ static BIGNUM *generate_rakshasa_prime(void) @@ -1871,13 +1875,8 @@ init_dh_param(void) r = BN_set_word(g, generator); tor_assert(r); - /* Are we generating a random DH parameter?*/ - log_notice(LD_OR, "Do we want to generate a Rakshasa prime?"); - rakshasa = get_rakshasa(); - log_notice(LD_OR, "We think: %i?", rakshasa); - /* This implements the prime number strategy outlined in prop 179 */ - if (rakshasa == 1) { + if (use_dynamic_primes) { rakshasa_prime = generate_rakshasa_prime(); } diff --git a/src/common/crypto.h b/src/common/crypto.h index 2929a2effb..99c52b1c42 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -87,7 +87,8 @@ typedef struct crypto_dh_env_t crypto_dh_env_t; /* global state */ int crypto_global_init(int hardwareAccel, const char *accelName, - const char *accelPath); + const char *accelPath, + int DynamicPrimes); void crypto_thread_cleanup(void); int crypto_global_cleanup(void); diff --git a/src/or/config.c b/src/or/config.c index 06d7d5c022..4766b24196 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -247,6 +247,7 @@ static config_var_t _option_vars[] = { VAR("DirServer", LINELIST, DirServers, NULL), V(DisableAllSwap, BOOL, "0"), V(DisableIOCP, BOOL, "1"), + V(DynamicPrimes, BOOL, "1"), V(DNSPort, LINELIST, NULL), V(DNSListenAddress, LINELIST, NULL), V(DownloadExtraInfo, BOOL, "0"), diff --git a/src/or/main.c b/src/or/main.c index 7008d388a1..3c75e1c645 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2275,7 +2275,8 @@ tor_init(int argc, char *argv[]) if (crypto_global_init(get_options()->HardwareAccel, get_options()->AccelName, - get_options()->AccelDir)) { + get_options()->AccelDir, + get_options()->DynamicPrimes)) { log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } diff --git a/src/or/or.h b/src/or/or.h index 67ba62bdd6..b2ea3bc7a7 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2873,6 +2873,8 @@ typedef struct { char *Address; /**< OR only: configured address for this onion router. */ char *PidFile; /**< Where to store PID of Tor process. */ + int DynamicPrimes; /**< Enable dynamic generation of primes for use in DH. */ + routerset_t *ExitNodes; /**< Structure containing nicknames, digests, * country codes and IP address patterns of ORs to * consider as exits. */ diff --git a/src/or/router.c b/src/or/router.c index b6b96a5fff..414d346bfa 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -514,7 +514,8 @@ init_keys(void) * openssl to initialize itself. */ if (crypto_global_init(get_options()->HardwareAccel, get_options()->AccelName, - get_options()->AccelDir)) { + get_options()->AccelDir, + get_options()->DynamicPrimes)) { log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } diff --git a/src/test/test.c b/src/test/test.c index d4edf1484b..26a55d13f2 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1903,7 +1903,7 @@ main(int c, const char **v) } options->command = CMD_RUN_UNITTESTS; - if (crypto_global_init(0, NULL, NULL)) { + if (crypto_global_init(0, NULL, NULL, 1)) { printf("Can't initialize crypto subsystem; exiting.\n"); return 1; } diff --git a/src/tools/tor-checkkey.c b/src/tools/tor-checkkey.c index 94c8cbd44c..55480b4881 100644 --- a/src/tools/tor-checkkey.c +++ b/src/tools/tor-checkkey.c @@ -31,7 +31,7 @@ main(int c, char **v) return 1; } - if (crypto_global_init(0, NULL, NULL)) { + if (crypto_global_init(0, NULL, NULL, 0)) { fprintf(stderr, "Couldn't initialize crypto library.\n"); return 1; } diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index 974a58becf..b9f16d9929 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -508,7 +508,7 @@ main(int argc, char **argv) init_logging(); /* Don't bother using acceleration. */ - if (crypto_global_init(0, NULL, NULL)) { + if (crypto_global_init(0, NULL, NULL, 0)) { fprintf(stderr, "Couldn't initialize crypto library.\n"); return 1; } From 375e55eaa2439e18f7a0c5a9f6bc6324cbca37a0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 22 Nov 2011 05:08:26 +0100 Subject: [PATCH 03/26] Rename "Rakshasa" to "Dynamic Prime". --- src/common/crypto.c | 39 ++++++++++++++++++--------------------- src/common/crypto.h | 2 -- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 790ea1646c..a07cc96575 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1821,35 +1821,32 @@ static BIGNUM *dh_param_g = NULL; static int use_dynamic_primes = 0; /** Generate and return a reasonable and safe DH parameter p. */ -static BIGNUM *generate_rakshasa_prime(void) +static BIGNUM * +crypto_generate_dynamic_prime(void) { - BIGNUM *rakshasa_prime, *misc; + BIGNUM *dynamic_prime, *misc; DH *dh_parameters; int r; int dh_codes; - int rakshasa_bits = RAKSHASA_BITS; - int generator = DH_GENERATOR; dh_parameters = DH_new(); - rakshasa_prime = BN_new(); + dynamic_prime = BN_new(); misc = BN_new(); - /** XXX - do we want to cache the result in a file? Or perhaps load from a file? */ - /* This implements the prime number strategy outlined in prop 179 */ - tor_assert(rakshasa_prime); - log_notice(LD_OR, "Generating Rakshasa prime; this will take a while..."); - dh_parameters = DH_generate_parameters(rakshasa_bits, generator, NULL, NULL); // XXX Do we want a pretty call back? + tor_assert(dynamic_prime); + log_notice(LD_OR, "Generating Dynamic prime; this will take a while..."); + dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL); // XXX Do we want a pretty call back? tor_assert(dh_parameters); - log_notice(LD_OR, "Rakshasa prime generated!"); - log_notice(LD_OR, "Testing our Rakshasa prime; this will take a while..."); + log_notice(LD_OR, "Dynamic prime generated!"); + log_notice(LD_OR, "Testing our Dynamic prime; this will take a while..."); r = DH_check(dh_parameters, &dh_codes); tor_assert(r); - log_notice(LD_OR, "Rakshasa prime seems probabilistically reasonable!"); - misc = BN_copy(rakshasa_prime, dh_parameters->p); + log_notice(LD_OR, "Dynamic prime seems probabilistically reasonable!"); + misc = BN_copy(dynamic_prime, dh_parameters->p); tor_assert(misc); DH_free(dh_parameters); - return rakshasa_prime; + return dynamic_prime; } /** Initialize dh_param_p and dh_param_g if they are not already @@ -1857,16 +1854,16 @@ static BIGNUM *generate_rakshasa_prime(void) static void init_dh_param(void) { - BIGNUM *rakshasa_prime, *p, *p2, *g; + BIGNUM *dynamic_prime, *p, *p2, *g; int r; if (dh_param_p && dh_param_g && dh_param_p_tls) return; - rakshasa_prime = BN_new(); + dynamic_prime = BN_new(); p = BN_new(); p2 = BN_new(); g = BN_new(); - tor_assert(rakshasa_prime); + tor_assert(dynamic_prime); tor_assert(p); tor_assert(p2); tor_assert(g); @@ -1877,7 +1874,7 @@ init_dh_param(void) /* This implements the prime number strategy outlined in prop 179 */ if (use_dynamic_primes) { - rakshasa_prime = generate_rakshasa_prime(); + dynamic_prime = crypto_generate_dynamic_prime(); } /* This is from rfc2409, section 6.2. It's a safe prime, and @@ -1906,8 +1903,8 @@ init_dh_param(void) r = BN_set_word(g, 2); tor_assert(r); dh_param_p = p; - if (rakshasa) { - dh_param_p_tls = rakshasa_prime; + if (use_dynamic_primes) { + dh_param_p_tls = dynamic_prime; } else { dh_param_p_tls = p2; } diff --git a/src/common/crypto.h b/src/common/crypto.h index 99c52b1c42..9e52bc4175 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -31,8 +31,6 @@ #define DH_BYTES (1024/8) /** Our DH 'g' parameter */ #define DH_GENERATOR 2 -/** Length of our Rakshasa DH parameter prime 'p' */ -#define RAKSHASA_BITS 1024 /** Length of a sha1 message digest when encoded in base64 with trailing = * signs removed. */ From 1797e0a39e85f81e773304d7121e1f5f36fe9de9 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 22 Nov 2011 05:13:34 +0100 Subject: [PATCH 04/26] Make it compile. --- src/common/crypto.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index a07cc96575..647d634fa7 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -105,6 +105,9 @@ static tor_mutex_t **_openssl_mutexes = NULL; static int _n_openssl_mutexes = 0; #endif +/** True if we use dynamic primes. */ +static int use_dynamic_primes = 0; + /** A public key, or a public/private key-pair. */ struct crypto_pk_env_t { @@ -1817,8 +1820,6 @@ static BIGNUM *dh_param_p = NULL; static BIGNUM *dh_param_p_tls = NULL; /** Shared G parameter for our DH key exchanges. */ static BIGNUM *dh_param_g = NULL; -/** True if we use dynamic primes. */ -static int use_dynamic_primes = 0; /** Generate and return a reasonable and safe DH parameter p. */ static BIGNUM * @@ -1869,7 +1870,7 @@ init_dh_param(void) tor_assert(g); /* Set our generator for all DH parameters */ - r = BN_set_word(g, generator); + r = BN_set_word(g, DH_GENERATOR); tor_assert(r); /* This implements the prime number strategy outlined in prop 179 */ From fb38e58d14e2557a07f0ea34568f8966946c4316 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 22 Nov 2011 13:55:07 +0100 Subject: [PATCH 05/26] Improve logging. --- src/common/crypto.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 647d634fa7..81690b26d7 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1829,24 +1829,27 @@ crypto_generate_dynamic_prime(void) DH *dh_parameters; int r; int dh_codes; + char *s; dh_parameters = DH_new(); dynamic_prime = BN_new(); misc = BN_new(); tor_assert(dynamic_prime); - log_notice(LD_OR, "Generating Dynamic prime; this will take a while..."); dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL); // XXX Do we want a pretty call back? tor_assert(dh_parameters); - log_notice(LD_OR, "Dynamic prime generated!"); - log_notice(LD_OR, "Testing our Dynamic prime; this will take a while..."); r = DH_check(dh_parameters, &dh_codes); tor_assert(r); - log_notice(LD_OR, "Dynamic prime seems probabilistically reasonable!"); misc = BN_copy(dynamic_prime, dh_parameters->p); tor_assert(misc); DH_free(dh_parameters); + { + s = BN_bn2hex(dynamic_prime); + log_notice(LD_OR, "Dynamic prime generated: [%s]", s); + OPENSSL_free(s); + } + return dynamic_prime; } @@ -1875,6 +1878,7 @@ init_dh_param(void) /* This implements the prime number strategy outlined in prop 179 */ if (use_dynamic_primes) { + log_notice(LD_OR, "Generating fresh dynamic prime."); dynamic_prime = crypto_generate_dynamic_prime(); } From 0e71be5d943811eb4ee9cfee0f435a184c10beb1 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 22 Nov 2011 15:08:27 +0100 Subject: [PATCH 06/26] Improve code in the dynamic primes realm. --- src/common/crypto.c | 87 +++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 81690b26d7..88cba033af 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1825,27 +1825,28 @@ static BIGNUM *dh_param_g = NULL; static BIGNUM * crypto_generate_dynamic_prime(void) { - BIGNUM *dynamic_prime, *misc; + BIGNUM *dynamic_prime; DH *dh_parameters; - int r; - int dh_codes; + int r, dh_codes; char *s; - dh_parameters = DH_new(); dynamic_prime = BN_new(); - misc = BN_new(); - tor_assert(dynamic_prime); - dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL); // XXX Do we want a pretty call back? + + dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL); tor_assert(dh_parameters); + r = DH_check(dh_parameters, &dh_codes); tor_assert(r); - misc = BN_copy(dynamic_prime, dh_parameters->p); - tor_assert(misc); + + BN_copy(dynamic_prime, dh_parameters->p); + tor_assert(dynamic_prime); + DH_free(dh_parameters); - { + { /* log the dynamic prime: */ s = BN_bn2hex(dynamic_prime); + tor_assert(s); log_notice(LD_OR, "Dynamic prime generated: [%s]", s); OPENSSL_free(s); } @@ -1858,62 +1859,56 @@ crypto_generate_dynamic_prime(void) static void init_dh_param(void) { - BIGNUM *dynamic_prime, *p, *p2, *g; + BIGNUM *circuit_dh_prime, *tls_prime, *generator; int r; if (dh_param_p && dh_param_g && dh_param_p_tls) return; - dynamic_prime = BN_new(); - p = BN_new(); - p2 = BN_new(); - g = BN_new(); - tor_assert(dynamic_prime); - tor_assert(p); - tor_assert(p2); - tor_assert(g); + 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(g, DH_GENERATOR); + r = BN_set_word(generator, DH_GENERATOR); tor_assert(r); - /* This implements the prime number strategy outlined in prop 179 */ - if (use_dynamic_primes) { - log_notice(LD_OR, "Generating fresh dynamic prime."); - dynamic_prime = crypto_generate_dynamic_prime(); - } - /* This is from rfc2409, section 6.2. It's a safe prime, and supposedly it equals: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. */ - r = BN_hex2bn(&p, + r = BN_hex2bn(&circuit_dh_prime, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" "49286651ECE65381FFFFFFFFFFFFFFFF"); 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(&p2, - "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" - "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" - "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" - "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" - "B0E7393E0F24218EB3"); - tor_assert(r); - r = BN_set_word(g, 2); - tor_assert(r); - dh_param_p = p; - if (use_dynamic_primes) { - dh_param_p_tls = dynamic_prime; - } else { - dh_param_p_tls = p2; + if (use_dynamic_primes) { /* use dynamic primes: */ + log_notice(LD_OR, "Generating fresh dynamic prime."); + tls_prime = crypto_generate_dynamic_prime(); + tor_assert(tls_prime); + } 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); } - dh_param_g = g; + + /* Set the new values as the global DH parameters. */ + dh_param_p = circuit_dh_prime; + dh_param_p_tls = tls_prime; + dh_param_g = generator; } /** Number of bits to use when choosing the x or y value in a Diffie-Hellman From 21babd152e2669d446610be6e343db667397dde4 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 22 Nov 2011 22:27:44 +0100 Subject: [PATCH 07/26] Document DynamicPrimes in the manual page. --- doc/tor.1.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/tor.1.txt b/doc/tor.1.txt index f5be391052..8859c3776c 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -239,6 +239,12 @@ Other options can be specified either on the command-line (--option distinguishable from other users, because you won't believe the same authorities they do. +**DynamicPrimes** **0**|**1**:: + If this option is set to 1, use a dynamic Diffie-Hellman prime + modulus instead of using the modulus of Apache's mod_ssl. This + option might help circumvent censorship based on static + Diffie-Hellman parameters. (Default: 1). + **AlternateDirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ + **AlternateHSAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ + From 42bda231ee10db0136cf2ffb56a38ce290891794 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 23 Nov 2011 23:39:46 +0100 Subject: [PATCH 08/26] Make DynamicPrimes SIGHUP-able. Instead of passing the DynamicPrimes configuration option to crypto_global_init(), generate and set a new TLS DH prime when we read the torrc. --- src/common/crypto.c | 82 +++++++++++++++++++++++++--------------- src/common/crypto.h | 3 +- src/or/config.c | 17 +++++++++ src/or/main.c | 3 +- src/test/test.c | 2 +- src/tools/tor-checkkey.c | 2 +- 6 files changed, 73 insertions(+), 36 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 88cba033af..bef62651fc 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -105,9 +105,6 @@ static tor_mutex_t **_openssl_mutexes = NULL; static int _n_openssl_mutexes = 0; #endif -/** True if we use dynamic primes. */ -static int use_dynamic_primes = 0; - /** A public key, or a public/private key-pair. */ struct crypto_pk_env_t { @@ -227,15 +224,13 @@ try_load_engine(const char *path, const char *engine) /** Initialize the crypto library. Return 0 on success, -1 on failure. */ int -crypto_global_init(int useAccel, const char *accelName, const char *accelDir, - int DynamicPrimes) +crypto_global_init(int useAccel, const char *accelName, const char *accelDir) { if (!_crypto_global_initialized) { ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); _crypto_global_initialized = 1; setup_openssl_threading(); - use_dynamic_primes = DynamicPrimes; if (useAccel > 0) { #ifdef DISABLE_ENGINES (void)accelName; @@ -1854,14 +1849,60 @@ crypto_generate_dynamic_prime(void) return dynamic_prime; } +/** Set the global TLS Diffie-Hellman modulus. + * If use_dynamic_primes is not set, use the prime + * modulus of mod_ssl. + * If use_dynamic_primes is set, use stored_dynamic_prime + * if it exists, otherwise generate and use a new prime modulus. */ +void +crypto_set_tls_dh_prime(int use_dynamic_primes, BIGNUM *stored_dynamic_prime) +{ + BIGNUM *tls_prime = NULL; + + /* If the space is occupied, free the previous TLS DH prime */ + if (dh_param_p_tls) { + BN_free(dh_param_p_tls); + dh_param_p_tls = NULL; + } + + if (use_dynamic_primes) { /* use dynamic primes: */ + if (stored_dynamic_prime) { + log_notice(LD_OR, "Using stored dynamic prime."); + tls_prime = stored_dynamic_prime; + } else { + log_notice(LD_OR, "Generating fresh dynamic prime."); + tls_prime = crypto_generate_dynamic_prime(); + } + } 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); + } + + tor_assert(tls_prime); + + dh_param_p_tls = tls_prime; +} + /** Initialize dh_param_p and dh_param_g if they are not already * set. */ static void init_dh_param(void) { - BIGNUM *circuit_dh_prime, *tls_prime, *generator; + BIGNUM *circuit_dh_prime, *generator; int r; - if (dh_param_p && dh_param_g && dh_param_p_tls) + if (dh_param_p && dh_param_g) return; circuit_dh_prime = BN_new(); @@ -1884,31 +1925,12 @@ init_dh_param(void) "49286651ECE65381FFFFFFFFFFFFFFFF"); tor_assert(r); - if (use_dynamic_primes) { /* use dynamic primes: */ - log_notice(LD_OR, "Generating fresh dynamic prime."); - tls_prime = crypto_generate_dynamic_prime(); - tor_assert(tls_prime); - } 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); - } - /* Set the new values as the global DH parameters. */ dh_param_p = circuit_dh_prime; - dh_param_p_tls = tls_prime; dh_param_g = generator; + + /* Should be already set by config.c. */ + tor_assert(dh_param_p_tls); } /** Number of bits to use when choosing the x or y value in a Diffie-Hellman diff --git a/src/common/crypto.h b/src/common/crypto.h index 9e52bc4175..b759459d40 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -85,8 +85,7 @@ typedef struct crypto_dh_env_t crypto_dh_env_t; /* global state */ int crypto_global_init(int hardwareAccel, const char *accelName, - const char *accelPath, - int DynamicPrimes); + const char *accelPath); void crypto_thread_cleanup(void); int crypto_global_cleanup(void); diff --git a/src/or/config.c b/src/or/config.c index 4766b24196..a113f7b2da 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1362,6 +1362,23 @@ options_act(const or_options_t *old_options) finish_daemon(options->DataDirectory); } + /* If needed, generate a new TLS DH prime according to the current torrc. */ + if (!old_options) { + if (options->DynamicPrimes) { + crypto_set_tls_dh_prime(1, router_get_stored_dynamic_prime()); + } else { + crypto_set_tls_dh_prime(0, NULL); + } + } else { + if (options->DynamicPrimes && !old_options->DynamicPrimes) { + crypto_set_tls_dh_prime(1, router_get_stored_dynamic_prime()); + } else if (!options->DynamicPrimes && old_options->DynamicPrimes) { + crypto_set_tlS_dh_prime(0, NULL); + } else { + tor_assert(crypto_get_tls_dh_prime); + } + } + /* We want to reinit keys as needed before we do much of anything else: keys are important, and other things can depend on them. */ if (transition_affects_workers || diff --git a/src/or/main.c b/src/or/main.c index 3c75e1c645..0d2127d336 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2275,8 +2275,7 @@ tor_init(int argc, char *argv[]) if (crypto_global_init(get_options()->HardwareAccel, get_options()->AccelName, - get_options()->AccelDir, - get_options()->DynamicPrimes)) { + get_options()->AccelDir) { log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } diff --git a/src/test/test.c b/src/test/test.c index 26a55d13f2..d4edf1484b 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1903,7 +1903,7 @@ main(int c, const char **v) } options->command = CMD_RUN_UNITTESTS; - if (crypto_global_init(0, NULL, NULL, 1)) { + if (crypto_global_init(0, NULL, NULL)) { printf("Can't initialize crypto subsystem; exiting.\n"); return 1; } diff --git a/src/tools/tor-checkkey.c b/src/tools/tor-checkkey.c index 55480b4881..94c8cbd44c 100644 --- a/src/tools/tor-checkkey.c +++ b/src/tools/tor-checkkey.c @@ -31,7 +31,7 @@ main(int c, char **v) return 1; } - if (crypto_global_init(0, NULL, NULL, 0)) { + if (crypto_global_init(0, NULL, NULL)) { fprintf(stderr, "Couldn't initialize crypto library.\n"); return 1; } From 8a726dd0dd28c4550a7f6f7d9aa5f72507d4716b Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 24 Nov 2011 00:22:31 +0100 Subject: [PATCH 09/26] Implement dynamic prime reading and storing to disk. --- src/common/crypto.c | 9 +++- src/common/crypto.h | 6 +++ src/or/config.c | 5 ++- src/or/main.c | 2 +- src/or/router.c | 94 ++++++++++++++++++++++++++++++++++++++++- src/or/router.h | 4 ++ src/tools/tor-gencert.c | 2 +- 7 files changed, 115 insertions(+), 7 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index bef62651fc..484366297d 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1849,6 +1849,12 @@ crypto_generate_dynamic_prime(void) return dynamic_prime; } +BIGNUM * +crypto_get_tls_dh_prime(void) +{ + return dh_param_p_tls; +} + /** Set the global TLS Diffie-Hellman modulus. * If use_dynamic_primes is not set, use the prime * modulus of mod_ssl. @@ -1858,6 +1864,7 @@ void crypto_set_tls_dh_prime(int use_dynamic_primes, BIGNUM *stored_dynamic_prime) { BIGNUM *tls_prime = NULL; + int r; /* If the space is occupied, free the previous TLS DH prime */ if (dh_param_p_tls) { @@ -1867,7 +1874,7 @@ crypto_set_tls_dh_prime(int use_dynamic_primes, BIGNUM *stored_dynamic_prime) if (use_dynamic_primes) { /* use dynamic primes: */ if (stored_dynamic_prime) { - log_notice(LD_OR, "Using stored dynamic prime."); + log_warn(LD_OR, "Using stored dynamic prime."); tls_prime = stored_dynamic_prime; } else { log_notice(LD_OR, "Generating fresh dynamic prime."); diff --git a/src/common/crypto.h b/src/common/crypto.h index b759459d40..5b753b83d6 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -16,6 +16,8 @@ #include #include "torint.h" +#include + /** Length of the output of our message digest. */ #define DIGEST_LEN 20 /** Length of the output of our second (improved) message digests. (For now @@ -93,6 +95,10 @@ int crypto_global_cleanup(void); crypto_pk_env_t *crypto_new_pk_env(void); void crypto_free_pk_env(crypto_pk_env_t *env); +void crypto_set_tls_dh_prime(int use_dynamic_primes, + BIGNUM *stored_dynamic_prime); +BIGNUM * crypto_get_tls_dh_prime(void); + /* convenience function: wraps crypto_create_crypto_env, set_key, and init. */ crypto_cipher_env_t *crypto_create_init_cipher(const char *key, int encrypt_mode); diff --git a/src/or/config.c b/src/or/config.c index a113f7b2da..78e91bbe11 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1373,9 +1373,9 @@ options_act(const or_options_t *old_options) if (options->DynamicPrimes && !old_options->DynamicPrimes) { crypto_set_tls_dh_prime(1, router_get_stored_dynamic_prime()); } else if (!options->DynamicPrimes && old_options->DynamicPrimes) { - crypto_set_tlS_dh_prime(0, NULL); + crypto_set_tls_dh_prime(0, NULL); } else { - tor_assert(crypto_get_tls_dh_prime); + tor_assert(crypto_get_tls_dh_prime()); } } @@ -4069,6 +4069,7 @@ options_transition_affects_workers(const or_options_t *old_options, { if (!opt_streq(old_options->DataDirectory, new_options->DataDirectory) || old_options->NumCPUs != new_options->NumCPUs || + old_options->DynamicPrimes != new_options->DynamicPrimes || old_options->ORPort != new_options->ORPort || old_options->ServerDNSSearchDomains != new_options->ServerDNSSearchDomains || diff --git a/src/or/main.c b/src/or/main.c index 0d2127d336..7008d388a1 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2275,7 +2275,7 @@ tor_init(int argc, char *argv[]) if (crypto_global_init(get_options()->HardwareAccel, get_options()->AccelName, - get_options()->AccelDir) { + get_options()->AccelDir)) { log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } diff --git a/src/or/router.c b/src/or/router.c index 414d346bfa..368ea1b741 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -484,6 +484,86 @@ v3_authority_check_key_expiry(void) last_warned = now; } + +/** Store dynamic_prime to disk for future use. */ +int +router_store_dynamic_prime(const BIGNUM *dynamic_prime) +{ + FILE *fp = NULL; + char *fname = get_datadir_fname2("keys", "dynamic_prime"); + int retval = -1; + + if (file_status(fname) != FN_NOENT) { + log_warn(LD_GENERAL, "Dynamic prime already occupied."); + goto done; + } + + if (!(fp = fopen(fname, "w"))) { + log_warn(LD_GENERAL, "Error writing to certificate file"); + goto done; + } + + if (BN_print_fp(fp, dynamic_prime) == 0) { + log_warn(LD_GENERAL, "Error on bn_print_fp()"); + goto done; + } + + retval = 0; + + done: + if (fp) + fclose(fp); + tor_free(fname); + + return retval; +} + +/** Return the dynamic prime stored in the disk. If there is no + dynamic prime stored in the disk, return NULL. */ +BIGNUM * +router_get_stored_dynamic_prime(void) +{ + int retval; + char *contents = NULL; + char *fname = get_datadir_fname2("keys", "dynamic_prime"); + BIGNUM *dynamic_prime = BN_new(); + if (!dynamic_prime) + goto err; + + contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + if (!contents) { + log_warn(LD_GENERAL, "Error reading dynamic prime from \"%s\"", fname); + goto err; + } + + retval = BN_hex2bn(&dynamic_prime, contents); + if (!retval) { + log_warn(LD_GENERAL, "C0rrupted dynamic prime?!?!"); + goto err; + } + + { /* log the dynamic prime: */ + char *s = BN_bn2hex(dynamic_prime); + tor_assert(s); + log_notice(LD_OR, "Found stored dynamic prime: [%s]", s); + OPENSSL_free(s); + } + + goto done; + + err: + if (dynamic_prime) { + BN_free(dynamic_prime); + dynamic_prime = NULL; + } + + done: + tor_free(fname); + tor_free(contents); + + return dynamic_prime; +} + /** Initialize all OR private keys, and the TLS context, as necessary. * On OPs, this only initializes the tls context. Return 0 on success, * or -1 if Tor should die. @@ -514,8 +594,7 @@ init_keys(void) * openssl to initialize itself. */ if (crypto_global_init(get_options()->HardwareAccel, get_options()->AccelName, - get_options()->AccelDir, - get_options()->DynamicPrimes)) { + get_options()->AccelDir)) { log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } @@ -634,6 +713,17 @@ init_keys(void) log_err(LD_GENERAL,"Error initializing TLS context"); return -1; } + + /** 3b. If we use a dynamic prime, store it to disk. */ + if (get_options()->DynamicPrimes) { + BIGNUM *dynamic_prime = crypto_get_tls_dh_prime(); + if (dynamic_prime) { + if (router_store_dynamic_prime(dynamic_prime) < 0) + log_warn(LD_GENERAL, "Failed while storing dynamic prime. " + "Make sure your data directory is sane."); + } + } + /* 4. Build our router descriptor. */ /* Must be called after keys are initialized. */ mydesc = router_get_my_descriptor(); diff --git a/src/or/router.h b/src/or/router.h index f9d156cb09..41ff139936 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -28,6 +28,10 @@ void dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last); void rotate_onion_key(void); crypto_pk_env_t *init_key_from_file(const char *fname, int generate, int severity); + +BIGNUM *router_get_stored_dynamic_prime(void); +int router_store_dynamic_prime(const BIGNUM *dynamic_prime); + void v3_authority_check_key_expiry(void); int init_keys(void); diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index b9f16d9929..974a58becf 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -508,7 +508,7 @@ main(int argc, char **argv) init_logging(); /* Don't bother using acceleration. */ - if (crypto_global_init(0, NULL, NULL, 0)) { + if (crypto_global_init(0, NULL, NULL)) { fprintf(stderr, "Couldn't initialize crypto library.\n"); return 1; } From cabb8e54c7240aeb20ccfa745d75c5ad4063edb3 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 24 Nov 2011 06:12:22 +0100 Subject: [PATCH 10/26] Tone down the logging. --- src/common/crypto.c | 6 +++--- src/or/router.c | 28 +++++++++++++++++----------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 484366297d..72c3dd7c12 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1842,7 +1842,7 @@ crypto_generate_dynamic_prime(void) { /* log the dynamic prime: */ s = BN_bn2hex(dynamic_prime); tor_assert(s); - log_notice(LD_OR, "Dynamic prime generated: [%s]", s); + log_info(LD_OR, "Dynamic prime generated: [%s]", s); OPENSSL_free(s); } @@ -1874,10 +1874,10 @@ crypto_set_tls_dh_prime(int use_dynamic_primes, BIGNUM *stored_dynamic_prime) if (use_dynamic_primes) { /* use dynamic primes: */ if (stored_dynamic_prime) { - log_warn(LD_OR, "Using stored dynamic prime."); + log_info(LD_OR, "Using stored dynamic prime."); tls_prime = stored_dynamic_prime; } else { - log_notice(LD_OR, "Generating fresh dynamic prime."); + log_info(LD_OR, "Generating fresh dynamic prime."); tls_prime = crypto_generate_dynamic_prime(); } } else { /* use the static DH prime modulus used by Apache in mod_ssl: */ diff --git a/src/or/router.c b/src/or/router.c index 368ea1b741..6b38c793ce 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -492,19 +492,26 @@ router_store_dynamic_prime(const BIGNUM *dynamic_prime) FILE *fp = NULL; char *fname = get_datadir_fname2("keys", "dynamic_prime"); int retval = -1; + file_status_t fname_status = file_status(fname); - if (file_status(fname) != FN_NOENT) { - log_warn(LD_GENERAL, "Dynamic prime already occupied."); + if (fname_status == FN_FILE) { + /* If the fname is a file, then the dynamic prime is already stored. */ + retval = 0; + goto done; + } else if (fname_status != FN_NOENT) { + log_info(LD_GENERAL, "Dynamic prime filename is occupied."); goto done; } + tor_assert(fname_status == FN_NOENT); + if (!(fp = fopen(fname, "w"))) { - log_warn(LD_GENERAL, "Error writing to certificate file"); + log_notice(LD_GENERAL, "Error while creating dynamic prime file."); goto done; } if (BN_print_fp(fp, dynamic_prime) == 0) { - log_warn(LD_GENERAL, "Error on bn_print_fp()"); + log_warn(LD_GENERAL, "Error while printing dynamic prime to file."); goto done; } @@ -531,21 +538,20 @@ router_get_stored_dynamic_prime(void) goto err; contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); - if (!contents) { - log_warn(LD_GENERAL, "Error reading dynamic prime from \"%s\"", fname); + if (!contents) goto err; - } retval = BN_hex2bn(&dynamic_prime, contents); if (!retval) { - log_warn(LD_GENERAL, "C0rrupted dynamic prime?!?!"); + log_notice(LD_GENERAL, "Could not understand the dynamic prime " + "format in '%s'", fname); goto err; } { /* log the dynamic prime: */ char *s = BN_bn2hex(dynamic_prime); tor_assert(s); - log_notice(LD_OR, "Found stored dynamic prime: [%s]", s); + log_info(LD_OR, "Found stored dynamic prime: [%s]", s); OPENSSL_free(s); } @@ -719,8 +725,8 @@ init_keys(void) BIGNUM *dynamic_prime = crypto_get_tls_dh_prime(); if (dynamic_prime) { if (router_store_dynamic_prime(dynamic_prime) < 0) - log_warn(LD_GENERAL, "Failed while storing dynamic prime. " - "Make sure your data directory is sane."); + log_notice(LD_GENERAL, "Failed while storing dynamic prime. " + "Make sure your data directory is sane."); } } From 2ef68980a778666bcc9b3b492c4acbd7af27fc28 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 24 Nov 2011 22:32:10 +0100 Subject: [PATCH 11/26] Move store_dynamic_prime() to crypto.c. --- src/common/crypto.c | 40 +++++++++++++++++++++++++++++++--- src/common/crypto.h | 2 +- src/or/router.c | 52 ++++++--------------------------------------- src/or/router.h | 1 - 4 files changed, 44 insertions(+), 51 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 72c3dd7c12..a3c292324b 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1849,10 +1849,44 @@ crypto_generate_dynamic_prime(void) return dynamic_prime; } -BIGNUM * -crypto_get_tls_dh_prime(void) +/** Store our dynamic prime to fname for future use. */ +int +router_store_dynamic_prime(const char *fname) { - return dh_param_p_tls; + FILE *fp = NULL; + int retval = -1; + file_status_t fname_status = file_status(fname); + + tor_assert(fname); + + if (fname_status == FN_FILE) { + /* If the fname is a file, then the dynamic prime is already stored. */ + retval = 0; + goto done; + } else if (fname_status != FN_NOENT) { + log_info(LD_GENERAL, "Dynamic prime filename is occupied."); + goto done; + } + + tor_assert(fname_status == FN_NOENT); + + if (!(fp = fopen(fname, "w"))) { + log_notice(LD_GENERAL, "Error while creating dynamic prime file."); + goto done; + } + + if (BN_print_fp(fp, dh_param_p_tls) == 0) { + log_warn(LD_GENERAL, "Error while printing dynamic prime to file."); + goto done; + } + + retval = 0; + + done: + if (fp) + fclose(fp); + + return retval; } /** Set the global TLS Diffie-Hellman modulus. diff --git a/src/common/crypto.h b/src/common/crypto.h index 5b753b83d6..8c99dd7a37 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -97,7 +97,7 @@ void crypto_free_pk_env(crypto_pk_env_t *env); void crypto_set_tls_dh_prime(int use_dynamic_primes, BIGNUM *stored_dynamic_prime); -BIGNUM * crypto_get_tls_dh_prime(void); +int router_store_dynamic_prime(const char *fname); /* convenience function: wraps crypto_create_crypto_env, set_key, and init. */ crypto_cipher_env_t *crypto_create_init_cipher(const char *key, diff --git a/src/or/router.c b/src/or/router.c index 6b38c793ce..dd5b9fff52 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -485,46 +485,6 @@ v3_authority_check_key_expiry(void) } -/** Store dynamic_prime to disk for future use. */ -int -router_store_dynamic_prime(const BIGNUM *dynamic_prime) -{ - FILE *fp = NULL; - char *fname = get_datadir_fname2("keys", "dynamic_prime"); - int retval = -1; - file_status_t fname_status = file_status(fname); - - if (fname_status == FN_FILE) { - /* If the fname is a file, then the dynamic prime is already stored. */ - retval = 0; - goto done; - } else if (fname_status != FN_NOENT) { - log_info(LD_GENERAL, "Dynamic prime filename is occupied."); - goto done; - } - - tor_assert(fname_status == FN_NOENT); - - if (!(fp = fopen(fname, "w"))) { - log_notice(LD_GENERAL, "Error while creating dynamic prime file."); - goto done; - } - - if (BN_print_fp(fp, dynamic_prime) == 0) { - log_warn(LD_GENERAL, "Error while printing dynamic prime to file."); - goto done; - } - - retval = 0; - - done: - if (fp) - fclose(fp); - tor_free(fname); - - return retval; -} - /** Return the dynamic prime stored in the disk. If there is no dynamic prime stored in the disk, return NULL. */ BIGNUM * @@ -722,12 +682,12 @@ init_keys(void) /** 3b. If we use a dynamic prime, store it to disk. */ if (get_options()->DynamicPrimes) { - BIGNUM *dynamic_prime = crypto_get_tls_dh_prime(); - if (dynamic_prime) { - if (router_store_dynamic_prime(dynamic_prime) < 0) - log_notice(LD_GENERAL, "Failed while storing dynamic prime. " - "Make sure your data directory is sane."); - } + const char *fname = get_datadir_fname2("keys", "dynamic_prime"); + if (crypto_store_dynamic_prime(fname)) { + log_notice(LD_GENERAL, "Failed while storing dynamic prime. " + "Make sure your data directory is sane."); + } + tor_free(fname); } /* 4. Build our router descriptor. */ diff --git a/src/or/router.h b/src/or/router.h index 41ff139936..a998335aa3 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -30,7 +30,6 @@ crypto_pk_env_t *init_key_from_file(const char *fname, int generate, int severity); BIGNUM *router_get_stored_dynamic_prime(void); -int router_store_dynamic_prime(const BIGNUM *dynamic_prime); void v3_authority_check_key_expiry(void); From 94076d9e3b74ad1f6aee8a96f51eb4af5f5bdb64 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 24 Nov 2011 22:59:01 +0100 Subject: [PATCH 12/26] Move crypto_get_stored_dynamic_prime() to crypto.c --- src/common/crypto.c | 70 ++++++++++++++++++++++++++++++++++++++------- src/common/crypto.h | 5 ++-- src/or/config.c | 14 +++++---- src/or/router.c | 58 ++++--------------------------------- src/or/router.h | 2 -- 5 files changed, 75 insertions(+), 74 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index a3c292324b..c6285e5ce9 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1851,7 +1851,7 @@ crypto_generate_dynamic_prime(void) /** Store our dynamic prime to fname for future use. */ int -router_store_dynamic_prime(const char *fname) +crypto_store_dynamic_prime(const char *fname) { FILE *fp = NULL; int retval = -1; @@ -1889,13 +1889,61 @@ router_store_dynamic_prime(const char *fname) return retval; } +/** Return the dynamic prime stored in fname. If there is no + dynamic prime stored in fname, return NULL. */ +static BIGNUM * +crypto_get_stored_dynamic_prime(const char *fname) +{ + int retval; + char *contents = NULL; + BIGNUM *dynamic_prime = BN_new(); + + tor_assert(fname); + + if (!dynamic_prime) + goto err; + + contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + if (!contents) + goto err; + + retval = BN_hex2bn(&dynamic_prime, contents); + if (!retval) { + log_notice(LD_GENERAL, "Could not understand the dynamic prime " + "format in '%s'", fname); + goto err; + } + + { /* log the dynamic prime: */ + char *s = BN_bn2hex(dynamic_prime); + tor_assert(s); + log_info(LD_OR, "Found stored dynamic prime: [%s]", s); + OPENSSL_free(s); + } + + goto done; + + err: + if (dynamic_prime) { + BN_free(dynamic_prime); + dynamic_prime = NULL; + } + + done: + tor_free(contents); + + return dynamic_prime; +} + + /** Set the global TLS Diffie-Hellman modulus. - * If use_dynamic_primes is not set, use the prime - * modulus of mod_ssl. - * If use_dynamic_primes is set, use stored_dynamic_prime - * if it exists, otherwise generate and use a new prime modulus. */ + * If dynamic_prime_fname is set, try to read a dynamic prime + * off it and use it as the DH modulus. If that's not possible, + * generate a new dynamic prime. + * If dynamic_prime_fname is NULL, use the Apache mod_ssl DH + * modulus. */ void -crypto_set_tls_dh_prime(int use_dynamic_primes, BIGNUM *stored_dynamic_prime) +crypto_set_tls_dh_prime(const char *dynamic_prime_fname) { BIGNUM *tls_prime = NULL; int r; @@ -1906,11 +1954,11 @@ crypto_set_tls_dh_prime(int use_dynamic_primes, BIGNUM *stored_dynamic_prime) dh_param_p_tls = NULL; } - if (use_dynamic_primes) { /* use dynamic primes: */ - if (stored_dynamic_prime) { - log_info(LD_OR, "Using stored dynamic prime."); - tls_prime = stored_dynamic_prime; - } else { + if (dynamic_prime_fname) { /* use dynamic primes: */ + log_info(LD_OR, "Using stored dynamic prime."); + tls_prime = crypto_get_stored_dynamic_prime(dynamic_prime_fname); + + if (!tls_prime) { log_info(LD_OR, "Generating fresh dynamic prime."); tls_prime = crypto_generate_dynamic_prime(); } diff --git a/src/common/crypto.h b/src/common/crypto.h index 8c99dd7a37..20298b3c49 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -95,9 +95,8 @@ int crypto_global_cleanup(void); crypto_pk_env_t *crypto_new_pk_env(void); void crypto_free_pk_env(crypto_pk_env_t *env); -void crypto_set_tls_dh_prime(int use_dynamic_primes, - BIGNUM *stored_dynamic_prime); -int router_store_dynamic_prime(const char *fname); +void crypto_set_tls_dh_prime(const char *dynamic_prime_fname); +int crypto_store_dynamic_prime(const char *fname); /* convenience function: wraps crypto_create_crypto_env, set_key, and init. */ crypto_cipher_env_t *crypto_create_init_cipher(const char *key, diff --git a/src/or/config.c b/src/or/config.c index 78e91bbe11..e1e71b0593 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1365,17 +1365,19 @@ options_act(const or_options_t *old_options) /* If needed, generate a new TLS DH prime according to the current torrc. */ if (!old_options) { if (options->DynamicPrimes) { - crypto_set_tls_dh_prime(1, router_get_stored_dynamic_prime()); + char *fname = get_datadir_fname2("keys", "dynamic_prime"); + crypto_set_tls_dh_prime(fname); + tor_free(fname); } else { - crypto_set_tls_dh_prime(0, NULL); + crypto_set_tls_dh_prime(NULL); } } else { if (options->DynamicPrimes && !old_options->DynamicPrimes) { - crypto_set_tls_dh_prime(1, router_get_stored_dynamic_prime()); + char *fname = get_datadir_fname2("keys", "dynamic_prime"); + crypto_set_tls_dh_prime(fname); + tor_free(fname); } else if (!options->DynamicPrimes && old_options->DynamicPrimes) { - crypto_set_tls_dh_prime(0, NULL); - } else { - tor_assert(crypto_get_tls_dh_prime()); + crypto_set_tls_dh_prime(NULL); } } diff --git a/src/or/router.c b/src/or/router.c index dd5b9fff52..c554d5b961 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -484,52 +484,6 @@ v3_authority_check_key_expiry(void) last_warned = now; } - -/** Return the dynamic prime stored in the disk. If there is no - dynamic prime stored in the disk, return NULL. */ -BIGNUM * -router_get_stored_dynamic_prime(void) -{ - int retval; - char *contents = NULL; - char *fname = get_datadir_fname2("keys", "dynamic_prime"); - BIGNUM *dynamic_prime = BN_new(); - if (!dynamic_prime) - goto err; - - contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); - if (!contents) - goto err; - - retval = BN_hex2bn(&dynamic_prime, contents); - if (!retval) { - log_notice(LD_GENERAL, "Could not understand the dynamic prime " - "format in '%s'", fname); - goto err; - } - - { /* log the dynamic prime: */ - char *s = BN_bn2hex(dynamic_prime); - tor_assert(s); - log_info(LD_OR, "Found stored dynamic prime: [%s]", s); - OPENSSL_free(s); - } - - goto done; - - err: - if (dynamic_prime) { - BN_free(dynamic_prime); - dynamic_prime = NULL; - } - - done: - tor_free(fname); - tor_free(contents); - - return dynamic_prime; -} - /** Initialize all OR private keys, and the TLS context, as necessary. * On OPs, this only initializes the tls context. Return 0 on success, * or -1 if Tor should die. @@ -682,12 +636,12 @@ init_keys(void) /** 3b. If we use a dynamic prime, store it to disk. */ if (get_options()->DynamicPrimes) { - const char *fname = get_datadir_fname2("keys", "dynamic_prime"); - if (crypto_store_dynamic_prime(fname)) { - log_notice(LD_GENERAL, "Failed while storing dynamic prime. " - "Make sure your data directory is sane."); - } - tor_free(fname); + char *fname = get_datadir_fname2("keys", "dynamic_prime"); + if (crypto_store_dynamic_prime(fname)) { + log_notice(LD_GENERAL, "Failed while storing dynamic prime. " + "Make sure your data directory is sane."); + } + tor_free(fname); } /* 4. Build our router descriptor. */ diff --git a/src/or/router.h b/src/or/router.h index a998335aa3..b9e9f2a713 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -29,8 +29,6 @@ void rotate_onion_key(void); crypto_pk_env_t *init_key_from_file(const char *fname, int generate, int severity); -BIGNUM *router_get_stored_dynamic_prime(void); - void v3_authority_check_key_expiry(void); int init_keys(void); From 5f3f41c23412e149add77a30e82431eb018cd376 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 00:33:40 +0100 Subject: [PATCH 13/26] Make sure that the stored DH prime is safe to use. --- src/common/crypto.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index c6285e5ce9..83f56a5d87 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1832,7 +1832,7 @@ crypto_generate_dynamic_prime(void) tor_assert(dh_parameters); r = DH_check(dh_parameters, &dh_codes); - tor_assert(r); + tor_assert(r && !dh_codes); BN_copy(dynamic_prime, dh_parameters->p); tor_assert(dynamic_prime); @@ -1855,10 +1855,12 @@ crypto_store_dynamic_prime(const char *fname) { FILE *fp = NULL; int retval = -1; - file_status_t fname_status = file_status(fname); + file_status_t fname_status; tor_assert(fname); + fname_status = file_status(fname); + if (fname_status == FN_FILE) { /* If the fname is a file, then the dynamic prime is already stored. */ retval = 0; @@ -1896,6 +1898,8 @@ crypto_get_stored_dynamic_prime(const char *fname) { int retval; char *contents = NULL; + DH *dh = NULL; + int dh_codes; BIGNUM *dynamic_prime = BN_new(); tor_assert(fname); @@ -1909,11 +1913,35 @@ crypto_get_stored_dynamic_prime(const char *fname) retval = BN_hex2bn(&dynamic_prime, contents); if (!retval) { - log_notice(LD_GENERAL, "Could not understand the dynamic prime " - "format in '%s'", fname); + log_warn(LD_GENERAL, "Could not understand the dynamic prime " + "format in '%s'", fname); goto err; } + { /* validate the stored prime */ + dh = DH_new(); + if (!dh) + goto err; + + dh->p = BN_dup(dynamic_prime); + dh->g = BN_new(); + BN_set_word(dh->g, DH_GENERATOR); + + retval = DH_check(dh, &dh_codes); + if (!retval || dh_codes) { + log_warn(LD_GENERAL, "Stored dynamic DH prime is not a safe prime."); + goto err; + } + + retval = DH_size(dh); + if (retval < DH_BYTES) { + log_warn(LD_GENERAL, "Stored dynamic DH prime is smaller " + "than '%d' bits.", DH_BYTES*8); + goto err; + } + + } + { /* log the dynamic prime: */ char *s = BN_bn2hex(dynamic_prime); tor_assert(s); @@ -1931,6 +1959,8 @@ crypto_get_stored_dynamic_prime(const char *fname) done: tor_free(contents); + if (dh) + DH_free(dh); return dynamic_prime; } From bdeb797a130c0d11dd6c1d7375eba468a09c6245 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 00:59:47 +0100 Subject: [PATCH 14/26] Notify the user that her computer is generating numbers. --- src/common/crypto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 83f56a5d87..4e96fed90a 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1989,7 +1989,8 @@ crypto_set_tls_dh_prime(const char *dynamic_prime_fname) tls_prime = crypto_get_stored_dynamic_prime(dynamic_prime_fname); if (!tls_prime) { - log_info(LD_OR, "Generating fresh dynamic prime."); + log_notice(LD_OR, "Generating fresh dynamic prime. " + "This might take a while..."); tls_prime = crypto_generate_dynamic_prime(); } } else { /* use the static DH prime modulus used by Apache in mod_ssl: */ From 782c907c7cbd3bf2bb75680f5d3deb2d984052de Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 01:00:14 +0100 Subject: [PATCH 15/26] s/DynamicPrimes/DynamicDHGroups/g --- src/or/config.c | 10 +++++----- src/or/or.h | 2 +- src/or/router.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index e1e71b0593..fc3cc745f9 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -247,7 +247,7 @@ static config_var_t _option_vars[] = { VAR("DirServer", LINELIST, DirServers, NULL), V(DisableAllSwap, BOOL, "0"), V(DisableIOCP, BOOL, "1"), - V(DynamicPrimes, BOOL, "1"), + V(DynamicDHGroups, BOOL, "1"), V(DNSPort, LINELIST, NULL), V(DNSListenAddress, LINELIST, NULL), V(DownloadExtraInfo, BOOL, "0"), @@ -1364,7 +1364,7 @@ options_act(const or_options_t *old_options) /* If needed, generate a new TLS DH prime according to the current torrc. */ if (!old_options) { - if (options->DynamicPrimes) { + if (options->DynamicDHGroups) { char *fname = get_datadir_fname2("keys", "dynamic_prime"); crypto_set_tls_dh_prime(fname); tor_free(fname); @@ -1372,11 +1372,11 @@ options_act(const or_options_t *old_options) crypto_set_tls_dh_prime(NULL); } } else { - if (options->DynamicPrimes && !old_options->DynamicPrimes) { + if (options->DynamicDHGroups && !old_options->DynamicDHGroups) { char *fname = get_datadir_fname2("keys", "dynamic_prime"); crypto_set_tls_dh_prime(fname); tor_free(fname); - } else if (!options->DynamicPrimes && old_options->DynamicPrimes) { + } else if (!options->DynamicDHGroups && old_options->DynamicDHGroups) { crypto_set_tls_dh_prime(NULL); } } @@ -4071,7 +4071,7 @@ options_transition_affects_workers(const or_options_t *old_options, { if (!opt_streq(old_options->DataDirectory, new_options->DataDirectory) || old_options->NumCPUs != new_options->NumCPUs || - old_options->DynamicPrimes != new_options->DynamicPrimes || + old_options->DynamicDHGroups != new_options->DynamicDHGroups || old_options->ORPort != new_options->ORPort || old_options->ServerDNSSearchDomains != new_options->ServerDNSSearchDomains || diff --git a/src/or/or.h b/src/or/or.h index b2ea3bc7a7..e3feeedc27 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2873,7 +2873,7 @@ typedef struct { char *Address; /**< OR only: configured address for this onion router. */ char *PidFile; /**< Where to store PID of Tor process. */ - int DynamicPrimes; /**< Enable dynamic generation of primes for use in DH. */ + int DynamicDHGroups; /**< Enable dynamic generation of primes for use in DH. */ routerset_t *ExitNodes; /**< Structure containing nicknames, digests, * country codes and IP address patterns of ORs to diff --git a/src/or/router.c b/src/or/router.c index c554d5b961..fa791fc85e 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -635,7 +635,7 @@ init_keys(void) } /** 3b. If we use a dynamic prime, store it to disk. */ - if (get_options()->DynamicPrimes) { + if (get_options()->DynamicDHGroups) { char *fname = get_datadir_fname2("keys", "dynamic_prime"); if (crypto_store_dynamic_prime(fname)) { log_notice(LD_GENERAL, "Failed while storing dynamic prime. " From 7c37a664c17f4dd9748f096ea385c3627cc323fa Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 01:00:58 +0100 Subject: [PATCH 16/26] Rename 'dynamic prime' to 'dynamic DH modulus'. --- src/common/crypto.c | 80 ++++++++++++++++++++++----------------------- src/common/crypto.h | 4 +-- src/or/config.c | 4 +-- src/or/router.c | 4 +-- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 4e96fed90a..0f828db81f 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1818,15 +1818,15 @@ static BIGNUM *dh_param_g = NULL; /** Generate and return a reasonable and safe DH parameter p. */ static BIGNUM * -crypto_generate_dynamic_prime(void) +crypto_generate_dynamic_dh_modulus(void) { - BIGNUM *dynamic_prime; + BIGNUM *dynamic_dh_modulus; DH *dh_parameters; int r, dh_codes; char *s; - dynamic_prime = BN_new(); - tor_assert(dynamic_prime); + dynamic_dh_modulus = BN_new(); + tor_assert(dynamic_dh_modulus); dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL); tor_assert(dh_parameters); @@ -1834,24 +1834,24 @@ crypto_generate_dynamic_prime(void) r = DH_check(dh_parameters, &dh_codes); tor_assert(r && !dh_codes); - BN_copy(dynamic_prime, dh_parameters->p); - tor_assert(dynamic_prime); + BN_copy(dynamic_dh_modulus, dh_parameters->p); + tor_assert(dynamic_dh_modulus); DH_free(dh_parameters); - { /* log the dynamic prime: */ - s = BN_bn2hex(dynamic_prime); + { /* log the dynamic DH modulus: */ + s = BN_bn2hex(dynamic_dh_modulus); tor_assert(s); - log_info(LD_OR, "Dynamic prime generated: [%s]", s); + log_info(LD_OR, "Dynamic DH modulus generated: [%s]", s); OPENSSL_free(s); } - return dynamic_prime; + return dynamic_dh_modulus; } -/** Store our dynamic prime to fname for future use. */ +/** Store our dynamic DH modulus to fname for future use. */ int -crypto_store_dynamic_prime(const char *fname) +crypto_store_dynamic_dh_modulus(const char *fname) { FILE *fp = NULL; int retval = -1; @@ -1862,23 +1862,23 @@ crypto_store_dynamic_prime(const char *fname) fname_status = file_status(fname); if (fname_status == FN_FILE) { - /* If the fname is a file, then the dynamic prime is already stored. */ + /* If the fname is a file, then the dynamic DH modulus is already stored. */ retval = 0; goto done; } else if (fname_status != FN_NOENT) { - log_info(LD_GENERAL, "Dynamic prime filename is occupied."); + log_info(LD_GENERAL, "Dynamic DH modulus filename is occupied."); goto done; } tor_assert(fname_status == FN_NOENT); if (!(fp = fopen(fname, "w"))) { - log_notice(LD_GENERAL, "Error while creating dynamic prime file."); + log_notice(LD_GENERAL, "Error while creating dynamic DH modulus file."); goto done; } if (BN_print_fp(fp, dh_param_p_tls) == 0) { - log_warn(LD_GENERAL, "Error while printing dynamic prime to file."); + log_warn(LD_GENERAL, "Error while printing dynamic DH modulus to file."); goto done; } @@ -1891,29 +1891,29 @@ crypto_store_dynamic_prime(const char *fname) return retval; } -/** Return the dynamic prime stored in fname. If there is no - dynamic prime stored in fname, return NULL. */ +/** Return the dynamic DH modulus stored in fname. If there is no + dynamic DH modulus stored in fname, return NULL. */ static BIGNUM * -crypto_get_stored_dynamic_prime(const char *fname) +crypto_get_stored_dynamic_dh_modulus(const char *fname) { int retval; char *contents = NULL; DH *dh = NULL; int dh_codes; - BIGNUM *dynamic_prime = BN_new(); + BIGNUM *dynamic_dh_modulus = BN_new(); tor_assert(fname); - if (!dynamic_prime) + if (!dynamic_dh_modulus) goto err; contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); if (!contents) goto err; - retval = BN_hex2bn(&dynamic_prime, contents); + retval = BN_hex2bn(&dynamic_dh_modulus, contents); if (!retval) { - log_warn(LD_GENERAL, "Could not understand the dynamic prime " + log_warn(LD_GENERAL, "Could not understand the dynamic DH modulus " "format in '%s'", fname); goto err; } @@ -1923,7 +1923,7 @@ crypto_get_stored_dynamic_prime(const char *fname) if (!dh) goto err; - dh->p = BN_dup(dynamic_prime); + dh->p = BN_dup(dynamic_dh_modulus); dh->g = BN_new(); BN_set_word(dh->g, DH_GENERATOR); @@ -1942,19 +1942,19 @@ crypto_get_stored_dynamic_prime(const char *fname) } - { /* log the dynamic prime: */ - char *s = BN_bn2hex(dynamic_prime); + { /* log the dynamic DH modulus: */ + char *s = BN_bn2hex(dynamic_dh_modulus); tor_assert(s); - log_info(LD_OR, "Found stored dynamic prime: [%s]", s); + log_info(LD_OR, "Found stored dynamic DH modulus: [%s]", s); OPENSSL_free(s); } goto done; err: - if (dynamic_prime) { - BN_free(dynamic_prime); - dynamic_prime = NULL; + if (dynamic_dh_modulus) { + BN_free(dynamic_dh_modulus); + dynamic_dh_modulus = NULL; } done: @@ -1962,18 +1962,18 @@ crypto_get_stored_dynamic_prime(const char *fname) if (dh) DH_free(dh); - return dynamic_prime; + return dynamic_dh_modulus; } /** Set the global TLS Diffie-Hellman modulus. - * If dynamic_prime_fname is set, try to read a dynamic prime + * If dynamic_dh_modulus_fname 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 prime. - * If dynamic_prime_fname is NULL, use the Apache mod_ssl DH + * generate a new dynamic DH modulus. + * If dynamic_dh_modulus_fname is NULL, use the Apache mod_ssl DH * modulus. */ void -crypto_set_tls_dh_prime(const char *dynamic_prime_fname) +crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) { BIGNUM *tls_prime = NULL; int r; @@ -1984,14 +1984,14 @@ crypto_set_tls_dh_prime(const char *dynamic_prime_fname) dh_param_p_tls = NULL; } - if (dynamic_prime_fname) { /* use dynamic primes: */ - log_info(LD_OR, "Using stored dynamic prime."); - tls_prime = crypto_get_stored_dynamic_prime(dynamic_prime_fname); + if (dynamic_dh_modulus_fname) { /* use dynamic DH moduluss: */ + 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 prime. " + log_notice(LD_OR, "Generating fresh dynamic DH modulus. " "This might take a while..."); - tls_prime = crypto_generate_dynamic_prime(); + tls_prime = crypto_generate_dynamic_dh_modulus(); } } else { /* use the static DH prime modulus used by Apache in mod_ssl: */ tls_prime = BN_new(); diff --git a/src/common/crypto.h b/src/common/crypto.h index 20298b3c49..504c59b1a7 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -95,8 +95,8 @@ int crypto_global_cleanup(void); crypto_pk_env_t *crypto_new_pk_env(void); void crypto_free_pk_env(crypto_pk_env_t *env); -void crypto_set_tls_dh_prime(const char *dynamic_prime_fname); -int crypto_store_dynamic_prime(const char *fname); +void crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname); +int crypto_store_dynamic_dh_modulus(const char *fname); /* convenience function: wraps crypto_create_crypto_env, set_key, and init. */ crypto_cipher_env_t *crypto_create_init_cipher(const char *key, diff --git a/src/or/config.c b/src/or/config.c index fc3cc745f9..d403decb18 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1365,7 +1365,7 @@ options_act(const or_options_t *old_options) /* If needed, generate a new TLS DH prime according to the current torrc. */ if (!old_options) { if (options->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_prime"); + char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); crypto_set_tls_dh_prime(fname); tor_free(fname); } else { @@ -1373,7 +1373,7 @@ options_act(const or_options_t *old_options) } } else { if (options->DynamicDHGroups && !old_options->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_prime"); + char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); crypto_set_tls_dh_prime(fname); tor_free(fname); } else if (!options->DynamicDHGroups && old_options->DynamicDHGroups) { diff --git a/src/or/router.c b/src/or/router.c index fa791fc85e..963c781733 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -636,8 +636,8 @@ init_keys(void) /** 3b. If we use a dynamic prime, store it to disk. */ if (get_options()->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_prime"); - if (crypto_store_dynamic_prime(fname)) { + char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); + if (crypto_store_dynamic_dh_modulus(fname)) { log_notice(LD_GENERAL, "Failed while storing dynamic prime. " "Make sure your data directory is sane."); } From 1d1d5ae7f8f91b62f0e86081ff1f7255c545383b Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 01:08:31 +0100 Subject: [PATCH 17/26] Finishing touches. - Make check-spaces happy. - Remove a stray header from crypto.h --- src/common/crypto.c | 16 +++++++--------- src/common/crypto.h | 2 -- src/or/or.h | 2 +- src/or/router.h | 1 - 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 0f828db81f..8b0f0ef9da 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1862,7 +1862,7 @@ crypto_store_dynamic_dh_modulus(const char *fname) fname_status = file_status(fname); if (fname_status == FN_FILE) { - /* If the fname is a file, then the dynamic DH modulus is already stored. */ + /* If the fname is a file, then the dynamic DH modulus is already stored.*/ retval = 0; goto done; } else if (fname_status != FN_NOENT) { @@ -1939,7 +1939,6 @@ crypto_get_stored_dynamic_dh_modulus(const char *fname) "than '%d' bits.", DH_BYTES*8); goto err; } - } { /* log the dynamic DH modulus: */ @@ -1965,7 +1964,6 @@ crypto_get_stored_dynamic_dh_modulus(const char *fname) return dynamic_dh_modulus; } - /** Set the global TLS Diffie-Hellman modulus. * If dynamic_dh_modulus_fname is set, try to read a dynamic DH modulus * off it and use it as the DH modulus. If that's not possible, @@ -2001,12 +1999,12 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) * 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"); + r =BN_hex2bn(&tls_prime, + "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" + "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" + "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" + "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" + "B0E7393E0F24218EB3"); tor_assert(r); } diff --git a/src/common/crypto.h b/src/common/crypto.h index 504c59b1a7..683c8ea38f 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -16,8 +16,6 @@ #include #include "torint.h" -#include - /** Length of the output of our message digest. */ #define DIGEST_LEN 20 /** Length of the output of our second (improved) message digests. (For now diff --git a/src/or/or.h b/src/or/or.h index e3feeedc27..ec49014d94 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2873,7 +2873,7 @@ typedef struct { char *Address; /**< OR only: configured address for this onion router. */ char *PidFile; /**< Where to store PID of Tor process. */ - int DynamicDHGroups; /**< Enable dynamic generation of primes for use in DH. */ + int DynamicDHGroups; /**< Dynamic generation of prime moduli for use in DH.*/ routerset_t *ExitNodes; /**< Structure containing nicknames, digests, * country codes and IP address patterns of ORs to diff --git a/src/or/router.h b/src/or/router.h index b9e9f2a713..f9d156cb09 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -28,7 +28,6 @@ void dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last); void rotate_onion_key(void); crypto_pk_env_t *init_key_from_file(const char *fname, int generate, int severity); - void v3_authority_check_key_expiry(void); int init_keys(void); From 4938bcc06a41b95f47def181ce03a7ade805595b Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 17:39:28 +0100 Subject: [PATCH 18/26] Do dynamic DH modulus storing in crypto.c. --- src/common/crypto.c | 15 +++++++++++++-- src/common/crypto.h | 1 - src/or/router.c | 10 ---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 8b0f0ef9da..1974a3931b 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1850,7 +1850,7 @@ crypto_generate_dynamic_dh_modulus(void) } /** Store our dynamic DH modulus to fname for future use. */ -int +static int crypto_store_dynamic_dh_modulus(const char *fname) { FILE *fp = NULL; @@ -1974,6 +1974,7 @@ void crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) { BIGNUM *tls_prime = NULL; + int store_dh_prime_afterwards = 0; int r; /* If the space is occupied, free the previous TLS DH prime */ @@ -1982,7 +1983,7 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) dh_param_p_tls = NULL; } - if (dynamic_dh_modulus_fname) { /* use dynamic DH moduluss: */ + 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); @@ -1990,6 +1991,8 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) log_notice(LD_OR, "Generating fresh dynamic DH modulus. " "This might take a while..."); tls_prime = crypto_generate_dynamic_dh_modulus(); + + store_dh_prime_afterwards++; } } else { /* use the static DH prime modulus used by Apache in mod_ssl: */ tls_prime = BN_new(); @@ -2011,6 +2014,14 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) 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_GENERAL, "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 diff --git a/src/common/crypto.h b/src/common/crypto.h index 683c8ea38f..bac6db920a 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -94,7 +94,6 @@ crypto_pk_env_t *crypto_new_pk_env(void); void crypto_free_pk_env(crypto_pk_env_t *env); void crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname); -int crypto_store_dynamic_dh_modulus(const char *fname); /* convenience function: wraps crypto_create_crypto_env, set_key, and init. */ crypto_cipher_env_t *crypto_create_init_cipher(const char *key, diff --git a/src/or/router.c b/src/or/router.c index 963c781733..fdc83f5087 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -634,16 +634,6 @@ init_keys(void) return -1; } - /** 3b. If we use a dynamic prime, store it to disk. */ - if (get_options()->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); - if (crypto_store_dynamic_dh_modulus(fname)) { - log_notice(LD_GENERAL, "Failed while storing dynamic prime. " - "Make sure your data directory is sane."); - } - tor_free(fname); - } - /* 4. Build our router descriptor. */ /* Must be called after keys are initialized. */ mydesc = router_get_my_descriptor(); From 1df6b5a734acd381d49a57bb689c7dcd2cd66ad9 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 17:39:45 +0100 Subject: [PATCH 19/26] Move broken primes to dynamic_dh_modulus.broken. --- src/common/crypto.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/common/crypto.c b/src/common/crypto.c index 1974a3931b..da3b80becb 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1900,6 +1900,7 @@ crypto_get_stored_dynamic_dh_modulus(const char *fname) char *contents = NULL; DH *dh = NULL; int dh_codes; + char *fname_new = NULL; BIGNUM *dynamic_dh_modulus = BN_new(); tor_assert(fname); @@ -1951,6 +1952,24 @@ crypto_get_stored_dynamic_dh_modulus(const char *fname) goto done; err: + + { /* move broken prime to $filename.broken */ + + fname_new = tor_malloc(strlen(fname) + 8); + + /* no can do if these functions return error */ + strlcpy(fname_new, fname, strlen(fname) + 8); + strlcat(fname_new, ".broken", strlen(fname) + 8); + + log_warn(LD_GENERAL, "Moving broken dynamic DH prime to '%s'.", fname_new); + + if (replace_file(fname, fname_new)) + log_warn(LD_GENERAL, "Error while moving '%s' to '%s'.", fname, fname_new); + + tor_free(fname_new); + + } + if (dynamic_dh_modulus) { BN_free(dynamic_dh_modulus); dynamic_dh_modulus = NULL; From b31601975b0be372f6c041868a54024a8d89ad8c Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 17:44:11 +0100 Subject: [PATCH 20/26] Move DH_GENERATOR to crypto.c. --- src/common/crypto.c | 3 +++ src/common/crypto.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index da3b80becb..8cf6231921 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1809,6 +1809,9 @@ crypto_hmac_sha256(char *hmac_out, /* DH */ +/** Our DH 'g' parameter */ +#define DH_GENERATOR 2 + /** Shared P parameter for our circuit-crypto DH key exchanges. */ static BIGNUM *dh_param_p = NULL; /** Shared P parameter for our TLS DH key exchanges. */ diff --git a/src/common/crypto.h b/src/common/crypto.h index bac6db920a..771c49c2d1 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -29,8 +29,6 @@ #define PK_BYTES (1024/8) /** Length of our DH keys. */ #define DH_BYTES (1024/8) -/** Our DH 'g' parameter */ -#define DH_GENERATOR 2 /** Length of a sha1 message digest when encoded in base64 with trailing = * signs removed. */ From f477ddcc20d5fc8c130b630854947a337881cd23 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 17:44:43 +0100 Subject: [PATCH 21/26] Only bother with dynamic DH moduli if we are a bridge. --- src/or/config.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index d403decb18..a846ca9079 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1363,22 +1363,26 @@ options_act(const or_options_t *old_options) } /* If needed, generate a new TLS DH prime according to the current torrc. */ - if (!old_options) { - if (options->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); - crypto_set_tls_dh_prime(fname); - tor_free(fname); + if (server_mode(options) && options->BridgeRelay) { + if (!old_options) { + if (options->DynamicDHGroups) { + char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); + crypto_set_tls_dh_prime(fname); + tor_free(fname); + } else { + crypto_set_tls_dh_prime(NULL); + } } else { - crypto_set_tls_dh_prime(NULL); - } - } else { - if (options->DynamicDHGroups && !old_options->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); - crypto_set_tls_dh_prime(fname); - tor_free(fname); - } else if (!options->DynamicDHGroups && old_options->DynamicDHGroups) { - crypto_set_tls_dh_prime(NULL); + if (options->DynamicDHGroups && !old_options->DynamicDHGroups) { + char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); + crypto_set_tls_dh_prime(fname); + tor_free(fname); + } else if (!options->DynamicDHGroups && old_options->DynamicDHGroups) { + crypto_set_tls_dh_prime(NULL); + } } + } else { /* clients don't need a dynamic DH prime. */ + crypto_set_tls_dh_prime(NULL); } /* We want to reinit keys as needed before we do much of anything else: From e2a189053dd93ba94d13035fff5008fcdefa8eca Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 25 Nov 2011 17:44:48 +0100 Subject: [PATCH 22/26] Add a changes file. --- changes/bug4548 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/bug4548 diff --git a/changes/bug4548 b/changes/bug4548 new file mode 100644 index 0000000000..e22e3f5077 --- /dev/null +++ b/changes/bug4548 @@ -0,0 +1,6 @@ + o Privacy/anonymity features (bridge detection): + - Introduce a new config option 'DynamicDHGroups', enabled by + default, which provides each bridge with a unique prime DH + modulus to be used during SSL handshakes. This option attempts + to help against censors using the Apache DH modulus as a static + identifier for bridges. From e3cee8bc2e8df6b39a4122829649e3f9ab920aa6 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 24 Nov 2011 06:40:02 +0100 Subject: [PATCH 23/26] Simply initialize TLS context if DynamicDHGroups change. We used to do init_keys() if DynamicDHGroups changed after a HUP, so that the dynamic DH modulus was stored on the disk. Since we are now doing dynamic DH modulus storing in crypto.c, we can simply initialize the TLS context and be good with it. Introduce a new function router_initialize_tls_context() which initializes the TLS context and use it appropriately. --- src/or/config.c | 26 +++++++++++++++++++++++++- src/or/main.c | 5 +---- src/or/router.c | 21 +++++++++++++-------- src/or/router.h | 1 + 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index a846ca9079..f8c4ab314d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1267,6 +1267,24 @@ get_effective_bwburst(const or_options_t *options) return (uint32_t)bw; } +/** Return True if any changes from old_options to + * new_options needs us to refresh our TLS context. */ +static int +options_transition_requires_fresh_tls_context(const or_options_t *old_options, + const or_options_t *new_options) +{ + tor_assert(new_options); + + if (!old_options) + return 0; + + if ((old_options->DynamicDHGroups != new_options->DynamicDHGroups)) { + return 1; + } + + return 0; +} + /** Fetch the active option list, and take actions based on it. All of the * things we do should survive being done repeatedly. If present, * old_options contains the previous value of the options. @@ -1394,6 +1412,13 @@ options_act(const or_options_t *old_options) log_warn(LD_BUG,"Error initializing keys; exiting"); return -1; } + } else if (old_options && + options_transition_requires_fresh_tls_context(old_options, + options)) { + if (router_initialize_tls_context() < 0) { + log_warn(LD_BUG,"Error initializing TLS context."); + return -1; + } } /* Write our PID to the PID file. If we do not have write permissions we @@ -4075,7 +4100,6 @@ options_transition_affects_workers(const or_options_t *old_options, { if (!opt_streq(old_options->DataDirectory, new_options->DataDirectory) || old_options->NumCPUs != new_options->NumCPUs || - old_options->DynamicDHGroups != new_options->DynamicDHGroups || old_options->ORPort != new_options->ORPort || old_options->ServerDNSSearchDomains != new_options->ServerDNSSearchDomains || diff --git a/src/or/main.c b/src/or/main.c index 7008d388a1..95f9958aa8 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1161,10 +1161,7 @@ run_scheduled_events(time_t now) last_rotated_x509_certificate = now; if (last_rotated_x509_certificate+MAX_SSL_KEY_LIFETIME_INTERNAL < now) { log_info(LD_GENERAL,"Rotating tls context."); - if (tor_tls_context_init(public_server_mode(options), - get_tlsclient_identity_key(), - is_server ? get_server_identity_key() : NULL, - MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + if (router_initialize_tls_context() < 0) { log_warn(LD_BUG, "Error reinitializing TLS context"); /* XXX is it a bug here, that we just keep going? -RD */ } diff --git a/src/or/router.c b/src/or/router.c index fdc83f5087..67e98da239 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -484,6 +484,17 @@ v3_authority_check_key_expiry(void) last_warned = now; } + +int +router_initialize_tls_context(void) +{ + return tor_tls_context_init(public_server_mode(get_options()), + get_tlsclient_identity_key(), + server_mode(get_options()) ? + get_server_identity_key() : NULL, + MAX_SSL_KEY_LIFETIME_ADVERTISED); +} + /** Initialize all OR private keys, and the TLS context, as necessary. * On OPs, this only initializes the tls context. Return 0 on success, * or -1 if Tor should die. @@ -530,10 +541,7 @@ init_keys(void) } set_client_identity_key(prkey); /* Create a TLS context. */ - if (tor_tls_context_init(0, - get_tlsclient_identity_key(), - NULL, - MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + if (router_initialize_tls_context() < 0) { log_err(LD_GENERAL,"Error creating TLS context for Tor client."); return -1; } @@ -626,10 +634,7 @@ init_keys(void) tor_free(keydir); /* 3. Initialize link key and TLS context. */ - if (tor_tls_context_init(public_server_mode(options), - get_tlsclient_identity_key(), - get_server_identity_key(), - MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + if (router_initialize_tls_context() < 0) { log_err(LD_GENERAL,"Error initializing TLS context"); return -1; } diff --git a/src/or/router.h b/src/or/router.h index f9d156cb09..68eadbf4c2 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -30,6 +30,7 @@ crypto_pk_env_t *init_key_from_file(const char *fname, int generate, int severity); void v3_authority_check_key_expiry(void); +int router_initialize_tls_context(void); int init_keys(void); int check_whether_orport_reachable(void); From fa013e1bc520e116fa63729041e00546d6787dd8 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sat, 26 Nov 2011 05:57:17 +0100 Subject: [PATCH 24/26] Normal relays should generate dynamic DH moduli as well. --- src/or/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/or/config.c b/src/or/config.c index f8c4ab314d..9c658614ba 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1381,7 +1381,7 @@ options_act(const or_options_t *old_options) } /* If needed, generate a new TLS DH prime according to the current torrc. */ - if (server_mode(options) && options->BridgeRelay) { + if (server_mode(options)) { if (!old_options) { if (options->DynamicDHGroups) { char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); From f28014bf1aa4274a35404ccc37b559b5531f1835 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sat, 26 Nov 2011 18:56:49 +0100 Subject: [PATCH 25/26] Introduce write_bytes_to_new_file(). Introduce write_bytes_to_new_file(), a function which writes bytes to a file only if that file did not exist. --- src/common/util.c | 42 ++++++++++++++++++++++++++++-------------- src/common/util.h | 3 +++ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index c44a4aa3b1..c19e4d20ca 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -2137,13 +2137,12 @@ write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin) return write_chunks_to_file_impl(fname, chunks, flags); } -/** As write_str_to_file, but does not assume a NUL-terminated - * string. Instead, we write len bytes, starting at str. */ -int -write_bytes_to_file(const char *fname, const char *str, size_t len, - int bin) +/** Write len bytes, starting at str, to fname + using the open() flags passed in flags. */ +static int +write_bytes_to_file_impl(const char *fname, const char *str, size_t len, + int flags) { - int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT); int r; sized_chunk_t c = { str, len }; smartlist_t *chunks = smartlist_create(); @@ -2153,20 +2152,35 @@ write_bytes_to_file(const char *fname, const char *str, size_t len, return r; } +/** As write_str_to_file, but does not assume a NUL-terminated + * string. Instead, we write len bytes, starting at str. */ +int +write_bytes_to_file(const char *fname, const char *str, size_t len, + int bin) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT)); +} + /** As write_bytes_to_file, but if the file already exists, append the bytes * to the end of the file instead of overwriting it. */ int append_bytes_to_file(const char *fname, const char *str, size_t len, int bin) { - int flags = OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT); - int r; - sized_chunk_t c = { str, len }; - smartlist_t *chunks = smartlist_create(); - smartlist_add(chunks, &c); - r = write_chunks_to_file_impl(fname, chunks, flags); - smartlist_free(chunks); - return r; + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT)); +} + +/** Like write_str_to_file(), but also return -1 if there was a file + already residing in fname. */ +int +write_bytes_to_new_file(const char *fname, const char *str, size_t len, + int bin) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_DONT_REPLACE| + (bin?O_BINARY:O_TEXT)); } /** Read the contents of filename into a newly allocated diff --git a/src/common/util.h b/src/common/util.h index 77ed1ca5ee..79b641a014 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -315,6 +315,7 @@ int check_private_dir(const char *dirname, cpd_check_t check, const char *effective_user); #define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC) #define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND) +#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY) typedef struct open_file_t open_file_t; int start_writing_to_file(const char *fname, int open_flags, int mode, open_file_t **data_out); @@ -336,6 +337,8 @@ int write_chunks_to_file(const char *fname, const struct smartlist_t *chunks, int bin); int append_bytes_to_file(const char *fname, const char *str, size_t len, int bin); +int write_bytes_to_new_file(const char *fname, const char *str, size_t len, + int bin); /** Flag for read_file_to_str: open the file in binary mode. */ #define RFTS_BIN 1 From 055d6c01fff3324dbb38c2d81ad49ccfdb5432c2 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sat, 26 Nov 2011 19:29:57 +0100 Subject: [PATCH 26/26] Write dynamic DH parameters to a file. Instead of only writing the dynamic DH prime modulus to a file, write the whole DH parameters set for forward compatibility. At the moment we only accept '2' as the group generator. The DH parameters gets stored in base64-ed DER format to the 'dynamic_dh_params' file. --- src/common/crypto.c | 140 +++++++++++++++++++++++++++----------------- src/or/config.c | 4 +- src/or/router.c | 1 - 3 files changed, 89 insertions(+), 56 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 8cf6231921..a38956d3e8 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1852,44 +1852,66 @@ crypto_generate_dynamic_dh_modulus(void) return dynamic_dh_modulus; } -/** Store our dynamic DH modulus to fname for future use. */ +/** Store our dynamic DH modulus (and its group parameters) to + fname for future use. */ static int crypto_store_dynamic_dh_modulus(const char *fname) { - FILE *fp = NULL; + int len, new_len; + DH *dh = NULL; + unsigned char *dh_string_repr = NULL, *cp = NULL; + char *base64_encoded_dh = NULL; int retval = -1; - file_status_t fname_status; tor_assert(fname); - fname_status = file_status(fname); - - if (fname_status == FN_FILE) { - /* If the fname is a file, then the dynamic DH modulus is already stored.*/ - retval = 0; - goto done; - } else if (fname_status != FN_NOENT) { - log_info(LD_GENERAL, "Dynamic DH modulus filename is occupied."); + if (!dh_param_p_tls) { + log_info(LD_CRYPTO, "Tried to store a DH modulus that does not exist."); goto done; } - tor_assert(fname_status == FN_NOENT); + 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; - if (!(fp = fopen(fname, "w"))) { - log_notice(LD_GENERAL, "Error while creating dynamic DH modulus file."); + len = i2d_DHparams(dh, NULL); + if (len < 0) { + log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (1)."); goto done; } - if (BN_print_fp(fp, dh_param_p_tls) == 0) { - log_warn(LD_GENERAL, "Error while printing dynamic DH modulus to file."); + cp = dh_string_repr = tor_malloc_zero(len+1); + len = i2d_DHparams(dh, &cp); + if ((len < 0) || ((cp - dh_string_repr) != len)) { + log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2)."); + goto done; + } + + base64_encoded_dh = tor_malloc_zero(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; + } + + if (write_bytes_to_new_file(fname, base64_encoded_dh, new_len, 0) < 0) { + log_info(LD_CRYPTO, "'%s' was already occupied.", fname); goto done; } retval = 0; done: - if (fp) - fclose(fp); + if (dh) + DH_free(dh); + tor_free(dh_string_repr); + tor_free(base64_encoded_dh); return retval; } @@ -1901,52 +1923,62 @@ crypto_get_stored_dynamic_dh_modulus(const char *fname) { int retval; char *contents = NULL; - DH *dh = NULL; int dh_codes; char *fname_new = NULL; - BIGNUM *dynamic_dh_modulus = BN_new(); + 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); - if (!dynamic_dh_modulus) - goto err; - contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); - if (!contents) - goto err; + 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.*/ + } - retval = BN_hex2bn(&dynamic_dh_modulus, contents); - if (!retval) { - log_warn(LD_GENERAL, "Could not understand the dynamic DH modulus " - "format in '%s'", fname); + /* 'fname' contains the DH parameters stored in base64-ed DER + format. We are only interested in the DH modulus. */ + + cp = base64_decoded_dh = tor_malloc_zero(strlen(contents)); + length = base64_decode((char *)base64_decoded_dh, strlen(contents), + contents, strlen(contents)); + if (length < 0) { + log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (base64)."); goto err; } - { /* validate the stored prime */ - dh = DH_new(); - if (!dh) - 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; + } - dh->p = BN_dup(dynamic_dh_modulus); - dh->g = BN_new(); - BN_set_word(dh->g, DH_GENERATOR); - - retval = DH_check(dh, &dh_codes); + { /* check the cryptographic qualities of the stored dynamic DH modulus: */ + retval = DH_check(stored_dh, &dh_codes); if (!retval || dh_codes) { - log_warn(LD_GENERAL, "Stored dynamic DH prime is not a safe prime."); + log_warn(LD_CRYPTO, "Stored dynamic DH modulus is not a safe prime."); goto err; } - retval = DH_size(dh); + retval = DH_size(stored_dh); if (retval < DH_BYTES) { - log_warn(LD_GENERAL, "Stored dynamic DH prime is smaller " + 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(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); @@ -1957,31 +1989,34 @@ crypto_get_stored_dynamic_dh_modulus(const char *fname) err: { /* move broken prime to $filename.broken */ - fname_new = tor_malloc(strlen(fname) + 8); /* no can do if these functions return error */ strlcpy(fname_new, fname, strlen(fname) + 8); strlcat(fname_new, ".broken", strlen(fname) + 8); - log_warn(LD_GENERAL, "Moving broken dynamic DH prime to '%s'.", fname_new); + log_warn(LD_CRYPTO, "Moving broken dynamic DH prime to '%s'.", fname_new); if (replace_file(fname, fname_new)) - log_warn(LD_GENERAL, "Error while moving '%s' to '%s'.", fname, fname_new); + log_notice(LD_CRYPTO, "Error while moving '%s' to '%s'.", + fname, fname_new); tor_free(fname_new); - } - if (dynamic_dh_modulus) { - BN_free(dynamic_dh_modulus); - dynamic_dh_modulus = NULL; + if (stored_dh) { + DH_free(stored_dh); + stored_dh = NULL; } done: tor_free(contents); - if (dh) - DH_free(dh); + tor_free(base64_decoded_dh); + + if (stored_dh) { + dynamic_dh_modulus = BN_dup(stored_dh->p); + DH_free(stored_dh); + } return dynamic_dh_modulus; } @@ -2040,10 +2075,9 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) 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_GENERAL, "Failed while storing dynamic DH modulus. " + 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 diff --git a/src/or/config.c b/src/or/config.c index 9c658614ba..06914b62af 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1384,7 +1384,7 @@ options_act(const or_options_t *old_options) if (server_mode(options)) { if (!old_options) { if (options->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); + char *fname = get_datadir_fname2("keys", "dynamic_dh_params"); crypto_set_tls_dh_prime(fname); tor_free(fname); } else { @@ -1392,7 +1392,7 @@ options_act(const or_options_t *old_options) } } else { if (options->DynamicDHGroups && !old_options->DynamicDHGroups) { - char *fname = get_datadir_fname2("keys", "dynamic_dh_modulus"); + char *fname = get_datadir_fname2("keys", "dynamic_dh_params"); crypto_set_tls_dh_prime(fname); tor_free(fname); } else if (!options->DynamicDHGroups && old_options->DynamicDHGroups) { diff --git a/src/or/router.c b/src/or/router.c index 67e98da239..5d36939a8b 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -484,7 +484,6 @@ v3_authority_check_key_expiry(void) last_warned = now; } - int router_initialize_tls_context(void) {