Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
crypto_dh_openssl.c
Go to the documentation of this file.
1/* Copyright (c) 2001, Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
5/* See LICENSE for licensing information */
6
7/**
8 * \file crypto_dh_openssl.c
9 * \brief Implement Tor's Z_p diffie-hellman stuff for OpenSSL.
10 **/
11
12#include "lib/crypt_ops/compat_openssl.h"
17#include "lib/log/log.h"
18#include "lib/log/util_bug.h"
19
20DISABLE_GCC_WARNING("-Wredundant-decls")
21
22#include <openssl/dh.h>
23
24ENABLE_GCC_WARNING("-Wredundant-decls")
25
26#include <openssl/bn.h>
27#include <string.h>
28
29#ifndef ENABLE_NSS
30static int tor_check_dh_key(int severity, const BIGNUM *bn,
31 const BIGNUM *dh_p);
32
33/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake
34 * while we're waiting for the second.*/
35struct crypto_dh_t {
36 DH *dh; /**< The openssl DH object */
37};
38#endif /* !defined(ENABLE_NSS) */
39
40static DH *new_openssl_dh_from_params(BIGNUM *p, BIGNUM *g);
41
42/** Shared P parameter for our circuit-crypto DH key exchanges. */
43static BIGNUM *dh_param_p = NULL;
44/** Shared P parameter for our TLS DH key exchanges. */
45static BIGNUM *dh_param_p_tls = NULL;
46/** Shared G parameter for our DH key exchanges. */
47static BIGNUM *dh_param_g = NULL;
48
49/* This function is disabled unless we change the DH parameters. */
50#if 0
51/** Validate a given set of Diffie-Hellman parameters. This is moderately
52 * computationally expensive (milliseconds), so should only be called when
53 * the DH parameters change. Returns 0 on success, * -1 on failure.
54 */
55static int
56crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g)
57{
58 DH *dh = NULL;
59 int ret = -1;
60
61 /* Copy into a temporary DH object, just so that DH_check() can be called. */
62 if (!(dh = DH_new()))
63 goto out;
64
65 BIGNUM *dh_p, *dh_g;
66 if (!(dh_p = BN_dup(p)))
67 goto out;
68 if (!(dh_g = BN_dup(g)))
69 goto out;
70 if (!DH_set0_pqg(dh, dh_p, NULL, dh_g))
71 goto out;
72
73 /* Perform the validation. */
74 int codes = 0;
75 if (!DH_check(dh, &codes))
76 goto out;
77 if (BN_is_word(g, DH_GENERATOR_2)) {
78 /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters
79 *
80 * OpenSSL checks the prime is congruent to 11 when g = 2; while the
81 * IETF's primes are congruent to 23 when g = 2.
82 */
83 BN_ULONG residue = BN_mod_word(p, 24);
84 if (residue == 11 || residue == 23)
85 codes &= ~DH_NOT_SUITABLE_GENERATOR;
86 }
87 if (codes != 0) /* Specifics on why the params suck is irrelevant. */
88 goto out;
89
90 /* Things are probably not evil. */
91 ret = 0;
92
93 out:
94 if (dh)
95 DH_free(dh);
96 return ret;
97}
98#endif /* 0 */
99
100/**
101 * Helper: convert <b>hex</b> to a bignum, and return it. Assert that the
102 * operation was successful.
103 */
104static BIGNUM *
105bignum_from_hex(const char *hex)
106{
107 BIGNUM *result = BN_new();
108 tor_assert(result);
109
110 int r = BN_hex2bn(&result, hex);
111 tor_assert(r);
112 tor_assert(result);
113 return result;
114}
115
116/** Set the global Diffie-Hellman generator, used for both TLS and internal
117 * DH stuff.
118 */
119static void
121{
122 BIGNUM *generator;
123 int r;
124
125 if (dh_param_g)
126 return;
127
128 generator = BN_new();
129 tor_assert(generator);
130
131 r = BN_set_word(generator, DH_GENERATOR);
132 tor_assert(r);
133
134 dh_param_g = generator;
135}
136
137/** Initialize our DH parameters. Idempotent. */
138void
140{
142 return;
143
144 tor_assert(dh_param_g == NULL);
145 tor_assert(dh_param_p == NULL);
146 tor_assert(dh_param_p_tls == NULL);
147
151
152 /* Checks below are disabled unless we change the hardcoded DH parameters. */
153#if 0
154 tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g));
155 tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g));
156#endif
157}
158
159/** Number of bits to use when choosing the x or y value in a Diffie-Hellman
160 * handshake. Since we exponentiate by this value, choosing a smaller one
161 * lets our handshake go faster.
162 */
163#define DH_PRIVATE_KEY_BITS 320
164
165/** Used by tortls.c: Get the DH* for use with TLS.
166 */
167DH *
169{
171}
172
173#ifndef ENABLE_NSS
174/** Allocate and return a new DH object for a key exchange. Returns NULL on
175 * failure.
176 */
178crypto_dh_new(int dh_type)
179{
180 crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t));
181
182 tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS ||
183 dh_type == DH_TYPE_REND);
184
185 if (!dh_param_p)
186 crypto_dh_init();
187
188 BIGNUM *dh_p = NULL;
189 if (dh_type == DH_TYPE_TLS) {
190 dh_p = dh_param_p_tls;
191 } else {
192 dh_p = dh_param_p;
193 }
194
196 if (res->dh == NULL)
197 tor_free(res); // sets res to NULL.
198 return res;
199}
200#endif /* !defined(ENABLE_NSS) */
201
202/** Create and return a new openssl DH from a given prime and generator. */
203static DH *
204new_openssl_dh_from_params(BIGNUM *p, BIGNUM *g)
205{
206 DH *res_dh;
207 if (!(res_dh = DH_new()))
208 goto err;
209
210 BIGNUM *dh_p = NULL, *dh_g = NULL;
211 dh_p = BN_dup(p);
212 if (!dh_p)
213 goto err;
214
215 dh_g = BN_dup(g);
216 if (!dh_g) {
217 BN_free(dh_p);
218 goto err;
219 }
220
221 if (!DH_set0_pqg(res_dh, dh_p, NULL, dh_g)) {
222 goto err;
223 }
224
225 if (!DH_set_length(res_dh, DH_PRIVATE_KEY_BITS))
226 goto err;
227
228 return res_dh;
229
230 /* LCOV_EXCL_START
231 * This error condition is only reached when an allocation fails */
232 err:
233 crypto_openssl_log_errors(LOG_WARN, "creating DH object");
234 if (res_dh) DH_free(res_dh); /* frees p and g too */
235 return NULL;
236 /* LCOV_EXCL_STOP */
237}
238
239#ifndef ENABLE_NSS
240/** Return a copy of <b>dh</b>, sharing its internal state. */
243{
244 crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t));
245 tor_assert(dh);
246 tor_assert(dh->dh);
247 dh_new->dh = dh->dh;
248 DH_up_ref(dh->dh);
249 return dh_new;
250}
251
252/** Return the length of the DH key in <b>dh</b>, in bytes.
253 */
254int
256{
257 tor_assert(dh);
258 return DH_size(dh->dh);
259}
260
261/** Generate <x,g^x> for our part of the key exchange. Return 0 on
262 * success, -1 on failure.
263 */
264int
266{
267 if (!DH_generate_key(dh->dh)) {
268 /* LCOV_EXCL_START
269 * To test this we would need some way to tell openssl to break DH. */
270 crypto_openssl_log_errors(LOG_WARN, "generating DH key");
271 return -1;
272 /* LCOV_EXCL_STOP */
273 }
274
275 /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without
276 * recreating the DH object. I have no idea what sort of aliasing madness
277 * can occur here, so do the check, and just bail on failure.
278 */
279 const BIGNUM *pub_key, *priv_key;
280 DH_get0_key(dh->dh, &pub_key, &priv_key);
281 if (tor_check_dh_key(LOG_WARN, pub_key, DH_get0_p(dh->dh))<0) {
282 log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-"
283 "the-universe chances really do happen. Treating as a failure.");
284 return -1;
285 }
286
287 return 0;
288}
289
290/** Generate g^x as necessary, and write the g^x for the key exchange
291 * as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on
292 * success, -1 on failure. <b>pubkey_len</b> must be >= DH1024_KEY_LEN.
293 */
294int
295crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len)
296{
297 int bytes;
298 tor_assert(dh);
299
300 const BIGNUM *dh_pub;
301
302 const BIGNUM *dh_priv;
303 DH_get0_key(dh->dh, &dh_pub, &dh_priv);
304
305 if (!dh_pub) {
307 return -1;
308 else {
309 DH_get0_key(dh->dh, &dh_pub, &dh_priv);
310 }
311 }
312
313 tor_assert(dh_pub);
314 bytes = BN_num_bytes(dh_pub);
315 tor_assert(bytes >= 0);
316 if (pubkey_len < (size_t)bytes) {
317 log_warn(LD_CRYPTO,
318 "Weird! pubkey_len (%d) was smaller than key length (%d)",
319 (int) pubkey_len, bytes);
320 return -1;
321 }
322
323 memset(pubkey, 0, pubkey_len);
324 BN_bn2bin(dh_pub, (unsigned char*)(pubkey+(pubkey_len-bytes)));
325
326 return 0;
327}
328
329/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is
330 * okay (in the subgroup [2,p-2]), or -1 if it's bad.
331 * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips.
332 */
333static int
334tor_check_dh_key(int severity, const BIGNUM *bn, const BIGNUM *dh_p)
335{
336 BIGNUM *x;
337 char *s;
338 tor_assert(bn);
339 x = BN_new();
340 tor_assert(x);
341 BN_set_word(x, 1);
342 if (BN_cmp(bn,x)<=0) {
343 log_fn(severity, LD_CRYPTO, "DH key must be at least 2.");
344 goto err;
345 }
346 BN_copy(x,dh_p);
347 BN_sub_word(x, 1);
348 if (BN_cmp(bn,x)>=0) {
349 log_fn(severity, LD_CRYPTO, "DH key must be at most p-2.");
350 goto err;
351 }
352 BN_clear_free(x);
353 return 0;
354 err:
355 BN_clear_free(x);
356 s = BN_bn2hex(bn);
357 log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
358 OPENSSL_free(s);
359 return -1;
360}
361
362/** Given a DH key exchange object, and our peer's value of g^y (as a
363 * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate
364 * g^xy as a big-endian integer in <b>secret_out</b>.
365 * Return the number of bytes generated on success,
366 * or -1 on failure.
367 *
368 * This function MUST validate that g^y is actually in the group.
369 */
370ssize_t
372 const char *pubkey, size_t pubkey_len,
373 unsigned char *secret_out, size_t secret_bytes_out)
374{
375 BIGNUM *pubkey_bn = NULL;
376 size_t secret_len=0;
377 int result=0;
378
379 tor_assert(dh);
380 tor_assert(secret_bytes_out/DIGEST_LEN <= 255);
381 tor_assert(pubkey_len < INT_MAX);
382
383 if (BUG(crypto_dh_get_bytes(dh) > (int)secret_bytes_out)) {
384 goto error;
385 }
386
387 if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey,
388 (int)pubkey_len, NULL)))
389 goto error;
390 if (tor_check_dh_key(severity, pubkey_bn, DH_get0_p(dh->dh))<0) {
391 /* Check for invalid public keys. */
392 log_fn(severity, LD_CRYPTO,"Rejected invalid g^x");
393 goto error;
394 }
395 result = DH_compute_key(secret_out, pubkey_bn, dh->dh);
396 if (result < 0) {
397 log_warn(LD_CRYPTO,"DH_compute_key() failed.");
398 goto error;
399 }
400 secret_len = result;
401
402 goto done;
403 error:
404 result = -1;
405 done:
406 crypto_openssl_log_errors(LOG_WARN, "completing DH handshake");
407 if (pubkey_bn)
408 BN_clear_free(pubkey_bn);
409 if (result < 0)
410 return result;
411 else
412 return secret_len;
413}
414
415/** Free a DH key exchange object.
416 */
417void
419{
420 if (!dh)
421 return;
422 tor_assert(dh->dh);
423 DH_free(dh->dh);
424 tor_free(dh);
425}
426#endif /* !defined(ENABLE_NSS) */
427
428void
429crypto_dh_free_all_openssl(void)
430{
431 if (dh_param_p)
432 BN_clear_free(dh_param_p);
433 if (dh_param_p_tls)
434 BN_clear_free(dh_param_p_tls);
435 if (dh_param_g)
436 BN_clear_free(dh_param_g);
437
439}
const char OAKLEY_PRIME_2[]
Definition: crypto_dh.c:43
const char TLS_DH_PRIME[]
Definition: crypto_dh.c:26
const unsigned DH_GENERATOR
Definition: crypto_dh.c:23
Headers for crypto_dh.c.
#define DH_PRIVATE_KEY_BITS
int crypto_dh_generate_public(crypto_dh_t *dh)
void crypto_dh_free_(crypto_dh_t *dh)
crypto_dh_t * crypto_dh_new(int dh_type)
DH * crypto_dh_new_openssl_tls(void)
int crypto_dh_get_bytes(crypto_dh_t *dh)
static BIGNUM * dh_param_p
void crypto_dh_init_openssl(void)
static BIGNUM * dh_param_p_tls
static BIGNUM * dh_param_g
static BIGNUM * bignum_from_hex(const char *hex)
static void crypto_set_dh_generator(void)
static int tor_check_dh_key(int severity, const BIGNUM *bn, const BIGNUM *dh_p)
ssize_t crypto_dh_handshake(int severity, crypto_dh_t *dh, const char *pubkey, size_t pubkey_len, unsigned char *secret_out, size_t secret_bytes_out)
int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len)
static DH * new_openssl_dh_from_params(BIGNUM *p, BIGNUM *g)
crypto_dh_t * crypto_dh_dup(const crypto_dh_t *dh)
Headers for crypto_digest.c.
Headers for crypto_hkdf.h.
void crypto_openssl_log_errors(int severity, const char *doing)
Common functions for cryptographic routines.
#define DIGEST_LEN
Definition: digest_sizes.h:20
Headers for log.c.
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_CRYPTO
Definition: log.h:64
#define LOG_WARN
Definition: log.h:53
#define tor_free(p)
Definition: malloc.h:56
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:103