1761efaa7SDag-Erling Smørgrav /* $OpenBSD: kex.c,v 1.76 2006/08/03 03:34:42 deraadt Exp $ */ 2a04a10f8SKris Kennaway /* 3ae1f160dSDag-Erling Smørgrav * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4a04a10f8SKris Kennaway * 5a04a10f8SKris Kennaway * Redistribution and use in source and binary forms, with or without 6a04a10f8SKris Kennaway * modification, are permitted provided that the following conditions 7a04a10f8SKris Kennaway * are met: 8a04a10f8SKris Kennaway * 1. Redistributions of source code must retain the above copyright 9a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer. 10a04a10f8SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 11a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer in the 12a04a10f8SKris Kennaway * documentation and/or other materials provided with the distribution. 13a04a10f8SKris Kennaway * 14a04a10f8SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15a04a10f8SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16a04a10f8SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17a04a10f8SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18a04a10f8SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19a04a10f8SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20a04a10f8SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21a04a10f8SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22a04a10f8SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23a04a10f8SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24a04a10f8SKris Kennaway */ 25a04a10f8SKris Kennaway 26a04a10f8SKris Kennaway #include "includes.h" 27761efaa7SDag-Erling Smørgrav 28761efaa7SDag-Erling Smørgrav #include <sys/param.h> 29761efaa7SDag-Erling Smørgrav 30761efaa7SDag-Erling Smørgrav #include <signal.h> 31761efaa7SDag-Erling Smørgrav #include <stdarg.h> 32761efaa7SDag-Erling Smørgrav #include <stdio.h> 33761efaa7SDag-Erling Smørgrav #include <stdlib.h> 34761efaa7SDag-Erling Smørgrav #include <string.h> 35a04a10f8SKris Kennaway 361e8db6e2SBrian Feldman #include <openssl/crypto.h> 371e8db6e2SBrian Feldman 38a04a10f8SKris Kennaway #include "xmalloc.h" 39761efaa7SDag-Erling Smørgrav #include "ssh2.h" 40a04a10f8SKris Kennaway #include "buffer.h" 412632b0c8SKris Kennaway #include "packet.h" 42a04a10f8SKris Kennaway #include "compat.h" 431e8db6e2SBrian Feldman #include "cipher.h" 441e8db6e2SBrian Feldman #include "key.h" 45761efaa7SDag-Erling Smørgrav #include "kex.h" 461e8db6e2SBrian Feldman #include "log.h" 471e8db6e2SBrian Feldman #include "mac.h" 481e8db6e2SBrian Feldman #include "match.h" 491e8db6e2SBrian Feldman #include "dispatch.h" 50545d5ecaSDag-Erling Smørgrav #include "monitor.h" 51a04a10f8SKris Kennaway 522632b0c8SKris Kennaway #define KEX_COOKIE_LEN 16 532632b0c8SKris Kennaway 54761efaa7SDag-Erling Smørgrav #if OPENSSL_VERSION_NUMBER >= 0x00907000L 55761efaa7SDag-Erling Smørgrav # if defined(HAVE_EVP_SHA256) 56761efaa7SDag-Erling Smørgrav # define evp_ssh_sha256 EVP_sha256 57761efaa7SDag-Erling Smørgrav # else 58761efaa7SDag-Erling Smørgrav extern const EVP_MD *evp_ssh_sha256(void); 59761efaa7SDag-Erling Smørgrav # endif 60761efaa7SDag-Erling Smørgrav #endif 61761efaa7SDag-Erling Smørgrav 62ae1f160dSDag-Erling Smørgrav /* prototype */ 63ae1f160dSDag-Erling Smørgrav static void kex_kexinit_finish(Kex *); 64ae1f160dSDag-Erling Smørgrav static void kex_choose_conf(Kex *); 651e8db6e2SBrian Feldman 661e8db6e2SBrian Feldman /* put algorithm proposal into buffer */ 67ae1f160dSDag-Erling Smørgrav static void 681e8db6e2SBrian Feldman kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 69a04a10f8SKris Kennaway { 70043840dfSDag-Erling Smørgrav u_int i; 711e8db6e2SBrian Feldman 721e8db6e2SBrian Feldman buffer_clear(b); 73545d5ecaSDag-Erling Smørgrav /* 74545d5ecaSDag-Erling Smørgrav * add a dummy cookie, the cookie will be overwritten by 75545d5ecaSDag-Erling Smørgrav * kex_send_kexinit(), each time a kexinit is set 76545d5ecaSDag-Erling Smørgrav */ 77545d5ecaSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) 78545d5ecaSDag-Erling Smørgrav buffer_put_char(b, 0); 79a04a10f8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) 801e8db6e2SBrian Feldman buffer_put_cstring(b, proposal[i]); 811e8db6e2SBrian Feldman buffer_put_char(b, 0); /* first_kex_packet_follows */ 821e8db6e2SBrian Feldman buffer_put_int(b, 0); /* uint32 reserved */ 83a04a10f8SKris Kennaway } 84a04a10f8SKris Kennaway 851e8db6e2SBrian Feldman /* parse buffer and return algorithm proposal */ 86ae1f160dSDag-Erling Smørgrav static char ** 87d0c8c0bcSDag-Erling Smørgrav kex_buf2prop(Buffer *raw, int *first_kex_follows) 882632b0c8SKris Kennaway { 891e8db6e2SBrian Feldman Buffer b; 902632b0c8SKris Kennaway int i; 911e8db6e2SBrian Feldman char **proposal; 922632b0c8SKris Kennaway 93761efaa7SDag-Erling Smørgrav proposal = xcalloc(PROPOSAL_MAX, sizeof(char *)); 942632b0c8SKris Kennaway 951e8db6e2SBrian Feldman buffer_init(&b); 961e8db6e2SBrian Feldman buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 972632b0c8SKris Kennaway /* skip cookie */ 982632b0c8SKris Kennaway for (i = 0; i < KEX_COOKIE_LEN; i++) 991e8db6e2SBrian Feldman buffer_get_char(&b); 1002632b0c8SKris Kennaway /* extract kex init proposal strings */ 1012632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 1021e8db6e2SBrian Feldman proposal[i] = buffer_get_string(&b,NULL); 1031e8db6e2SBrian Feldman debug2("kex_parse_kexinit: %s", proposal[i]); 1042632b0c8SKris Kennaway } 1051e8db6e2SBrian Feldman /* first kex follows / reserved */ 1061e8db6e2SBrian Feldman i = buffer_get_char(&b); 107d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows != NULL) 108d0c8c0bcSDag-Erling Smørgrav *first_kex_follows = i; 1091e8db6e2SBrian Feldman debug2("kex_parse_kexinit: first_kex_follows %d ", i); 1101e8db6e2SBrian Feldman i = buffer_get_int(&b); 1111e8db6e2SBrian Feldman debug2("kex_parse_kexinit: reserved %d ", i); 1121e8db6e2SBrian Feldman buffer_free(&b); 1131e8db6e2SBrian Feldman return proposal; 1145b9b2fafSBrian Feldman } 1155b9b2fafSBrian Feldman 116ae1f160dSDag-Erling Smørgrav static void 1171e8db6e2SBrian Feldman kex_prop_free(char **proposal) 118a04a10f8SKris Kennaway { 119043840dfSDag-Erling Smørgrav u_int i; 1201e8db6e2SBrian Feldman 1211e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 1221e8db6e2SBrian Feldman xfree(proposal[i]); 1231e8db6e2SBrian Feldman xfree(proposal); 124a04a10f8SKris Kennaway } 125a04a10f8SKris Kennaway 126ae1f160dSDag-Erling Smørgrav static void 127ae1f160dSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, void *ctxt) 128a04a10f8SKris Kennaway { 129ae1f160dSDag-Erling Smørgrav error("Hm, kex protocol error: type %d seq %u", type, seq); 130a04a10f8SKris Kennaway } 131a04a10f8SKris Kennaway 132ae1f160dSDag-Erling Smørgrav static void 133ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(void) 1345b9b2fafSBrian Feldman { 135ae1f160dSDag-Erling Smørgrav dispatch_range(SSH2_MSG_TRANSPORT_MIN, 136ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 137ae1f160dSDag-Erling Smørgrav dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 1385b9b2fafSBrian Feldman } 1395b9b2fafSBrian Feldman 1401e8db6e2SBrian Feldman void 1411e8db6e2SBrian Feldman kex_finish(Kex *kex) 142a04a10f8SKris Kennaway { 143ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 144a04a10f8SKris Kennaway 1451e8db6e2SBrian Feldman packet_start(SSH2_MSG_NEWKEYS); 1461e8db6e2SBrian Feldman packet_send(); 1471e8db6e2SBrian Feldman /* packet_write_wait(); */ 1481e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 149a04a10f8SKris Kennaway 150d0c8c0bcSDag-Erling Smørgrav debug("expecting SSH2_MSG_NEWKEYS"); 151ae1f160dSDag-Erling Smørgrav packet_read_expect(SSH2_MSG_NEWKEYS); 152ae1f160dSDag-Erling Smørgrav packet_check_eom(); 1531e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS received"); 1541e8db6e2SBrian Feldman 1551e8db6e2SBrian Feldman kex->done = 1; 1561e8db6e2SBrian Feldman buffer_clear(&kex->peer); 1571e8db6e2SBrian Feldman /* buffer_clear(&kex->my); */ 1581e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 1591e8db6e2SBrian Feldman xfree(kex->name); 1601e8db6e2SBrian Feldman kex->name = NULL; 161a04a10f8SKris Kennaway } 162a04a10f8SKris Kennaway 1631e8db6e2SBrian Feldman void 1641e8db6e2SBrian Feldman kex_send_kexinit(Kex *kex) 165a04a10f8SKris Kennaway { 166d74d50a8SDag-Erling Smørgrav u_int32_t rnd = 0; 167545d5ecaSDag-Erling Smørgrav u_char *cookie; 168043840dfSDag-Erling Smørgrav u_int i; 169545d5ecaSDag-Erling Smørgrav 1701e8db6e2SBrian Feldman if (kex == NULL) { 1711e8db6e2SBrian Feldman error("kex_send_kexinit: no kex, cannot rekey"); 1721e8db6e2SBrian Feldman return; 1731e8db6e2SBrian Feldman } 1741e8db6e2SBrian Feldman if (kex->flags & KEX_INIT_SENT) { 1751e8db6e2SBrian Feldman debug("KEX_INIT_SENT"); 1761e8db6e2SBrian Feldman return; 1771e8db6e2SBrian Feldman } 1781e8db6e2SBrian Feldman kex->done = 0; 179545d5ecaSDag-Erling Smørgrav 180545d5ecaSDag-Erling Smørgrav /* generate a random cookie */ 181545d5ecaSDag-Erling Smørgrav if (buffer_len(&kex->my) < KEX_COOKIE_LEN) 182545d5ecaSDag-Erling Smørgrav fatal("kex_send_kexinit: kex proposal too short"); 183545d5ecaSDag-Erling Smørgrav cookie = buffer_ptr(&kex->my); 184545d5ecaSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) { 185545d5ecaSDag-Erling Smørgrav if (i % 4 == 0) 186d74d50a8SDag-Erling Smørgrav rnd = arc4random(); 187d74d50a8SDag-Erling Smørgrav cookie[i] = rnd; 188d74d50a8SDag-Erling Smørgrav rnd >>= 8; 189545d5ecaSDag-Erling Smørgrav } 1901e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEXINIT); 1911e8db6e2SBrian Feldman packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 1921e8db6e2SBrian Feldman packet_send(); 1931e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 1941e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 1951e8db6e2SBrian Feldman } 196a04a10f8SKris Kennaway 1971e8db6e2SBrian Feldman void 198ae1f160dSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, void *ctxt) 1991e8db6e2SBrian Feldman { 2001e8db6e2SBrian Feldman char *ptr; 201043840dfSDag-Erling Smørgrav u_int i, dlen; 2021e8db6e2SBrian Feldman Kex *kex = (Kex *)ctxt; 2032632b0c8SKris Kennaway 2041e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 2051e8db6e2SBrian Feldman if (kex == NULL) 2061e8db6e2SBrian Feldman fatal("kex_input_kexinit: no kex, cannot rekey"); 2071e8db6e2SBrian Feldman 2081e8db6e2SBrian Feldman ptr = packet_get_raw(&dlen); 2091e8db6e2SBrian Feldman buffer_append(&kex->peer, ptr, dlen); 2101e8db6e2SBrian Feldman 2111e8db6e2SBrian Feldman /* discard packet */ 2121e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 2131e8db6e2SBrian Feldman packet_get_char(); 2141e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 2151e8db6e2SBrian Feldman xfree(packet_get_string(NULL)); 216ee21a45fSDag-Erling Smørgrav (void) packet_get_char(); 217ee21a45fSDag-Erling Smørgrav (void) packet_get_int(); 218ae1f160dSDag-Erling Smørgrav packet_check_eom(); 2191e8db6e2SBrian Feldman 2201e8db6e2SBrian Feldman kex_kexinit_finish(kex); 2211e8db6e2SBrian Feldman } 2221e8db6e2SBrian Feldman 2231e8db6e2SBrian Feldman Kex * 2241e8db6e2SBrian Feldman kex_setup(char *proposal[PROPOSAL_MAX]) 2251e8db6e2SBrian Feldman { 2261e8db6e2SBrian Feldman Kex *kex; 2271e8db6e2SBrian Feldman 228761efaa7SDag-Erling Smørgrav kex = xcalloc(1, sizeof(*kex)); 2291e8db6e2SBrian Feldman buffer_init(&kex->peer); 2301e8db6e2SBrian Feldman buffer_init(&kex->my); 2311e8db6e2SBrian Feldman kex_prop2buf(&kex->my, proposal); 2321e8db6e2SBrian Feldman kex->done = 0; 2331e8db6e2SBrian Feldman 2341e8db6e2SBrian Feldman kex_send_kexinit(kex); /* we start */ 235ae1f160dSDag-Erling Smørgrav kex_reset_dispatch(); 2361e8db6e2SBrian Feldman 2371e8db6e2SBrian Feldman return kex; 2381e8db6e2SBrian Feldman } 2391e8db6e2SBrian Feldman 240ae1f160dSDag-Erling Smørgrav static void 2411e8db6e2SBrian Feldman kex_kexinit_finish(Kex *kex) 2421e8db6e2SBrian Feldman { 2431e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 2441e8db6e2SBrian Feldman kex_send_kexinit(kex); 2451e8db6e2SBrian Feldman 2461e8db6e2SBrian Feldman kex_choose_conf(kex); 2471e8db6e2SBrian Feldman 248d0c8c0bcSDag-Erling Smørgrav if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 249d0c8c0bcSDag-Erling Smørgrav kex->kex[kex->kex_type] != NULL) { 250d0c8c0bcSDag-Erling Smørgrav (kex->kex[kex->kex_type])(kex); 251d0c8c0bcSDag-Erling Smørgrav } else { 2521e8db6e2SBrian Feldman fatal("Unsupported key exchange %d", kex->kex_type); 253a04a10f8SKris Kennaway } 2541e8db6e2SBrian Feldman } 255a04a10f8SKris Kennaway 256ae1f160dSDag-Erling Smørgrav static void 257a04a10f8SKris Kennaway choose_enc(Enc *enc, char *client, char *server) 258a04a10f8SKris Kennaway { 2591e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 260a04a10f8SKris Kennaway if (name == NULL) 261a04a10f8SKris Kennaway fatal("no matching cipher found: client %s server %s", client, server); 262ae1f160dSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) 2635b9b2fafSBrian Feldman fatal("matching cipher is not supported: %s", name); 264a04a10f8SKris Kennaway enc->name = name; 265a04a10f8SKris Kennaway enc->enabled = 0; 266a04a10f8SKris Kennaway enc->iv = NULL; 267a04a10f8SKris Kennaway enc->key = NULL; 268ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 269ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 270a04a10f8SKris Kennaway } 271761efaa7SDag-Erling Smørgrav 272ae1f160dSDag-Erling Smørgrav static void 273a04a10f8SKris Kennaway choose_mac(Mac *mac, 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 mac found: client %s server %s", client, server); 2781e8db6e2SBrian Feldman if (mac_init(mac, name) < 0) 279a04a10f8SKris Kennaway fatal("unsupported mac %s", name); 2801e8db6e2SBrian Feldman /* truncate the key */ 2811e8db6e2SBrian Feldman if (datafellows & SSH_BUG_HMAC) 2821e8db6e2SBrian Feldman mac->key_len = 16; 283a04a10f8SKris Kennaway mac->name = name; 284a04a10f8SKris Kennaway mac->key = NULL; 285a04a10f8SKris Kennaway mac->enabled = 0; 286a04a10f8SKris Kennaway } 287761efaa7SDag-Erling Smørgrav 288ae1f160dSDag-Erling Smørgrav static void 289a04a10f8SKris Kennaway choose_comp(Comp *comp, char *client, char *server) 290a04a10f8SKris Kennaway { 2911e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 292a04a10f8SKris Kennaway if (name == NULL) 293a04a10f8SKris Kennaway fatal("no matching comp found: client %s server %s", client, server); 294043840dfSDag-Erling Smørgrav if (strcmp(name, "zlib@openssh.com") == 0) { 295043840dfSDag-Erling Smørgrav comp->type = COMP_DELAYED; 296043840dfSDag-Erling Smørgrav } else if (strcmp(name, "zlib") == 0) { 297043840dfSDag-Erling Smørgrav comp->type = COMP_ZLIB; 298a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 299043840dfSDag-Erling Smørgrav comp->type = COMP_NONE; 300a04a10f8SKris Kennaway } else { 301a04a10f8SKris Kennaway fatal("unsupported comp %s", name); 302a04a10f8SKris Kennaway } 303a04a10f8SKris Kennaway comp->name = name; 304a04a10f8SKris Kennaway } 305761efaa7SDag-Erling Smørgrav 306ae1f160dSDag-Erling Smørgrav static void 307a04a10f8SKris Kennaway choose_kex(Kex *k, char *client, char *server) 308a04a10f8SKris Kennaway { 3091e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 310a04a10f8SKris Kennaway if (k->name == NULL) 311a04a10f8SKris Kennaway fatal("no kex alg"); 3125b9b2fafSBrian Feldman if (strcmp(k->name, KEX_DH1) == 0) { 313d0c8c0bcSDag-Erling Smørgrav k->kex_type = KEX_DH_GRP1_SHA1; 314021d409fSDag-Erling Smørgrav k->evp_md = EVP_sha1(); 315d74d50a8SDag-Erling Smørgrav } else if (strcmp(k->name, KEX_DH14) == 0) { 316d74d50a8SDag-Erling Smørgrav k->kex_type = KEX_DH_GRP14_SHA1; 317021d409fSDag-Erling Smørgrav k->evp_md = EVP_sha1(); 318021d409fSDag-Erling Smørgrav } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { 319d0c8c0bcSDag-Erling Smørgrav k->kex_type = KEX_DH_GEX_SHA1; 320021d409fSDag-Erling Smørgrav k->evp_md = EVP_sha1(); 321761efaa7SDag-Erling Smørgrav #if OPENSSL_VERSION_NUMBER >= 0x00907000L 322761efaa7SDag-Erling Smørgrav } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { 323761efaa7SDag-Erling Smørgrav k->kex_type = KEX_DH_GEX_SHA256; 324761efaa7SDag-Erling Smørgrav k->evp_md = evp_ssh_sha256(); 325761efaa7SDag-Erling Smørgrav #endif 3265b9b2fafSBrian Feldman } else 327a04a10f8SKris Kennaway fatal("bad kex alg %s", k->name); 328a04a10f8SKris Kennaway } 329021d409fSDag-Erling Smørgrav 330ae1f160dSDag-Erling Smørgrav static void 331a04a10f8SKris Kennaway choose_hostkeyalg(Kex *k, char *client, char *server) 332a04a10f8SKris Kennaway { 3331e8db6e2SBrian Feldman char *hostkeyalg = match_list(client, server, NULL); 3341e8db6e2SBrian Feldman if (hostkeyalg == NULL) 335a04a10f8SKris Kennaway fatal("no hostkey alg"); 3361e8db6e2SBrian Feldman k->hostkey_type = key_type_from_name(hostkeyalg); 3371e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 3381e8db6e2SBrian Feldman fatal("bad hostkey alg '%s'", hostkeyalg); 3391e8db6e2SBrian Feldman xfree(hostkeyalg); 340a04a10f8SKris Kennaway } 341a04a10f8SKris Kennaway 342d0c8c0bcSDag-Erling Smørgrav static int 343d0c8c0bcSDag-Erling Smørgrav proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 344d0c8c0bcSDag-Erling Smørgrav { 345d0c8c0bcSDag-Erling Smørgrav static int check[] = { 346d0c8c0bcSDag-Erling Smørgrav PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 347d0c8c0bcSDag-Erling Smørgrav }; 348d0c8c0bcSDag-Erling Smørgrav int *idx; 349d0c8c0bcSDag-Erling Smørgrav char *p; 350d0c8c0bcSDag-Erling Smørgrav 351d0c8c0bcSDag-Erling Smørgrav for (idx = &check[0]; *idx != -1; idx++) { 352d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(my[*idx], ',')) != NULL) 353d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 354d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(peer[*idx], ',')) != NULL) 355d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 356d0c8c0bcSDag-Erling Smørgrav if (strcmp(my[*idx], peer[*idx]) != 0) { 357d0c8c0bcSDag-Erling Smørgrav debug2("proposal mismatch: my %s peer %s", 358d0c8c0bcSDag-Erling Smørgrav my[*idx], peer[*idx]); 359d0c8c0bcSDag-Erling Smørgrav return (0); 360d0c8c0bcSDag-Erling Smørgrav } 361d0c8c0bcSDag-Erling Smørgrav } 362d0c8c0bcSDag-Erling Smørgrav debug2("proposals match"); 363d0c8c0bcSDag-Erling Smørgrav return (1); 364d0c8c0bcSDag-Erling Smørgrav } 365d0c8c0bcSDag-Erling Smørgrav 366ae1f160dSDag-Erling Smørgrav static void 3671e8db6e2SBrian Feldman kex_choose_conf(Kex *kex) 368a04a10f8SKris Kennaway { 3691e8db6e2SBrian Feldman Newkeys *newkeys; 3701e8db6e2SBrian Feldman char **my, **peer; 3711e8db6e2SBrian Feldman char **cprop, **sprop; 3721e8db6e2SBrian Feldman int nenc, nmac, ncomp; 373043840dfSDag-Erling Smørgrav u_int mode, ctos, need; 374d0c8c0bcSDag-Erling Smørgrav int first_kex_follows, type; 375a04a10f8SKris Kennaway 376d0c8c0bcSDag-Erling Smørgrav my = kex_buf2prop(&kex->my, NULL); 377d0c8c0bcSDag-Erling Smørgrav peer = kex_buf2prop(&kex->peer, &first_kex_follows); 378a04a10f8SKris Kennaway 3791e8db6e2SBrian Feldman if (kex->server) { 3801e8db6e2SBrian Feldman cprop=peer; 3811e8db6e2SBrian Feldman sprop=my; 3821e8db6e2SBrian Feldman } else { 3831e8db6e2SBrian Feldman cprop=my; 3841e8db6e2SBrian Feldman sprop=peer; 3851e8db6e2SBrian Feldman } 3861e8db6e2SBrian Feldman 3871e8db6e2SBrian Feldman /* Algorithm Negotiation */ 388a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 389761efaa7SDag-Erling Smørgrav newkeys = xcalloc(1, sizeof(*newkeys)); 3901e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 3911e8db6e2SBrian Feldman ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 392a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 393a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 394a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 3951e8db6e2SBrian Feldman choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 3961e8db6e2SBrian Feldman choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 3971e8db6e2SBrian Feldman choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 398a04a10f8SKris Kennaway debug("kex: %s %s %s %s", 399a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 4001e8db6e2SBrian Feldman newkeys->enc.name, 4011e8db6e2SBrian Feldman newkeys->mac.name, 4021e8db6e2SBrian Feldman newkeys->comp.name); 403a04a10f8SKris Kennaway } 4041e8db6e2SBrian Feldman choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 4051e8db6e2SBrian Feldman choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 406a04a10f8SKris Kennaway sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 407a04a10f8SKris Kennaway need = 0; 408a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 4091e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 410ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.key_len) 411ae1f160dSDag-Erling Smørgrav need = newkeys->enc.key_len; 412ae1f160dSDag-Erling Smørgrav if (need < newkeys->enc.block_size) 413ae1f160dSDag-Erling Smørgrav need = newkeys->enc.block_size; 4141e8db6e2SBrian Feldman if (need < newkeys->mac.key_len) 4151e8db6e2SBrian Feldman need = newkeys->mac.key_len; 416a04a10f8SKris Kennaway } 4172632b0c8SKris Kennaway /* XXX need runden? */ 4181e8db6e2SBrian Feldman kex->we_need = need; 4191e8db6e2SBrian Feldman 420d0c8c0bcSDag-Erling Smørgrav /* ignore the next message if the proposals do not match */ 421d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows && !proposals_match(my, peer) && 422d0c8c0bcSDag-Erling Smørgrav !(datafellows & SSH_BUG_FIRSTKEX)) { 423d0c8c0bcSDag-Erling Smørgrav type = packet_read(); 424d0c8c0bcSDag-Erling Smørgrav debug2("skipping next packet (type %u)", type); 425d0c8c0bcSDag-Erling Smørgrav } 426d0c8c0bcSDag-Erling Smørgrav 4271e8db6e2SBrian Feldman kex_prop_free(my); 4281e8db6e2SBrian Feldman kex_prop_free(peer); 429a04a10f8SKris Kennaway } 430a04a10f8SKris Kennaway 431ae1f160dSDag-Erling Smørgrav static u_char * 432021d409fSDag-Erling Smørgrav derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, 433021d409fSDag-Erling Smørgrav BIGNUM *shared_secret) 434a04a10f8SKris Kennaway { 4351e8db6e2SBrian Feldman Buffer b; 4361e8db6e2SBrian Feldman EVP_MD_CTX md; 4371e8db6e2SBrian Feldman char c = id; 438043840dfSDag-Erling Smørgrav u_int have; 439021d409fSDag-Erling Smørgrav int mdsz; 440043840dfSDag-Erling Smørgrav u_char *digest; 441043840dfSDag-Erling Smørgrav 442021d409fSDag-Erling Smørgrav if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) 443021d409fSDag-Erling Smørgrav fatal("bad kex md size %d", mdsz); 444043840dfSDag-Erling Smørgrav digest = xmalloc(roundup(need, mdsz)); 4451e8db6e2SBrian Feldman 4461e8db6e2SBrian Feldman buffer_init(&b); 4471e8db6e2SBrian Feldman buffer_put_bignum2(&b, shared_secret); 4481e8db6e2SBrian Feldman 4491e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 450021d409fSDag-Erling Smørgrav EVP_DigestInit(&md, kex->evp_md); 451ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 4521e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 453021d409fSDag-Erling Smørgrav EVP_DigestUpdate(&md, hash, hashlen); 4541e8db6e2SBrian Feldman EVP_DigestUpdate(&md, &c, 1); 4551e8db6e2SBrian Feldman EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 4561e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest, NULL); 4571e8db6e2SBrian Feldman 4581e8db6e2SBrian Feldman /* 4591e8db6e2SBrian Feldman * expand key: 4601e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 4611e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 4621e8db6e2SBrian Feldman */ 4631e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 464021d409fSDag-Erling Smørgrav EVP_DigestInit(&md, kex->evp_md); 465ae1f160dSDag-Erling Smørgrav if (!(datafellows & SSH_BUG_DERIVEKEY)) 4661e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 467021d409fSDag-Erling Smørgrav EVP_DigestUpdate(&md, hash, hashlen); 4681e8db6e2SBrian Feldman EVP_DigestUpdate(&md, digest, have); 4691e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest + have, NULL); 4701e8db6e2SBrian Feldman } 4711e8db6e2SBrian Feldman buffer_free(&b); 4721e8db6e2SBrian Feldman #ifdef DEBUG_KEX 4731e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 4741e8db6e2SBrian Feldman dump_digest("key", digest, need); 4751e8db6e2SBrian Feldman #endif 4761e8db6e2SBrian Feldman return digest; 4771e8db6e2SBrian Feldman } 4781e8db6e2SBrian Feldman 4791e8db6e2SBrian Feldman Newkeys *current_keys[MODE_MAX]; 4801e8db6e2SBrian Feldman 4811e8db6e2SBrian Feldman #define NKEYS 6 4821e8db6e2SBrian Feldman void 483021d409fSDag-Erling Smørgrav kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) 4841e8db6e2SBrian Feldman { 4851e8db6e2SBrian Feldman u_char *keys[NKEYS]; 486043840dfSDag-Erling Smørgrav u_int i, mode, ctos; 487a04a10f8SKris Kennaway 488021d409fSDag-Erling Smørgrav for (i = 0; i < NKEYS; i++) { 489021d409fSDag-Erling Smørgrav keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, 490021d409fSDag-Erling Smørgrav shared_secret); 491021d409fSDag-Erling Smørgrav } 492a04a10f8SKris Kennaway 493d0c8c0bcSDag-Erling Smørgrav debug2("kex_derive_keys"); 494a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 4951e8db6e2SBrian Feldman current_keys[mode] = kex->newkeys[mode]; 4961e8db6e2SBrian Feldman kex->newkeys[mode] = NULL; 497761efaa7SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 498761efaa7SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 4991e8db6e2SBrian Feldman current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 5001e8db6e2SBrian Feldman current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 5011e8db6e2SBrian Feldman current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 502a04a10f8SKris Kennaway } 503a04a10f8SKris Kennaway } 5041e8db6e2SBrian Feldman 5051e8db6e2SBrian Feldman Newkeys * 5061e8db6e2SBrian Feldman kex_get_newkeys(int mode) 5071e8db6e2SBrian Feldman { 5081e8db6e2SBrian Feldman Newkeys *ret; 5091e8db6e2SBrian Feldman 5101e8db6e2SBrian Feldman ret = current_keys[mode]; 5111e8db6e2SBrian Feldman current_keys[mode] = NULL; 5121e8db6e2SBrian Feldman return ret; 5131e8db6e2SBrian Feldman } 5141e8db6e2SBrian Feldman 515d74d50a8SDag-Erling Smørgrav void 516d74d50a8SDag-Erling Smørgrav derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 517d74d50a8SDag-Erling Smørgrav u_int8_t cookie[8], u_int8_t id[16]) 518d74d50a8SDag-Erling Smørgrav { 519d74d50a8SDag-Erling Smørgrav const EVP_MD *evp_md = EVP_md5(); 520d74d50a8SDag-Erling Smørgrav EVP_MD_CTX md; 521d74d50a8SDag-Erling Smørgrav u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; 522d74d50a8SDag-Erling Smørgrav int len; 523d74d50a8SDag-Erling Smørgrav 524d74d50a8SDag-Erling Smørgrav EVP_DigestInit(&md, evp_md); 525d74d50a8SDag-Erling Smørgrav 526d74d50a8SDag-Erling Smørgrav len = BN_num_bytes(host_modulus); 527043840dfSDag-Erling Smørgrav if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 528d74d50a8SDag-Erling Smørgrav fatal("%s: bad host modulus (len %d)", __func__, len); 529d74d50a8SDag-Erling Smørgrav BN_bn2bin(host_modulus, nbuf); 530d74d50a8SDag-Erling Smørgrav EVP_DigestUpdate(&md, nbuf, len); 531d74d50a8SDag-Erling Smørgrav 532d74d50a8SDag-Erling Smørgrav len = BN_num_bytes(server_modulus); 533043840dfSDag-Erling Smørgrav if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 534d74d50a8SDag-Erling Smørgrav fatal("%s: bad server modulus (len %d)", __func__, len); 535d74d50a8SDag-Erling Smørgrav BN_bn2bin(server_modulus, nbuf); 536d74d50a8SDag-Erling Smørgrav EVP_DigestUpdate(&md, nbuf, len); 537d74d50a8SDag-Erling Smørgrav 538d74d50a8SDag-Erling Smørgrav EVP_DigestUpdate(&md, cookie, 8); 539d74d50a8SDag-Erling Smørgrav 540d74d50a8SDag-Erling Smørgrav EVP_DigestFinal(&md, obuf, NULL); 541d74d50a8SDag-Erling Smørgrav memcpy(id, obuf, 16); 542d74d50a8SDag-Erling Smørgrav 543d74d50a8SDag-Erling Smørgrav memset(nbuf, 0, sizeof(nbuf)); 544d74d50a8SDag-Erling Smørgrav memset(obuf, 0, sizeof(obuf)); 545d74d50a8SDag-Erling Smørgrav memset(&md, 0, sizeof(md)); 546d74d50a8SDag-Erling Smørgrav } 547d74d50a8SDag-Erling Smørgrav 5481e8db6e2SBrian Feldman #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 5491e8db6e2SBrian Feldman void 5501e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 5511e8db6e2SBrian Feldman { 552043840dfSDag-Erling Smørgrav u_int i; 5531e8db6e2SBrian Feldman 5541e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 5551e8db6e2SBrian Feldman for (i = 0; i< len; i++) { 5561e8db6e2SBrian Feldman fprintf(stderr, "%02x", digest[i]); 5571e8db6e2SBrian Feldman if (i%32 == 31) 5581e8db6e2SBrian Feldman fprintf(stderr, "\n"); 5591e8db6e2SBrian Feldman else if (i%8 == 7) 5601e8db6e2SBrian Feldman fprintf(stderr, " "); 5611e8db6e2SBrian Feldman } 5621e8db6e2SBrian Feldman fprintf(stderr, "\n"); 5631e8db6e2SBrian Feldman } 5641e8db6e2SBrian Feldman #endif 565