1*36e94dc5SPeter Avalos /* $OpenBSD: kexgexs.c,v 1.19 2014/02/02 03:44:31 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2000 Niels Provos. All rights reserved. 418de8d7fSPeter Avalos * Copyright (c) 2001 Markus Friedl. All rights reserved. 518de8d7fSPeter Avalos * 618de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 718de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 818de8d7fSPeter Avalos * are met: 918de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 1018de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 1118de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1218de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 1318de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 1418de8d7fSPeter Avalos * 1518de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1618de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1718de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1818de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1918de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2018de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2118de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2218de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2318de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2418de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2518de8d7fSPeter Avalos */ 2618de8d7fSPeter Avalos 2718de8d7fSPeter Avalos #include "includes.h" 2818de8d7fSPeter Avalos 2918de8d7fSPeter Avalos #include <sys/param.h> 3018de8d7fSPeter Avalos 3118de8d7fSPeter Avalos #include <stdarg.h> 3218de8d7fSPeter Avalos #include <stdio.h> 3318de8d7fSPeter Avalos #include <string.h> 3418de8d7fSPeter Avalos #include <signal.h> 3518de8d7fSPeter Avalos 369f304aafSPeter Avalos #include <openssl/dh.h> 379f304aafSPeter Avalos 3818de8d7fSPeter Avalos #include "xmalloc.h" 3918de8d7fSPeter Avalos #include "buffer.h" 4018de8d7fSPeter Avalos #include "key.h" 4118de8d7fSPeter Avalos #include "cipher.h" 4218de8d7fSPeter Avalos #include "kex.h" 4318de8d7fSPeter Avalos #include "log.h" 4418de8d7fSPeter Avalos #include "packet.h" 4518de8d7fSPeter Avalos #include "dh.h" 4618de8d7fSPeter Avalos #include "ssh2.h" 4718de8d7fSPeter Avalos #include "compat.h" 4818de8d7fSPeter Avalos #ifdef GSSAPI 4918de8d7fSPeter Avalos #include "ssh-gss.h" 5018de8d7fSPeter Avalos #endif 5118de8d7fSPeter Avalos #include "monitor_wrap.h" 5218de8d7fSPeter Avalos 5318de8d7fSPeter Avalos void 5418de8d7fSPeter Avalos kexgex_server(Kex *kex) 5518de8d7fSPeter Avalos { 5618de8d7fSPeter Avalos BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; 57856ea928SPeter Avalos Key *server_host_public, *server_host_private; 5818de8d7fSPeter Avalos DH *dh; 5918de8d7fSPeter Avalos u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; 6018de8d7fSPeter Avalos u_int sbloblen, klen, slen, hashlen; 61cb5eb4f1SPeter Avalos int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; 62cb5eb4f1SPeter Avalos int type, kout; 6318de8d7fSPeter Avalos 64856ea928SPeter Avalos if (kex->load_host_public_key == NULL || 65856ea928SPeter Avalos kex->load_host_private_key == NULL) 6618de8d7fSPeter Avalos fatal("Cannot load hostkey"); 67856ea928SPeter Avalos server_host_public = kex->load_host_public_key(kex->hostkey_type); 68856ea928SPeter Avalos if (server_host_public == NULL) 6918de8d7fSPeter Avalos fatal("Unsupported hostkey type %d", kex->hostkey_type); 70856ea928SPeter Avalos server_host_private = kex->load_host_private_key(kex->hostkey_type); 7118de8d7fSPeter Avalos 7218de8d7fSPeter Avalos type = packet_read(); 7318de8d7fSPeter Avalos switch (type) { 7418de8d7fSPeter Avalos case SSH2_MSG_KEX_DH_GEX_REQUEST: 7518de8d7fSPeter Avalos debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); 76cb5eb4f1SPeter Avalos omin = min = packet_get_int(); 77cb5eb4f1SPeter Avalos onbits = nbits = packet_get_int(); 78cb5eb4f1SPeter Avalos omax = max = packet_get_int(); 7918de8d7fSPeter Avalos min = MAX(DH_GRP_MIN, min); 8018de8d7fSPeter Avalos max = MIN(DH_GRP_MAX, max); 81cb5eb4f1SPeter Avalos nbits = MAX(DH_GRP_MIN, nbits); 82cb5eb4f1SPeter Avalos nbits = MIN(DH_GRP_MAX, nbits); 8318de8d7fSPeter Avalos break; 8418de8d7fSPeter Avalos case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: 8518de8d7fSPeter Avalos debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); 86cb5eb4f1SPeter Avalos onbits = nbits = packet_get_int(); 8718de8d7fSPeter Avalos /* unused for old GEX */ 88cb5eb4f1SPeter Avalos omin = min = DH_GRP_MIN; 89cb5eb4f1SPeter Avalos omax = max = DH_GRP_MAX; 9018de8d7fSPeter Avalos break; 9118de8d7fSPeter Avalos default: 9218de8d7fSPeter Avalos fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); 9318de8d7fSPeter Avalos } 9418de8d7fSPeter Avalos packet_check_eom(); 9518de8d7fSPeter Avalos 96cb5eb4f1SPeter Avalos if (omax < omin || onbits < omin || omax < onbits) 9718de8d7fSPeter Avalos fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", 98cb5eb4f1SPeter Avalos omin, onbits, omax); 9918de8d7fSPeter Avalos 10018de8d7fSPeter Avalos /* Contact privileged parent */ 10118de8d7fSPeter Avalos dh = PRIVSEP(choose_dh(min, nbits, max)); 10218de8d7fSPeter Avalos if (dh == NULL) 10318de8d7fSPeter Avalos packet_disconnect("Protocol error: no matching DH grp found"); 10418de8d7fSPeter Avalos 10518de8d7fSPeter Avalos debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 10618de8d7fSPeter Avalos packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); 10718de8d7fSPeter Avalos packet_put_bignum2(dh->p); 10818de8d7fSPeter Avalos packet_put_bignum2(dh->g); 10918de8d7fSPeter Avalos packet_send(); 11018de8d7fSPeter Avalos 11118de8d7fSPeter Avalos /* flush */ 11218de8d7fSPeter Avalos packet_write_wait(); 11318de8d7fSPeter Avalos 11418de8d7fSPeter Avalos /* Compute our exchange value in parallel with the client */ 11518de8d7fSPeter Avalos dh_gen_key(dh, kex->we_need * 8); 11618de8d7fSPeter Avalos 11718de8d7fSPeter Avalos debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); 11818de8d7fSPeter Avalos packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); 11918de8d7fSPeter Avalos 12018de8d7fSPeter Avalos /* key, cert */ 12118de8d7fSPeter Avalos if ((dh_client_pub = BN_new()) == NULL) 12218de8d7fSPeter Avalos fatal("dh_client_pub == NULL"); 12318de8d7fSPeter Avalos packet_get_bignum2(dh_client_pub); 12418de8d7fSPeter Avalos packet_check_eom(); 12518de8d7fSPeter Avalos 12618de8d7fSPeter Avalos #ifdef DEBUG_KEXDH 12718de8d7fSPeter Avalos fprintf(stderr, "dh_client_pub= "); 12818de8d7fSPeter Avalos BN_print_fp(stderr, dh_client_pub); 12918de8d7fSPeter Avalos fprintf(stderr, "\n"); 13018de8d7fSPeter Avalos debug("bits %d", BN_num_bits(dh_client_pub)); 13118de8d7fSPeter Avalos #endif 13218de8d7fSPeter Avalos 13318de8d7fSPeter Avalos #ifdef DEBUG_KEXDH 13418de8d7fSPeter Avalos DHparams_print_fp(stderr, dh); 13518de8d7fSPeter Avalos fprintf(stderr, "pub= "); 13618de8d7fSPeter Avalos BN_print_fp(stderr, dh->pub_key); 13718de8d7fSPeter Avalos fprintf(stderr, "\n"); 13818de8d7fSPeter Avalos #endif 13918de8d7fSPeter Avalos if (!dh_pub_is_valid(dh, dh_client_pub)) 14018de8d7fSPeter Avalos packet_disconnect("bad client public DH value"); 14118de8d7fSPeter Avalos 14218de8d7fSPeter Avalos klen = DH_size(dh); 14318de8d7fSPeter Avalos kbuf = xmalloc(klen); 14418de8d7fSPeter Avalos if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) 14518de8d7fSPeter Avalos fatal("DH_compute_key: failed"); 14618de8d7fSPeter Avalos #ifdef DEBUG_KEXDH 14718de8d7fSPeter Avalos dump_digest("shared secret", kbuf, kout); 14818de8d7fSPeter Avalos #endif 14918de8d7fSPeter Avalos if ((shared_secret = BN_new()) == NULL) 15018de8d7fSPeter Avalos fatal("kexgex_server: BN_new failed"); 15118de8d7fSPeter Avalos if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 15218de8d7fSPeter Avalos fatal("kexgex_server: BN_bin2bn failed"); 153*36e94dc5SPeter Avalos explicit_bzero(kbuf, klen); 154*36e94dc5SPeter Avalos free(kbuf); 15518de8d7fSPeter Avalos 156856ea928SPeter Avalos key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); 15718de8d7fSPeter Avalos 15818de8d7fSPeter Avalos if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) 159cb5eb4f1SPeter Avalos omin = min = omax = max = -1; 16018de8d7fSPeter Avalos 16118de8d7fSPeter Avalos /* calc H */ 16218de8d7fSPeter Avalos kexgex_hash( 163*36e94dc5SPeter Avalos kex->hash_alg, 16418de8d7fSPeter Avalos kex->client_version_string, 16518de8d7fSPeter Avalos kex->server_version_string, 16618de8d7fSPeter Avalos buffer_ptr(&kex->peer), buffer_len(&kex->peer), 16718de8d7fSPeter Avalos buffer_ptr(&kex->my), buffer_len(&kex->my), 16818de8d7fSPeter Avalos server_host_key_blob, sbloblen, 169cb5eb4f1SPeter Avalos omin, onbits, omax, 17018de8d7fSPeter Avalos dh->p, dh->g, 17118de8d7fSPeter Avalos dh_client_pub, 17218de8d7fSPeter Avalos dh->pub_key, 17318de8d7fSPeter Avalos shared_secret, 17418de8d7fSPeter Avalos &hash, &hashlen 17518de8d7fSPeter Avalos ); 17618de8d7fSPeter Avalos BN_clear_free(dh_client_pub); 17718de8d7fSPeter Avalos 17818de8d7fSPeter Avalos /* save session id := H */ 17918de8d7fSPeter Avalos if (kex->session_id == NULL) { 18018de8d7fSPeter Avalos kex->session_id_len = hashlen; 18118de8d7fSPeter Avalos kex->session_id = xmalloc(kex->session_id_len); 18218de8d7fSPeter Avalos memcpy(kex->session_id, hash, kex->session_id_len); 18318de8d7fSPeter Avalos } 18418de8d7fSPeter Avalos 18518de8d7fSPeter Avalos /* sign H */ 186*36e94dc5SPeter Avalos kex->sign(server_host_private, server_host_public, &signature, &slen, 187*36e94dc5SPeter Avalos hash, hashlen); 18818de8d7fSPeter Avalos 18918de8d7fSPeter Avalos /* destroy_sensitive_data(); */ 19018de8d7fSPeter Avalos 19118de8d7fSPeter Avalos /* send server hostkey, DH pubkey 'f' and singed H */ 19218de8d7fSPeter Avalos debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); 19318de8d7fSPeter Avalos packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); 19418de8d7fSPeter Avalos packet_put_string(server_host_key_blob, sbloblen); 19518de8d7fSPeter Avalos packet_put_bignum2(dh->pub_key); /* f */ 19618de8d7fSPeter Avalos packet_put_string(signature, slen); 19718de8d7fSPeter Avalos packet_send(); 19818de8d7fSPeter Avalos 199*36e94dc5SPeter Avalos free(signature); 200*36e94dc5SPeter Avalos free(server_host_key_blob); 20118de8d7fSPeter Avalos /* have keys, free DH */ 20218de8d7fSPeter Avalos DH_free(dh); 20318de8d7fSPeter Avalos 204*36e94dc5SPeter Avalos kex_derive_keys_bn(kex, hash, hashlen, shared_secret); 20518de8d7fSPeter Avalos BN_clear_free(shared_secret); 20618de8d7fSPeter Avalos 20718de8d7fSPeter Avalos kex_finish(kex); 20818de8d7fSPeter Avalos } 209