xref: /onnv-gate/usr/src/cmd/ssh/libssh/common/dh.c (revision 7574:e19e13b485fa)
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