1a04a10f8SKris Kennaway /* 2ae1f160dSDag-Erling Smørgrav * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3a04a10f8SKris Kennaway * 4a04a10f8SKris Kennaway * Redistribution and use in source and binary forms, with or without 5a04a10f8SKris Kennaway * modification, are permitted provided that the following conditions 6a04a10f8SKris Kennaway * are met: 7a04a10f8SKris Kennaway * 1. Redistributions of source code must retain the above copyright 8a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer. 9a04a10f8SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 10a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer in the 11a04a10f8SKris Kennaway * documentation and/or other materials provided with the distribution. 12a04a10f8SKris Kennaway * 13a04a10f8SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14a04a10f8SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15a04a10f8SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16a04a10f8SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17a04a10f8SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18a04a10f8SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19a04a10f8SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20a04a10f8SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21a04a10f8SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22a04a10f8SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23a04a10f8SKris Kennaway */ 24a04a10f8SKris Kennaway 25a04a10f8SKris Kennaway #include "includes.h" 26ae1f160dSDag-Erling Smørgrav RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $"); 27a04a10f8SKris Kennaway 281e8db6e2SBrian Feldman #include <openssl/crypto.h> 291e8db6e2SBrian Feldman 30a04a10f8SKris Kennaway #include "ssh2.h" 31a04a10f8SKris Kennaway #include "xmalloc.h" 32a04a10f8SKris Kennaway #include "buffer.h" 33a04a10f8SKris Kennaway #include "bufaux.h" 342632b0c8SKris Kennaway #include "packet.h" 35a04a10f8SKris Kennaway #include "compat.h" 361e8db6e2SBrian Feldman #include "cipher.h" 37a04a10f8SKris Kennaway #include "kex.h" 381e8db6e2SBrian Feldman #include "key.h" 391e8db6e2SBrian Feldman #include "log.h" 401e8db6e2SBrian Feldman #include "mac.h" 411e8db6e2SBrian Feldman #include "match.h" 421e8db6e2SBrian Feldman #include "dispatch.h" 43a04a10f8SKris Kennaway 442632b0c8SKris Kennaway #define KEX_COOKIE_LEN 16 452632b0c8SKris Kennaway 46ae1f160dSDag-Erling Smørgrav /* prototype */ 47ae1f160dSDag-Erling Smørgrav static void kex_kexinit_finish(Kex *); 48ae1f160dSDag-Erling Smørgrav static void kex_choose_conf(Kex *); 491e8db6e2SBrian Feldman 501e8db6e2SBrian Feldman /* put algorithm proposal into buffer */ 51ae1f160dSDag-Erling Smørgrav static void 521e8db6e2SBrian Feldman kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 53a04a10f8SKris Kennaway { 54a04a10f8SKris Kennaway u_int32_t rand = 0; 55a04a10f8SKris Kennaway int i; 561e8db6e2SBrian Feldman 571e8db6e2SBrian Feldman buffer_clear(b); 582632b0c8SKris Kennaway for (i = 0; i < KEX_COOKIE_LEN; i++) { 59a04a10f8SKris Kennaway if (i % 4 == 0) 60a04a10f8SKris Kennaway rand = arc4random(); 611e8db6e2SBrian Feldman buffer_put_char(b, rand & 0xff); 62a04a10f8SKris Kennaway rand >>= 8; 63a04a10f8SKris Kennaway } 64a04a10f8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) 651e8db6e2SBrian Feldman buffer_put_cstring(b, proposal[i]); 661e8db6e2SBrian Feldman buffer_put_char(b, 0); /* first_kex_packet_follows */ 671e8db6e2SBrian Feldman buffer_put_int(b, 0); /* uint32 reserved */ 68a04a10f8SKris Kennaway } 69a04a10f8SKris Kennaway 701e8db6e2SBrian Feldman /* parse buffer and return algorithm proposal */ 71ae1f160dSDag-Erling Smørgrav static char ** 721e8db6e2SBrian Feldman kex_buf2prop(Buffer *raw) 732632b0c8SKris Kennaway { 741e8db6e2SBrian Feldman Buffer b; 752632b0c8SKris Kennaway int i; 761e8db6e2SBrian Feldman char **proposal; 772632b0c8SKris Kennaway 781e8db6e2SBrian Feldman proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); 792632b0c8SKris Kennaway 801e8db6e2SBrian Feldman buffer_init(&b); 811e8db6e2SBrian Feldman buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 822632b0c8SKris Kennaway /* skip cookie */ 832632b0c8SKris Kennaway for (i = 0; i < KEX_COOKIE_LEN; i++) 841e8db6e2SBrian Feldman buffer_get_char(&b); 852632b0c8SKris Kennaway /* extract kex init proposal strings */ 862632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 871e8db6e2SBrian Feldman proposal[i] = buffer_get_string(&b,NULL); 881e8db6e2SBrian Feldman debug2("kex_parse_kexinit: %s", proposal[i]); 892632b0c8SKris Kennaway } 901e8db6e2SBrian Feldman /* first kex follows / reserved */ 911e8db6e2SBrian Feldman i = buffer_get_char(&b); 921e8db6e2SBrian Feldman debug2("kex_parse_kexinit: first_kex_follows %d ", i); 931e8db6e2SBrian Feldman i = buffer_get_int(&b); 941e8db6e2SBrian Feldman debug2("kex_parse_kexinit: reserved %d ", i); 951e8db6e2SBrian Feldman buffer_free(&b); 961e8db6e2SBrian Feldman return proposal; 975b9b2fafSBrian Feldman } 985b9b2fafSBrian Feldman 99ae1f160dSDag-Erling Smørgrav static void 1001e8db6e2SBrian Feldman kex_prop_free(char **proposal) 101a04a10f8SKris Kennaway { 102a04a10f8SKris Kennaway int i; 1031e8db6e2SBrian Feldman 1041e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 1051e8db6e2SBrian Feldman xfree(proposal[i]); 1061e8db6e2SBrian Feldman xfree(proposal); 107a04a10f8SKris Kennaway } 108a04a10f8SKris Kennaway 109ae1f160dSDag-Erling Smørgrav static void 110ae1f160dSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, void *ctxt) 111a04a10f8SKris Kennaway { 112ae1f160dSDag-Erling Smørgrav error("Hm, kex protocol error: type %d seq %u", type, seq); 113a04a10f8SKris Kennaway } 114a04a10f8SKris Kennaway 115ae1f160dSDag-Erling Smørgrav static void 116ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(void) 1175b9b2fafSBrian Feldman { 118ae1f160dSDag-Erling Smørgrav dispatch_range(SSH2_MSG_TRANSPORT_MIN, 119ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 120ae1f160dSDag-Erling Smørgrav dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 1215b9b2fafSBrian Feldman } 1225b9b2fafSBrian Feldman 1231e8db6e2SBrian Feldman void 1241e8db6e2SBrian Feldman kex_finish(Kex *kex) 125a04a10f8SKris Kennaway { 126ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 127a04a10f8SKris Kennaway 1281e8db6e2SBrian Feldman packet_start(SSH2_MSG_NEWKEYS); 1291e8db6e2SBrian Feldman packet_send(); 1301e8db6e2SBrian Feldman /* packet_write_wait(); */ 1311e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 132a04a10f8SKris Kennaway 1331e8db6e2SBrian Feldman debug("waiting for SSH2_MSG_NEWKEYS"); 134ae1f160dSDag-Erling Smørgrav packet_read_expect(SSH2_MSG_NEWKEYS); 135ae1f160dSDag-Erling Smørgrav packet_check_eom(); 1361e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS received"); 1371e8db6e2SBrian Feldman 1381e8db6e2SBrian Feldman kex->done = 1; 1391e8db6e2SBrian Feldman buffer_clear(&kex->peer); 1401e8db6e2SBrian Feldman /* buffer_clear(&kex->my); */ 1411e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 1421e8db6e2SBrian Feldman xfree(kex->name); 1431e8db6e2SBrian Feldman kex->name = NULL; 144a04a10f8SKris Kennaway } 145a04a10f8SKris Kennaway 1461e8db6e2SBrian Feldman void 1471e8db6e2SBrian Feldman kex_send_kexinit(Kex *kex) 148a04a10f8SKris Kennaway { 1491e8db6e2SBrian Feldman if (kex == NULL) { 1501e8db6e2SBrian Feldman error("kex_send_kexinit: no kex, cannot rekey"); 1511e8db6e2SBrian Feldman return; 1521e8db6e2SBrian Feldman } 1531e8db6e2SBrian Feldman if (kex->flags & KEX_INIT_SENT) { 1541e8db6e2SBrian Feldman debug("KEX_INIT_SENT"); 1551e8db6e2SBrian Feldman return; 1561e8db6e2SBrian Feldman } 1571e8db6e2SBrian Feldman kex->done = 0; 1581e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEXINIT); 1591e8db6e2SBrian Feldman packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 1601e8db6e2SBrian Feldman packet_send(); 1611e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 1621e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 1631e8db6e2SBrian Feldman } 164a04a10f8SKris Kennaway 1651e8db6e2SBrian Feldman void 166ae1f160dSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, void *ctxt) 1671e8db6e2SBrian Feldman { 1681e8db6e2SBrian Feldman char *ptr; 1691e8db6e2SBrian Feldman int dlen; 1701e8db6e2SBrian Feldman int i; 1711e8db6e2SBrian Feldman Kex *kex = (Kex *)ctxt; 1722632b0c8SKris Kennaway 1731e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 1741e8db6e2SBrian Feldman if (kex == NULL) 1751e8db6e2SBrian Feldman fatal("kex_input_kexinit: no kex, cannot rekey"); 1761e8db6e2SBrian Feldman 1771e8db6e2SBrian Feldman ptr = packet_get_raw(&dlen); 1781e8db6e2SBrian Feldman buffer_append(&kex->peer, ptr, dlen); 1791e8db6e2SBrian Feldman 1801e8db6e2SBrian Feldman /* discard packet */ 1811e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 1821e8db6e2SBrian Feldman packet_get_char(); 1831e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 1841e8db6e2SBrian Feldman xfree(packet_get_string(NULL)); 1851e8db6e2SBrian Feldman packet_get_char(); 1861e8db6e2SBrian Feldman packet_get_int(); 187ae1f160dSDag-Erling Smørgrav packet_check_eom(); 1881e8db6e2SBrian Feldman 1891e8db6e2SBrian Feldman kex_kexinit_finish(kex); 1901e8db6e2SBrian Feldman } 1911e8db6e2SBrian Feldman 1921e8db6e2SBrian Feldman Kex * 1931e8db6e2SBrian Feldman kex_setup(char *proposal[PROPOSAL_MAX]) 1941e8db6e2SBrian Feldman { 1951e8db6e2SBrian Feldman Kex *kex; 1961e8db6e2SBrian Feldman 1971e8db6e2SBrian Feldman kex = xmalloc(sizeof(*kex)); 1981e8db6e2SBrian Feldman memset(kex, 0, sizeof(*kex)); 1991e8db6e2SBrian Feldman buffer_init(&kex->peer); 2001e8db6e2SBrian Feldman buffer_init(&kex->my); 2011e8db6e2SBrian Feldman kex_prop2buf(&kex->my, proposal); 2021e8db6e2SBrian Feldman kex->done = 0; 2031e8db6e2SBrian Feldman 2041e8db6e2SBrian Feldman kex_send_kexinit(kex); /* we start */ 205ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 2061e8db6e2SBrian Feldman 2071e8db6e2SBrian Feldman return kex; 2081e8db6e2SBrian Feldman } 2091e8db6e2SBrian Feldman 210ae1f160dSDag-Erling Smørgrav static void 2111e8db6e2SBrian Feldman kex_kexinit_finish(Kex *kex) 2121e8db6e2SBrian Feldman { 2131e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 2141e8db6e2SBrian Feldman kex_send_kexinit(kex); 2151e8db6e2SBrian Feldman 2161e8db6e2SBrian Feldman kex_choose_conf(kex); 2171e8db6e2SBrian Feldman 2181e8db6e2SBrian Feldman switch (kex->kex_type) { 2191e8db6e2SBrian Feldman case DH_GRP1_SHA1: 2201e8db6e2SBrian Feldman kexdh(kex); 221a04a10f8SKris Kennaway break; 2221e8db6e2SBrian Feldman case DH_GEX_SHA1: 2231e8db6e2SBrian Feldman kexgex(kex); 2241e8db6e2SBrian Feldman break; 2251e8db6e2SBrian Feldman default: 2261e8db6e2SBrian Feldman fatal("Unsupported key exchange %d", kex->kex_type); 227a04a10f8SKris Kennaway } 2281e8db6e2SBrian Feldman } 229a04a10f8SKris Kennaway 230ae1f160dSDag-Erling Smørgrav static void 231a04a10f8SKris Kennaway choose_enc(Enc *enc, char *client, char *server) 232a04a10f8SKris Kennaway { 2331e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 234a04a10f8SKris Kennaway if (name == NULL) 235a04a10f8SKris Kennaway fatal("no matching cipher found: client %s server %s", client, server); 236ae1f160dSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) 2375b9b2fafSBrian Feldman fatal("matching cipher is not supported: %s", name); 238a04a10f8SKris Kennaway enc->name = name; 239a04a10f8SKris Kennaway enc->enabled = 0; 240a04a10f8SKris Kennaway enc->iv = NULL; 241a04a10f8SKris Kennaway enc->key = NULL; 242ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 243ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 244a04a10f8SKris Kennaway } 245ae1f160dSDag-Erling Smørgrav static void 246a04a10f8SKris Kennaway choose_mac(Mac *mac, char *client, char *server) 247a04a10f8SKris Kennaway { 2481e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 249a04a10f8SKris Kennaway if (name == NULL) 250a04a10f8SKris Kennaway fatal("no matching mac found: client %s server %s", client, server); 2511e8db6e2SBrian Feldman if (mac_init(mac, name) < 0) 252a04a10f8SKris Kennaway fatal("unsupported mac %s", name); 2531e8db6e2SBrian Feldman /* truncate the key */ 2541e8db6e2SBrian Feldman if (datafellows & SSH_BUG_HMAC) 2551e8db6e2SBrian Feldman mac->key_len = 16; 256a04a10f8SKris Kennaway mac->name = name; 257a04a10f8SKris Kennaway mac->key = NULL; 258a04a10f8SKris Kennaway mac->enabled = 0; 259a04a10f8SKris Kennaway } 260ae1f160dSDag-Erling Smørgrav static void 261a04a10f8SKris Kennaway choose_comp(Comp *comp, char *client, char *server) 262a04a10f8SKris Kennaway { 2631e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 264a04a10f8SKris Kennaway if (name == NULL) 265a04a10f8SKris Kennaway fatal("no matching comp found: client %s server %s", client, server); 266a04a10f8SKris Kennaway if (strcmp(name, "zlib") == 0) { 267a04a10f8SKris Kennaway comp->type = 1; 268a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 269a04a10f8SKris Kennaway comp->type = 0; 270a04a10f8SKris Kennaway } else { 271a04a10f8SKris Kennaway fatal("unsupported comp %s", name); 272a04a10f8SKris Kennaway } 273a04a10f8SKris Kennaway comp->name = name; 274a04a10f8SKris Kennaway } 275ae1f160dSDag-Erling Smørgrav static void 276a04a10f8SKris Kennaway choose_kex(Kex *k, char *client, char *server) 277a04a10f8SKris Kennaway { 2781e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 279a04a10f8SKris Kennaway if (k->name == NULL) 280a04a10f8SKris Kennaway fatal("no kex alg"); 2815b9b2fafSBrian Feldman if (strcmp(k->name, KEX_DH1) == 0) { 2825b9b2fafSBrian Feldman k->kex_type = DH_GRP1_SHA1; 2835b9b2fafSBrian Feldman } else if (strcmp(k->name, KEX_DHGEX) == 0) { 2845b9b2fafSBrian Feldman k->kex_type = DH_GEX_SHA1; 2855b9b2fafSBrian Feldman } else 286a04a10f8SKris Kennaway fatal("bad kex alg %s", k->name); 287a04a10f8SKris Kennaway } 288ae1f160dSDag-Erling Smørgrav static void 289a04a10f8SKris Kennaway choose_hostkeyalg(Kex *k, char *client, char *server) 290a04a10f8SKris Kennaway { 2911e8db6e2SBrian Feldman char *hostkeyalg = match_list(client, server, NULL); 2921e8db6e2SBrian Feldman if (hostkeyalg == NULL) 293a04a10f8SKris Kennaway fatal("no hostkey alg"); 2941e8db6e2SBrian Feldman k->hostkey_type = key_type_from_name(hostkeyalg); 2951e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 2961e8db6e2SBrian Feldman fatal("bad hostkey alg '%s'", hostkeyalg); 2971e8db6e2SBrian Feldman xfree(hostkeyalg); 298a04a10f8SKris Kennaway } 299a04a10f8SKris Kennaway 300ae1f160dSDag-Erling Smørgrav static void 3011e8db6e2SBrian Feldman kex_choose_conf(Kex *kex) 302a04a10f8SKris Kennaway { 3031e8db6e2SBrian Feldman Newkeys *newkeys; 3041e8db6e2SBrian Feldman char **my, **peer; 3051e8db6e2SBrian Feldman char **cprop, **sprop; 3061e8db6e2SBrian Feldman int nenc, nmac, ncomp; 307a04a10f8SKris Kennaway int mode; 308a04a10f8SKris Kennaway int ctos; /* direction: if true client-to-server */ 309a04a10f8SKris Kennaway int need; 310a04a10f8SKris Kennaway 3111e8db6e2SBrian Feldman my = kex_buf2prop(&kex->my); 3121e8db6e2SBrian Feldman peer = kex_buf2prop(&kex->peer); 313a04a10f8SKris Kennaway 3141e8db6e2SBrian Feldman if (kex->server) { 3151e8db6e2SBrian Feldman cprop=peer; 3161e8db6e2SBrian Feldman sprop=my; 3171e8db6e2SBrian Feldman } else { 3181e8db6e2SBrian Feldman cprop=my; 3191e8db6e2SBrian Feldman sprop=peer; 3201e8db6e2SBrian Feldman } 3211e8db6e2SBrian Feldman 3221e8db6e2SBrian Feldman /* Algorithm Negotiation */ 323a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3241e8db6e2SBrian Feldman newkeys = xmalloc(sizeof(*newkeys)); 3251e8db6e2SBrian Feldman memset(newkeys, 0, sizeof(*newkeys)); 3261e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 3271e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 328a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 329a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 330a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 3311e8db6e2SBrian Feldman choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 3321e8db6e2SBrian Feldman choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 3331e8db6e2SBrian Feldman choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 334a04a10f8SKris Kennaway debug("kex: %s %s %s %s", 335a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 3361e8db6e2SBrian Feldman newkeys->enc.name, 3371e8db6e2SBrian Feldman newkeys->mac.name, 3381e8db6e2SBrian Feldman newkeys->comp.name); 339a04a10f8SKris Kennaway } 3401e8db6e2SBrian Feldman choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 3411e8db6e2SBrian Feldman choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 342a04a10f8SKris Kennaway sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 343a04a10f8SKris Kennaway need = 0; 344a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3451e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 346ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.key_len) 347ae1f160dSDag-Erling Smørgrav need = newkeys->enc.key_len; 348ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.block_size) 349ae1f160dSDag-Erling Smørgrav need = newkeys->enc.block_size; 3501e8db6e2SBrian Feldman if (need < newkeys->mac.key_len) 3511e8db6e2SBrian Feldman need = newkeys->mac.key_len; 352a04a10f8SKris Kennaway } 3532632b0c8SKris Kennaway /* XXX need runden? */ 3541e8db6e2SBrian Feldman kex->we_need = need; 3551e8db6e2SBrian Feldman 3561e8db6e2SBrian Feldman kex_prop_free(my); 3571e8db6e2SBrian Feldman kex_prop_free(peer); 358a04a10f8SKris Kennaway } 359a04a10f8SKris Kennaway 360ae1f160dSDag-Erling Smørgrav static u_char * 3611e8db6e2SBrian Feldman derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) 362a04a10f8SKris Kennaway { 3631e8db6e2SBrian Feldman Buffer b; 364ae1f160dSDag-Erling Smørgrav const EVP_MD *evp_md = EVP_sha1(); 3651e8db6e2SBrian Feldman EVP_MD_CTX md; 3661e8db6e2SBrian Feldman char c = id; 3671e8db6e2SBrian Feldman int have; 368ae1f160dSDag-Erling Smørgrav int mdsz = EVP_MD_size(evp_md); 3691e8db6e2SBrian Feldman u_char *digest = xmalloc(roundup(need, mdsz)); 3701e8db6e2SBrian Feldman 3711e8db6e2SBrian Feldman buffer_init(&b); 3721e8db6e2SBrian Feldman buffer_put_bignum2(&b, shared_secret); 3731e8db6e2SBrian Feldman 3741e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 3751e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 376ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 3771e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 3781e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 3791e8db6e2SBrian Feldman EVP_DigestUpdate(&md, &c, 1); 3801e8db6e2SBrian Feldman EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 3811e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest, NULL); 3821e8db6e2SBrian Feldman 3831e8db6e2SBrian Feldman /* 3841e8db6e2SBrian Feldman * expand key: 3851e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 3861e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 3871e8db6e2SBrian Feldman */ 3881e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 3891e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 390ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 3911e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 3921e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 3931e8db6e2SBrian Feldman EVP_DigestUpdate(&md, digest, have); 3941e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest + have, NULL); 3951e8db6e2SBrian Feldman } 3961e8db6e2SBrian Feldman buffer_free(&b); 3971e8db6e2SBrian Feldman #ifdef DEBUG_KEX 3981e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 3991e8db6e2SBrian Feldman dump_digest("key", digest, need); 4001e8db6e2SBrian Feldman #endif 4011e8db6e2SBrian Feldman return digest; 4021e8db6e2SBrian Feldman } 4031e8db6e2SBrian Feldman 4041e8db6e2SBrian Feldman Newkeys *current_keys[MODE_MAX]; 4051e8db6e2SBrian Feldman 4061e8db6e2SBrian Feldman #define NKEYS 6 4071e8db6e2SBrian Feldman void 4081e8db6e2SBrian Feldman kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) 4091e8db6e2SBrian Feldman { 4101e8db6e2SBrian Feldman u_char *keys[NKEYS]; 4111e8db6e2SBrian Feldman int i, mode, ctos; 412a04a10f8SKris Kennaway 413a04a10f8SKris Kennaway for (i = 0; i < NKEYS; i++) 4141e8db6e2SBrian Feldman keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); 415a04a10f8SKris Kennaway 4161e8db6e2SBrian Feldman debug("kex_derive_keys"); 417a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 4181e8db6e2SBrian Feldman current_keys[mode] = kex->newkeys[mode]; 4191e8db6e2SBrian Feldman kex->newkeys[mode] = NULL; 4201e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 4211e8db6e2SBrian Feldman current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 4221e8db6e2SBrian Feldman current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 4231e8db6e2SBrian Feldman current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 424a04a10f8SKris Kennaway } 425a04a10f8SKris Kennaway } 4261e8db6e2SBrian Feldman 4271e8db6e2SBrian Feldman Newkeys * 4281e8db6e2SBrian Feldman kex_get_newkeys(int mode) 4291e8db6e2SBrian Feldman { 4301e8db6e2SBrian Feldman Newkeys *ret; 4311e8db6e2SBrian Feldman 4321e8db6e2SBrian Feldman ret = current_keys[mode]; 4331e8db6e2SBrian Feldman current_keys[mode] = NULL; 4341e8db6e2SBrian Feldman return ret; 4351e8db6e2SBrian Feldman } 4361e8db6e2SBrian Feldman 4371e8db6e2SBrian Feldman #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 4381e8db6e2SBrian Feldman void 4391e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 4401e8db6e2SBrian Feldman { 4411e8db6e2SBrian Feldman int i; 4421e8db6e2SBrian Feldman 4431e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 4441e8db6e2SBrian Feldman for (i = 0; i< len; i++) { 4451e8db6e2SBrian Feldman fprintf(stderr, "%02x", digest[i]); 4461e8db6e2SBrian Feldman if (i%32 == 31) 4471e8db6e2SBrian Feldman fprintf(stderr, "\n"); 4481e8db6e2SBrian Feldman else if (i%8 == 7) 4491e8db6e2SBrian Feldman fprintf(stderr, " "); 4501e8db6e2SBrian Feldman } 4511e8db6e2SBrian Feldman fprintf(stderr, "\n"); 4521e8db6e2SBrian Feldman } 4531e8db6e2SBrian Feldman #endif 454