diff options
Diffstat (limited to 'dh.c')
-rw-r--r-- | dh.c | 76 |
1 files changed, 47 insertions, 29 deletions
@@ -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 | |||
46 | static int | 48 | static int |
47 | parse_prime(int linenum, char *line, struct dhgroup *dhg) | 49 | parse_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 | ||
218 | int | 222 | int |
219 | dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) | 223 | dh_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 | |||
264 | dh_gen_key(DH *dh, int need) | 271 | dh_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 * | |||
289 | dh_new_group_asc(const char *gen, const char *modulus) | 300 | dh_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 | |||
308 | DH * | 324 | DH * |
309 | dh_new_group(BIGNUM *gen, BIGNUM *modulus) | 325 | dh_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) */ |