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" 26d0c8c0bcSDag-Erling Smørgrav RCSID("$OpenBSD: kex.c,v 1.55 2003/04/01 10:31:26 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 { 55a04a10f8SKris Kennaway 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 { 104a04a10f8SKris Kennaway 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 { 151545d5ecaSDag-Erling Smørgrav u_int32_t rand = 0; 152545d5ecaSDag-Erling Smørgrav u_char *cookie; 153545d5ecaSDag-Erling Smørgrav 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) 171545d5ecaSDag-Erling Smørgrav rand = arc4random(); 172545d5ecaSDag-Erling Smørgrav cookie[i] = rand; 173545d5ecaSDag-Erling Smørgrav rand >>= 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; 1861e8db6e2SBrian Feldman int dlen; 1871e8db6e2SBrian Feldman int i; 1881e8db6e2SBrian Feldman Kex *kex = (Kex *)ctxt; 1892632b0c8SKris Kennaway 1901e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 1911e8db6e2SBrian Feldman if (kex == NULL) 1921e8db6e2SBrian Feldman fatal("kex_input_kexinit: no kex, cannot rekey"); 1931e8db6e2SBrian Feldman 1941e8db6e2SBrian Feldman ptr = packet_get_raw(&dlen); 1951e8db6e2SBrian Feldman buffer_append(&kex->peer, ptr, dlen); 1961e8db6e2SBrian Feldman 1971e8db6e2SBrian Feldman /* discard packet */ 1981e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 1991e8db6e2SBrian Feldman packet_get_char(); 2001e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 2011e8db6e2SBrian Feldman xfree(packet_get_string(NULL)); 202ee21a45fSDag-Erling Smørgrav (void) packet_get_char(); 203ee21a45fSDag-Erling Smørgrav (void) packet_get_int(); 204ae1f160dSDag-Erling Smørgrav packet_check_eom(); 2051e8db6e2SBrian Feldman 2061e8db6e2SBrian Feldman kex_kexinit_finish(kex); 2071e8db6e2SBrian Feldman } 2081e8db6e2SBrian Feldman 2091e8db6e2SBrian Feldman Kex * 2101e8db6e2SBrian Feldman kex_setup(char *proposal[PROPOSAL_MAX]) 2111e8db6e2SBrian Feldman { 2121e8db6e2SBrian Feldman Kex *kex; 2131e8db6e2SBrian Feldman 2141e8db6e2SBrian Feldman kex = xmalloc(sizeof(*kex)); 2151e8db6e2SBrian Feldman memset(kex, 0, sizeof(*kex)); 2161e8db6e2SBrian Feldman buffer_init(&kex->peer); 2171e8db6e2SBrian Feldman buffer_init(&kex->my); 2181e8db6e2SBrian Feldman kex_prop2buf(&kex->my, proposal); 2191e8db6e2SBrian Feldman kex->done = 0; 2201e8db6e2SBrian Feldman 2211e8db6e2SBrian Feldman kex_send_kexinit(kex); /* we start */ 222ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 2231e8db6e2SBrian Feldman 2241e8db6e2SBrian Feldman return kex; 2251e8db6e2SBrian Feldman } 2261e8db6e2SBrian Feldman 227ae1f160dSDag-Erling Smørgrav static void 2281e8db6e2SBrian Feldman kex_kexinit_finish(Kex *kex) 2291e8db6e2SBrian Feldman { 2301e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 2311e8db6e2SBrian Feldman kex_send_kexinit(kex); 2321e8db6e2SBrian Feldman 2331e8db6e2SBrian Feldman kex_choose_conf(kex); 2341e8db6e2SBrian Feldman 235d0c8c0bcSDag-Erling Smørgrav if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 236d0c8c0bcSDag-Erling Smørgrav kex->kex[kex->kex_type] != NULL) { 237d0c8c0bcSDag-Erling Smørgrav (kex->kex[kex->kex_type])(kex); 238d0c8c0bcSDag-Erling Smørgrav } else { 2391e8db6e2SBrian Feldman fatal("Unsupported key exchange %d", kex->kex_type); 240a04a10f8SKris Kennaway } 2411e8db6e2SBrian Feldman } 242a04a10f8SKris Kennaway 243ae1f160dSDag-Erling Smørgrav static void 244a04a10f8SKris Kennaway choose_enc(Enc *enc, char *client, char *server) 245a04a10f8SKris Kennaway { 2461e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 247a04a10f8SKris Kennaway if (name == NULL) 248a04a10f8SKris Kennaway fatal("no matching cipher found: client %s server %s", client, server); 249ae1f160dSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) 2505b9b2fafSBrian Feldman fatal("matching cipher is not supported: %s", name); 251a04a10f8SKris Kennaway enc->name = name; 252a04a10f8SKris Kennaway enc->enabled = 0; 253a04a10f8SKris Kennaway enc->iv = NULL; 254a04a10f8SKris Kennaway enc->key = NULL; 255ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 256ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 257a04a10f8SKris Kennaway } 258ae1f160dSDag-Erling Smørgrav static void 259a04a10f8SKris Kennaway choose_mac(Mac *mac, char *client, char *server) 260a04a10f8SKris Kennaway { 2611e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 262a04a10f8SKris Kennaway if (name == NULL) 263a04a10f8SKris Kennaway fatal("no matching mac found: client %s server %s", client, server); 2641e8db6e2SBrian Feldman if (mac_init(mac, name) < 0) 265a04a10f8SKris Kennaway fatal("unsupported mac %s", name); 2661e8db6e2SBrian Feldman /* truncate the key */ 2671e8db6e2SBrian Feldman if (datafellows & SSH_BUG_HMAC) 2681e8db6e2SBrian Feldman mac->key_len = 16; 269a04a10f8SKris Kennaway mac->name = name; 270a04a10f8SKris Kennaway mac->key = NULL; 271a04a10f8SKris Kennaway mac->enabled = 0; 272a04a10f8SKris Kennaway } 273ae1f160dSDag-Erling Smørgrav static void 274a04a10f8SKris Kennaway choose_comp(Comp *comp, char *client, char *server) 275a04a10f8SKris Kennaway { 2761e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 277a04a10f8SKris Kennaway if (name == NULL) 278a04a10f8SKris Kennaway fatal("no matching comp found: client %s server %s", client, server); 279a04a10f8SKris Kennaway if (strcmp(name, "zlib") == 0) { 280a04a10f8SKris Kennaway comp->type = 1; 281a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 282a04a10f8SKris Kennaway comp->type = 0; 283a04a10f8SKris Kennaway } else { 284a04a10f8SKris Kennaway fatal("unsupported comp %s", name); 285a04a10f8SKris Kennaway } 286a04a10f8SKris Kennaway comp->name = name; 287a04a10f8SKris Kennaway } 288ae1f160dSDag-Erling Smørgrav static void 289a04a10f8SKris Kennaway choose_kex(Kex *k, char *client, char *server) 290a04a10f8SKris Kennaway { 2911e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 292a04a10f8SKris Kennaway if (k->name == NULL) 293a04a10f8SKris Kennaway fatal("no kex alg"); 2945b9b2fafSBrian Feldman if (strcmp(k->name, KEX_DH1) == 0) { 295d0c8c0bcSDag-Erling Smørgrav k->kex_type = KEX_DH_GRP1_SHA1; 2965b9b2fafSBrian Feldman } else if (strcmp(k->name, KEX_DHGEX) == 0) { 297d0c8c0bcSDag-Erling Smørgrav k->kex_type = KEX_DH_GEX_SHA1; 2985b9b2fafSBrian Feldman } else 299a04a10f8SKris Kennaway fatal("bad kex alg %s", k->name); 300a04a10f8SKris Kennaway } 301ae1f160dSDag-Erling Smørgrav static void 302a04a10f8SKris Kennaway choose_hostkeyalg(Kex *k, char *client, char *server) 303a04a10f8SKris Kennaway { 3041e8db6e2SBrian Feldman char *hostkeyalg = match_list(client, server, NULL); 3051e8db6e2SBrian Feldman if (hostkeyalg == NULL) 306a04a10f8SKris Kennaway fatal("no hostkey alg"); 3071e8db6e2SBrian Feldman k->hostkey_type = key_type_from_name(hostkeyalg); 3081e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 3091e8db6e2SBrian Feldman fatal("bad hostkey alg '%s'", hostkeyalg); 3101e8db6e2SBrian Feldman xfree(hostkeyalg); 311a04a10f8SKris Kennaway } 312a04a10f8SKris Kennaway 313d0c8c0bcSDag-Erling Smørgrav static int 314d0c8c0bcSDag-Erling Smørgrav proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 315d0c8c0bcSDag-Erling Smørgrav { 316d0c8c0bcSDag-Erling Smørgrav static int check[] = { 317d0c8c0bcSDag-Erling Smørgrav PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 318d0c8c0bcSDag-Erling Smørgrav }; 319d0c8c0bcSDag-Erling Smørgrav int *idx; 320d0c8c0bcSDag-Erling Smørgrav char *p; 321d0c8c0bcSDag-Erling Smørgrav 322d0c8c0bcSDag-Erling Smørgrav for (idx = &check[0]; *idx != -1; idx++) { 323d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(my[*idx], ',')) != NULL) 324d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 325d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(peer[*idx], ',')) != NULL) 326d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 327d0c8c0bcSDag-Erling Smørgrav if (strcmp(my[*idx], peer[*idx]) != 0) { 328d0c8c0bcSDag-Erling Smørgrav debug2("proposal mismatch: my %s peer %s", 329d0c8c0bcSDag-Erling Smørgrav my[*idx], peer[*idx]); 330d0c8c0bcSDag-Erling Smørgrav return (0); 331d0c8c0bcSDag-Erling Smørgrav } 332d0c8c0bcSDag-Erling Smørgrav } 333d0c8c0bcSDag-Erling Smørgrav debug2("proposals match"); 334d0c8c0bcSDag-Erling Smørgrav return (1); 335d0c8c0bcSDag-Erling Smørgrav } 336d0c8c0bcSDag-Erling Smørgrav 337ae1f160dSDag-Erling Smørgrav static void 3381e8db6e2SBrian Feldman kex_choose_conf(Kex *kex) 339a04a10f8SKris Kennaway { 3401e8db6e2SBrian Feldman Newkeys *newkeys; 3411e8db6e2SBrian Feldman char **my, **peer; 3421e8db6e2SBrian Feldman char **cprop, **sprop; 3431e8db6e2SBrian Feldman int nenc, nmac, ncomp; 344a04a10f8SKris Kennaway int mode; 345a04a10f8SKris Kennaway int ctos; /* direction: if true client-to-server */ 346a04a10f8SKris Kennaway int need; 347d0c8c0bcSDag-Erling Smørgrav int first_kex_follows, type; 348a04a10f8SKris Kennaway 349d0c8c0bcSDag-Erling Smørgrav my = kex_buf2prop(&kex->my, NULL); 350d0c8c0bcSDag-Erling Smørgrav peer = kex_buf2prop(&kex->peer, &first_kex_follows); 351a04a10f8SKris Kennaway 3521e8db6e2SBrian Feldman if (kex->server) { 3531e8db6e2SBrian Feldman cprop=peer; 3541e8db6e2SBrian Feldman sprop=my; 3551e8db6e2SBrian Feldman } else { 3561e8db6e2SBrian Feldman cprop=my; 3571e8db6e2SBrian Feldman sprop=peer; 3581e8db6e2SBrian Feldman } 3591e8db6e2SBrian Feldman 3601e8db6e2SBrian Feldman /* Algorithm Negotiation */ 361a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3621e8db6e2SBrian Feldman newkeys = xmalloc(sizeof(*newkeys)); 3631e8db6e2SBrian Feldman memset(newkeys, 0, sizeof(*newkeys)); 3641e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 3651e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 366a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 367a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 368a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 3691e8db6e2SBrian Feldman choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 3701e8db6e2SBrian Feldman choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 3711e8db6e2SBrian Feldman choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 372a04a10f8SKris Kennaway debug("kex: %s %s %s %s", 373a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 3741e8db6e2SBrian Feldman newkeys->enc.name, 3751e8db6e2SBrian Feldman newkeys->mac.name, 3761e8db6e2SBrian Feldman newkeys->comp.name); 377a04a10f8SKris Kennaway } 3781e8db6e2SBrian Feldman choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 3791e8db6e2SBrian Feldman choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 380a04a10f8SKris Kennaway sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 381a04a10f8SKris Kennaway need = 0; 382a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 3831e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 384ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.key_len) 385ae1f160dSDag-Erling Smørgrav need = newkeys->enc.key_len; 386ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.block_size) 387ae1f160dSDag-Erling Smørgrav need = newkeys->enc.block_size; 3881e8db6e2SBrian Feldman if (need < newkeys->mac.key_len) 3891e8db6e2SBrian Feldman need = newkeys->mac.key_len; 390a04a10f8SKris Kennaway } 3912632b0c8SKris Kennaway /* XXX need runden? */ 3921e8db6e2SBrian Feldman kex->we_need = need; 3931e8db6e2SBrian Feldman 394d0c8c0bcSDag-Erling Smørgrav /* ignore the next message if the proposals do not match */ 395d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows && !proposals_match(my, peer) && 396d0c8c0bcSDag-Erling Smørgrav !(datafellows & SSH_BUG_FIRSTKEX)) { 397d0c8c0bcSDag-Erling Smørgrav type = packet_read(); 398d0c8c0bcSDag-Erling Smørgrav debug2("skipping next packet (type %u)", type); 399d0c8c0bcSDag-Erling Smørgrav } 400d0c8c0bcSDag-Erling Smørgrav 4011e8db6e2SBrian Feldman kex_prop_free(my); 4021e8db6e2SBrian Feldman kex_prop_free(peer); 403a04a10f8SKris Kennaway } 404a04a10f8SKris Kennaway 405ae1f160dSDag-Erling Smørgrav static u_char * 4061e8db6e2SBrian Feldman derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) 407a04a10f8SKris Kennaway { 4081e8db6e2SBrian Feldman Buffer b; 409ae1f160dSDag-Erling Smørgrav const EVP_MD *evp_md = EVP_sha1(); 4101e8db6e2SBrian Feldman EVP_MD_CTX md; 4111e8db6e2SBrian Feldman char c = id; 4121e8db6e2SBrian Feldman int have; 413ae1f160dSDag-Erling Smørgrav int mdsz = EVP_MD_size(evp_md); 4141e8db6e2SBrian Feldman u_char *digest = xmalloc(roundup(need, mdsz)); 4151e8db6e2SBrian Feldman 4161e8db6e2SBrian Feldman buffer_init(&b); 4171e8db6e2SBrian Feldman buffer_put_bignum2(&b, shared_secret); 4181e8db6e2SBrian Feldman 4191e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 4201e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 421ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 4221e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 4231e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 4241e8db6e2SBrian Feldman EVP_DigestUpdate(&md, &c, 1); 4251e8db6e2SBrian Feldman EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 4261e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest, NULL); 4271e8db6e2SBrian Feldman 4281e8db6e2SBrian Feldman /* 4291e8db6e2SBrian Feldman * expand key: 4301e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 4311e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 4321e8db6e2SBrian Feldman */ 4331e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 4341e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 435ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 4361e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 4371e8db6e2SBrian Feldman EVP_DigestUpdate(&md, hash, mdsz); 4381e8db6e2SBrian Feldman EVP_DigestUpdate(&md, digest, have); 4391e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest + have, NULL); 4401e8db6e2SBrian Feldman } 4411e8db6e2SBrian Feldman buffer_free(&b); 4421e8db6e2SBrian Feldman #ifdef DEBUG_KEX 4431e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 4441e8db6e2SBrian Feldman dump_digest("key", digest, need); 4451e8db6e2SBrian Feldman #endif 4461e8db6e2SBrian Feldman return digest; 4471e8db6e2SBrian Feldman } 4481e8db6e2SBrian Feldman 4491e8db6e2SBrian Feldman Newkeys *current_keys[MODE_MAX]; 4501e8db6e2SBrian Feldman 4511e8db6e2SBrian Feldman #define NKEYS 6 4521e8db6e2SBrian Feldman void 4531e8db6e2SBrian Feldman kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) 4541e8db6e2SBrian Feldman { 4551e8db6e2SBrian Feldman u_char *keys[NKEYS]; 4561e8db6e2SBrian Feldman int i, mode, ctos; 457a04a10f8SKris Kennaway 458a04a10f8SKris Kennaway for (i = 0; i < NKEYS; i++) 4591e8db6e2SBrian Feldman keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); 460a04a10f8SKris Kennaway 461d0c8c0bcSDag-Erling Smørgrav debug2("kex_derive_keys"); 462a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 4631e8db6e2SBrian Feldman current_keys[mode] = kex->newkeys[mode]; 4641e8db6e2SBrian Feldman kex->newkeys[mode] = NULL; 4651e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 4661e8db6e2SBrian Feldman current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 4671e8db6e2SBrian Feldman current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 4681e8db6e2SBrian Feldman current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 469a04a10f8SKris Kennaway } 470a04a10f8SKris Kennaway } 4711e8db6e2SBrian Feldman 4721e8db6e2SBrian Feldman Newkeys * 4731e8db6e2SBrian Feldman kex_get_newkeys(int mode) 4741e8db6e2SBrian Feldman { 4751e8db6e2SBrian Feldman Newkeys *ret; 4761e8db6e2SBrian Feldman 4771e8db6e2SBrian Feldman ret = current_keys[mode]; 4781e8db6e2SBrian Feldman current_keys[mode] = NULL; 4791e8db6e2SBrian Feldman return ret; 4801e8db6e2SBrian Feldman } 4811e8db6e2SBrian Feldman 4821e8db6e2SBrian Feldman #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 4831e8db6e2SBrian Feldman void 4841e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 4851e8db6e2SBrian Feldman { 4861e8db6e2SBrian Feldman int i; 4871e8db6e2SBrian Feldman 4881e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 4891e8db6e2SBrian Feldman for (i = 0; i< len; i++) { 4901e8db6e2SBrian Feldman fprintf(stderr, "%02x", digest[i]); 4911e8db6e2SBrian Feldman if (i%32 == 31) 4921e8db6e2SBrian Feldman fprintf(stderr, "\n"); 4931e8db6e2SBrian Feldman else if (i%8 == 7) 4941e8db6e2SBrian Feldman fprintf(stderr, " "); 4951e8db6e2SBrian Feldman } 4961e8db6e2SBrian Feldman fprintf(stderr, "\n"); 4971e8db6e2SBrian Feldman } 4981e8db6e2SBrian Feldman #endif 499