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" 26545d5ecaSDag-Erling Smørgrav RCSID("$OpenBSD: kex.c,v 1.50 2002/05/15 15:47:49 mouring 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" 43545d5ecaSDag-Erling Smørgrav #include "monitor.h" 44a04a10f8SKris Kennaway 452632b0c8SKris Kennaway #define KEX_COOKIE_LEN 16 462632b0c8SKris Kennaway 47545d5ecaSDag-Erling Smørgrav /* Use privilege separation for sshd */ 48545d5ecaSDag-Erling Smørgrav int use_privsep; 49545d5ecaSDag-Erling Smørgrav struct monitor *pmonitor; 50545d5ecaSDag-Erling Smørgrav 51545d5ecaSDag-Erling Smørgrav 52ae1f160dSDag-Erling Smørgrav /* prototype */ 53ae1f160dSDag-Erling Smørgrav static void kex_kexinit_finish(Kex *); 54ae1f160dSDag-Erling Smørgrav static void kex_choose_conf(Kex *); 551e8db6e2SBrian Feldman 561e8db6e2SBrian Feldman /* put algorithm proposal into buffer */ 57ae1f160dSDag-Erling Smørgrav static void 581e8db6e2SBrian Feldman kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 59a04a10f8SKris Kennaway { 60a04a10f8SKris Kennaway int i; 611e8db6e2SBrian Feldman 621e8db6e2SBrian Feldman buffer_clear(b); 63545d5ecaSDag-Erling Smørgrav /* 64545d5ecaSDag-Erling Smørgrav * add a dummy cookie, the cookie will be overwritten by 65545d5ecaSDag-Erling Smørgrav * kex_send_kexinit(), each time a kexinit is set 66545d5ecaSDag-Erling Smørgrav */ 67545d5ecaSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) 68545d5ecaSDag-Erling Smørgrav buffer_put_char(b, 0); 69a04a10f8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) 701e8db6e2SBrian Feldman buffer_put_cstring(b, proposal[i]); 711e8db6e2SBrian Feldman buffer_put_char(b, 0); /* first_kex_packet_follows */ 721e8db6e2SBrian Feldman buffer_put_int(b, 0); /* uint32 reserved */ 73a04a10f8SKris Kennaway } 74a04a10f8SKris Kennaway 751e8db6e2SBrian Feldman /* parse buffer and return algorithm proposal */ 76ae1f160dSDag-Erling Smørgrav static char ** 771e8db6e2SBrian Feldman kex_buf2prop(Buffer *raw) 782632b0c8SKris Kennaway { 791e8db6e2SBrian Feldman Buffer b; 802632b0c8SKris Kennaway int i; 811e8db6e2SBrian Feldman char **proposal; 822632b0c8SKris Kennaway 831e8db6e2SBrian Feldman proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); 842632b0c8SKris Kennaway 851e8db6e2SBrian Feldman buffer_init(&b); 861e8db6e2SBrian Feldman buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 872632b0c8SKris Kennaway /* skip cookie */ 882632b0c8SKris Kennaway for (i = 0; i < KEX_COOKIE_LEN; i++) 891e8db6e2SBrian Feldman buffer_get_char(&b); 902632b0c8SKris Kennaway /* extract kex init proposal strings */ 912632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 921e8db6e2SBrian Feldman proposal[i] = buffer_get_string(&b,NULL); 931e8db6e2SBrian Feldman debug2("kex_parse_kexinit: %s", proposal[i]); 942632b0c8SKris Kennaway } 951e8db6e2SBrian Feldman /* first kex follows / reserved */ 961e8db6e2SBrian Feldman i = buffer_get_char(&b); 971e8db6e2SBrian Feldman debug2("kex_parse_kexinit: first_kex_follows %d ", i); 981e8db6e2SBrian Feldman i = buffer_get_int(&b); 991e8db6e2SBrian Feldman debug2("kex_parse_kexinit: reserved %d ", i); 1001e8db6e2SBrian Feldman buffer_free(&b); 1011e8db6e2SBrian Feldman return proposal; 1025b9b2fafSBrian Feldman } 1035b9b2fafSBrian Feldman 104ae1f160dSDag-Erling Smørgrav static void 1051e8db6e2SBrian Feldman kex_prop_free(char **proposal) 106a04a10f8SKris Kennaway { 107a04a10f8SKris Kennaway int i; 1081e8db6e2SBrian Feldman 1091e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 1101e8db6e2SBrian Feldman xfree(proposal[i]); 1111e8db6e2SBrian Feldman xfree(proposal); 112a04a10f8SKris Kennaway } 113a04a10f8SKris Kennaway 114ae1f160dSDag-Erling Smørgrav static void 115ae1f160dSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, void *ctxt) 116a04a10f8SKris Kennaway { 117ae1f160dSDag-Erling Smørgrav error("Hm, kex protocol error: type %d seq %u", type, seq); 118a04a10f8SKris Kennaway } 119a04a10f8SKris Kennaway 120ae1f160dSDag-Erling Smørgrav static void 121ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(void) 1225b9b2fafSBrian Feldman { 123ae1f160dSDag-Erling Smørgrav dispatch_range(SSH2_MSG_TRANSPORT_MIN, 124ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 125ae1f160dSDag-Erling Smørgrav dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 1265b9b2fafSBrian Feldman } 1275b9b2fafSBrian Feldman 1281e8db6e2SBrian Feldman void 1291e8db6e2SBrian Feldman kex_finish(Kex *kex) 130a04a10f8SKris Kennaway { 131ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 132a04a10f8SKris Kennaway 1331e8db6e2SBrian Feldman packet_start(SSH2_MSG_NEWKEYS); 1341e8db6e2SBrian Feldman packet_send(); 1351e8db6e2SBrian Feldman /* packet_write_wait(); */ 1361e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 137a04a10f8SKris Kennaway 1381e8db6e2SBrian Feldman debug("waiting for SSH2_MSG_NEWKEYS"); 139ae1f160dSDag-Erling Smørgrav packet_read_expect(SSH2_MSG_NEWKEYS); 140ae1f160dSDag-Erling Smørgrav packet_check_eom(); 1411e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS received"); 1421e8db6e2SBrian Feldman 1431e8db6e2SBrian Feldman kex->done = 1; 1441e8db6e2SBrian Feldman buffer_clear(&kex->peer); 1451e8db6e2SBrian Feldman /* buffer_clear(&kex->my); */ 1461e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 1471e8db6e2SBrian Feldman xfree(kex->name); 1481e8db6e2SBrian Feldman kex->name = NULL; 149a04a10f8SKris Kennaway } 150a04a10f8SKris Kennaway 1511e8db6e2SBrian Feldman void 1521e8db6e2SBrian Feldman kex_send_kexinit(Kex *kex) 153a04a10f8SKris Kennaway { 154545d5ecaSDag-Erling Smørgrav u_int32_t rand = 0; 155545d5ecaSDag-Erling Smørgrav u_char *cookie; 156545d5ecaSDag-Erling Smørgrav int i; 157545d5ecaSDag-Erling Smørgrav 1581e8db6e2SBrian Feldman if (kex == NULL) { 1591e8db6e2SBrian Feldman error("kex_send_kexinit: no kex, cannot rekey"); 1601e8db6e2SBrian Feldman return; 1611e8db6e2SBrian Feldman } 1621e8db6e2SBrian Feldman if (kex->flags & KEX_INIT_SENT) { 1631e8db6e2SBrian Feldman debug("KEX_INIT_SENT"); 1641e8db6e2SBrian Feldman return; 1651e8db6e2SBrian Feldman } 1661e8db6e2SBrian Feldman kex->done = 0; 167545d5ecaSDag-Erling Smørgrav 168545d5ecaSDag-Erling Smørgrav /* generate a random cookie */ 169545d5ecaSDag-Erling Smørgrav if (buffer_len(&kex->my) < KEX_COOKIE_LEN) 170545d5ecaSDag-Erling Smørgrav fatal("kex_send_kexinit: kex proposal too short"); 171545d5ecaSDag-Erling Smørgrav cookie = buffer_ptr(&kex->my); 172545d5ecaSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) { 173545d5ecaSDag-Erling Smørgrav if (i % 4 == 0) 174545d5ecaSDag-Erling Smørgrav rand = arc4random(); 175545d5ecaSDag-Erling Smørgrav cookie[i] = rand; 176545d5ecaSDag-Erling Smørgrav rand >>= 8; 177545d5ecaSDag-Erling Smørgrav } 1781e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEXINIT); 1791e8db6e2SBrian Feldman packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 1801e8db6e2SBrian Feldman packet_send(); 1811e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 1821e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 1831e8db6e2SBrian Feldman } 184a04a10f8SKris Kennaway 1851e8db6e2SBrian Feldman void 186ae1f160dSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, void *ctxt) 1871e8db6e2SBrian Feldman { 1881e8db6e2SBrian Feldman char *ptr; 1891e8db6e2SBrian Feldman int dlen; 1901e8db6e2SBrian Feldman int i; 1911e8db6e2SBrian Feldman Kex *kex = (Kex *)ctxt; 1922632b0c8SKris Kennaway 1931e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 1941e8db6e2SBrian Feldman if (kex == NULL) 1951e8db6e2SBrian Feldman fatal("kex_input_kexinit: no kex, cannot rekey"); 1961e8db6e2SBrian Feldman 1971e8db6e2SBrian Feldman ptr = packet_get_raw(&dlen); 1981e8db6e2SBrian Feldman buffer_append(&kex->peer, ptr, dlen); 1991e8db6e2SBrian Feldman 2001e8db6e2SBrian Feldman /* discard packet */ 2011e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 2021e8db6e2SBrian Feldman packet_get_char(); 2031e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 2041e8db6e2SBrian Feldman xfree(packet_get_string(NULL)); 2051e8db6e2SBrian Feldman packet_get_char(); 2061e8db6e2SBrian Feldman packet_get_int(); 207ae1f160dSDag-Erling Smørgrav packet_check_eom(); 2081e8db6e2SBrian Feldman 2091e8db6e2SBrian Feldman kex_kexinit_finish(kex); 2101e8db6e2SBrian Feldman } 2111e8db6e2SBrian Feldman 2121e8db6e2SBrian Feldman Kex * 2131e8db6e2SBrian Feldman kex_setup(char *proposal[PROPOSAL_MAX]) 2141e8db6e2SBrian Feldman { 2151e8db6e2SBrian Feldman Kex *kex; 2161e8db6e2SBrian Feldman 2171e8db6e2SBrian Feldman kex = xmalloc(sizeof(*kex)); 2181e8db6e2SBrian Feldman memset(kex, 0, sizeof(*kex)); 2191e8db6e2SBrian Feldman buffer_init(&kex->peer); 2201e8db6e2SBrian Feldman buffer_init(&kex->my); 2211e8db6e2SBrian Feldman kex_prop2buf(&kex->my, proposal); 2221e8db6e2SBrian Feldman kex->done = 0; 2231e8db6e2SBrian Feldman 2241e8db6e2SBrian Feldman kex_send_kexinit(kex); /* we start */ 225ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 2261e8db6e2SBrian Feldman 2271e8db6e2SBrian Feldman return kex; 2281e8db6e2SBrian Feldman } 2291e8db6e2SBrian Feldman 230ae1f160dSDag-Erling Smørgrav static void 2311e8db6e2SBrian Feldman kex_kexinit_finish(Kex *kex) 2321e8db6e2SBrian Feldman { 2331e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 2341e8db6e2SBrian Feldman kex_send_kexinit(kex); 2351e8db6e2SBrian Feldman 2361e8db6e2SBrian Feldman kex_choose_conf(kex); 2371e8db6e2SBrian Feldman 2381e8db6e2SBrian Feldman switch (kex->kex_type) { 2391e8db6e2SBrian Feldman case DH_GRP1_SHA1: 2401e8db6e2SBrian Feldman kexdh(kex); 241a04a10f8SKris Kennaway break; 2421e8db6e2SBrian Feldman case DH_GEX_SHA1: 2431e8db6e2SBrian Feldman kexgex(kex); 2441e8db6e2SBrian Feldman break; 2451e8db6e2SBrian Feldman default: 2461e8db6e2SBrian Feldman fatal("Unsupported key exchange %d", kex->kex_type); 247a04a10f8SKris Kennaway } 2481e8db6e2SBrian Feldman } 249a04a10f8SKris Kennaway 250ae1f160dSDag-Erling Smørgrav static void 251a04a10f8SKris Kennaway choose_enc(Enc *enc, char *client, char *server) 252a04a10f8SKris Kennaway { 2531e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 254a04a10f8SKris Kennaway if (name == NULL) 255a04a10f8SKris Kennaway fatal("no matching cipher found: client %s server %s", client, server); 256ae1f160dSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) 2575b9b2fafSBrian Feldman fatal("matching cipher is not supported: %s", name); 258a04a10f8SKris Kennaway enc->name = name; 259a04a10f8SKris Kennaway enc->enabled = 0; 260a04a10f8SKris Kennaway enc->iv = NULL; 261a04a10f8SKris Kennaway enc->key = NULL; 262ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 263ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 264a04a10f8SKris Kennaway } 265ae1f160dSDag-Erling Smørgrav static void 266a04a10f8SKris Kennaway choose_mac(Mac *mac, char *client, char *server) 267a04a10f8SKris Kennaway { 2681e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 269a04a10f8SKris Kennaway if (name == NULL) 270a04a10f8SKris Kennaway fatal("no matching mac found: client %s server %s", client, server); 2711e8db6e2SBrian Feldman if (mac_init(mac, name) < 0) 272a04a10f8SKris Kennaway fatal("unsupported mac %s", name); 2731e8db6e2SBrian Feldman /* truncate the key */ 2741e8db6e2SBrian Feldman if (datafellows & SSH_BUG_HMAC) 2751e8db6e2SBrian Feldman mac->key_len = 16; 276a04a10f8SKris Kennaway mac->name = name; 277a04a10f8SKris Kennaway mac->key = NULL; 278a04a10f8SKris Kennaway mac->enabled = 0; 279a04a10f8SKris Kennaway } 280ae1f160dSDag-Erling Smørgrav static void 281a04a10f8SKris Kennaway choose_comp(Comp *comp, char *client, char *server) 282a04a10f8SKris Kennaway { 2831e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 284a04a10f8SKris Kennaway if (name == NULL) 285a04a10f8SKris Kennaway fatal("no matching comp found: client %s server %s", client, server); 286a04a10f8SKris Kennaway if (strcmp(name, "zlib") == 0) { 287a04a10f8SKris Kennaway comp->type = 1; 288a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 289a04a10f8SKris Kennaway comp->type = 0; 290a04a10f8SKris Kennaway } else { 291a04a10f8SKris Kennaway fatal("unsupported comp %s", name); 292a04a10f8SKris Kennaway } 293a04a10f8SKris Kennaway comp->name = name; 294a04a10f8SKris Kennaway } 295ae1f160dSDag-Erling Smørgrav static void 296a04a10f8SKris Kennaway choose_kex(Kex *k, char *client, char *server) 297a04a10f8SKris Kennaway { 2981e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 299a04a10f8SKris Kennaway if (k->name == NULL) 300a04a10f8SKris Kennaway fatal("no kex alg"); 3015b9b2fafSBrian Feldman if (strcmp(k->name, KEX_DH1) == 0) { 3025b9b2fafSBrian Feldman k->kex_type = DH_GRP1_SHA1; 3035b9b2fafSBrian Feldman } else if (strcmp(k->name, KEX_DHGEX) == 0) { 3045b9b2fafSBrian Feldman k->kex_type = DH_GEX_SHA1; 3055b9b2fafSBrian Feldman } else 306a04a10f8SKris Kennaway fatal("bad kex alg %s", k->name); 307a04a10f8SKris Kennaway } 308ae1f160dSDag-Erling Smørgrav static void 309a04a10f8SKris Kennaway choose_hostkeyalg(Kex *k, char *client, char *server) 310a04a10f8SKris Kennaway { 3111e8db6e2SBrian Feldman char *hostkeyalg = match_list(client, server, NULL); 3121e8db6e2SBrian Feldman if (hostkeyalg == NULL) 313a04a10f8SKris Kennaway fatal("no hostkey alg"); 3141e8db6e2SBrian Feldman k->hostkey_type = key_type_from_name(hostkeyalg); 3151e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 3161e8db6e2SBrian Feldman fatal("bad hostkey alg '%s'", hostkeyalg); 3171e8db6e2SBrian Feldman xfree(hostkeyalg); 318a04a10f8SKris Kennaway } 319a04a10f8SKris Kennaway 320ae1f160dSDag-Erling Smørgrav static void 3211e8db6e2SBrian Feldman kex_choose_conf(Kex *kex) 322a04a10f8SKris Kennaway { 3231e8db6e2SBrian Feldman Newkeys *newkeys; 3241e8db6e2SBrian Feldman char **my, **peer; 3251e8db6e2SBrian Feldman char **cprop, **sprop; 3261e8db6e2SBrian Feldman int nenc, nmac, ncomp; 327a04a10f8SKris Kennaway int mode; 328a04a10f8SKris Kennaway int ctos; /* direction: if true client-to-server */ 329a04a10f8SKris Kennaway int need; 330a04a10f8SKris Kennaway 3311e8db6e2SBrian Feldman my = kex_buf2prop(&kex->my); 3321e8db6e2SBrian Feldman peer = kex_buf2prop(&kex->peer); 333a04a10f8SKris Kennaway 3341e8db6e2SBrian Feldman if (kex->server) { 3351e8db6e2SBrian Feldman cprop=peer; 3361e8db6e2SBrian Feldman sprop=my; 3371e8db6e2SBrian Feldman } else { 3381e8db6e2SBrian Feldman cprop=my; 3391e8db6e2SBrian Feldman sprop=peer; 3401e8db6e2SBrian Feldman } 3411e8db6e2SBrian Feldman 3421e8db6e2SBrian Feldman /* Algorithm Negotiation */ 343a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3441e8db6e2SBrian Feldman newkeys = xmalloc(sizeof(*newkeys)); 3451e8db6e2SBrian Feldman memset(newkeys, 0, sizeof(*newkeys)); 3461e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 3471e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 348a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 349a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 350a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 3511e8db6e2SBrian Feldman choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 3521e8db6e2SBrian Feldman choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 3531e8db6e2SBrian Feldman choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 354a04a10f8SKris Kennaway debug("kex: %s %s %s %s", 355a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 3561e8db6e2SBrian Feldman newkeys->enc.name, 3571e8db6e2SBrian Feldman newkeys->mac.name, 3581e8db6e2SBrian Feldman newkeys->comp.name); 359a04a10f8SKris Kennaway } 3601e8db6e2SBrian Feldman choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 3611e8db6e2SBrian Feldman choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 362a04a10f8SKris Kennaway sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 363a04a10f8SKris Kennaway need = 0; 364a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3651e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 366ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.key_len) 367ae1f160dSDag-Erling Smørgrav need = newkeys->enc.key_len; 368ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.block_size) 369ae1f160dSDag-Erling Smørgrav need = newkeys->enc.block_size; 3701e8db6e2SBrian Feldman if (need < newkeys->mac.key_len) 3711e8db6e2SBrian Feldman need = newkeys->mac.key_len; 372a04a10f8SKris Kennaway } 3732632b0c8SKris Kennaway /* XXX need runden? */ 3741e8db6e2SBrian Feldman kex->we_need = need; 3751e8db6e2SBrian Feldman 3761e8db6e2SBrian Feldman kex_prop_free(my); 3771e8db6e2SBrian Feldman kex_prop_free(peer); 378a04a10f8SKris Kennaway } 379a04a10f8SKris Kennaway 380ae1f160dSDag-Erling Smørgrav static u_char * 3811e8db6e2SBrian Feldman derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) 382a04a10f8SKris Kennaway { 3831e8db6e2SBrian Feldman Buffer b; 384ae1f160dSDag-Erling Smørgrav const EVP_MD *evp_md = EVP_sha1(); 3851e8db6e2SBrian Feldman EVP_MD_CTX md; 3861e8db6e2SBrian Feldman char c = id; 3871e8db6e2SBrian Feldman int have; 388ae1f160dSDag-Erling Smørgrav int mdsz = EVP_MD_size(evp_md); 3891e8db6e2SBrian Feldman u_char *digest = xmalloc(roundup(need, mdsz)); 3901e8db6e2SBrian Feldman 3911e8db6e2SBrian Feldman buffer_init(&b); 3921e8db6e2SBrian Feldman buffer_put_bignum2(&b, shared_secret); 3931e8db6e2SBrian Feldman 3941e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 3951e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 396ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 3971e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 3981e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 3991e8db6e2SBrian Feldman EVP_DigestUpdate(&md, &c, 1); 4001e8db6e2SBrian Feldman EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 4011e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest, NULL); 4021e8db6e2SBrian Feldman 4031e8db6e2SBrian Feldman /* 4041e8db6e2SBrian Feldman * expand key: 4051e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 4061e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 4071e8db6e2SBrian Feldman */ 4081e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 4091e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 410ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 4111e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 4121e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 4131e8db6e2SBrian Feldman EVP_DigestUpdate(&md, digest, have); 4141e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest + have, NULL); 4151e8db6e2SBrian Feldman } 4161e8db6e2SBrian Feldman buffer_free(&b); 4171e8db6e2SBrian Feldman #ifdef DEBUG_KEX 4181e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 4191e8db6e2SBrian Feldman dump_digest("key", digest, need); 4201e8db6e2SBrian Feldman #endif 4211e8db6e2SBrian Feldman return digest; 4221e8db6e2SBrian Feldman } 4231e8db6e2SBrian Feldman 4241e8db6e2SBrian Feldman Newkeys *current_keys[MODE_MAX]; 4251e8db6e2SBrian Feldman 4261e8db6e2SBrian Feldman #define NKEYS 6 4271e8db6e2SBrian Feldman void 4281e8db6e2SBrian Feldman kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) 4291e8db6e2SBrian Feldman { 4301e8db6e2SBrian Feldman u_char *keys[NKEYS]; 4311e8db6e2SBrian Feldman int i, mode, ctos; 432a04a10f8SKris Kennaway 433a04a10f8SKris Kennaway for (i = 0; i < NKEYS; i++) 4341e8db6e2SBrian Feldman keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); 435a04a10f8SKris Kennaway 4361e8db6e2SBrian Feldman debug("kex_derive_keys"); 437a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 4381e8db6e2SBrian Feldman current_keys[mode] = kex->newkeys[mode]; 4391e8db6e2SBrian Feldman kex->newkeys[mode] = NULL; 4401e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 4411e8db6e2SBrian Feldman current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 4421e8db6e2SBrian Feldman current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 4431e8db6e2SBrian Feldman current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 444a04a10f8SKris Kennaway } 445a04a10f8SKris Kennaway } 4461e8db6e2SBrian Feldman 4471e8db6e2SBrian Feldman Newkeys * 4481e8db6e2SBrian Feldman kex_get_newkeys(int mode) 4491e8db6e2SBrian Feldman { 4501e8db6e2SBrian Feldman Newkeys *ret; 4511e8db6e2SBrian Feldman 4521e8db6e2SBrian Feldman ret = current_keys[mode]; 4531e8db6e2SBrian Feldman current_keys[mode] = NULL; 4541e8db6e2SBrian Feldman return ret; 4551e8db6e2SBrian Feldman } 4561e8db6e2SBrian Feldman 4571e8db6e2SBrian Feldman #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 4581e8db6e2SBrian Feldman void 4591e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 4601e8db6e2SBrian Feldman { 4611e8db6e2SBrian Feldman int i; 4621e8db6e2SBrian Feldman 4631e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 4641e8db6e2SBrian Feldman for (i = 0; i< len; i++) { 4651e8db6e2SBrian Feldman fprintf(stderr, "%02x", digest[i]); 4661e8db6e2SBrian Feldman if (i%32 == 31) 4671e8db6e2SBrian Feldman fprintf(stderr, "\n"); 4681e8db6e2SBrian Feldman else if (i%8 == 7) 4691e8db6e2SBrian Feldman fprintf(stderr, " "); 4701e8db6e2SBrian Feldman } 4711e8db6e2SBrian Feldman fprintf(stderr, "\n"); 4721e8db6e2SBrian Feldman } 4731e8db6e2SBrian Feldman #endif 474