10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * Copyright (c) 2000 Niels Provos. All rights reserved.
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
50Sstevel@tonic-gate * modification, are permitted provided that the following conditions
60Sstevel@tonic-gate * are met:
70Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
80Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
90Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
100Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
110Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
140Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
150Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
160Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
170Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
180Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
190Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
200Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
210Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
220Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include "includes.h"
260Sstevel@tonic-gate RCSID("$OpenBSD: dh.c,v 1.22 2002/06/27 08:49:44 markus Exp $");
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include "xmalloc.h"
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <openssl/bn.h>
310Sstevel@tonic-gate #include <openssl/dh.h>
320Sstevel@tonic-gate #include <openssl/evp.h>
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include "buffer.h"
350Sstevel@tonic-gate #include "cipher.h"
360Sstevel@tonic-gate #include "kex.h"
370Sstevel@tonic-gate #include "dh.h"
380Sstevel@tonic-gate #include "pathnames.h"
390Sstevel@tonic-gate #include "log.h"
400Sstevel@tonic-gate #include "misc.h"
410Sstevel@tonic-gate
420Sstevel@tonic-gate static int
parse_prime(int linenum,char * line,struct dhgroup * dhg)430Sstevel@tonic-gate parse_prime(int linenum, char *line, struct dhgroup *dhg)
440Sstevel@tonic-gate {
450Sstevel@tonic-gate char *cp, *arg;
460Sstevel@tonic-gate char *strsize, *gen, *prime;
470Sstevel@tonic-gate
480Sstevel@tonic-gate cp = line;
490Sstevel@tonic-gate arg = strdelim(&cp);
500Sstevel@tonic-gate /* Ignore leading whitespace */
510Sstevel@tonic-gate if (*arg == '\0')
520Sstevel@tonic-gate arg = strdelim(&cp);
530Sstevel@tonic-gate if (!arg || !*arg || *arg == '#')
540Sstevel@tonic-gate return 0;
550Sstevel@tonic-gate
560Sstevel@tonic-gate /* time */
570Sstevel@tonic-gate if (cp == NULL || *arg == '\0')
580Sstevel@tonic-gate goto fail;
590Sstevel@tonic-gate arg = strsep(&cp, " "); /* type */
600Sstevel@tonic-gate if (cp == NULL || *arg == '\0')
610Sstevel@tonic-gate goto fail;
620Sstevel@tonic-gate arg = strsep(&cp, " "); /* tests */
630Sstevel@tonic-gate if (cp == NULL || *arg == '\0')
640Sstevel@tonic-gate goto fail;
650Sstevel@tonic-gate arg = strsep(&cp, " "); /* tries */
660Sstevel@tonic-gate if (cp == NULL || *arg == '\0')
670Sstevel@tonic-gate goto fail;
680Sstevel@tonic-gate strsize = strsep(&cp, " "); /* size */
690Sstevel@tonic-gate if (cp == NULL || *strsize == '\0' ||
700Sstevel@tonic-gate (dhg->size = atoi(strsize)) == 0)
710Sstevel@tonic-gate goto fail;
720Sstevel@tonic-gate /* The whole group is one bit larger */
730Sstevel@tonic-gate dhg->size++;
740Sstevel@tonic-gate gen = strsep(&cp, " "); /* gen */
750Sstevel@tonic-gate if (cp == NULL || *gen == '\0')
760Sstevel@tonic-gate goto fail;
770Sstevel@tonic-gate prime = strsep(&cp, " "); /* prime */
780Sstevel@tonic-gate if (cp != NULL || *prime == '\0')
790Sstevel@tonic-gate goto fail;
800Sstevel@tonic-gate
810Sstevel@tonic-gate if ((dhg->g = BN_new()) == NULL)
820Sstevel@tonic-gate fatal("parse_prime: BN_new failed");
830Sstevel@tonic-gate if ((dhg->p = BN_new()) == NULL)
840Sstevel@tonic-gate fatal("parse_prime: BN_new failed");
850Sstevel@tonic-gate if (BN_hex2bn(&dhg->g, gen) == 0)
860Sstevel@tonic-gate goto failclean;
870Sstevel@tonic-gate
880Sstevel@tonic-gate if (BN_hex2bn(&dhg->p, prime) == 0)
890Sstevel@tonic-gate goto failclean;
900Sstevel@tonic-gate
910Sstevel@tonic-gate if (BN_num_bits(dhg->p) != dhg->size)
920Sstevel@tonic-gate goto failclean;
930Sstevel@tonic-gate
940Sstevel@tonic-gate return (1);
950Sstevel@tonic-gate
960Sstevel@tonic-gate failclean:
970Sstevel@tonic-gate BN_clear_free(dhg->g);
980Sstevel@tonic-gate BN_clear_free(dhg->p);
990Sstevel@tonic-gate fail:
1000Sstevel@tonic-gate error("Bad prime description in line %d", linenum);
1010Sstevel@tonic-gate return (0);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate DH *
choose_dh(int min,int wantbits,int max)1050Sstevel@tonic-gate choose_dh(int min, int wantbits, int max)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate FILE *f;
1080Sstevel@tonic-gate char line[2048];
1090Sstevel@tonic-gate int best, bestcount, which;
1100Sstevel@tonic-gate int linenum;
1110Sstevel@tonic-gate struct dhgroup dhg;
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
1140Sstevel@tonic-gate (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
1150Sstevel@tonic-gate log("WARNING: %s does not exist, using old modulus", _PATH_DH_MODULI);
1160Sstevel@tonic-gate return (dh_new_group1());
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate linenum = 0;
1200Sstevel@tonic-gate best = bestcount = 0;
1210Sstevel@tonic-gate while (fgets(line, sizeof(line), f)) {
1220Sstevel@tonic-gate linenum++;
1230Sstevel@tonic-gate if (!parse_prime(linenum, line, &dhg))
1240Sstevel@tonic-gate continue;
1250Sstevel@tonic-gate BN_clear_free(dhg.g);
1260Sstevel@tonic-gate BN_clear_free(dhg.p);
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate if (dhg.size > max || dhg.size < min)
1290Sstevel@tonic-gate continue;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate if ((dhg.size > wantbits && dhg.size < best) ||
1320Sstevel@tonic-gate (dhg.size > best && best < wantbits)) {
1330Sstevel@tonic-gate best = dhg.size;
1340Sstevel@tonic-gate bestcount = 0;
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate if (dhg.size == best)
1370Sstevel@tonic-gate bestcount++;
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate rewind(f);
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate if (bestcount == 0) {
1420Sstevel@tonic-gate fclose(f);
1430Sstevel@tonic-gate log("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
1440Sstevel@tonic-gate return (NULL);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate linenum = 0;
1480Sstevel@tonic-gate which = arc4random() % bestcount;
1490Sstevel@tonic-gate while (fgets(line, sizeof(line), f)) {
1500Sstevel@tonic-gate if (!parse_prime(linenum, line, &dhg))
1510Sstevel@tonic-gate continue;
1520Sstevel@tonic-gate if ((dhg.size > max || dhg.size < min) ||
1530Sstevel@tonic-gate dhg.size != best ||
1540Sstevel@tonic-gate linenum++ != which) {
1550Sstevel@tonic-gate BN_clear_free(dhg.g);
1560Sstevel@tonic-gate BN_clear_free(dhg.p);
1570Sstevel@tonic-gate continue;
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate break;
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate fclose(f);
1620Sstevel@tonic-gate if (linenum != which+1)
1630Sstevel@tonic-gate fatal("WARNING: line %d disappeared in %s, giving up",
1640Sstevel@tonic-gate which, _PATH_DH_PRIMES);
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate return (dh_new_group(dhg.g, dhg.p));
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /* diffie-hellman-group1-sha1 */
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate int
dh_pub_is_valid(DH * dh,BIGNUM * dh_pub)1720Sstevel@tonic-gate dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate int i;
1750Sstevel@tonic-gate int n = BN_num_bits(dh_pub);
1760Sstevel@tonic-gate int bits_set = 0;
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate if (dh_pub->neg) {
1790Sstevel@tonic-gate log("invalid public DH value: negativ");
1800Sstevel@tonic-gate return 0;
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate for (i = 0; i <= n; i++)
1830Sstevel@tonic-gate if (BN_is_bit_set(dh_pub, i))
1840Sstevel@tonic-gate bits_set++;
1850Sstevel@tonic-gate debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
1880Sstevel@tonic-gate if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
1890Sstevel@tonic-gate return 1;
1900Sstevel@tonic-gate log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
1910Sstevel@tonic-gate return 0;
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate void
dh_gen_key(DH * dh,int need)1950Sstevel@tonic-gate dh_gen_key(DH *dh, int need)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate int i, bits_set = 0, tries = 0;
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate if (dh->p == NULL)
2000Sstevel@tonic-gate fatal("dh_gen_key: dh->p == NULL");
2010Sstevel@tonic-gate if (2*need >= BN_num_bits(dh->p))
2020Sstevel@tonic-gate fatal("dh_gen_key: group too small: %d (2*need %d)",
2030Sstevel@tonic-gate BN_num_bits(dh->p), 2*need);
2040Sstevel@tonic-gate do {
2050Sstevel@tonic-gate if (dh->priv_key != NULL)
2060Sstevel@tonic-gate BN_clear_free(dh->priv_key);
2070Sstevel@tonic-gate if ((dh->priv_key = BN_new()) == NULL)
2080Sstevel@tonic-gate fatal("dh_gen_key: BN_new failed");
2090Sstevel@tonic-gate /* generate a 2*need bits random private exponent */
2100Sstevel@tonic-gate if (!BN_rand(dh->priv_key, 2*need, 0, 0))
2110Sstevel@tonic-gate fatal("dh_gen_key: BN_rand failed");
2120Sstevel@tonic-gate if (DH_generate_key(dh) == 0)
213*7574SJan.Pechanec@Sun.COM fatal("dh_gen_key: DH_generate_key() failed");
2140Sstevel@tonic-gate for (i = 0; i <= BN_num_bits(dh->priv_key); i++)
2150Sstevel@tonic-gate if (BN_is_bit_set(dh->priv_key, i))
2160Sstevel@tonic-gate bits_set++;
2170Sstevel@tonic-gate debug("dh_gen_key: priv key bits set: %d/%d",
2180Sstevel@tonic-gate bits_set, BN_num_bits(dh->priv_key));
2190Sstevel@tonic-gate if (tries++ > 10)
2200Sstevel@tonic-gate fatal("dh_gen_key: too many bad keys: giving up");
2210Sstevel@tonic-gate } while (!dh_pub_is_valid(dh, dh->pub_key));
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate DH *
dh_new_group_asc(const char * gen,const char * modulus)2250Sstevel@tonic-gate dh_new_group_asc(const char *gen, const char *modulus)
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate DH *dh;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate if ((dh = DH_new()) == NULL)
2300Sstevel@tonic-gate fatal("dh_new_group_asc: DH_new");
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate if (BN_hex2bn(&dh->p, modulus) == 0)
2330Sstevel@tonic-gate fatal("BN_hex2bn p");
2340Sstevel@tonic-gate if (BN_hex2bn(&dh->g, gen) == 0)
2350Sstevel@tonic-gate fatal("BN_hex2bn g");
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate return (dh);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate * This just returns the group, we still need to generate the exchange
2420Sstevel@tonic-gate * value.
2430Sstevel@tonic-gate */
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate DH *
dh_new_group(BIGNUM * gen,BIGNUM * modulus)2460Sstevel@tonic-gate dh_new_group(BIGNUM *gen, BIGNUM *modulus)
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate DH *dh;
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate if ((dh = DH_new()) == NULL)
2510Sstevel@tonic-gate fatal("dh_new_group: DH_new");
2520Sstevel@tonic-gate dh->p = modulus;
2530Sstevel@tonic-gate dh->g = gen;
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate return (dh);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate DH *
dh_new_group1(void)2590Sstevel@tonic-gate dh_new_group1(void)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate static char *gen = "2", *group1 =
2620Sstevel@tonic-gate "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2630Sstevel@tonic-gate "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2640Sstevel@tonic-gate "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2650Sstevel@tonic-gate "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2660Sstevel@tonic-gate "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2670Sstevel@tonic-gate "FFFFFFFF" "FFFFFFFF";
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate return (dh_new_group_asc(gen, group1));
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * Estimates the group order for a Diffie-Hellman group that has an
2740Sstevel@tonic-gate * attack complexity approximately the same as O(2**bits). Estimate
2750Sstevel@tonic-gate * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
2760Sstevel@tonic-gate */
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate int
dh_estimate(int bits)2790Sstevel@tonic-gate dh_estimate(int bits)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate if (bits < 64)
2830Sstevel@tonic-gate return (512); /* O(2**63) */
2840Sstevel@tonic-gate if (bits < 128)
2850Sstevel@tonic-gate return (1024); /* O(2**86) */
2860Sstevel@tonic-gate if (bits < 192)
2870Sstevel@tonic-gate return (2048); /* O(2**116) */
2880Sstevel@tonic-gate return (4096); /* O(2**156) */
2890Sstevel@tonic-gate }
290