version 1.2.2.6, 2002/03/08 17:04:42 |
version 1.3, 2000/11/16 17:55:43 |
|
|
#include <openssl/dh.h> |
#include <openssl/dh.h> |
#include <openssl/evp.h> |
#include <openssl/evp.h> |
|
|
|
#include "ssh.h" |
#include "buffer.h" |
#include "buffer.h" |
#include "cipher.h" |
|
#include "kex.h" |
#include "kex.h" |
#include "dh.h" |
#include "dh.h" |
#include "pathnames.h" |
|
#include "log.h" |
|
#include "misc.h" |
|
|
|
static int |
int |
parse_prime(int linenum, char *line, struct dhgroup *dhg) |
parse_prime(int linenum, char *line, struct dhgroup *dhg) |
{ |
{ |
char *cp, *arg; |
char *cp, *arg; |
|
|
if (cp == NULL || *strsize == '\0' || |
if (cp == NULL || *strsize == '\0' || |
(dhg->size = atoi(strsize)) == 0) |
(dhg->size = atoi(strsize)) == 0) |
goto fail; |
goto fail; |
/* The whole group is one bit larger */ |
|
dhg->size++; |
|
gen = strsep(&cp, " "); /* gen */ |
gen = strsep(&cp, " "); /* gen */ |
if (cp == NULL || *gen == '\0') |
if (cp == NULL || *gen == '\0') |
goto fail; |
goto fail; |
|
|
if (cp != NULL || *prime == '\0') |
if (cp != NULL || *prime == '\0') |
goto fail; |
goto fail; |
|
|
if ((dhg->g = BN_new()) == NULL) |
dhg->g = BN_new(); |
fatal("parse_prime: BN_new failed"); |
if (BN_hex2bn(&dhg->g, gen) < 0) { |
if ((dhg->p = BN_new()) == NULL) |
BN_free(dhg->g); |
fatal("parse_prime: BN_new failed"); |
goto fail; |
if (BN_hex2bn(&dhg->g, gen) == 0) |
} |
goto failclean; |
dhg->p = BN_new(); |
|
if (BN_hex2bn(&dhg->p, prime) < 0) { |
|
BN_free(dhg->g); |
|
BN_free(dhg->p); |
|
goto fail; |
|
} |
|
|
if (BN_hex2bn(&dhg->p, prime) == 0) |
|
goto failclean; |
|
|
|
if (BN_num_bits(dhg->p) != dhg->size) |
|
goto failclean; |
|
|
|
return (1); |
return (1); |
|
|
failclean: |
|
BN_clear_free(dhg->g); |
|
BN_clear_free(dhg->p); |
|
fail: |
fail: |
error("Bad prime description in line %d", linenum); |
fprintf(stderr, "Bad prime description in line %d\n", linenum); |
return (0); |
return (0); |
} |
} |
|
|
DH * |
DH * |
choose_dh(int min, int wantbits, int max) |
choose_dh(int minbits) |
{ |
{ |
FILE *f; |
FILE *f; |
char line[2048]; |
char line[1024]; |
int best, bestcount, which; |
int best, bestcount, which; |
int linenum; |
int linenum; |
struct dhgroup dhg; |
struct dhgroup dhg; |
|
|
if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL && |
f = fopen(DH_PRIMES, "r"); |
(f = fopen(_PATH_DH_PRIMES, "r")) == NULL) { |
if (!f) { |
log("WARNING: %s does not exist, using old modulus", _PATH_DH_MODULI); |
log("WARNING: %s does not exist, using old prime", DH_PRIMES); |
return (dh_new_group1()); |
return (dh_new_group1()); |
} |
} |
|
|
|
|
linenum++; |
linenum++; |
if (!parse_prime(linenum, line, &dhg)) |
if (!parse_prime(linenum, line, &dhg)) |
continue; |
continue; |
BN_clear_free(dhg.g); |
BN_free(dhg.g); |
BN_clear_free(dhg.p); |
BN_free(dhg.p); |
|
|
if (dhg.size > max || dhg.size < min) |
if ((dhg.size > minbits && dhg.size < best) || |
continue; |
(dhg.size > best && best < minbits)) { |
|
|
if ((dhg.size > wantbits && dhg.size < best) || |
|
(dhg.size > best && best < wantbits)) { |
|
best = dhg.size; |
best = dhg.size; |
bestcount = 0; |
bestcount = 0; |
} |
} |
if (dhg.size == best) |
if (dhg.size == best) |
bestcount++; |
bestcount++; |
} |
} |
rewind(f); |
fclose (f); |
|
|
if (bestcount == 0) { |
if (bestcount == 0) { |
fclose(f); |
log("WARNING: no primes in %s, using old prime", DH_PRIMES); |
log("WARNING: no suitable primes in %s", _PATH_DH_PRIMES); |
return (dh_new_group1()); |
return (NULL); |
|
} |
} |
|
|
|
f = fopen(DH_PRIMES, "r"); |
|
if (!f) { |
|
fatal("WARNING: %s dissappeared, giving up", DH_PRIMES); |
|
} |
|
|
linenum = 0; |
linenum = 0; |
which = arc4random() % bestcount; |
which = arc4random() % bestcount; |
while (fgets(line, sizeof(line), f)) { |
while (fgets(line, sizeof(line), f)) { |
if (!parse_prime(linenum, line, &dhg)) |
if (!parse_prime(linenum, line, &dhg)) |
continue; |
continue; |
if ((dhg.size > max || dhg.size < min) || |
if (dhg.size != best) |
dhg.size != best || |
|
linenum++ != which) { |
|
BN_clear_free(dhg.g); |
|
BN_clear_free(dhg.p); |
|
continue; |
continue; |
|
if (linenum++ != which) { |
|
BN_free(dhg.g); |
|
BN_free(dhg.p); |
|
continue; |
} |
} |
break; |
break; |
} |
} |
fclose(f); |
fclose(f); |
if (linenum != which+1) |
|
fatal("WARNING: line %d disappeared in %s, giving up", |
|
which, _PATH_DH_PRIMES); |
|
|
|
return (dh_new_group(dhg.g, dhg.p)); |
return (dh_new_group(dhg.g, dhg.p)); |
} |
|
|
|
/* diffie-hellman-group1-sha1 */ |
|
|
|
int |
|
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) |
|
{ |
|
int i; |
|
int n = BN_num_bits(dh_pub); |
|
int bits_set = 0; |
|
|
|
if (dh_pub->neg) { |
|
log("invalid public DH value: negativ"); |
|
return 0; |
|
} |
|
for (i = 0; i <= n; i++) |
|
if (BN_is_bit_set(dh_pub, i)) |
|
bits_set++; |
|
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); |
|
|
|
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ |
|
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) |
|
return 1; |
|
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); |
|
return 0; |
|
} |
|
|
|
void |
|
dh_gen_key(DH *dh, int need) |
|
{ |
|
int i, bits_set = 0, tries = 0; |
|
|
|
if (dh->p == NULL) |
|
fatal("dh_gen_key: dh->p == NULL"); |
|
if (2*need >= BN_num_bits(dh->p)) |
|
fatal("dh_gen_key: group too small: %d (2*need %d)", |
|
BN_num_bits(dh->p), 2*need); |
|
do { |
|
if (dh->priv_key != NULL) |
|
BN_clear_free(dh->priv_key); |
|
if ((dh->priv_key = BN_new()) == NULL) |
|
fatal("dh_gen_key: BN_new failed"); |
|
/* generate a 2*need bits random private exponent */ |
|
if (!BN_rand(dh->priv_key, 2*need, 0, 0)) |
|
fatal("dh_gen_key: BN_rand failed"); |
|
if (DH_generate_key(dh) == 0) |
|
fatal("DH_generate_key"); |
|
for (i = 0; i <= BN_num_bits(dh->priv_key); i++) |
|
if (BN_is_bit_set(dh->priv_key, i)) |
|
bits_set++; |
|
debug("dh_gen_key: priv key bits set: %d/%d", |
|
bits_set, BN_num_bits(dh->priv_key)); |
|
if (tries++ > 10) |
|
fatal("dh_gen_key: too many bad keys: giving up"); |
|
} while (!dh_pub_is_valid(dh, dh->pub_key)); |
|
} |
|
|
|
DH * |
|
dh_new_group_asc(const char *gen, const char *modulus) |
|
{ |
|
DH *dh; |
|
|
|
if ((dh = DH_new()) == NULL) |
|
fatal("dh_new_group_asc: DH_new"); |
|
|
|
if (BN_hex2bn(&dh->p, modulus) == 0) |
|
fatal("BN_hex2bn p"); |
|
if (BN_hex2bn(&dh->g, gen) == 0) |
|
fatal("BN_hex2bn g"); |
|
|
|
return (dh); |
|
} |
|
|
|
/* |
|
* This just returns the group, we still need to generate the exchange |
|
* value. |
|
*/ |
|
|
|
DH * |
|
dh_new_group(BIGNUM *gen, BIGNUM *modulus) |
|
{ |
|
DH *dh; |
|
|
|
if ((dh = DH_new()) == NULL) |
|
fatal("dh_new_group: DH_new"); |
|
dh->p = modulus; |
|
dh->g = gen; |
|
|
|
return (dh); |
|
} |
|
|
|
DH * |
|
dh_new_group1(void) |
|
{ |
|
static char *gen = "2", *group1 = |
|
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" |
|
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" |
|
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" |
|
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" |
|
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" |
|
"FFFFFFFF" "FFFFFFFF"; |
|
|
|
return (dh_new_group_asc(gen, group1)); |
|
} |
|
|
|
/* |
|
* Estimates the group order for a Diffie-Hellman group that has an |
|
* attack complexity approximately the same as O(2**bits). Estimate |
|
* with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) |
|
*/ |
|
|
|
int |
|
dh_estimate(int bits) |
|
{ |
|
|
|
if (bits < 64) |
|
return (512); /* O(2**63) */ |
|
if (bits < 128) |
|
return (1024); /* O(2**86) */ |
|
if (bits < 192) |
|
return (2048); /* O(2**116) */ |
|
return (4096); /* O(2**156) */ |
|
} |
} |