=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/kex.c,v retrieving revision 1.64 retrieving revision 1.64.2.2 diff -u -r1.64 -r1.64.2.2 --- src/usr.bin/ssh/kex.c 2005/07/25 11:59:39 1.64 +++ src/usr.bin/ssh/kex.c 2006/10/06 03:19:32 1.64.2.2 @@ -1,3 +1,4 @@ +/* $OpenBSD: kex.c,v 1.64.2.2 2006/10/06 03:19:32 brad Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -22,20 +23,23 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.64 2005/07/25 11:59:39 markus Exp $"); +#include +#include +#include +#include +#include + #include -#include "ssh2.h" #include "xmalloc.h" +#include "ssh2.h" #include "buffer.h" -#include "bufaux.h" #include "packet.h" #include "compat.h" #include "cipher.h" -#include "kex.h" #include "key.h" +#include "kex.h" #include "log.h" #include "mac.h" #include "match.h" @@ -44,6 +48,8 @@ #define KEX_COOKIE_LEN 16 +extern const EVP_MD *evp_ssh_sha256(void); + /* prototype */ static void kex_kexinit_finish(Kex *); static void kex_choose_conf(Kex *); @@ -75,7 +81,7 @@ int i; char **proposal; - proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); + proposal = xcalloc(PROPOSAL_MAX, sizeof(char *)); buffer_init(&b); buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); @@ -210,8 +216,7 @@ { Kex *kex; - kex = xmalloc(sizeof(*kex)); - memset(kex, 0, sizeof(*kex)); + kex = xcalloc(1, sizeof(*kex)); buffer_init(&kex->peer); buffer_init(&kex->my); kex_prop2buf(&kex->my, proposal); @@ -254,6 +259,7 @@ enc->key_len = cipher_keylen(enc->cipher); enc->block_size = cipher_blocksize(enc->cipher); } + static void choose_mac(Mac *mac, char *client, char *server) { @@ -269,6 +275,7 @@ mac->key = NULL; mac->enabled = 0; } + static void choose_comp(Comp *comp, char *client, char *server) { @@ -286,6 +293,7 @@ } comp->name = name; } + static void choose_kex(Kex *k, char *client, char *server) { @@ -294,13 +302,20 @@ fatal("no kex alg"); if (strcmp(k->name, KEX_DH1) == 0) { k->kex_type = KEX_DH_GRP1_SHA1; + k->evp_md = EVP_sha1(); } else if (strcmp(k->name, KEX_DH14) == 0) { k->kex_type = KEX_DH_GRP14_SHA1; - } else if (strcmp(k->name, KEX_DHGEX) == 0) { + k->evp_md = EVP_sha1(); + } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { k->kex_type = KEX_DH_GEX_SHA1; + k->evp_md = EVP_sha1(); + } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { + k->kex_type = KEX_DH_GEX_SHA256; + k->evp_md = evp_ssh_sha256(); } else fatal("bad kex alg %s", k->name); } + static void choose_hostkeyalg(Kex *k, char *client, char *server) { @@ -360,8 +375,7 @@ /* Algorithm Negotiation */ for (mode = 0; mode < MODE_MAX; mode++) { - newkeys = xmalloc(sizeof(*newkeys)); - memset(newkeys, 0, sizeof(*newkeys)); + newkeys = xcalloc(1, sizeof(*newkeys)); kex->newkeys[mode] = newkeys; ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; @@ -404,28 +418,28 @@ } static u_char * -derive_key(Kex *kex, int id, u_int need, u_char *hash, BIGNUM *shared_secret) +derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, + BIGNUM *shared_secret) { Buffer b; - const EVP_MD *evp_md = EVP_sha1(); EVP_MD_CTX md; char c = id; u_int have; - int mdsz = EVP_MD_size(evp_md); + int mdsz; u_char *digest; - if (mdsz < 0) - fatal("derive_key: mdsz < 0"); + if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) + fatal("bad kex md size %d", mdsz); digest = xmalloc(roundup(need, mdsz)); buffer_init(&b); buffer_put_bignum2(&b, shared_secret); /* K1 = HASH(K || H || "A" || session_id) */ - EVP_DigestInit(&md, evp_md); + EVP_DigestInit(&md, kex->evp_md); if (!(datafellows & SSH_BUG_DERIVEKEY)) EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, hash, hashlen); EVP_DigestUpdate(&md, &c, 1); EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); EVP_DigestFinal(&md, digest, NULL); @@ -436,10 +450,10 @@ * Key = K1 || K2 || ... || Kn */ for (have = mdsz; need > have; have += mdsz) { - EVP_DigestInit(&md, evp_md); + EVP_DigestInit(&md, kex->evp_md); if (!(datafellows & SSH_BUG_DERIVEKEY)) EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, hash, hashlen); EVP_DigestUpdate(&md, digest, have); EVP_DigestFinal(&md, digest + have, NULL); } @@ -455,19 +469,22 @@ #define NKEYS 6 void -kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) +kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) { u_char *keys[NKEYS]; u_int i, mode, ctos; - for (i = 0; i < NKEYS; i++) - keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); + for (i = 0; i < NKEYS; i++) { + keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, + shared_secret); + } debug2("kex_derive_keys"); for (mode = 0; mode < MODE_MAX; mode++) { current_keys[mode] = kex->newkeys[mode]; kex->newkeys[mode] = NULL; - ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); + ctos = (!kex->server && mode == MODE_OUT) || + (kex->server && mode == MODE_IN); current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; current_keys[mode]->mac.key = keys[ctos ? 4 : 5];