summaryrefslogtreecommitdiff
path: root/dh.c
diff options
context:
space:
mode:
Diffstat (limited to 'dh.c')
-rw-r--r--dh.c76
1 files changed, 47 insertions, 29 deletions
diff --git a/dh.c b/dh.c
index ac8d5a0ae..657b32da3 100644
--- a/dh.c
+++ b/dh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: dh.c,v 1.66 2018/08/04 00:55:06 djm Exp $ */ 1/* $OpenBSD: dh.c,v 1.68 2018/09/17 15:40:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Niels Provos. All rights reserved. 3 * Copyright (c) 2000 Niels Provos. All rights reserved.
4 * 4 *
@@ -43,6 +43,8 @@
43#include "misc.h" 43#include "misc.h"
44#include "ssherr.h" 44#include "ssherr.h"
45 45
46#include "openbsd-compat/openssl-compat.h"
47
46static int 48static int
47parse_prime(int linenum, char *line, struct dhgroup *dhg) 49parse_prime(int linenum, char *line, struct dhgroup *dhg)
48{ 50{
@@ -186,15 +188,17 @@ choose_dh(int min, int wantbits, int max)
186 logit("WARNING: no suitable primes in %s", _PATH_DH_MODULI); 188 logit("WARNING: no suitable primes in %s", _PATH_DH_MODULI);
187 return (dh_new_group_fallback(max)); 189 return (dh_new_group_fallback(max));
188 } 190 }
191 which = arc4random_uniform(bestcount);
189 192
190 linenum = 0; 193 linenum = 0;
191 which = arc4random_uniform(bestcount); 194 bestcount = 0;
192 while (getline(&line, &linesize, f) != -1) { 195 while (getline(&line, &linesize, f) != -1) {
196 linenum++;
193 if (!parse_prime(linenum, line, &dhg)) 197 if (!parse_prime(linenum, line, &dhg))
194 continue; 198 continue;
195 if ((dhg.size > max || dhg.size < min) || 199 if ((dhg.size > max || dhg.size < min) ||
196 dhg.size != best || 200 dhg.size != best ||
197 linenum++ != which) { 201 bestcount++ != which) {
198 BN_clear_free(dhg.g); 202 BN_clear_free(dhg.g);
199 BN_clear_free(dhg.p); 203 BN_clear_free(dhg.p);
200 continue; 204 continue;
@@ -204,9 +208,9 @@ choose_dh(int min, int wantbits, int max)
204 free(line); 208 free(line);
205 line = NULL; 209 line = NULL;
206 fclose(f); 210 fclose(f);
207 if (linenum != which+1) { 211 if (bestcount != which + 1) {
208 logit("WARNING: line %d disappeared in %s, giving up", 212 logit("WARNING: selected prime disappeared in %s, giving up",
209 which, _PATH_DH_MODULI); 213 _PATH_DH_MODULI);
210 return (dh_new_group_fallback(max)); 214 return (dh_new_group_fallback(max));
211 } 215 }
212 216
@@ -216,14 +220,17 @@ choose_dh(int min, int wantbits, int max)
216/* diffie-hellman-groupN-sha1 */ 220/* diffie-hellman-groupN-sha1 */
217 221
218int 222int
219dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) 223dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub)
220{ 224{
221 int i; 225 int i;
222 int n = BN_num_bits(dh_pub); 226 int n = BN_num_bits(dh_pub);
223 int bits_set = 0; 227 int bits_set = 0;
224 BIGNUM *tmp; 228 BIGNUM *tmp;
229 const BIGNUM *dh_p;
230
231 DH_get0_pqg(dh, &dh_p, NULL, NULL);
225 232
226 if (dh_pub->neg) { 233 if (BN_is_negative(dh_pub)) {
227 logit("invalid public DH value: negative"); 234 logit("invalid public DH value: negative");
228 return 0; 235 return 0;
229 } 236 }
@@ -236,7 +243,7 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
236 error("%s: BN_new failed", __func__); 243 error("%s: BN_new failed", __func__);
237 return 0; 244 return 0;
238 } 245 }
239 if (!BN_sub(tmp, dh->p, BN_value_one()) || 246 if (!BN_sub(tmp, dh_p, BN_value_one()) ||
240 BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */ 247 BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
241 BN_clear_free(tmp); 248 BN_clear_free(tmp);
242 logit("invalid public DH value: >= p-1"); 249 logit("invalid public DH value: >= p-1");
@@ -247,14 +254,14 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
247 for (i = 0; i <= n; i++) 254 for (i = 0; i <= n; i++)
248 if (BN_is_bit_set(dh_pub, i)) 255 if (BN_is_bit_set(dh_pub, i))
249 bits_set++; 256 bits_set++;
250 debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); 257 debug2("bits set: %d/%d", bits_set, BN_num_bits(dh_p));
251 258
252 /* 259 /*
253 * if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial 260 * if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial
254 */ 261 */
255 if (bits_set < 4) { 262 if (bits_set < 4) {
256 logit("invalid public DH value (%d/%d)", 263 logit("invalid public DH value (%d/%d)",
257 bits_set, BN_num_bits(dh->p)); 264 bits_set, BN_num_bits(dh_p));
258 return 0; 265 return 0;
259 } 266 }
260 return 1; 267 return 1;
@@ -264,9 +271,12 @@ int
264dh_gen_key(DH *dh, int need) 271dh_gen_key(DH *dh, int need)
265{ 272{
266 int pbits; 273 int pbits;
274 const BIGNUM *dh_p, *pub_key;
267 275
268 if (need < 0 || dh->p == NULL || 276 DH_get0_pqg(dh, &dh_p, NULL, NULL);
269 (pbits = BN_num_bits(dh->p)) <= 0 || 277
278 if (need < 0 || dh_p == NULL ||
279 (pbits = BN_num_bits(dh_p)) <= 0 ||
270 need > INT_MAX / 2 || 2 * need > pbits) 280 need > INT_MAX / 2 || 2 * need > pbits)
271 return SSH_ERR_INVALID_ARGUMENT; 281 return SSH_ERR_INVALID_ARGUMENT;
272 if (need < 256) 282 if (need < 256)
@@ -275,13 +285,14 @@ dh_gen_key(DH *dh, int need)
275 * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), 285 * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)),
276 * so double requested need here. 286 * so double requested need here.
277 */ 287 */
278 dh->length = MINIMUM(need * 2, pbits - 1); 288 if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1)))
279 if (DH_generate_key(dh) == 0 ||
280 !dh_pub_is_valid(dh, dh->pub_key)) {
281 BN_clear_free(dh->priv_key);
282 dh->priv_key = NULL;
283 return SSH_ERR_LIBCRYPTO_ERROR; 289 return SSH_ERR_LIBCRYPTO_ERROR;
284 } 290
291 if (DH_generate_key(dh) == 0)
292 return SSH_ERR_LIBCRYPTO_ERROR;
293 DH_get0_key(dh, &pub_key, NULL);
294 if (!dh_pub_is_valid(dh, pub_key))
295 return SSH_ERR_INVALID_FORMAT;
285 return 0; 296 return 0;
286} 297}
287 298
@@ -289,22 +300,27 @@ DH *
289dh_new_group_asc(const char *gen, const char *modulus) 300dh_new_group_asc(const char *gen, const char *modulus)
290{ 301{
291 DH *dh; 302 DH *dh;
303 BIGNUM *dh_p = NULL, *dh_g = NULL;
292 304
293 if ((dh = DH_new()) == NULL) 305 if ((dh = DH_new()) == NULL)
294 return NULL; 306 return NULL;
295 if (BN_hex2bn(&dh->p, modulus) == 0 || 307 if (BN_hex2bn(&dh_p, modulus) == 0 ||
296 BN_hex2bn(&dh->g, gen) == 0) { 308 BN_hex2bn(&dh_g, gen) == 0)
297 DH_free(dh); 309 goto fail;
298 return NULL; 310 if (!DH_set0_pqg(dh, dh_p, NULL, dh_g))
299 } 311 goto fail;
300 return (dh); 312 return dh;
313 fail:
314 DH_free(dh);
315 BN_clear_free(dh_p);
316 BN_clear_free(dh_g);
317 return NULL;
301} 318}
302 319
303/* 320/*
304 * This just returns the group, we still need to generate the exchange 321 * This just returns the group, we still need to generate the exchange
305 * value. 322 * value.
306 */ 323 */
307
308DH * 324DH *
309dh_new_group(BIGNUM *gen, BIGNUM *modulus) 325dh_new_group(BIGNUM *gen, BIGNUM *modulus)
310{ 326{
@@ -312,10 +328,12 @@ dh_new_group(BIGNUM *gen, BIGNUM *modulus)
312 328
313 if ((dh = DH_new()) == NULL) 329 if ((dh = DH_new()) == NULL)
314 return NULL; 330 return NULL;
315 dh->p = modulus; 331 if (!DH_set0_pqg(dh, modulus, NULL, gen)) {
316 dh->g = gen; 332 DH_free(dh);
333 return NULL;
334 }
317 335
318 return (dh); 336 return dh;
319} 337}
320 338
321/* rfc2409 "Second Oakley Group" (1024 bits) */ 339/* rfc2409 "Second Oakley Group" (1024 bits) */