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" 26043840dfSDag-Erling Smørgrav RCSID("$OpenBSD: kex.c,v 1.64 2005/07/25 11:59:39 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" 43545d5ecaSDag-Erling Smørgrav #include "monitor.h" 44a04a10f8SKris Kennaway 452632b0c8SKris Kennaway #define KEX_COOKIE_LEN 16 462632b0c8SKris Kennaway 47ae1f160dSDag-Erling Smørgrav /* prototype */ 48ae1f160dSDag-Erling Smørgrav static void kex_kexinit_finish(Kex *); 49ae1f160dSDag-Erling Smørgrav static void kex_choose_conf(Kex *); 501e8db6e2SBrian Feldman 511e8db6e2SBrian Feldman /* put algorithm proposal into buffer */ 52ae1f160dSDag-Erling Smørgrav static void 531e8db6e2SBrian Feldman kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 54a04a10f8SKris Kennaway { 55043840dfSDag-Erling Smørgrav u_int i; 561e8db6e2SBrian Feldman 571e8db6e2SBrian Feldman buffer_clear(b); 58545d5ecaSDag-Erling Smørgrav /* 59545d5ecaSDag-Erling Smørgrav * add a dummy cookie, the cookie will be overwritten by 60545d5ecaSDag-Erling Smørgrav * kex_send_kexinit(), each time a kexinit is set 61545d5ecaSDag-Erling Smørgrav */ 62545d5ecaSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) 63545d5ecaSDag-Erling Smørgrav buffer_put_char(b, 0); 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 ** 72d0c8c0bcSDag-Erling Smørgrav kex_buf2prop(Buffer *raw, int *first_kex_follows) 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); 92d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows != NULL) 93d0c8c0bcSDag-Erling Smørgrav *first_kex_follows = i; 941e8db6e2SBrian Feldman debug2("kex_parse_kexinit: first_kex_follows %d ", i); 951e8db6e2SBrian Feldman i = buffer_get_int(&b); 961e8db6e2SBrian Feldman debug2("kex_parse_kexinit: reserved %d ", i); 971e8db6e2SBrian Feldman buffer_free(&b); 981e8db6e2SBrian Feldman return proposal; 995b9b2fafSBrian Feldman } 1005b9b2fafSBrian Feldman 101ae1f160dSDag-Erling Smørgrav static void 1021e8db6e2SBrian Feldman kex_prop_free(char **proposal) 103a04a10f8SKris Kennaway { 104043840dfSDag-Erling Smørgrav u_int i; 1051e8db6e2SBrian Feldman 1061e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 1071e8db6e2SBrian Feldman xfree(proposal[i]); 1081e8db6e2SBrian Feldman xfree(proposal); 109a04a10f8SKris Kennaway } 110a04a10f8SKris Kennaway 111ae1f160dSDag-Erling Smørgrav static void 112ae1f160dSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, void *ctxt) 113a04a10f8SKris Kennaway { 114ae1f160dSDag-Erling Smørgrav error("Hm, kex protocol error: type %d seq %u", type, seq); 115a04a10f8SKris Kennaway } 116a04a10f8SKris Kennaway 117ae1f160dSDag-Erling Smørgrav static void 118ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(void) 1195b9b2fafSBrian Feldman { 120ae1f160dSDag-Erling Smørgrav dispatch_range(SSH2_MSG_TRANSPORT_MIN, 121ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 122ae1f160dSDag-Erling Smørgrav dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 1235b9b2fafSBrian Feldman } 1245b9b2fafSBrian Feldman 1251e8db6e2SBrian Feldman void 1261e8db6e2SBrian Feldman kex_finish(Kex *kex) 127a04a10f8SKris Kennaway { 128ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 129a04a10f8SKris Kennaway 1301e8db6e2SBrian Feldman packet_start(SSH2_MSG_NEWKEYS); 1311e8db6e2SBrian Feldman packet_send(); 1321e8db6e2SBrian Feldman /* packet_write_wait(); */ 1331e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 134a04a10f8SKris Kennaway 135d0c8c0bcSDag-Erling Smørgrav debug("expecting SSH2_MSG_NEWKEYS"); 136ae1f160dSDag-Erling Smørgrav packet_read_expect(SSH2_MSG_NEWKEYS); 137ae1f160dSDag-Erling Smørgrav packet_check_eom(); 1381e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS received"); 1391e8db6e2SBrian Feldman 1401e8db6e2SBrian Feldman kex->done = 1; 1411e8db6e2SBrian Feldman buffer_clear(&kex->peer); 1421e8db6e2SBrian Feldman /* buffer_clear(&kex->my); */ 1431e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 1441e8db6e2SBrian Feldman xfree(kex->name); 1451e8db6e2SBrian Feldman kex->name = NULL; 146a04a10f8SKris Kennaway } 147a04a10f8SKris Kennaway 1481e8db6e2SBrian Feldman void 1491e8db6e2SBrian Feldman kex_send_kexinit(Kex *kex) 150a04a10f8SKris Kennaway { 151d74d50a8SDag-Erling Smørgrav u_int32_t rnd = 0; 152545d5ecaSDag-Erling Smørgrav u_char *cookie; 153043840dfSDag-Erling Smørgrav u_int i; 154545d5ecaSDag-Erling Smørgrav 1551e8db6e2SBrian Feldman if (kex == NULL) { 1561e8db6e2SBrian Feldman error("kex_send_kexinit: no kex, cannot rekey"); 1571e8db6e2SBrian Feldman return; 1581e8db6e2SBrian Feldman } 1591e8db6e2SBrian Feldman if (kex->flags & KEX_INIT_SENT) { 1601e8db6e2SBrian Feldman debug("KEX_INIT_SENT"); 1611e8db6e2SBrian Feldman return; 1621e8db6e2SBrian Feldman } 1631e8db6e2SBrian Feldman kex->done = 0; 164545d5ecaSDag-Erling Smørgrav 165545d5ecaSDag-Erling Smørgrav /* generate a random cookie */ 166545d5ecaSDag-Erling Smørgrav if (buffer_len(&kex->my) < KEX_COOKIE_LEN) 167545d5ecaSDag-Erling Smørgrav fatal("kex_send_kexinit: kex proposal too short"); 168545d5ecaSDag-Erling Smørgrav cookie = buffer_ptr(&kex->my); 169545d5ecaSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) { 170545d5ecaSDag-Erling Smørgrav if (i % 4 == 0) 171d74d50a8SDag-Erling Smørgrav rnd = arc4random(); 172d74d50a8SDag-Erling Smørgrav cookie[i] = rnd; 173d74d50a8SDag-Erling Smørgrav rnd >>= 8; 174545d5ecaSDag-Erling Smørgrav } 1751e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEXINIT); 1761e8db6e2SBrian Feldman packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 1771e8db6e2SBrian Feldman packet_send(); 1781e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 1791e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 1801e8db6e2SBrian Feldman } 181a04a10f8SKris Kennaway 1821e8db6e2SBrian Feldman void 183ae1f160dSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, void *ctxt) 1841e8db6e2SBrian Feldman { 1851e8db6e2SBrian Feldman char *ptr; 186043840dfSDag-Erling Smørgrav u_int i, dlen; 1871e8db6e2SBrian Feldman Kex *kex = (Kex *)ctxt; 1882632b0c8SKris Kennaway 1891e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 1901e8db6e2SBrian Feldman if (kex == NULL) 1911e8db6e2SBrian Feldman fatal("kex_input_kexinit: no kex, cannot rekey"); 1921e8db6e2SBrian Feldman 1931e8db6e2SBrian Feldman ptr = packet_get_raw(&dlen); 1941e8db6e2SBrian Feldman buffer_append(&kex->peer, ptr, dlen); 1951e8db6e2SBrian Feldman 1961e8db6e2SBrian Feldman /* discard packet */ 1971e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 1981e8db6e2SBrian Feldman packet_get_char(); 1991e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 2001e8db6e2SBrian Feldman xfree(packet_get_string(NULL)); 201ee21a45fSDag-Erling Smørgrav (void) packet_get_char(); 202ee21a45fSDag-Erling Smørgrav (void) packet_get_int(); 203ae1f160dSDag-Erling Smørgrav packet_check_eom(); 2041e8db6e2SBrian Feldman 2051e8db6e2SBrian Feldman kex_kexinit_finish(kex); 2061e8db6e2SBrian Feldman } 2071e8db6e2SBrian Feldman 2081e8db6e2SBrian Feldman Kex * 2091e8db6e2SBrian Feldman kex_setup(char *proposal[PROPOSAL_MAX]) 2101e8db6e2SBrian Feldman { 2111e8db6e2SBrian Feldman Kex *kex; 2121e8db6e2SBrian Feldman 2131e8db6e2SBrian Feldman kex = xmalloc(sizeof(*kex)); 2141e8db6e2SBrian Feldman memset(kex, 0, sizeof(*kex)); 2151e8db6e2SBrian Feldman buffer_init(&kex->peer); 2161e8db6e2SBrian Feldman buffer_init(&kex->my); 2171e8db6e2SBrian Feldman kex_prop2buf(&kex->my, proposal); 2181e8db6e2SBrian Feldman kex->done = 0; 2191e8db6e2SBrian Feldman 2201e8db6e2SBrian Feldman kex_send_kexinit(kex); /* we start */ 221ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 2221e8db6e2SBrian Feldman 2231e8db6e2SBrian Feldman return kex; 2241e8db6e2SBrian Feldman } 2251e8db6e2SBrian Feldman 226ae1f160dSDag-Erling Smørgrav static void 2271e8db6e2SBrian Feldman kex_kexinit_finish(Kex *kex) 2281e8db6e2SBrian Feldman { 2291e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 2301e8db6e2SBrian Feldman kex_send_kexinit(kex); 2311e8db6e2SBrian Feldman 2321e8db6e2SBrian Feldman kex_choose_conf(kex); 2331e8db6e2SBrian Feldman 234d0c8c0bcSDag-Erling Smørgrav if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 235d0c8c0bcSDag-Erling Smørgrav kex->kex[kex->kex_type] != NULL) { 236d0c8c0bcSDag-Erling Smørgrav (kex->kex[kex->kex_type])(kex); 237d0c8c0bcSDag-Erling Smørgrav } else { 2381e8db6e2SBrian Feldman fatal("Unsupported key exchange %d", kex->kex_type); 239a04a10f8SKris Kennaway } 2401e8db6e2SBrian Feldman } 241a04a10f8SKris Kennaway 242ae1f160dSDag-Erling Smørgrav static void 243a04a10f8SKris Kennaway choose_enc(Enc *enc, char *client, char *server) 244a04a10f8SKris Kennaway { 2451e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 246a04a10f8SKris Kennaway if (name == NULL) 247a04a10f8SKris Kennaway fatal("no matching cipher found: client %s server %s", client, server); 248ae1f160dSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) 2495b9b2fafSBrian Feldman fatal("matching cipher is not supported: %s", name); 250a04a10f8SKris Kennaway enc->name = name; 251a04a10f8SKris Kennaway enc->enabled = 0; 252a04a10f8SKris Kennaway enc->iv = NULL; 253a04a10f8SKris Kennaway enc->key = NULL; 254ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 255ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 256a04a10f8SKris Kennaway } 257ae1f160dSDag-Erling Smørgrav static void 258a04a10f8SKris Kennaway choose_mac(Mac *mac, char *client, char *server) 259a04a10f8SKris Kennaway { 2601e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 261a04a10f8SKris Kennaway if (name == NULL) 262a04a10f8SKris Kennaway fatal("no matching mac found: client %s server %s", client, server); 2631e8db6e2SBrian Feldman if (mac_init(mac, name) < 0) 264a04a10f8SKris Kennaway fatal("unsupported mac %s", name); 2651e8db6e2SBrian Feldman /* truncate the key */ 2661e8db6e2SBrian Feldman if (datafellows & SSH_BUG_HMAC) 2671e8db6e2SBrian Feldman mac->key_len = 16; 268a04a10f8SKris Kennaway mac->name = name; 269a04a10f8SKris Kennaway mac->key = NULL; 270a04a10f8SKris Kennaway mac->enabled = 0; 271a04a10f8SKris Kennaway } 272ae1f160dSDag-Erling Smørgrav static void 273a04a10f8SKris Kennaway choose_comp(Comp *comp, char *client, char *server) 274a04a10f8SKris Kennaway { 2751e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 276a04a10f8SKris Kennaway if (name == NULL) 277a04a10f8SKris Kennaway fatal("no matching comp found: client %s server %s", client, server); 278043840dfSDag-Erling Smørgrav if (strcmp(name, "zlib@openssh.com") == 0) { 279043840dfSDag-Erling Smørgrav comp->type = COMP_DELAYED; 280043840dfSDag-Erling Smørgrav } else if (strcmp(name, "zlib") == 0) { 281043840dfSDag-Erling Smørgrav comp->type = COMP_ZLIB; 282a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 283043840dfSDag-Erling Smørgrav comp->type = COMP_NONE; 284a04a10f8SKris Kennaway } else { 285a04a10f8SKris Kennaway fatal("unsupported comp %s", name); 286a04a10f8SKris Kennaway } 287a04a10f8SKris Kennaway comp->name = name; 288a04a10f8SKris Kennaway } 289ae1f160dSDag-Erling Smørgrav static void 290a04a10f8SKris Kennaway choose_kex(Kex *k, char *client, char *server) 291a04a10f8SKris Kennaway { 2921e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 293a04a10f8SKris Kennaway if (k->name == NULL) 294a04a10f8SKris Kennaway fatal("no kex alg"); 2955b9b2fafSBrian Feldman if (strcmp(k->name, KEX_DH1) == 0) { 296d0c8c0bcSDag-Erling Smørgrav k->kex_type = KEX_DH_GRP1_SHA1; 297d74d50a8SDag-Erling Smørgrav } else if (strcmp(k->name, KEX_DH14) == 0) { 298d74d50a8SDag-Erling Smørgrav k->kex_type = KEX_DH_GRP14_SHA1; 2995b9b2fafSBrian Feldman } else if (strcmp(k->name, KEX_DHGEX) == 0) { 300d0c8c0bcSDag-Erling Smørgrav k->kex_type = KEX_DH_GEX_SHA1; 3015b9b2fafSBrian Feldman } else 302a04a10f8SKris Kennaway fatal("bad kex alg %s", k->name); 303a04a10f8SKris Kennaway } 304ae1f160dSDag-Erling Smørgrav static void 305a04a10f8SKris Kennaway choose_hostkeyalg(Kex *k, char *client, char *server) 306a04a10f8SKris Kennaway { 3071e8db6e2SBrian Feldman char *hostkeyalg = match_list(client, server, NULL); 3081e8db6e2SBrian Feldman if (hostkeyalg == NULL) 309a04a10f8SKris Kennaway fatal("no hostkey alg"); 3101e8db6e2SBrian Feldman k->hostkey_type = key_type_from_name(hostkeyalg); 3111e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 3121e8db6e2SBrian Feldman fatal("bad hostkey alg '%s'", hostkeyalg); 3131e8db6e2SBrian Feldman xfree(hostkeyalg); 314a04a10f8SKris Kennaway } 315a04a10f8SKris Kennaway 316d0c8c0bcSDag-Erling Smørgrav static int 317d0c8c0bcSDag-Erling Smørgrav proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 318d0c8c0bcSDag-Erling Smørgrav { 319d0c8c0bcSDag-Erling Smørgrav static int check[] = { 320d0c8c0bcSDag-Erling Smørgrav PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 321d0c8c0bcSDag-Erling Smørgrav }; 322d0c8c0bcSDag-Erling Smørgrav int *idx; 323d0c8c0bcSDag-Erling Smørgrav char *p; 324d0c8c0bcSDag-Erling Smørgrav 325d0c8c0bcSDag-Erling Smørgrav for (idx = &check[0]; *idx != -1; idx++) { 326d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(my[*idx], ',')) != NULL) 327d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 328d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(peer[*idx], ',')) != NULL) 329d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 330d0c8c0bcSDag-Erling Smørgrav if (strcmp(my[*idx], peer[*idx]) != 0) { 331d0c8c0bcSDag-Erling Smørgrav debug2("proposal mismatch: my %s peer %s", 332d0c8c0bcSDag-Erling Smørgrav my[*idx], peer[*idx]); 333d0c8c0bcSDag-Erling Smørgrav return (0); 334d0c8c0bcSDag-Erling Smørgrav } 335d0c8c0bcSDag-Erling Smørgrav } 336d0c8c0bcSDag-Erling Smørgrav debug2("proposals match"); 337d0c8c0bcSDag-Erling Smørgrav return (1); 338d0c8c0bcSDag-Erling Smørgrav } 339d0c8c0bcSDag-Erling Smørgrav 340ae1f160dSDag-Erling Smørgrav static void 3411e8db6e2SBrian Feldman kex_choose_conf(Kex *kex) 342a04a10f8SKris Kennaway { 3431e8db6e2SBrian Feldman Newkeys *newkeys; 3441e8db6e2SBrian Feldman char **my, **peer; 3451e8db6e2SBrian Feldman char **cprop, **sprop; 3461e8db6e2SBrian Feldman int nenc, nmac, ncomp; 347043840dfSDag-Erling Smørgrav u_int mode, ctos, need; 348d0c8c0bcSDag-Erling Smørgrav int first_kex_follows, type; 349a04a10f8SKris Kennaway 350d0c8c0bcSDag-Erling Smørgrav my = kex_buf2prop(&kex->my, NULL); 351d0c8c0bcSDag-Erling Smørgrav peer = kex_buf2prop(&kex->peer, &first_kex_follows); 352a04a10f8SKris Kennaway 3531e8db6e2SBrian Feldman if (kex->server) { 3541e8db6e2SBrian Feldman cprop=peer; 3551e8db6e2SBrian Feldman sprop=my; 3561e8db6e2SBrian Feldman } else { 3571e8db6e2SBrian Feldman cprop=my; 3581e8db6e2SBrian Feldman sprop=peer; 3591e8db6e2SBrian Feldman } 3601e8db6e2SBrian Feldman 3611e8db6e2SBrian Feldman /* Algorithm Negotiation */ 362a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3631e8db6e2SBrian Feldman newkeys = xmalloc(sizeof(*newkeys)); 3641e8db6e2SBrian Feldman memset(newkeys, 0, sizeof(*newkeys)); 3651e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 3661e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 367a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 368a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 369a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 3701e8db6e2SBrian Feldman choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 3711e8db6e2SBrian Feldman choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 3721e8db6e2SBrian Feldman choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 373a04a10f8SKris Kennaway debug("kex: %s %s %s %s", 374a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 3751e8db6e2SBrian Feldman newkeys->enc.name, 3761e8db6e2SBrian Feldman newkeys->mac.name, 3771e8db6e2SBrian Feldman newkeys->comp.name); 378a04a10f8SKris Kennaway } 3791e8db6e2SBrian Feldman choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 3801e8db6e2SBrian Feldman choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 381a04a10f8SKris Kennaway sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 382a04a10f8SKris Kennaway need = 0; 383a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3841e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 385ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.key_len) 386ae1f160dSDag-Erling Smørgrav need = newkeys->enc.key_len; 387ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.block_size) 388ae1f160dSDag-Erling Smørgrav need = newkeys->enc.block_size; 3891e8db6e2SBrian Feldman if (need < newkeys->mac.key_len) 3901e8db6e2SBrian Feldman need = newkeys->mac.key_len; 391a04a10f8SKris Kennaway } 3922632b0c8SKris Kennaway /* XXX need runden? */ 3931e8db6e2SBrian Feldman kex->we_need = need; 3941e8db6e2SBrian Feldman 395d0c8c0bcSDag-Erling Smørgrav /* ignore the next message if the proposals do not match */ 396d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows && !proposals_match(my, peer) && 397d0c8c0bcSDag-Erling Smørgrav !(datafellows & SSH_BUG_FIRSTKEX)) { 398d0c8c0bcSDag-Erling Smørgrav type = packet_read(); 399d0c8c0bcSDag-Erling Smørgrav debug2("skipping next packet (type %u)", type); 400d0c8c0bcSDag-Erling Smørgrav } 401d0c8c0bcSDag-Erling Smørgrav 4021e8db6e2SBrian Feldman kex_prop_free(my); 4031e8db6e2SBrian Feldman kex_prop_free(peer); 404a04a10f8SKris Kennaway } 405a04a10f8SKris Kennaway 406ae1f160dSDag-Erling Smørgrav static u_char * 407043840dfSDag-Erling Smørgrav derive_key(Kex *kex, int id, u_int need, u_char *hash, BIGNUM *shared_secret) 408a04a10f8SKris Kennaway { 4091e8db6e2SBrian Feldman Buffer b; 410ae1f160dSDag-Erling Smørgrav const EVP_MD *evp_md = EVP_sha1(); 4111e8db6e2SBrian Feldman EVP_MD_CTX md; 4121e8db6e2SBrian Feldman char c = id; 413043840dfSDag-Erling Smørgrav u_int have; 414ae1f160dSDag-Erling Smørgrav int mdsz = EVP_MD_size(evp_md); 415043840dfSDag-Erling Smørgrav u_char *digest; 416043840dfSDag-Erling Smørgrav 417043840dfSDag-Erling Smørgrav if (mdsz < 0) 418043840dfSDag-Erling Smørgrav fatal("derive_key: mdsz < 0"); 419043840dfSDag-Erling Smørgrav digest = xmalloc(roundup(need, mdsz)); 4201e8db6e2SBrian Feldman 4211e8db6e2SBrian Feldman buffer_init(&b); 4221e8db6e2SBrian Feldman buffer_put_bignum2(&b, shared_secret); 4231e8db6e2SBrian Feldman 4241e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 4251e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 426ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 4271e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 4281e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 4291e8db6e2SBrian Feldman EVP_DigestUpdate(&md, &c, 1); 4301e8db6e2SBrian Feldman EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 4311e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest, NULL); 4321e8db6e2SBrian Feldman 4331e8db6e2SBrian Feldman /* 4341e8db6e2SBrian Feldman * expand key: 4351e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 4361e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 4371e8db6e2SBrian Feldman */ 4381e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 4391e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 440ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 4411e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 4421e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 4431e8db6e2SBrian Feldman EVP_DigestUpdate(&md, digest, have); 4441e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest + have, NULL); 4451e8db6e2SBrian Feldman } 4461e8db6e2SBrian Feldman buffer_free(&b); 4471e8db6e2SBrian Feldman #ifdef DEBUG_KEX 4481e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 4491e8db6e2SBrian Feldman dump_digest("key", digest, need); 4501e8db6e2SBrian Feldman #endif 4511e8db6e2SBrian Feldman return digest; 4521e8db6e2SBrian Feldman } 4531e8db6e2SBrian Feldman 4541e8db6e2SBrian Feldman Newkeys *current_keys[MODE_MAX]; 4551e8db6e2SBrian Feldman 4561e8db6e2SBrian Feldman #define NKEYS 6 4571e8db6e2SBrian Feldman void 4581e8db6e2SBrian Feldman kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) 4591e8db6e2SBrian Feldman { 4601e8db6e2SBrian Feldman u_char *keys[NKEYS]; 461043840dfSDag-Erling Smørgrav u_int i, mode, ctos; 462a04a10f8SKris Kennaway 463a04a10f8SKris Kennaway for (i = 0; i < NKEYS; i++) 4641e8db6e2SBrian Feldman keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); 465a04a10f8SKris Kennaway 466d0c8c0bcSDag-Erling Smørgrav debug2("kex_derive_keys"); 467a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 4681e8db6e2SBrian Feldman current_keys[mode] = kex->newkeys[mode]; 4691e8db6e2SBrian Feldman kex->newkeys[mode] = NULL; 4701e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 4711e8db6e2SBrian Feldman current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 4721e8db6e2SBrian Feldman current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 4731e8db6e2SBrian Feldman current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 474a04a10f8SKris Kennaway } 475a04a10f8SKris Kennaway } 4761e8db6e2SBrian Feldman 4771e8db6e2SBrian Feldman Newkeys * 4781e8db6e2SBrian Feldman kex_get_newkeys(int mode) 4791e8db6e2SBrian Feldman { 4801e8db6e2SBrian Feldman Newkeys *ret; 4811e8db6e2SBrian Feldman 4821e8db6e2SBrian Feldman ret = current_keys[mode]; 4831e8db6e2SBrian Feldman current_keys[mode] = NULL; 4841e8db6e2SBrian Feldman return ret; 4851e8db6e2SBrian Feldman } 4861e8db6e2SBrian Feldman 487d74d50a8SDag-Erling Smørgrav void 488d74d50a8SDag-Erling Smørgrav derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 489d74d50a8SDag-Erling Smørgrav u_int8_t cookie[8], u_int8_t id[16]) 490d74d50a8SDag-Erling Smørgrav { 491d74d50a8SDag-Erling Smørgrav const EVP_MD *evp_md = EVP_md5(); 492d74d50a8SDag-Erling Smørgrav EVP_MD_CTX md; 493d74d50a8SDag-Erling Smørgrav u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; 494d74d50a8SDag-Erling Smørgrav int len; 495d74d50a8SDag-Erling Smørgrav 496d74d50a8SDag-Erling Smørgrav EVP_DigestInit(&md, evp_md); 497d74d50a8SDag-Erling Smørgrav 498d74d50a8SDag-Erling Smørgrav len = BN_num_bytes(host_modulus); 499043840dfSDag-Erling Smørgrav if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 500d74d50a8SDag-Erling Smørgrav fatal("%s: bad host modulus (len %d)", __func__, len); 501d74d50a8SDag-Erling Smørgrav BN_bn2bin(host_modulus, nbuf); 502d74d50a8SDag-Erling Smørgrav EVP_DigestUpdate(&md, nbuf, len); 503d74d50a8SDag-Erling Smørgrav 504d74d50a8SDag-Erling Smørgrav len = BN_num_bytes(server_modulus); 505043840dfSDag-Erling Smørgrav if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 506d74d50a8SDag-Erling Smørgrav fatal("%s: bad server modulus (len %d)", __func__, len); 507d74d50a8SDag-Erling Smørgrav BN_bn2bin(server_modulus, nbuf); 508d74d50a8SDag-Erling Smørgrav EVP_DigestUpdate(&md, nbuf, len); 509d74d50a8SDag-Erling Smørgrav 510d74d50a8SDag-Erling Smørgrav EVP_DigestUpdate(&md, cookie, 8); 511d74d50a8SDag-Erling Smørgrav 512d74d50a8SDag-Erling Smørgrav EVP_DigestFinal(&md, obuf, NULL); 513d74d50a8SDag-Erling Smørgrav memcpy(id, obuf, 16); 514d74d50a8SDag-Erling Smørgrav 515d74d50a8SDag-Erling Smørgrav memset(nbuf, 0, sizeof(nbuf)); 516d74d50a8SDag-Erling Smørgrav memset(obuf, 0, sizeof(obuf)); 517d74d50a8SDag-Erling Smørgrav memset(&md, 0, sizeof(md)); 518d74d50a8SDag-Erling Smørgrav } 519d74d50a8SDag-Erling Smørgrav 5201e8db6e2SBrian Feldman #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 5211e8db6e2SBrian Feldman void 5221e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 5231e8db6e2SBrian Feldman { 524043840dfSDag-Erling Smørgrav u_int i; 5251e8db6e2SBrian Feldman 5261e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 5271e8db6e2SBrian Feldman for (i = 0; i< len; i++) { 5281e8db6e2SBrian Feldman fprintf(stderr, "%02x", digest[i]); 5291e8db6e2SBrian Feldman if (i%32 == 31) 5301e8db6e2SBrian Feldman fprintf(stderr, "\n"); 5311e8db6e2SBrian Feldman else if (i%8 == 7) 5321e8db6e2SBrian Feldman fprintf(stderr, " "); 5331e8db6e2SBrian Feldman } 5341e8db6e2SBrian Feldman fprintf(stderr, "\n"); 5351e8db6e2SBrian Feldman } 5361e8db6e2SBrian Feldman #endif 537