11e8db6e2SBrian Feldman /* 21e8db6e2SBrian Feldman * Copyright (c) 2000 Niels Provos. All rights reserved. 31e8db6e2SBrian Feldman * Copyright (c) 2001 Markus Friedl. All rights reserved. 41e8db6e2SBrian Feldman * 51e8db6e2SBrian Feldman * Redistribution and use in source and binary forms, with or without 61e8db6e2SBrian Feldman * modification, are permitted provided that the following conditions 71e8db6e2SBrian Feldman * are met: 81e8db6e2SBrian Feldman * 1. Redistributions of source code must retain the above copyright 91e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer. 101e8db6e2SBrian Feldman * 2. Redistributions in binary form must reproduce the above copyright 111e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer in the 121e8db6e2SBrian Feldman * documentation and/or other materials provided with the distribution. 131e8db6e2SBrian Feldman * 141e8db6e2SBrian Feldman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 151e8db6e2SBrian Feldman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 161e8db6e2SBrian Feldman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 171e8db6e2SBrian Feldman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 181e8db6e2SBrian Feldman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 191e8db6e2SBrian Feldman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 201e8db6e2SBrian Feldman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 211e8db6e2SBrian Feldman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 221e8db6e2SBrian Feldman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 231e8db6e2SBrian Feldman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 241e8db6e2SBrian Feldman */ 251e8db6e2SBrian Feldman 261e8db6e2SBrian Feldman #include "includes.h" 271e8db6e2SBrian Feldman RCSID("$OpenBSD: kexgex.c,v 1.5 2001/04/05 10:42:50 markus Exp $"); 281e8db6e2SBrian Feldman 291e8db6e2SBrian Feldman #include <openssl/bn.h> 301e8db6e2SBrian Feldman 311e8db6e2SBrian Feldman #include "xmalloc.h" 321e8db6e2SBrian Feldman #include "buffer.h" 331e8db6e2SBrian Feldman #include "bufaux.h" 341e8db6e2SBrian Feldman #include "key.h" 351e8db6e2SBrian Feldman #include "kex.h" 361e8db6e2SBrian Feldman #include "log.h" 371e8db6e2SBrian Feldman #include "packet.h" 381e8db6e2SBrian Feldman #include "dh.h" 391e8db6e2SBrian Feldman #include "ssh2.h" 401e8db6e2SBrian Feldman #include "compat.h" 411e8db6e2SBrian Feldman 421e8db6e2SBrian Feldman u_char * 431e8db6e2SBrian Feldman kexgex_hash( 441e8db6e2SBrian Feldman char *client_version_string, 451e8db6e2SBrian Feldman char *server_version_string, 461e8db6e2SBrian Feldman char *ckexinit, int ckexinitlen, 471e8db6e2SBrian Feldman char *skexinit, int skexinitlen, 481e8db6e2SBrian Feldman char *serverhostkeyblob, int sbloblen, 491e8db6e2SBrian Feldman int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen, 501e8db6e2SBrian Feldman BIGNUM *client_dh_pub, 511e8db6e2SBrian Feldman BIGNUM *server_dh_pub, 521e8db6e2SBrian Feldman BIGNUM *shared_secret) 531e8db6e2SBrian Feldman { 541e8db6e2SBrian Feldman Buffer b; 551e8db6e2SBrian Feldman static u_char digest[EVP_MAX_MD_SIZE]; 561e8db6e2SBrian Feldman EVP_MD *evp_md = EVP_sha1(); 571e8db6e2SBrian Feldman EVP_MD_CTX md; 581e8db6e2SBrian Feldman 591e8db6e2SBrian Feldman buffer_init(&b); 601e8db6e2SBrian Feldman buffer_put_string(&b, client_version_string, strlen(client_version_string)); 611e8db6e2SBrian Feldman buffer_put_string(&b, server_version_string, strlen(server_version_string)); 621e8db6e2SBrian Feldman 631e8db6e2SBrian Feldman /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 641e8db6e2SBrian Feldman buffer_put_int(&b, ckexinitlen+1); 651e8db6e2SBrian Feldman buffer_put_char(&b, SSH2_MSG_KEXINIT); 661e8db6e2SBrian Feldman buffer_append(&b, ckexinit, ckexinitlen); 671e8db6e2SBrian Feldman buffer_put_int(&b, skexinitlen+1); 681e8db6e2SBrian Feldman buffer_put_char(&b, SSH2_MSG_KEXINIT); 691e8db6e2SBrian Feldman buffer_append(&b, skexinit, skexinitlen); 701e8db6e2SBrian Feldman 711e8db6e2SBrian Feldman buffer_put_string(&b, serverhostkeyblob, sbloblen); 721e8db6e2SBrian Feldman if (min == -1 || max == -1) 731e8db6e2SBrian Feldman buffer_put_int(&b, wantbits); 741e8db6e2SBrian Feldman else { 751e8db6e2SBrian Feldman buffer_put_int(&b, min); 761e8db6e2SBrian Feldman buffer_put_int(&b, wantbits); 771e8db6e2SBrian Feldman buffer_put_int(&b, max); 781e8db6e2SBrian Feldman } 791e8db6e2SBrian Feldman buffer_put_bignum2(&b, prime); 801e8db6e2SBrian Feldman buffer_put_bignum2(&b, gen); 811e8db6e2SBrian Feldman buffer_put_bignum2(&b, client_dh_pub); 821e8db6e2SBrian Feldman buffer_put_bignum2(&b, server_dh_pub); 831e8db6e2SBrian Feldman buffer_put_bignum2(&b, shared_secret); 841e8db6e2SBrian Feldman 851e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 861e8db6e2SBrian Feldman buffer_dump(&b); 871e8db6e2SBrian Feldman #endif 881e8db6e2SBrian Feldman EVP_DigestInit(&md, evp_md); 891e8db6e2SBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 901e8db6e2SBrian Feldman EVP_DigestFinal(&md, digest, NULL); 911e8db6e2SBrian Feldman 921e8db6e2SBrian Feldman buffer_free(&b); 931e8db6e2SBrian Feldman 941e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 951e8db6e2SBrian Feldman dump_digest("hash", digest, evp_md->md_size); 961e8db6e2SBrian Feldman #endif 971e8db6e2SBrian Feldman return digest; 981e8db6e2SBrian Feldman } 991e8db6e2SBrian Feldman 1001e8db6e2SBrian Feldman /* client */ 1011e8db6e2SBrian Feldman 1021e8db6e2SBrian Feldman void 1031e8db6e2SBrian Feldman kexgex_client(Kex *kex) 1041e8db6e2SBrian Feldman { 1051e8db6e2SBrian Feldman BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 1061e8db6e2SBrian Feldman BIGNUM *p = NULL, *g = NULL; 1071e8db6e2SBrian Feldman Key *server_host_key; 1081e8db6e2SBrian Feldman u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; 1091e8db6e2SBrian Feldman u_int klen, kout, slen, sbloblen; 1101e8db6e2SBrian Feldman int dlen, plen, min, max, nbits; 1111e8db6e2SBrian Feldman DH *dh; 1121e8db6e2SBrian Feldman 1131e8db6e2SBrian Feldman nbits = dh_estimate(kex->we_need * 8); 1141e8db6e2SBrian Feldman 1151e8db6e2SBrian Feldman if (datafellows & SSH_OLD_DHGEX) { 1161e8db6e2SBrian Feldman debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent"); 1171e8db6e2SBrian Feldman 1181e8db6e2SBrian Feldman /* Old GEX request */ 1191e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); 1201e8db6e2SBrian Feldman packet_put_int(nbits); 1211e8db6e2SBrian Feldman min = DH_GRP_MIN; 1221e8db6e2SBrian Feldman max = DH_GRP_MAX; 1231e8db6e2SBrian Feldman } else { 1241e8db6e2SBrian Feldman debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent"); 1251e8db6e2SBrian Feldman 1261e8db6e2SBrian Feldman /* New GEX request */ 1271e8db6e2SBrian Feldman min = DH_GRP_MIN; 1281e8db6e2SBrian Feldman max = DH_GRP_MAX; 1291e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); 1301e8db6e2SBrian Feldman packet_put_int(min); 1311e8db6e2SBrian Feldman packet_put_int(nbits); 1321e8db6e2SBrian Feldman packet_put_int(max); 1331e8db6e2SBrian Feldman } 1341e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 1351e8db6e2SBrian Feldman fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", 1361e8db6e2SBrian Feldman min, nbits, max); 1371e8db6e2SBrian Feldman #endif 1381e8db6e2SBrian Feldman packet_send(); 1391e8db6e2SBrian Feldman 1401e8db6e2SBrian Feldman debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); 1411e8db6e2SBrian Feldman packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); 1421e8db6e2SBrian Feldman 1431e8db6e2SBrian Feldman if ((p = BN_new()) == NULL) 1441e8db6e2SBrian Feldman fatal("BN_new"); 1451e8db6e2SBrian Feldman packet_get_bignum2(p, &dlen); 1461e8db6e2SBrian Feldman if ((g = BN_new()) == NULL) 1471e8db6e2SBrian Feldman fatal("BN_new"); 1481e8db6e2SBrian Feldman packet_get_bignum2(g, &dlen); 1491e8db6e2SBrian Feldman packet_done(); 1501e8db6e2SBrian Feldman 1511e8db6e2SBrian Feldman if (BN_num_bits(p) < min || BN_num_bits(p) > max) 1521e8db6e2SBrian Feldman fatal("DH_GEX group out of range: %d !< %d !< %d", 1531e8db6e2SBrian Feldman min, BN_num_bits(p), max); 1541e8db6e2SBrian Feldman 1551e8db6e2SBrian Feldman dh = dh_new_group(g, p); 1561e8db6e2SBrian Feldman dh_gen_key(dh, kex->we_need * 8); 1571e8db6e2SBrian Feldman 1581e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 1591e8db6e2SBrian Feldman DHparams_print_fp(stderr, dh); 1601e8db6e2SBrian Feldman fprintf(stderr, "pub= "); 1611e8db6e2SBrian Feldman BN_print_fp(stderr, dh->pub_key); 1621e8db6e2SBrian Feldman fprintf(stderr, "\n"); 1631e8db6e2SBrian Feldman #endif 1641e8db6e2SBrian Feldman 1651e8db6e2SBrian Feldman debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); 1661e8db6e2SBrian Feldman /* generate and send 'e', client DH public key */ 1671e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEX_DH_GEX_INIT); 1681e8db6e2SBrian Feldman packet_put_bignum2(dh->pub_key); 1691e8db6e2SBrian Feldman packet_send(); 1701e8db6e2SBrian Feldman 1711e8db6e2SBrian Feldman debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); 1721e8db6e2SBrian Feldman packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); 1731e8db6e2SBrian Feldman 1741e8db6e2SBrian Feldman /* key, cert */ 1751e8db6e2SBrian Feldman server_host_key_blob = packet_get_string(&sbloblen); 1761e8db6e2SBrian Feldman server_host_key = key_from_blob(server_host_key_blob, sbloblen); 1771e8db6e2SBrian Feldman if (server_host_key == NULL) 1781e8db6e2SBrian Feldman fatal("cannot decode server_host_key_blob"); 1791e8db6e2SBrian Feldman 1801e8db6e2SBrian Feldman if (kex->check_host_key == NULL) 1811e8db6e2SBrian Feldman fatal("cannot check server_host_key"); 1821e8db6e2SBrian Feldman kex->check_host_key(server_host_key); 1831e8db6e2SBrian Feldman 1841e8db6e2SBrian Feldman /* DH paramter f, server public DH key */ 1851e8db6e2SBrian Feldman dh_server_pub = BN_new(); 1861e8db6e2SBrian Feldman if (dh_server_pub == NULL) 1871e8db6e2SBrian Feldman fatal("dh_server_pub == NULL"); 1881e8db6e2SBrian Feldman packet_get_bignum2(dh_server_pub, &dlen); 1891e8db6e2SBrian Feldman 1901e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 1911e8db6e2SBrian Feldman fprintf(stderr, "dh_server_pub= "); 1921e8db6e2SBrian Feldman BN_print_fp(stderr, dh_server_pub); 1931e8db6e2SBrian Feldman fprintf(stderr, "\n"); 1941e8db6e2SBrian Feldman debug("bits %d", BN_num_bits(dh_server_pub)); 1951e8db6e2SBrian Feldman #endif 1961e8db6e2SBrian Feldman 1971e8db6e2SBrian Feldman /* signed H */ 1981e8db6e2SBrian Feldman signature = packet_get_string(&slen); 1991e8db6e2SBrian Feldman packet_done(); 2001e8db6e2SBrian Feldman 2011e8db6e2SBrian Feldman if (!dh_pub_is_valid(dh, dh_server_pub)) 2021e8db6e2SBrian Feldman packet_disconnect("bad server public DH value"); 2031e8db6e2SBrian Feldman 2041e8db6e2SBrian Feldman klen = DH_size(dh); 2051e8db6e2SBrian Feldman kbuf = xmalloc(klen); 2061e8db6e2SBrian Feldman kout = DH_compute_key(kbuf, dh_server_pub, dh); 2071e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 2081e8db6e2SBrian Feldman dump_digest("shared secret", kbuf, kout); 2091e8db6e2SBrian Feldman #endif 2101e8db6e2SBrian Feldman shared_secret = BN_new(); 2111e8db6e2SBrian Feldman BN_bin2bn(kbuf, kout, shared_secret); 2121e8db6e2SBrian Feldman memset(kbuf, 0, klen); 2131e8db6e2SBrian Feldman xfree(kbuf); 2141e8db6e2SBrian Feldman 2151e8db6e2SBrian Feldman if (datafellows & SSH_OLD_DHGEX) 2161e8db6e2SBrian Feldman min = max = -1; 2171e8db6e2SBrian Feldman 2181e8db6e2SBrian Feldman /* calc and verify H */ 2191e8db6e2SBrian Feldman hash = kexgex_hash( 2201e8db6e2SBrian Feldman kex->client_version_string, 2211e8db6e2SBrian Feldman kex->server_version_string, 2221e8db6e2SBrian Feldman buffer_ptr(&kex->my), buffer_len(&kex->my), 2231e8db6e2SBrian Feldman buffer_ptr(&kex->peer), buffer_len(&kex->peer), 2241e8db6e2SBrian Feldman server_host_key_blob, sbloblen, 2251e8db6e2SBrian Feldman min, nbits, max, 2261e8db6e2SBrian Feldman dh->p, dh->g, 2271e8db6e2SBrian Feldman dh->pub_key, 2281e8db6e2SBrian Feldman dh_server_pub, 2291e8db6e2SBrian Feldman shared_secret 2301e8db6e2SBrian Feldman ); 2311e8db6e2SBrian Feldman /* have keys, free DH */ 2321e8db6e2SBrian Feldman DH_free(dh); 2331e8db6e2SBrian Feldman xfree(server_host_key_blob); 2341e8db6e2SBrian Feldman BN_free(dh_server_pub); 2351e8db6e2SBrian Feldman 2361e8db6e2SBrian Feldman if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) 2371e8db6e2SBrian Feldman fatal("key_verify failed for server_host_key"); 2381e8db6e2SBrian Feldman key_free(server_host_key); 2391e8db6e2SBrian Feldman xfree(signature); 2401e8db6e2SBrian Feldman 2411e8db6e2SBrian Feldman /* save session id */ 2421e8db6e2SBrian Feldman if (kex->session_id == NULL) { 2431e8db6e2SBrian Feldman kex->session_id_len = 20; 2441e8db6e2SBrian Feldman kex->session_id = xmalloc(kex->session_id_len); 2451e8db6e2SBrian Feldman memcpy(kex->session_id, hash, kex->session_id_len); 2461e8db6e2SBrian Feldman } 2471e8db6e2SBrian Feldman kex_derive_keys(kex, hash, shared_secret); 2481e8db6e2SBrian Feldman BN_clear_free(shared_secret); 2491e8db6e2SBrian Feldman 2501e8db6e2SBrian Feldman kex_finish(kex); 2511e8db6e2SBrian Feldman } 2521e8db6e2SBrian Feldman 2531e8db6e2SBrian Feldman /* server */ 2541e8db6e2SBrian Feldman 2551e8db6e2SBrian Feldman void 2561e8db6e2SBrian Feldman kexgex_server(Kex *kex) 2571e8db6e2SBrian Feldman { 2581e8db6e2SBrian Feldman BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; 2591e8db6e2SBrian Feldman Key *server_host_key; 2601e8db6e2SBrian Feldman DH *dh = dh; 2611e8db6e2SBrian Feldman u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; 2621e8db6e2SBrian Feldman u_int sbloblen, klen, kout; 2631e8db6e2SBrian Feldman int min = -1, max = -1, nbits = -1, type, plen, dlen, slen; 2641e8db6e2SBrian Feldman 2651e8db6e2SBrian Feldman if (kex->load_host_key == NULL) 2661e8db6e2SBrian Feldman fatal("Cannot load hostkey"); 2671e8db6e2SBrian Feldman server_host_key = kex->load_host_key(kex->hostkey_type); 2681e8db6e2SBrian Feldman if (server_host_key == NULL) 2691e8db6e2SBrian Feldman fatal("Unsupported hostkey type %d", kex->hostkey_type); 2701e8db6e2SBrian Feldman 2711e8db6e2SBrian Feldman type = packet_read(&plen); 2721e8db6e2SBrian Feldman switch(type){ 2731e8db6e2SBrian Feldman case SSH2_MSG_KEX_DH_GEX_REQUEST: 2741e8db6e2SBrian Feldman debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); 2751e8db6e2SBrian Feldman min = packet_get_int(); 2761e8db6e2SBrian Feldman nbits = packet_get_int(); 2771e8db6e2SBrian Feldman max = packet_get_int(); 2781e8db6e2SBrian Feldman min = MAX(DH_GRP_MIN, min); 2791e8db6e2SBrian Feldman max = MIN(DH_GRP_MAX, max); 2801e8db6e2SBrian Feldman break; 2811e8db6e2SBrian Feldman case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: 2821e8db6e2SBrian Feldman debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); 2831e8db6e2SBrian Feldman nbits = packet_get_int(); 2841e8db6e2SBrian Feldman min = DH_GRP_MIN; 2851e8db6e2SBrian Feldman max = DH_GRP_MAX; 2861e8db6e2SBrian Feldman /* unused for old GEX */ 2871e8db6e2SBrian Feldman break; 2881e8db6e2SBrian Feldman default: 2891e8db6e2SBrian Feldman fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); 2901e8db6e2SBrian Feldman } 2911e8db6e2SBrian Feldman packet_done(); 2921e8db6e2SBrian Feldman 2931e8db6e2SBrian Feldman if (max < min || nbits < min || max < nbits) 2941e8db6e2SBrian Feldman fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", 2951e8db6e2SBrian Feldman min, nbits, max); 2961e8db6e2SBrian Feldman 2971e8db6e2SBrian Feldman dh = choose_dh(min, nbits, max); 2981e8db6e2SBrian Feldman if (dh == NULL) 2991e8db6e2SBrian Feldman packet_disconnect("Protocol error: no matching DH grp found"); 3001e8db6e2SBrian Feldman 3011e8db6e2SBrian Feldman debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 3021e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); 3031e8db6e2SBrian Feldman packet_put_bignum2(dh->p); 3041e8db6e2SBrian Feldman packet_put_bignum2(dh->g); 3051e8db6e2SBrian Feldman packet_send(); 3061e8db6e2SBrian Feldman 3071e8db6e2SBrian Feldman /* flush */ 3081e8db6e2SBrian Feldman packet_write_wait(); 3091e8db6e2SBrian Feldman 3101e8db6e2SBrian Feldman /* Compute our exchange value in parallel with the client */ 3111e8db6e2SBrian Feldman dh_gen_key(dh, kex->we_need * 8); 3121e8db6e2SBrian Feldman 3131e8db6e2SBrian Feldman debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); 3141e8db6e2SBrian Feldman packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_INIT); 3151e8db6e2SBrian Feldman 3161e8db6e2SBrian Feldman /* key, cert */ 3171e8db6e2SBrian Feldman dh_client_pub = BN_new(); 3181e8db6e2SBrian Feldman if (dh_client_pub == NULL) 3191e8db6e2SBrian Feldman fatal("dh_client_pub == NULL"); 3201e8db6e2SBrian Feldman packet_get_bignum2(dh_client_pub, &dlen); 3211e8db6e2SBrian Feldman 3221e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 3231e8db6e2SBrian Feldman fprintf(stderr, "dh_client_pub= "); 3241e8db6e2SBrian Feldman BN_print_fp(stderr, dh_client_pub); 3251e8db6e2SBrian Feldman fprintf(stderr, "\n"); 3261e8db6e2SBrian Feldman debug("bits %d", BN_num_bits(dh_client_pub)); 3271e8db6e2SBrian Feldman #endif 3281e8db6e2SBrian Feldman 3291e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 3301e8db6e2SBrian Feldman DHparams_print_fp(stderr, dh); 3311e8db6e2SBrian Feldman fprintf(stderr, "pub= "); 3321e8db6e2SBrian Feldman BN_print_fp(stderr, dh->pub_key); 3331e8db6e2SBrian Feldman fprintf(stderr, "\n"); 3341e8db6e2SBrian Feldman #endif 3351e8db6e2SBrian Feldman if (!dh_pub_is_valid(dh, dh_client_pub)) 3361e8db6e2SBrian Feldman packet_disconnect("bad client public DH value"); 3371e8db6e2SBrian Feldman 3381e8db6e2SBrian Feldman klen = DH_size(dh); 3391e8db6e2SBrian Feldman kbuf = xmalloc(klen); 3401e8db6e2SBrian Feldman kout = DH_compute_key(kbuf, dh_client_pub, dh); 3411e8db6e2SBrian Feldman #ifdef DEBUG_KEXDH 3421e8db6e2SBrian Feldman dump_digest("shared secret", kbuf, kout); 3431e8db6e2SBrian Feldman #endif 3441e8db6e2SBrian Feldman shared_secret = BN_new(); 3451e8db6e2SBrian Feldman BN_bin2bn(kbuf, kout, shared_secret); 3461e8db6e2SBrian Feldman memset(kbuf, 0, klen); 3471e8db6e2SBrian Feldman xfree(kbuf); 3481e8db6e2SBrian Feldman 3491e8db6e2SBrian Feldman key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); 3501e8db6e2SBrian Feldman 3511e8db6e2SBrian Feldman if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) 3521e8db6e2SBrian Feldman min = max = -1; 3531e8db6e2SBrian Feldman 3541e8db6e2SBrian Feldman /* calc H */ /* XXX depends on 'kex' */ 3551e8db6e2SBrian Feldman hash = kexgex_hash( 3561e8db6e2SBrian Feldman kex->client_version_string, 3571e8db6e2SBrian Feldman kex->server_version_string, 3581e8db6e2SBrian Feldman buffer_ptr(&kex->peer), buffer_len(&kex->peer), 3591e8db6e2SBrian Feldman buffer_ptr(&kex->my), buffer_len(&kex->my), 3601e8db6e2SBrian Feldman (char *)server_host_key_blob, sbloblen, 3611e8db6e2SBrian Feldman min, nbits, max, 3621e8db6e2SBrian Feldman dh->p, dh->g, 3631e8db6e2SBrian Feldman dh_client_pub, 3641e8db6e2SBrian Feldman dh->pub_key, 3651e8db6e2SBrian Feldman shared_secret 3661e8db6e2SBrian Feldman ); 3671e8db6e2SBrian Feldman BN_free(dh_client_pub); 3681e8db6e2SBrian Feldman 3691e8db6e2SBrian Feldman /* save session id := H */ 3701e8db6e2SBrian Feldman /* XXX hashlen depends on KEX */ 3711e8db6e2SBrian Feldman if (kex->session_id == NULL) { 3721e8db6e2SBrian Feldman kex->session_id_len = 20; 3731e8db6e2SBrian Feldman kex->session_id = xmalloc(kex->session_id_len); 3741e8db6e2SBrian Feldman memcpy(kex->session_id, hash, kex->session_id_len); 3751e8db6e2SBrian Feldman } 3761e8db6e2SBrian Feldman 3771e8db6e2SBrian Feldman /* sign H */ 3781e8db6e2SBrian Feldman /* XXX hashlen depends on KEX */ 3791e8db6e2SBrian Feldman key_sign(server_host_key, &signature, &slen, hash, 20); 3801e8db6e2SBrian Feldman 3811e8db6e2SBrian Feldman /* destroy_sensitive_data(); */ 3821e8db6e2SBrian Feldman 3831e8db6e2SBrian Feldman /* send server hostkey, DH pubkey 'f' and singed H */ 3841e8db6e2SBrian Feldman debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); 3851e8db6e2SBrian Feldman packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); 3861e8db6e2SBrian Feldman packet_put_string((char *)server_host_key_blob, sbloblen); 3871e8db6e2SBrian Feldman packet_put_bignum2(dh->pub_key); /* f */ 3881e8db6e2SBrian Feldman packet_put_string((char *)signature, slen); 3891e8db6e2SBrian Feldman packet_send(); 3901e8db6e2SBrian Feldman xfree(signature); 3911e8db6e2SBrian Feldman xfree(server_host_key_blob); 3921e8db6e2SBrian Feldman /* have keys, free DH */ 3931e8db6e2SBrian Feldman DH_free(dh); 3941e8db6e2SBrian Feldman 3951e8db6e2SBrian Feldman kex_derive_keys(kex, hash, shared_secret); 3961e8db6e2SBrian Feldman BN_clear_free(shared_secret); 3971e8db6e2SBrian Feldman 3981e8db6e2SBrian Feldman kex_finish(kex); 3991e8db6e2SBrian Feldman } 4001e8db6e2SBrian Feldman 4011e8db6e2SBrian Feldman void 4021e8db6e2SBrian Feldman kexgex(Kex *kex) 4031e8db6e2SBrian Feldman { 4041e8db6e2SBrian Feldman if (kex->server) 4051e8db6e2SBrian Feldman kexgex_server(kex); 4061e8db6e2SBrian Feldman else 4071e8db6e2SBrian Feldman kexgex_client(kex); 4081e8db6e2SBrian Feldman } 409