xref: /freebsd/crypto/openssh/dh.c (revision c68159a6d8eede11766cf13896d0f7670dbd51aa)
1 /*
2  * Copyright (c) 2000 Niels Provos.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #include "includes.h"
26 RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $");
27 
28 #include "xmalloc.h"
29 
30 #include <openssl/bn.h>
31 #include <openssl/dh.h>
32 #include <openssl/evp.h>
33 
34 #include "ssh.h"
35 #include "buffer.h"
36 #include "kex.h"
37 #include "dh.h"
38 
39 int
40 parse_prime(int linenum, char *line, struct dhgroup *dhg)
41 {
42 	char *cp, *arg;
43 	char *strsize, *gen, *prime;
44 
45 	cp = line;
46 	arg = strdelim(&cp);
47 	/* Ignore leading whitespace */
48 	if (*arg == '\0')
49 		arg = strdelim(&cp);
50 	if (!*arg || *arg == '#')
51 		return 0;
52 
53 	/* time */
54 	if (cp == NULL || *arg == '\0')
55 		goto fail;
56 	arg = strsep(&cp, " "); /* type */
57 	if (cp == NULL || *arg == '\0')
58 		goto fail;
59 	arg = strsep(&cp, " "); /* tests */
60 	if (cp == NULL || *arg == '\0')
61 		goto fail;
62 	arg = strsep(&cp, " "); /* tries */
63 	if (cp == NULL || *arg == '\0')
64 		goto fail;
65 	strsize = strsep(&cp, " "); /* size */
66 	if (cp == NULL || *strsize == '\0' ||
67 	    (dhg->size = atoi(strsize)) == 0)
68 		goto fail;
69 	gen = strsep(&cp, " "); /* gen */
70 	if (cp == NULL || *gen == '\0')
71 		goto fail;
72 	prime = strsep(&cp, " "); /* prime */
73 	if (cp != NULL || *prime == '\0')
74 		goto fail;
75 
76 	dhg->g = BN_new();
77 	if (BN_hex2bn(&dhg->g, gen) < 0) {
78 		BN_free(dhg->g);
79 		goto fail;
80 	}
81 	dhg->p = BN_new();
82 	if (BN_hex2bn(&dhg->p, prime) < 0) {
83 		BN_free(dhg->g);
84 		BN_free(dhg->p);
85 		goto fail;
86 	}
87 
88 	return (1);
89  fail:
90 	fprintf(stderr, "Bad prime description in line %d\n", linenum);
91 	return (0);
92 }
93 
94 DH *
95 choose_dh(int minbits)
96 {
97 	FILE *f;
98 	char line[1024];
99 	int best, bestcount, which;
100 	int linenum;
101 	struct dhgroup dhg;
102 
103 	f = fopen(DH_PRIMES, "r");
104 	if (!f) {
105 		perror(DH_PRIMES);
106 		log("WARNING: %s does not exist, using old prime", DH_PRIMES);
107 		return (dh_new_group1());
108 	}
109 
110 	linenum = 0;
111 	best = bestcount = 0;
112 	while (fgets(line, sizeof(line), f)) {
113 		linenum++;
114 		if (!parse_prime(linenum, line, &dhg))
115 			continue;
116 		BN_free(dhg.g);
117 		BN_free(dhg.p);
118 
119 		if ((dhg.size > minbits && dhg.size < best) ||
120 		    (dhg.size > best && best < minbits)) {
121 			best = dhg.size;
122 			bestcount = 0;
123 		}
124 		if (dhg.size == best)
125 			bestcount++;
126 	}
127 	fclose (f);
128 
129 	if (bestcount == 0) {
130 		log("WARNING: no primes in %s, using old prime", DH_PRIMES);
131 		return (dh_new_group1());
132 	}
133 
134 	f = fopen(DH_PRIMES, "r");
135 	if (!f) {
136 		perror(DH_PRIMES);
137 		exit(1);
138 	}
139 
140 	linenum = 0;
141 	which = arc4random() % bestcount;
142 	while (fgets(line, sizeof(line), f)) {
143 		if (!parse_prime(linenum, line, &dhg))
144 			continue;
145 		if (dhg.size != best)
146 			continue;
147 		if (linenum++ != which) {
148 			BN_free(dhg.g);
149 			BN_free(dhg.p);
150 			continue;
151 		}
152 		break;
153 	}
154 	fclose(f);
155 
156 	return (dh_new_group(dhg.g, dhg.p));
157 }
158