blob: 3331cda6c71cc73a65063a2921d47f13956dc0fd [file] [log] [blame]
Damien Miller0fde8ac2013-11-21 14:12:23 +11001/* $OpenBSD: dh.c,v 1.53 2013/11/21 00:45:44 djm 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 Miller2e9cf492008-06-29 22:47:04 +100049 long long n;
Damien Miller874d77b2000-10-14 16:23:11 +110050
Damien Miller0d02c3e2013-07-18 16:12:06 +100051 dhg->p = dhg->g = NULL;
Damien Miller874d77b2000-10-14 16:23:11 +110052 cp = line;
Damien Miller928b2362006-03-26 13:53:32 +110053 if ((arg = strdelim(&cp)) == NULL)
54 return 0;
Damien Miller874d77b2000-10-14 16:23:11 +110055 /* Ignore leading whitespace */
56 if (*arg == '\0')
57 arg = strdelim(&cp);
Ben Lindstrom04f9af72002-07-04 00:03:56 +000058 if (!arg || !*arg || *arg == '#')
Damien Miller874d77b2000-10-14 16:23:11 +110059 return 0;
60
61 /* time */
62 if (cp == NULL || *arg == '\0')
Damien Millerbbeb1da2013-07-18 16:10:49 +100063 goto truncated;
Damien Miller874d77b2000-10-14 16:23:11 +110064 arg = strsep(&cp, " "); /* type */
65 if (cp == NULL || *arg == '\0')
Damien Millerbbeb1da2013-07-18 16:10:49 +100066 goto truncated;
Damien Miller2e9cf492008-06-29 22:47:04 +100067 /* Ensure this is a safe prime */
68 n = strtonum(arg, 0, 5, &errstr);
Damien Millerbbeb1da2013-07-18 16:10:49 +100069 if (errstr != NULL || n != MODULI_TYPE_SAFE) {
70 error("moduli:%d: type is not %d", linenum, MODULI_TYPE_SAFE);
Damien Miller2e9cf492008-06-29 22:47:04 +100071 goto fail;
Damien Millerbbeb1da2013-07-18 16:10:49 +100072 }
Damien Miller874d77b2000-10-14 16:23:11 +110073 arg = strsep(&cp, " "); /* tests */
74 if (cp == NULL || *arg == '\0')
Damien Millerbbeb1da2013-07-18 16:10:49 +100075 goto truncated;
Damien Miller2e9cf492008-06-29 22:47:04 +100076 /* Ensure prime has been tested and is not composite */
77 n = strtonum(arg, 0, 0x1f, &errstr);
78 if (errstr != NULL ||
Damien Millerbbeb1da2013-07-18 16:10:49 +100079 (n & MODULI_TESTS_COMPOSITE) || !(n & ~MODULI_TESTS_COMPOSITE)) {
80 error("moduli:%d: invalid moduli tests flag", linenum);
Damien Miller2e9cf492008-06-29 22:47:04 +100081 goto fail;
Damien Millerbbeb1da2013-07-18 16:10:49 +100082 }
Damien Miller874d77b2000-10-14 16:23:11 +110083 arg = strsep(&cp, " "); /* tries */
84 if (cp == NULL || *arg == '\0')
Damien Millerbbeb1da2013-07-18 16:10:49 +100085 goto truncated;
Damien Miller2e9cf492008-06-29 22:47:04 +100086 n = strtonum(arg, 0, 1<<30, &errstr);
Damien Millerbbeb1da2013-07-18 16:10:49 +100087 if (errstr != NULL || n == 0) {
88 error("moduli:%d: invalid primality trial count", linenum);
Damien Miller2e9cf492008-06-29 22:47:04 +100089 goto fail;
Damien Millerbbeb1da2013-07-18 16:10:49 +100090 }
Damien Miller874d77b2000-10-14 16:23:11 +110091 strsize = strsep(&cp, " "); /* size */
92 if (cp == NULL || *strsize == '\0' ||
Darren Tucker759cb2a2009-10-07 09:01:50 +110093 (dhg->size = (int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 ||
Damien Millerbbeb1da2013-07-18 16:10:49 +100094 errstr) {
95 error("moduli:%d: invalid prime length", linenum);
Damien Miller874d77b2000-10-14 16:23:11 +110096 goto fail;
Damien Millerbbeb1da2013-07-18 16:10:49 +100097 }
Ben Lindstromdf221392001-03-29 00:36:16 +000098 /* The whole group is one bit larger */
99 dhg->size++;
Damien Miller874d77b2000-10-14 16:23:11 +1100100 gen = strsep(&cp, " "); /* gen */
101 if (cp == NULL || *gen == '\0')
Damien Millerbbeb1da2013-07-18 16:10:49 +1000102 goto truncated;
Damien Miller874d77b2000-10-14 16:23:11 +1100103 prime = strsep(&cp, " "); /* prime */
Damien Millerbbeb1da2013-07-18 16:10:49 +1000104 if (cp != NULL || *prime == '\0') {
105 truncated:
106 error("moduli:%d: truncated", linenum);
Damien Miller874d77b2000-10-14 16:23:11 +1100107 goto fail;
Damien Millerbbeb1da2013-07-18 16:10:49 +1000108 }
Damien Miller874d77b2000-10-14 16:23:11 +1100109
Damien Millerda755162002-01-22 23:09:22 +1100110 if ((dhg->g = BN_new()) == NULL)
111 fatal("parse_prime: BN_new failed");
112 if ((dhg->p = BN_new()) == NULL)
113 fatal("parse_prime: BN_new failed");
Damien Millerbbeb1da2013-07-18 16:10:49 +1000114 if (BN_hex2bn(&dhg->g, gen) == 0) {
115 error("moduli:%d: could not parse generator value", linenum);
116 goto fail;
117 }
118 if (BN_hex2bn(&dhg->p, prime) == 0) {
119 error("moduli:%d: could not parse prime value", linenum);
120 goto fail;
121 }
122 if (BN_num_bits(dhg->p) != dhg->size) {
123 error("moduli:%d: prime has wrong size: actual %d listed %d",
124 linenum, BN_num_bits(dhg->p), dhg->size - 1);
125 goto fail;
126 }
127 if (BN_cmp(dhg->g, BN_value_one()) <= 0) {
128 error("moduli:%d: generator is invalid", linenum);
129 goto fail;
130 }
Damien Miller23e526e2001-03-30 10:47:43 +1000131
Damien Millerbbeb1da2013-07-18 16:10:49 +1000132 return 1;
Damien Miller23e526e2001-03-30 10:47:43 +1000133
Damien Miller874d77b2000-10-14 16:23:11 +1100134 fail:
Damien Millerbbeb1da2013-07-18 16:10:49 +1000135 if (dhg->g != NULL)
136 BN_clear_free(dhg->g);
137 if (dhg->p != NULL)
138 BN_clear_free(dhg->p);
139 dhg->g = dhg->p = NULL;
Ben Lindstrom6df8ef42001-03-05 07:47:23 +0000140 error("Bad prime description in line %d", linenum);
Damien Millerbbeb1da2013-07-18 16:10:49 +1000141 return 0;
Damien Miller874d77b2000-10-14 16:23:11 +1100142}
143
144DH *
Ben Lindstromdf221392001-03-29 00:36:16 +0000145choose_dh(int min, int wantbits, int max)
Damien Miller874d77b2000-10-14 16:23:11 +1100146{
147 FILE *f;
Darren Tuckerc56c7ef2004-02-29 20:13:34 +1100148 char line[4096];
Damien Miller874d77b2000-10-14 16:23:11 +1100149 int best, bestcount, which;
150 int linenum;
151 struct dhgroup dhg;
152
Ben Lindstrom93a29e02001-06-25 04:13:25 +0000153 if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
154 (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
Damien Millerf675fc42004-06-15 10:30:09 +1000155 logit("WARNING: %s does not exist, using fixed modulus",
156 _PATH_DH_MODULI);
157 return (dh_new_group14());
Damien Miller874d77b2000-10-14 16:23:11 +1100158 }
159
160 linenum = 0;
161 best = bestcount = 0;
162 while (fgets(line, sizeof(line), f)) {
163 linenum++;
164 if (!parse_prime(linenum, line, &dhg))
165 continue;
Damien Miller9ef95dd2002-01-22 23:10:33 +1100166 BN_clear_free(dhg.g);
167 BN_clear_free(dhg.p);
Damien Miller874d77b2000-10-14 16:23:11 +1100168
Ben Lindstromdf221392001-03-29 00:36:16 +0000169 if (dhg.size > max || dhg.size < min)
170 continue;
171
172 if ((dhg.size > wantbits && dhg.size < best) ||
173 (dhg.size > best && best < wantbits)) {
Damien Miller874d77b2000-10-14 16:23:11 +1100174 best = dhg.size;
175 bestcount = 0;
176 }
177 if (dhg.size == best)
178 bestcount++;
179 }
Ben Lindstromaf738802001-06-25 04:18:59 +0000180 rewind(f);
Damien Miller874d77b2000-10-14 16:23:11 +1100181
182 if (bestcount == 0) {
Ben Lindstromaf738802001-06-25 04:18:59 +0000183 fclose(f);
Damien Miller996acd22003-04-09 20:59:48 +1000184 logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
Darren Tucker9a2bd112004-08-12 22:40:59 +1000185 return (dh_new_group14());
Damien Miller874d77b2000-10-14 16:23:11 +1100186 }
187
Damien Miller874d77b2000-10-14 16:23:11 +1100188 linenum = 0;
Damien Miller354c48c2008-05-19 14:50:00 +1000189 which = arc4random_uniform(bestcount);
Damien Miller874d77b2000-10-14 16:23:11 +1100190 while (fgets(line, sizeof(line), f)) {
191 if (!parse_prime(linenum, line, &dhg))
192 continue;
Ben Lindstrom5ba23b32001-04-05 02:05:21 +0000193 if ((dhg.size > max || dhg.size < min) ||
194 dhg.size != best ||
195 linenum++ != which) {
Damien Miller9ef95dd2002-01-22 23:10:33 +1100196 BN_clear_free(dhg.g);
197 BN_clear_free(dhg.p);
Damien Miller874d77b2000-10-14 16:23:11 +1100198 continue;
199 }
200 break;
201 }
202 fclose(f);
Ben Lindstrom5ba23b32001-04-05 02:05:21 +0000203 if (linenum != which+1)
204 fatal("WARNING: line %d disappeared in %s, giving up",
205 which, _PATH_DH_PRIMES);
Damien Miller874d77b2000-10-14 16:23:11 +1100206
207 return (dh_new_group(dhg.g, dhg.p));
208}
Damien Miller9709f902001-03-30 10:50:10 +1000209
Damien Millerf675fc42004-06-15 10:30:09 +1000210/* diffie-hellman-groupN-sha1 */
Damien Miller9709f902001-03-30 10:50:10 +1000211
212int
213dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
214{
215 int i;
216 int n = BN_num_bits(dh_pub);
217 int bits_set = 0;
Darren Tucker31cde682006-05-06 17:43:33 +1000218 BIGNUM *tmp;
Damien Miller9709f902001-03-30 10:50:10 +1000219
220 if (dh_pub->neg) {
Damien Miller603077a2007-10-26 14:25:55 +1000221 logit("invalid public DH value: negative");
Damien Miller9709f902001-03-30 10:50:10 +1000222 return 0;
223 }
Darren Tucker31cde682006-05-06 17:43:33 +1000224 if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */
225 logit("invalid public DH value: <= 1");
226 return 0;
227 }
228
Damien Miller603077a2007-10-26 14:25:55 +1000229 if ((tmp = BN_new()) == NULL) {
230 error("%s: BN_new failed", __func__);
231 return 0;
232 }
Darren Tucker31cde682006-05-06 17:43:33 +1000233 if (!BN_sub(tmp, dh->p, BN_value_one()) ||
234 BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
235 BN_clear_free(tmp);
236 logit("invalid public DH value: >= p-1");
237 return 0;
238 }
239 BN_clear_free(tmp);
240
Damien Miller9709f902001-03-30 10:50:10 +1000241 for (i = 0; i <= n; i++)
242 if (BN_is_bit_set(dh_pub, i))
243 bits_set++;
Ben Lindstrom1f530832002-12-23 02:03:02 +0000244 debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000245
246 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
Darren Tucker31cde682006-05-06 17:43:33 +1000247 if (bits_set > 1)
Damien Miller9709f902001-03-30 10:50:10 +1000248 return 1;
Darren Tucker31cde682006-05-06 17:43:33 +1000249
Damien Miller996acd22003-04-09 20:59:48 +1000250 logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
Damien Miller9709f902001-03-30 10:50:10 +1000251 return 0;
252}
253
254void
255dh_gen_key(DH *dh, int need)
256{
Damien Miller0fde8ac2013-11-21 14:12:23 +1100257 int pbits;
Damien Miller9709f902001-03-30 10:50:10 +1000258
Damien Miller0fde8ac2013-11-21 14:12:23 +1100259 if (need <= 0)
260 fatal("%s: need <= 0", __func__);
Damien Miller9709f902001-03-30 10:50:10 +1000261 if (dh->p == NULL)
Damien Miller0fde8ac2013-11-21 14:12:23 +1100262 fatal("%s: dh->p == NULL", __func__);
263 if ((pbits = BN_num_bits(dh->p)) <= 0)
264 fatal("%s: bits(p) <= 0", __func__);
265 dh->length = MIN(need * 2, pbits - 1);
266 if (DH_generate_key(dh) == 0)
267 fatal("%s: key generation failed", __func__);
268 if (!dh_pub_is_valid(dh, dh->pub_key))
269 fatal("%s: generated invalid key", __func__);
Damien Miller9709f902001-03-30 10:50:10 +1000270}
271
272DH *
273dh_new_group_asc(const char *gen, const char *modulus)
274{
275 DH *dh;
Damien Miller9709f902001-03-30 10:50:10 +1000276
Damien Millerda755162002-01-22 23:09:22 +1100277 if ((dh = DH_new()) == NULL)
278 fatal("dh_new_group_asc: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000279
Darren Tuckerb0781f72006-11-08 10:01:36 +1100280 if (BN_hex2bn(&dh->p, modulus) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000281 fatal("BN_hex2bn p");
Darren Tuckerb0781f72006-11-08 10:01:36 +1100282 if (BN_hex2bn(&dh->g, gen) == 0)
Damien Miller9709f902001-03-30 10:50:10 +1000283 fatal("BN_hex2bn g");
284
285 return (dh);
286}
287
288/*
289 * This just returns the group, we still need to generate the exchange
290 * value.
291 */
292
293DH *
294dh_new_group(BIGNUM *gen, BIGNUM *modulus)
295{
296 DH *dh;
297
Damien Millerda755162002-01-22 23:09:22 +1100298 if ((dh = DH_new()) == NULL)
299 fatal("dh_new_group: DH_new");
Damien Miller9709f902001-03-30 10:50:10 +1000300 dh->p = modulus;
301 dh->g = gen;
302
303 return (dh);
304}
305
306DH *
307dh_new_group1(void)
308{
309 static char *gen = "2", *group1 =
310 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
311 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
312 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
313 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
314 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
315 "FFFFFFFF" "FFFFFFFF";
316
317 return (dh_new_group_asc(gen, group1));
318}
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000319
Damien Millerf675fc42004-06-15 10:30:09 +1000320DH *
321dh_new_group14(void)
322{
323 static char *gen = "2", *group14 =
324 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
325 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
326 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
327 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
328 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
329 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
330 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
331 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
332 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
333 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
334 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
335
336 return (dh_new_group_asc(gen, group14));
337}
338
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000339/*
340 * Estimates the group order for a Diffie-Hellman group that has an
Darren Tuckerdf62d712013-10-10 10:32:39 +1100341 * attack complexity approximately the same as O(2**bits).
342 * Values from NIST Special Publication 800-57: Recommendation for Key
343 * Management Part 1 (rev 3) limited by the recommended maximum value
344 * from RFC4419 section 3.
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000345 */
346
347int
348dh_estimate(int bits)
349{
Darren Tuckerdf62d712013-10-10 10:32:39 +1100350 if (bits <= 112)
351 return 2048;
Damien Miller8975ddf2003-12-17 16:33:53 +1100352 if (bits <= 128)
Darren Tuckerdf62d712013-10-10 10:32:39 +1100353 return 3072;
Damien Miller8975ddf2003-12-17 16:33:53 +1100354 if (bits <= 192)
Darren Tuckerdf62d712013-10-10 10:32:39 +1100355 return 7680;
356 return 8192;
Ben Lindstrom20d7c7b2001-04-04 01:56:17 +0000357}