blob: 66858104cb9383916fc4a76409ed94042c446261 [file] [log] [blame]
Damien Miller603077a2007-10-26 14:25:55 +10001/* $OpenBSD: dh.c,v 1.45 2007/09/27 00:15:57 ray Exp $ */
Damien Miller874d77b2000-10-14 16:23:11 +11002/*
3 * Copyright (c) 2000 Niels Provos. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
Damien Miller874d77b2000-10-14 16:23:11 +110027
Damien Miller8dbffe72006-08-05 11:02:17 +100028#include <sys/param.h>
29
Damien Miller874d77b2000-10-14 16:23:11 +110030#include <openssl/bn.h>
31#include <openssl/dh.h>
Damien Miller874d77b2000-10-14 16:23:11 +110032
Damien Millerded319c2006-09-01 15:38:36 +100033#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100034#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100035#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100036#include <string.h>
37
Damien Miller874d77b2000-10-14 16:23:11 +110038#include "dh.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000039#include "pathnames.h"
40#include "log.h"
41#include "misc.h"
Damien Miller874d77b2000-10-14 16:23:11 +110042
Ben Lindstrombba81212001-06-25 05:01:22 +000043static int
Damien Miller874d77b2000-10-14 16:23:11 +110044parse_prime(int linenum, char *line, struct dhgroup *dhg)
45{
46 char *cp, *arg;
47 char *strsize, *gen, *prime;
Damien Miller5a73c1a2006-03-31 23:09:41 +110048 const char *errstr = NULL;
Damien Miller874d77b2000-10-14 16:23:11 +110049
50 cp = line;
Damien Miller928b2362006-03-26 13:53:32 +110051 if ((arg = strdelim(&cp)) == NULL)
52 return 0;
Damien Miller874d77b2000-10-14 16:23:11 +110053 /* Ignore leading whitespace */
54 if (*arg == '\0')
55 arg = strdelim(&cp);
Ben Lindstrom04f9af72002-07-04 00:03:56 +000056 if (!arg || !*arg || *arg == '#')
Damien Miller874d77b2000-10-14 16:23:11 +110057 return 0;
58
59 /* time */
60 if (cp == NULL || *arg == '\0')
61 goto fail;
62 arg = strsep(&cp, " "); /* type */
63 if (cp == NULL || *arg == '\0')
64 goto fail;
65 arg = strsep(&cp, " "); /* tests */
66 if (cp == NULL || *arg == '\0')
67 goto fail;
68 arg = strsep(&cp, " "); /* tries */
69 if (cp == NULL || *arg == '\0')
70 goto fail;
71 strsize = strsep(&cp, " "); /* size */
72 if (cp == NULL || *strsize == '\0' ||
Damien Miller5a73c1a2006-03-31 23:09:41 +110073 (dhg->size = (u_int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 ||
74 errstr)
Damien Miller874d77b2000-10-14 16:23:11 +110075 goto fail;
Ben Lindstromdf221392001-03-29 00:36:16 +000076 /* The whole group is one bit larger */
77 dhg->size++;
Damien Miller874d77b2000-10-14 16:23:11 +110078 gen = strsep(&cp, " "); /* gen */
79 if (cp == NULL || *gen == '\0')
80 goto fail;
81 prime = strsep(&cp, " "); /* prime */
82 if (cp != NULL || *prime == '\0')
83 goto fail;
84
Damien Millerda755162002-01-22 23:09:22 +110085 if ((dhg->g = BN_new()) == NULL)
86 fatal("parse_prime: BN_new failed");
87 if ((dhg->p = BN_new()) == NULL)
88 fatal("parse_prime: BN_new failed");
Ben Lindstrom206941f2001-04-15 14:27:16 +000089 if (BN_hex2bn(&dhg->g, gen) == 0)
Damien Miller23e526e2001-03-30 10:47:43 +100090 goto failclean;
91
Ben Lindstrom206941f2001-04-15 14:27:16 +000092 if (BN_hex2bn(&dhg->p, prime) == 0)
Damien Miller23e526e2001-03-30 10:47:43 +100093 goto failclean;
94
95 if (BN_num_bits(dhg->p) != dhg->size)
96 goto failclean;
Damien Miller874d77b2000-10-14 16:23:11 +110097
Darren Tuckerfc113c92004-02-29 20:12:33 +110098 if (BN_is_zero(dhg->g) || BN_is_one(dhg->g))
99 goto failclean;
100
Damien Miller874d77b2000-10-14 16:23:11 +1100101 return (1);
Damien Miller23e526e2001-03-30 10:47:43 +1000102
103 failclean:
Damien Miller9ef95dd2002-01-22 23:10:33 +1100104 BN_clear_free(dhg->g);
105 BN_clear_free(dhg->p);
Damien Miller874d77b2000-10-14 16:23:11 +1100106 fail:
Ben Lindstrom6df8ef42001-03-05 07:47:23 +0000107 error("Bad prime description in line %d", linenum);
Damien Miller874d77b2000-10-14 16:23:11 +1100108 return (0);
109}
110
111DH *
Ben Lindstromdf221392001-03-29 00:36:16 +0000112choose_dh(int min, int wantbits, int max)
Damien Miller874d77b2000-10-14 16:23:11 +1100113{
114 FILE *f;
Darren Tuckerc56c7ef2004-02-29 20:13:34 +1100115 char line[4096];
Damien Miller874d77b2000-10-14 16:23:11 +1100116 int best, bestcount, which;
117 int linenum;
118 struct dhgroup dhg;
119
Ben Lindstrom93a29e02001-06-25 04:13:25 +0000120 if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
121 (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
Damien Millerf675fc42004-06-15 10:30:09 +1000122 logit("WARNING: %s does not exist, using fixed modulus",
123 _PATH_DH_MODULI);
124 return (dh_new_group14());
Damien Miller874d77b2000-10-14 16:23:11 +1100125 }
126
127 linenum = 0;
128 best = bestcount = 0;
129 while (fgets(line, sizeof(line), f)) {
130 linenum++;
131 if (!parse_prime(linenum, line, &dhg))
132 continue;
Damien Miller9ef95dd2002-01-22 23:10:33 +1100133 BN_clear_free(dhg.g);
134 BN_clear_free(dhg.p);
Damien Miller874d77b2000-10-14 16:23:11 +1100135
Ben Lindstromdf221392001-03-29 00:36:16 +0000136 if (dhg.size > max || dhg.size < min)
137 continue;
138
139 if ((dhg.size > wantbits && dhg.size < best) ||
140 (dhg.size > best && best < wantbits)) {
Damien Miller874d77b2000-10-14 16:23:11 +1100141 best = dhg.size;
142 bestcount = 0;
143 }
144 if (dhg.size == best)
145 bestcount++;
146 }
Ben Lindstromaf738802001-06-25 04:18:59 +0000147 rewind(f);
Damien Miller874d77b2000-10-14 16:23:11 +1100148
149 if (bestcount == 0) {
Ben Lindstromaf738802001-06-25 04:18:59 +0000150 fclose(f);
Damien Miller996acd22003-04-09 20:59:48 +1000151 logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
Darren Tucker9a2bd112004-08-12 22:40:59 +1000152 return (dh_new_group14());
Damien Miller874d77b2000-10-14 16:23:11 +1100153 }
154
Damien Miller874d77b2000-10-14 16:23:11 +1100155 linenum = 0;
156 which = arc4random() % bestcount;
157 while (fgets(line, sizeof(line), f)) {
158 if (!parse_prime(linenum, line, &dhg))
159 continue;
Ben Lindstrom5ba23b32001-04-05 02:05:21 +0000160 if ((dhg.size > max || dhg.size < min) ||
161 dhg.size != best ||
162 linenum++ != which) {
Damien Miller9ef95dd2002-01-22 23:10:33 +1100163 BN_clear_free(dhg.g);
164 BN_clear_free(dhg.p);
Damien Miller874d77b2000-10-14 16:23:11 +1100165 continue;
166 }
167 break;
168 }
169 fclose(f);
Ben Lindstrom5ba23b32001-04-05 02:05:21 +0000170 if (linenum != which+1)
171 fatal("WARNING: line %d disappeared in %s, giving up",
172 which, _PATH_DH_PRIMES);
Damien Miller874d77b2000-10-14 16:23:11 +1100173
174 return (dh_new_group(dhg.g, dhg.p));
175}
Damien Miller9709f902001-03-30 10:50:10 +1000176
Damien Millerf675fc42004-06-15 10:30:09 +1000177/* diffie-hellman-groupN-sha1 */
Damien Miller9709f902001-03-30 10:50:10 +1000178
179int
180dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
181{
182 int i;
183 int n = BN_num_bits(dh_pub);
184 int bits_set = 0;
Darren Tucker31cde682006-05-06 17:43:33 +1000185 BIGNUM *tmp;
Damien Miller9709f902001-03-30 10:50:10 +1000186
187 if (dh_pub->neg) {
Damien Miller603077a2007-10-26 14:25:55 +1000188 logit("invalid public DH value: negative");
Damien Miller9709f902001-03-30 10:50:10 +1000189 return 0;
190 }
Darren Tucker31cde682006-05-06 17:43:33 +1000191 if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */
192 logit("invalid public DH value: <= 1");
193 return 0;
194 }
195
Damien Miller603077a2007-10-26 14:25:55 +1000196 if ((tmp = BN_new()) == NULL) {
197 error("%s: BN_new failed", __func__);
198 return 0;
199 }
Darren Tucker31cde682006-05-06 17:43:33 +1000200 if (!BN_sub(tmp, dh->p, BN_value_one()) ||
201 BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
202 BN_clear_free(tmp);
203 logit("invalid public DH value: >= p-1");
204 return 0;
205 }
206 BN_clear_free(tmp);
207
Damien Miller9709f902001-03-30 10:50:10 +1000208 for (i = 0; i <= n; i++)
209 if (BN_is_bit_set(dh_pub, i))
210 bits_set++;
Ben Lindstrom1f530832002-12-23 02:03:02 +0000211 debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000212
213 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
Darren Tucker31cde682006-05-06 17:43:33 +1000214 if (bits_set > 1)
Damien Miller9709f902001-03-30 10:50:10 +1000215 return 1;
Darren Tucker31cde682006-05-06 17:43:33 +1000216
Damien Miller996acd22003-04-09 20:59:48 +1000217 logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000218 return 0;
219}
220
221void
222dh_gen_key(DH *dh, int need)
223{
Darren Tuckereffc84c2004-02-29 20:15:08 +1100224 int i, bits_set, tries = 0;
Damien Miller9709f902001-03-30 10:50:10 +1000225
226 if (dh->p == NULL)
227 fatal("dh_gen_key: dh->p == NULL");
Darren Tuckerc0815c92003-09-22 21:05:50 +1000228 if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p))
Damien Miller9709f902001-03-30 10:50:10 +1000229 fatal("dh_gen_key: group too small: %d (2*need %d)",
230 BN_num_bits(dh->p), 2*need);
231 do {
232 if (dh->priv_key != NULL)
Damien Miller9ef95dd2002-01-22 23:10:33 +1100233 BN_clear_free(dh->priv_key);
Damien Millerda755162002-01-22 23:09:22 +1100234 if ((dh->priv_key = BN_new()) == NULL)
Damien Miller9709f902001-03-30 10:50:10 +1000235 fatal("dh_gen_key: BN_new failed");
236 /* generate a 2*need bits random private exponent */
Damien Miller6d6c5d22002-03-07 12:58:42 +1100237 if (!BN_rand(dh->priv_key, 2*need, 0, 0))
238 fatal("dh_gen_key: BN_rand failed");
Damien Miller9709f902001-03-30 10:50:10 +1000239 if (DH_generate_key(dh) == 0)
240 fatal("DH_generate_key");
Darren Tuckereffc84c2004-02-29 20:15:08 +1100241 for (i = 0, bits_set = 0; i <= BN_num_bits(dh->priv_key); i++)
Damien Miller9709f902001-03-30 10:50:10 +1000242 if (BN_is_bit_set(dh->priv_key, i))
243 bits_set++;
Ben Lindstrom1f530832002-12-23 02:03:02 +0000244 debug2("dh_gen_key: priv key bits set: %d/%d",
Damien Miller9709f902001-03-30 10:50:10 +1000245 bits_set, BN_num_bits(dh->priv_key));
246 if (tries++ > 10)
247 fatal("dh_gen_key: too many bad keys: giving up");
248 } while (!dh_pub_is_valid(dh, dh->pub_key));
249}
250
251DH *
252dh_new_group_asc(const char *gen, const char *modulus)
253{
254 DH *dh;
Damien Miller9709f902001-03-30 10:50:10 +1000255
Damien Millerda755162002-01-22 23:09:22 +1100256 if ((dh = DH_new()) == NULL)
257 fatal("dh_new_group_asc: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000258
Darren Tuckerb0781f72006-11-08 10:01:36 +1100259 if (BN_hex2bn(&dh->p, modulus) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000260 fatal("BN_hex2bn p");
Darren Tuckerb0781f72006-11-08 10:01:36 +1100261 if (BN_hex2bn(&dh->g, gen) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000262 fatal("BN_hex2bn g");
263
264 return (dh);
265}
266
267/*
268 * This just returns the group, we still need to generate the exchange
269 * value.
270 */
271
272DH *
273dh_new_group(BIGNUM *gen, BIGNUM *modulus)
274{
275 DH *dh;
276
Damien Millerda755162002-01-22 23:09:22 +1100277 if ((dh = DH_new()) == NULL)
278 fatal("dh_new_group: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000279 dh->p = modulus;
280 dh->g = gen;
281
282 return (dh);
283}
284
285DH *
286dh_new_group1(void)
287{
288 static char *gen = "2", *group1 =
289 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
290 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
291 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
292 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
293 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
294 "FFFFFFFF" "FFFFFFFF";
295
296 return (dh_new_group_asc(gen, group1));
297}
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000298
Damien Millerf675fc42004-06-15 10:30:09 +1000299DH *
300dh_new_group14(void)
301{
302 static char *gen = "2", *group14 =
303 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
304 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
305 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
306 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
307 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
308 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
309 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
310 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
311 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
312 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
313 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
314
315 return (dh_new_group_asc(gen, group14));
316}
317
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000318/*
319 * Estimates the group order for a Diffie-Hellman group that has an
320 * attack complexity approximately the same as O(2**bits). Estimate
321 * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
322 */
323
324int
325dh_estimate(int bits)
326{
327
Damien Miller8975ddf2003-12-17 16:33:53 +1100328 if (bits <= 128)
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000329 return (1024); /* O(2**86) */
Damien Miller8975ddf2003-12-17 16:33:53 +1100330 if (bits <= 192)
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000331 return (2048); /* O(2**116) */
332 return (4096); /* O(2**156) */
333}