=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/kex.c,v retrieving revision 1.6.2.2 retrieving revision 1.6.2.3 diff -u -r1.6.2.2 -r1.6.2.3 --- src/usr.bin/ssh/kex.c 2000/09/01 18:23:20 1.6.2.2 +++ src/usr.bin/ssh/kex.c 2000/11/08 21:30:51 1.6.2.3 @@ -9,11 +9,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Markus Friedl. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -28,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.6.2.2 2000/09/01 18:23:20 jason Exp $"); +RCSID("$OpenBSD: kex.c,v 1.6.2.3 2000/11/08 21:30:51 jason Exp $"); #include "ssh.h" #include "ssh2.h" @@ -36,7 +31,6 @@ #include "buffer.h" #include "bufaux.h" #include "packet.h" -#include "cipher.h" #include "compat.h" #include @@ -128,11 +122,6 @@ int n = BN_num_bits(dh_pub); int bits_set = 0; - /* we only accept g==2 */ - if (!BN_is_word(dh->g, 2)) { - log("invalid DH base != 2"); - return 0; - } if (dh_pub->neg) { log("invalid public DH value: negativ"); return 0; @@ -150,27 +139,10 @@ } DH * -dh_new_group1() +dh_gen_key(DH *dh) { - static char *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"; - DH *dh; - int ret, tries = 0; - dh = DH_new(); - if(dh == NULL) - fatal("DH_new"); - ret = BN_hex2bn(&dh->p, group1); - if(ret<0) - fatal("BN_hex2bn"); - dh->g = BN_new(); - if(dh->g == NULL) - fatal("DH_new g"); - BN_set_word(dh->g, 2); + int tries = 0; + do { if (DH_generate_key(dh) == 0) fatal("DH_generate_key"); @@ -180,6 +152,52 @@ return dh; } +DH * +dh_new_group_asc(const char *gen, const char *modulus) +{ + DH *dh; + int ret; + + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + + if ((ret = BN_hex2bn(&dh->p, modulus)) < 0) + fatal("BN_hex2bn p"); + if ((ret = BN_hex2bn(&dh->g, gen)) < 0) + fatal("BN_hex2bn g"); + + return (dh_gen_key(dh)); +} + +DH * +dh_new_group(BIGNUM *gen, BIGNUM *modulus) +{ + DH *dh; + + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + dh->p = modulus; + dh->g = gen; + + return (dh_gen_key(dh)); +} + +DH * +dh_new_group1() +{ + 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)); +} + void dump_digest(unsigned char *digest, int len) { @@ -242,6 +260,59 @@ } unsigned char * +kex_hash_gex( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + char *serverhostkeyblob, int sbloblen, + int minbits, BIGNUM *prime, BIGNUM *gen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) +{ + Buffer b; + static unsigned char digest[EVP_MAX_MD_SIZE]; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + + buffer_init(&b); + buffer_put_string(&b, client_version_string, strlen(client_version_string)); + buffer_put_string(&b, server_version_string, strlen(server_version_string)); + + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); + + buffer_put_string(&b, serverhostkeyblob, sbloblen); + buffer_put_int(&b, minbits); + buffer_put_bignum2(&b, prime); + buffer_put_bignum2(&b, gen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEX + buffer_dump(&b); +#endif + + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEX + dump_digest(digest, evp_md->md_size); +#endif + return digest; +} + +unsigned char * derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) { Buffer b; @@ -323,28 +394,9 @@ char *name = get_match(client, server); if (name == NULL) fatal("no matching cipher found: client %s server %s", client, server); - enc->type = cipher_number(name); - - switch (enc->type) { - case SSH_CIPHER_3DES_CBC: - enc->key_len = 24; - enc->iv_len = 8; - enc->block_size = 8; - break; - case SSH_CIPHER_BLOWFISH_CBC: - case SSH_CIPHER_CAST128_CBC: - enc->key_len = 16; - enc->iv_len = 8; - enc->block_size = 8; - break; - case SSH_CIPHER_ARCFOUR: - enc->key_len = 16; - enc->iv_len = 0; - enc->block_size = 8; - break; - default: - fatal("unsupported cipher %s", name); - } + enc->cipher = cipher_by_name(name); + if (enc->cipher == NULL) + fatal("matching cipher is not supported: %s", name); enc->name = name; enc->enabled = 0; enc->iv = NULL; @@ -392,7 +444,11 @@ k->name = get_match(client, server); if (k->name == NULL) fatal("no kex alg"); - if (strcmp(k->name, KEX_DH1) != 0) + if (strcmp(k->name, KEX_DH1) == 0) { + k->kex_type = DH_GRP1_SHA1; + } else if (strcmp(k->name, KEX_DHGEX) == 0) { + k->kex_type = DH_GEX_SHA1; + } else fatal("bad kex alg %s", k->name); } void @@ -437,10 +493,10 @@ sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); need = 0; for (mode = 0; mode < MODE_MAX; mode++) { - if (need < k->enc[mode].key_len) - need = k->enc[mode].key_len; - if (need < k->enc[mode].iv_len) - need = k->enc[mode].iv_len; + if (need < k->enc[mode].cipher->key_len) + need = k->enc[mode].cipher->key_len; + if (need < k->enc[mode].cipher->block_size) + need = k->enc[mode].cipher->block_size; if (need < k->mac[mode].key_len) need = k->mac[mode].key_len; }