summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2016-02-06 15:30:22 -0500
committerNick Mathewson <nickm@torproject.org>2016-02-06 15:30:22 -0500
commit0f5f6b8a412615026603954b1760006723026da1 (patch)
tree842e59ae1ea39f387f3ab407ea6dbb88d04c46f8 /src
parentb645e2f2b0113b143078a4fb6c227280b17fcb00 (diff)
parentc625ab9f5a36a99f9dff2fa842d2e43d23ad1908 (diff)
downloadtor-0f5f6b8a412615026603954b1760006723026da1.tar.gz
tor-0f5f6b8a412615026603954b1760006723026da1.zip
Merge remote-tracking branch 'yawning/bug18221'
Diffstat (limited to 'src')
-rw-r--r--src/common/crypto.c79
1 files changed, 71 insertions, 8 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 372869d41e..06446ba050 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -2089,6 +2089,71 @@ static BIGNUM *dh_param_p_tls = NULL;
/** Shared G parameter for our DH key exchanges. */
static BIGNUM *dh_param_g = NULL;
+/** Validate a given set of Diffie-Hellman parameters. This is moderately
+ * computationally expensive (milliseconds), so should only be called when
+ * the DH parameters change. Returns 0 on success, * -1 on failure.
+ */
+static int
+crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g)
+{
+ DH *dh = NULL;
+ int ret = -1;
+
+ /* Copy into a temporary DH object. */
+ if (!(dh = DH_new()))
+ goto out;
+ if (!(dh->p = BN_dup(p)))
+ goto out;
+ if (!(dh->g = BN_dup(g)))
+ goto out;
+
+ /* Perform the validation. */
+ int codes = 0;
+ if (!DH_check(dh, &codes))
+ goto out;
+ if (BN_is_word(dh->g, DH_GENERATOR_2)) {
+ /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters
+ *
+ * OpenSSL checks the prime is congruent to 11 when g = 2; while the
+ * IETF's primes are congruent to 23 when g = 2.
+ */
+ BN_ULONG residue = BN_mod_word(dh->p, 24);
+ if (residue == 11 || residue == 23)
+ codes &= ~DH_NOT_SUITABLE_GENERATOR;
+ }
+ if (codes != 0) /* Specifics on why the params suck is irrelevant. */
+ goto out;
+
+ /* Things are probably not evil. */
+ ret = 0;
+
+ out:
+ if (dh)
+ DH_free(dh);
+ return ret;
+}
+
+/** Set the global Diffie-Hellman generator, used for both TLS and internal
+ * DH stuff.
+ */
+static void
+crypto_set_dh_generator(void)
+{
+ BIGNUM *generator;
+ int r;
+
+ if (dh_param_g)
+ return;
+
+ generator = BN_new();
+ tor_assert(generator);
+
+ r = BN_set_word(generator, DH_GENERATOR);
+ tor_assert(r);
+
+ dh_param_g = generator;
+}
+
/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH
* modulus. */
void
@@ -2121,6 +2186,8 @@ crypto_set_tls_dh_prime(void)
tor_assert(tls_prime);
dh_param_p_tls = tls_prime;
+ crypto_set_dh_generator();
+ tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g));
}
/** Initialize dh_param_p and dh_param_g if they are not already
@@ -2128,18 +2195,13 @@ crypto_set_tls_dh_prime(void)
static void
init_dh_param(void)
{
- BIGNUM *circuit_dh_prime, *generator;
+ BIGNUM *circuit_dh_prime;
int r;
if (dh_param_p && dh_param_g)
return;
circuit_dh_prime = BN_new();
- generator = BN_new();
- tor_assert(circuit_dh_prime && generator);
-
- /* Set our generator for all DH parameters */
- r = BN_set_word(generator, DH_GENERATOR);
- tor_assert(r);
+ tor_assert(circuit_dh_prime);
/* This is from rfc2409, section 6.2. It's a safe prime, and
supposedly it equals:
@@ -2155,7 +2217,8 @@ init_dh_param(void)
/* Set the new values as the global DH parameters. */
dh_param_p = circuit_dh_prime;
- dh_param_g = generator;
+ crypto_set_dh_generator();
+ tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g));
if (!dh_param_p_tls) {
crypto_set_tls_dh_prime();