blob: 925eedddf834038b00edd843426ed53fa821c56b [file] [log] [blame]
Damien Millerd7834352006-08-05 12:39:39 +10001/* $OpenBSD: dh.c,v 1.42 2006/08/03 03:34:42 deraadt 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 Millera7a73ee2006-08-05 11:37:59 +100033#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100034#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100035#include <string.h>
36
Damien Miller874d77b2000-10-14 16:23:11 +110037#include "dh.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000038#include "pathnames.h"
39#include "log.h"
40#include "misc.h"
Damien Miller874d77b2000-10-14 16:23:11 +110041
Ben Lindstrombba81212001-06-25 05:01:22 +000042static int
Damien Miller874d77b2000-10-14 16:23:11 +110043parse_prime(int linenum, char *line, struct dhgroup *dhg)
44{
45 char *cp, *arg;
46 char *strsize, *gen, *prime;
Damien Miller5a73c1a2006-03-31 23:09:41 +110047 const char *errstr = NULL;
Damien Miller874d77b2000-10-14 16:23:11 +110048
49 cp = line;
Damien Miller928b2362006-03-26 13:53:32 +110050 if ((arg = strdelim(&cp)) == NULL)
51 return 0;
Damien Miller874d77b2000-10-14 16:23:11 +110052 /* Ignore leading whitespace */
53 if (*arg == '\0')
54 arg = strdelim(&cp);
Ben Lindstrom04f9af72002-07-04 00:03:56 +000055 if (!arg || !*arg || *arg == '#')
Damien Miller874d77b2000-10-14 16:23:11 +110056 return 0;
57
58 /* time */
59 if (cp == NULL || *arg == '\0')
60 goto fail;
61 arg = strsep(&cp, " "); /* type */
62 if (cp == NULL || *arg == '\0')
63 goto fail;
64 arg = strsep(&cp, " "); /* tests */
65 if (cp == NULL || *arg == '\0')
66 goto fail;
67 arg = strsep(&cp, " "); /* tries */
68 if (cp == NULL || *arg == '\0')
69 goto fail;
70 strsize = strsep(&cp, " "); /* size */
71 if (cp == NULL || *strsize == '\0' ||
Damien Miller5a73c1a2006-03-31 23:09:41 +110072 (dhg->size = (u_int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 ||
73 errstr)
Damien Miller874d77b2000-10-14 16:23:11 +110074 goto fail;
Ben Lindstromdf221392001-03-29 00:36:16 +000075 /* The whole group is one bit larger */
76 dhg->size++;
Damien Miller874d77b2000-10-14 16:23:11 +110077 gen = strsep(&cp, " "); /* gen */
78 if (cp == NULL || *gen == '\0')
79 goto fail;
80 prime = strsep(&cp, " "); /* prime */
81 if (cp != NULL || *prime == '\0')
82 goto fail;
83
Damien Millerda755162002-01-22 23:09:22 +110084 if ((dhg->g = BN_new()) == NULL)
85 fatal("parse_prime: BN_new failed");
86 if ((dhg->p = BN_new()) == NULL)
87 fatal("parse_prime: BN_new failed");
Ben Lindstrom206941f2001-04-15 14:27:16 +000088 if (BN_hex2bn(&dhg->g, gen) == 0)
Damien Miller23e526e2001-03-30 10:47:43 +100089 goto failclean;
90
Ben Lindstrom206941f2001-04-15 14:27:16 +000091 if (BN_hex2bn(&dhg->p, prime) == 0)
Damien Miller23e526e2001-03-30 10:47:43 +100092 goto failclean;
93
94 if (BN_num_bits(dhg->p) != dhg->size)
95 goto failclean;
Damien Miller874d77b2000-10-14 16:23:11 +110096
Darren Tuckerfc113c92004-02-29 20:12:33 +110097 if (BN_is_zero(dhg->g) || BN_is_one(dhg->g))
98 goto failclean;
99
Damien Miller874d77b2000-10-14 16:23:11 +1100100 return (1);
Damien Miller23e526e2001-03-30 10:47:43 +1000101
102 failclean:
Damien Miller9ef95dd2002-01-22 23:10:33 +1100103 BN_clear_free(dhg->g);
104 BN_clear_free(dhg->p);
Damien Miller874d77b2000-10-14 16:23:11 +1100105 fail:
Ben Lindstrom6df8ef42001-03-05 07:47:23 +0000106 error("Bad prime description in line %d", linenum);
Damien Miller874d77b2000-10-14 16:23:11 +1100107 return (0);
108}
109
110DH *
Ben Lindstromdf221392001-03-29 00:36:16 +0000111choose_dh(int min, int wantbits, int max)
Damien Miller874d77b2000-10-14 16:23:11 +1100112{
113 FILE *f;
Darren Tuckerc56c7ef2004-02-29 20:13:34 +1100114 char line[4096];
Damien Miller874d77b2000-10-14 16:23:11 +1100115 int best, bestcount, which;
116 int linenum;
117 struct dhgroup dhg;
118
Ben Lindstrom93a29e02001-06-25 04:13:25 +0000119 if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
120 (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
Damien Millerf675fc42004-06-15 10:30:09 +1000121 logit("WARNING: %s does not exist, using fixed modulus",
122 _PATH_DH_MODULI);
123 return (dh_new_group14());
Damien Miller874d77b2000-10-14 16:23:11 +1100124 }
125
126 linenum = 0;
127 best = bestcount = 0;
128 while (fgets(line, sizeof(line), f)) {
129 linenum++;
130 if (!parse_prime(linenum, line, &dhg))
131 continue;
Damien Miller9ef95dd2002-01-22 23:10:33 +1100132 BN_clear_free(dhg.g);
133 BN_clear_free(dhg.p);
Damien Miller874d77b2000-10-14 16:23:11 +1100134
Ben Lindstromdf221392001-03-29 00:36:16 +0000135 if (dhg.size > max || dhg.size < min)
136 continue;
137
138 if ((dhg.size > wantbits && dhg.size < best) ||
139 (dhg.size > best && best < wantbits)) {
Damien Miller874d77b2000-10-14 16:23:11 +1100140 best = dhg.size;
141 bestcount = 0;
142 }
143 if (dhg.size == best)
144 bestcount++;
145 }
Ben Lindstromaf738802001-06-25 04:18:59 +0000146 rewind(f);
Damien Miller874d77b2000-10-14 16:23:11 +1100147
148 if (bestcount == 0) {
Ben Lindstromaf738802001-06-25 04:18:59 +0000149 fclose(f);
Damien Miller996acd22003-04-09 20:59:48 +1000150 logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
Darren Tucker9a2bd112004-08-12 22:40:59 +1000151 return (dh_new_group14());
Damien Miller874d77b2000-10-14 16:23:11 +1100152 }
153
Damien Miller874d77b2000-10-14 16:23:11 +1100154 linenum = 0;
155 which = arc4random() % bestcount;
156 while (fgets(line, sizeof(line), f)) {
157 if (!parse_prime(linenum, line, &dhg))
158 continue;
Ben Lindstrom5ba23b32001-04-05 02:05:21 +0000159 if ((dhg.size > max || dhg.size < min) ||
160 dhg.size != best ||
161 linenum++ != which) {
Damien Miller9ef95dd2002-01-22 23:10:33 +1100162 BN_clear_free(dhg.g);
163 BN_clear_free(dhg.p);
Damien Miller874d77b2000-10-14 16:23:11 +1100164 continue;
165 }
166 break;
167 }
168 fclose(f);
Ben Lindstrom5ba23b32001-04-05 02:05:21 +0000169 if (linenum != which+1)
170 fatal("WARNING: line %d disappeared in %s, giving up",
171 which, _PATH_DH_PRIMES);
Damien Miller874d77b2000-10-14 16:23:11 +1100172
173 return (dh_new_group(dhg.g, dhg.p));
174}
Damien Miller9709f902001-03-30 10:50:10 +1000175
Damien Millerf675fc42004-06-15 10:30:09 +1000176/* diffie-hellman-groupN-sha1 */
Damien Miller9709f902001-03-30 10:50:10 +1000177
178int
179dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
180{
181 int i;
182 int n = BN_num_bits(dh_pub);
183 int bits_set = 0;
Darren Tucker31cde682006-05-06 17:43:33 +1000184 BIGNUM *tmp;
Damien Miller9709f902001-03-30 10:50:10 +1000185
186 if (dh_pub->neg) {
Damien Miller996acd22003-04-09 20:59:48 +1000187 logit("invalid public DH value: negativ");
Damien Miller9709f902001-03-30 10:50:10 +1000188 return 0;
189 }
Darren Tucker31cde682006-05-06 17:43:33 +1000190 if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */
191 logit("invalid public DH value: <= 1");
192 return 0;
193 }
194
195 if ((tmp = BN_new()) == NULL)
196 return (-1);
197 if (!BN_sub(tmp, dh->p, BN_value_one()) ||
198 BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
199 BN_clear_free(tmp);
200 logit("invalid public DH value: >= p-1");
201 return 0;
202 }
203 BN_clear_free(tmp);
204
Damien Miller9709f902001-03-30 10:50:10 +1000205 for (i = 0; i <= n; i++)
206 if (BN_is_bit_set(dh_pub, i))
207 bits_set++;
Ben Lindstrom1f530832002-12-23 02:03:02 +0000208 debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000209
210 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
Darren Tucker31cde682006-05-06 17:43:33 +1000211 if (bits_set > 1)
Damien Miller9709f902001-03-30 10:50:10 +1000212 return 1;
Darren Tucker31cde682006-05-06 17:43:33 +1000213
Damien Miller996acd22003-04-09 20:59:48 +1000214 logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000215 return 0;
216}
217
218void
219dh_gen_key(DH *dh, int need)
220{
Darren Tuckereffc84c2004-02-29 20:15:08 +1100221 int i, bits_set, tries = 0;
Damien Miller9709f902001-03-30 10:50:10 +1000222
223 if (dh->p == NULL)
224 fatal("dh_gen_key: dh->p == NULL");
Darren Tuckerc0815c92003-09-22 21:05:50 +1000225 if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p))
Damien Miller9709f902001-03-30 10:50:10 +1000226 fatal("dh_gen_key: group too small: %d (2*need %d)",
227 BN_num_bits(dh->p), 2*need);
228 do {
229 if (dh->priv_key != NULL)
Damien Miller9ef95dd2002-01-22 23:10:33 +1100230 BN_clear_free(dh->priv_key);
Damien Millerda755162002-01-22 23:09:22 +1100231 if ((dh->priv_key = BN_new()) == NULL)
Damien Miller9709f902001-03-30 10:50:10 +1000232 fatal("dh_gen_key: BN_new failed");
233 /* generate a 2*need bits random private exponent */
Damien Miller6d6c5d22002-03-07 12:58:42 +1100234 if (!BN_rand(dh->priv_key, 2*need, 0, 0))
235 fatal("dh_gen_key: BN_rand failed");
Damien Miller9709f902001-03-30 10:50:10 +1000236 if (DH_generate_key(dh) == 0)
237 fatal("DH_generate_key");
Darren Tuckereffc84c2004-02-29 20:15:08 +1100238 for (i = 0, bits_set = 0; i <= BN_num_bits(dh->priv_key); i++)
Damien Miller9709f902001-03-30 10:50:10 +1000239 if (BN_is_bit_set(dh->priv_key, i))
240 bits_set++;
Ben Lindstrom1f530832002-12-23 02:03:02 +0000241 debug2("dh_gen_key: priv key bits set: %d/%d",
Damien Miller9709f902001-03-30 10:50:10 +1000242 bits_set, BN_num_bits(dh->priv_key));
243 if (tries++ > 10)
244 fatal("dh_gen_key: too many bad keys: giving up");
245 } while (!dh_pub_is_valid(dh, dh->pub_key));
246}
247
248DH *
249dh_new_group_asc(const char *gen, const char *modulus)
250{
251 DH *dh;
Damien Miller9709f902001-03-30 10:50:10 +1000252
Damien Millerda755162002-01-22 23:09:22 +1100253 if ((dh = DH_new()) == NULL)
254 fatal("dh_new_group_asc: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000255
Ben Lindstrom206941f2001-04-15 14:27:16 +0000256 if (BN_hex2bn(&dh->p, modulus) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000257 fatal("BN_hex2bn p");
Ben Lindstrom206941f2001-04-15 14:27:16 +0000258 if (BN_hex2bn(&dh->g, gen) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000259 fatal("BN_hex2bn g");
260
261 return (dh);
262}
263
264/*
265 * This just returns the group, we still need to generate the exchange
266 * value.
267 */
268
269DH *
270dh_new_group(BIGNUM *gen, BIGNUM *modulus)
271{
272 DH *dh;
273
Damien Millerda755162002-01-22 23:09:22 +1100274 if ((dh = DH_new()) == NULL)
275 fatal("dh_new_group: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000276 dh->p = modulus;
277 dh->g = gen;
278
279 return (dh);
280}
281
282DH *
283dh_new_group1(void)
284{
285 static char *gen = "2", *group1 =
286 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
287 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
288 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
289 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
290 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
291 "FFFFFFFF" "FFFFFFFF";
292
293 return (dh_new_group_asc(gen, group1));
294}
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000295
Damien Millerf675fc42004-06-15 10:30:09 +1000296DH *
297dh_new_group14(void)
298{
299 static char *gen = "2", *group14 =
300 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
301 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
302 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
303 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
304 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
305 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
306 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
307 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
308 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
309 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
310 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
311
312 return (dh_new_group_asc(gen, group14));
313}
314
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000315/*
316 * Estimates the group order for a Diffie-Hellman group that has an
317 * attack complexity approximately the same as O(2**bits). Estimate
318 * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
319 */
320
321int
322dh_estimate(int bits)
323{
324
Damien Miller8975ddf2003-12-17 16:33:53 +1100325 if (bits <= 128)
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000326 return (1024); /* O(2**86) */
Damien Miller8975ddf2003-12-17 16:33:53 +1100327 if (bits <= 192)
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000328 return (2048); /* O(2**116) */
329 return (4096); /* O(2**156) */
330}