blob: 78e230b9f2417c4233748c8e5fb6606167284843 [file] [log] [blame]
Darren Tuckerb0781f72006-11-08 10:01:36 +11001/* $OpenBSD: dh.c,v 1.44 2006/11/07 13:02:07 markus 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 Miller996acd22003-04-09 20:59:48 +1000188 logit("invalid public DH value: negativ");
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
196 if ((tmp = BN_new()) == NULL)
197 return (-1);
198 if (!BN_sub(tmp, dh->p, BN_value_one()) ||
199 BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
200 BN_clear_free(tmp);
201 logit("invalid public DH value: >= p-1");
202 return 0;
203 }
204 BN_clear_free(tmp);
205
Damien Miller9709f902001-03-30 10:50:10 +1000206 for (i = 0; i <= n; i++)
207 if (BN_is_bit_set(dh_pub, i))
208 bits_set++;
Ben Lindstrom1f530832002-12-23 02:03:02 +0000209 debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000210
211 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
Darren Tucker31cde682006-05-06 17:43:33 +1000212 if (bits_set > 1)
Damien Miller9709f902001-03-30 10:50:10 +1000213 return 1;
Darren Tucker31cde682006-05-06 17:43:33 +1000214
Damien Miller996acd22003-04-09 20:59:48 +1000215 logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000216 return 0;
217}
218
219void
220dh_gen_key(DH *dh, int need)
221{
Darren Tuckereffc84c2004-02-29 20:15:08 +1100222 int i, bits_set, tries = 0;
Damien Miller9709f902001-03-30 10:50:10 +1000223
224 if (dh->p == NULL)
225 fatal("dh_gen_key: dh->p == NULL");
Darren Tuckerc0815c92003-09-22 21:05:50 +1000226 if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p))
Damien Miller9709f902001-03-30 10:50:10 +1000227 fatal("dh_gen_key: group too small: %d (2*need %d)",
228 BN_num_bits(dh->p), 2*need);
229 do {
230 if (dh->priv_key != NULL)
Damien Miller9ef95dd2002-01-22 23:10:33 +1100231 BN_clear_free(dh->priv_key);
Damien Millerda755162002-01-22 23:09:22 +1100232 if ((dh->priv_key = BN_new()) == NULL)
Damien Miller9709f902001-03-30 10:50:10 +1000233 fatal("dh_gen_key: BN_new failed");
234 /* generate a 2*need bits random private exponent */
Damien Miller6d6c5d22002-03-07 12:58:42 +1100235 if (!BN_rand(dh->priv_key, 2*need, 0, 0))
236 fatal("dh_gen_key: BN_rand failed");
Damien Miller9709f902001-03-30 10:50:10 +1000237 if (DH_generate_key(dh) == 0)
238 fatal("DH_generate_key");
Darren Tuckereffc84c2004-02-29 20:15:08 +1100239 for (i = 0, bits_set = 0; i <= BN_num_bits(dh->priv_key); i++)
Damien Miller9709f902001-03-30 10:50:10 +1000240 if (BN_is_bit_set(dh->priv_key, i))
241 bits_set++;
Ben Lindstrom1f530832002-12-23 02:03:02 +0000242 debug2("dh_gen_key: priv key bits set: %d/%d",
Damien Miller9709f902001-03-30 10:50:10 +1000243 bits_set, BN_num_bits(dh->priv_key));
244 if (tries++ > 10)
245 fatal("dh_gen_key: too many bad keys: giving up");
246 } while (!dh_pub_is_valid(dh, dh->pub_key));
247}
248
249DH *
250dh_new_group_asc(const char *gen, const char *modulus)
251{
252 DH *dh;
Damien Miller9709f902001-03-30 10:50:10 +1000253
Damien Millerda755162002-01-22 23:09:22 +1100254 if ((dh = DH_new()) == NULL)
255 fatal("dh_new_group_asc: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000256
Darren Tuckerb0781f72006-11-08 10:01:36 +1100257 if (BN_hex2bn(&dh->p, modulus) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000258 fatal("BN_hex2bn p");
Darren Tuckerb0781f72006-11-08 10:01:36 +1100259 if (BN_hex2bn(&dh->g, gen) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000260 fatal("BN_hex2bn g");
261
262 return (dh);
263}
264
265/*
266 * This just returns the group, we still need to generate the exchange
267 * value.
268 */
269
270DH *
271dh_new_group(BIGNUM *gen, BIGNUM *modulus)
272{
273 DH *dh;
274
Damien Millerda755162002-01-22 23:09:22 +1100275 if ((dh = DH_new()) == NULL)
276 fatal("dh_new_group: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000277 dh->p = modulus;
278 dh->g = gen;
279
280 return (dh);
281}
282
283DH *
284dh_new_group1(void)
285{
286 static char *gen = "2", *group1 =
287 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
288 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
289 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
290 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
291 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
292 "FFFFFFFF" "FFFFFFFF";
293
294 return (dh_new_group_asc(gen, group1));
295}
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000296
Damien Millerf675fc42004-06-15 10:30:09 +1000297DH *
298dh_new_group14(void)
299{
300 static char *gen = "2", *group14 =
301 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
302 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
303 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
304 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
305 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
306 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
307 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
308 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
309 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
310 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
311 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
312
313 return (dh_new_group_asc(gen, group14));
314}
315
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000316/*
317 * Estimates the group order for a Diffie-Hellman group that has an
318 * attack complexity approximately the same as O(2**bits). Estimate
319 * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
320 */
321
322int
323dh_estimate(int bits)
324{
325
Damien Miller8975ddf2003-12-17 16:33:53 +1100326 if (bits <= 128)
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000327 return (1024); /* O(2**86) */
Damien Miller8975ddf2003-12-17 16:33:53 +1100328 if (bits <= 192)
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000329 return (2048); /* O(2**116) */
330 return (4096); /* O(2**156) */
331}