147dd1d1bSDag-Erling Smørgrav /* $OpenBSD: kexgexc.c,v 1.27 2018/02/07 02:06:51 jsing Exp $ */ 2d0c8c0bcSDag-Erling Smørgrav /* 3d0c8c0bcSDag-Erling Smørgrav * Copyright (c) 2000 Niels Provos. All rights reserved. 4d0c8c0bcSDag-Erling Smørgrav * Copyright (c) 2001 Markus Friedl. All rights reserved. 5d0c8c0bcSDag-Erling Smørgrav * 6d0c8c0bcSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 7d0c8c0bcSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 8d0c8c0bcSDag-Erling Smørgrav * are met: 9d0c8c0bcSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 10d0c8c0bcSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 11d0c8c0bcSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 12d0c8c0bcSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 13d0c8c0bcSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 14d0c8c0bcSDag-Erling Smørgrav * 15d0c8c0bcSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16d0c8c0bcSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17d0c8c0bcSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18d0c8c0bcSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19d0c8c0bcSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20d0c8c0bcSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21d0c8c0bcSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22d0c8c0bcSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23d0c8c0bcSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24d0c8c0bcSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25d0c8c0bcSDag-Erling Smørgrav */ 26d0c8c0bcSDag-Erling Smørgrav 27d0c8c0bcSDag-Erling Smørgrav #include "includes.h" 28761efaa7SDag-Erling Smørgrav 29bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 30bc5531deSDag-Erling Smørgrav 31761efaa7SDag-Erling Smørgrav #include <sys/types.h> 32761efaa7SDag-Erling Smørgrav 334a421b63SDag-Erling Smørgrav #include <openssl/dh.h> 344a421b63SDag-Erling Smørgrav 35761efaa7SDag-Erling Smørgrav #include <stdarg.h> 36761efaa7SDag-Erling Smørgrav #include <stdio.h> 37761efaa7SDag-Erling Smørgrav #include <string.h> 38761efaa7SDag-Erling Smørgrav #include <signal.h> 39d0c8c0bcSDag-Erling Smørgrav 40*2a01feabSEd Maste #include "openbsd-compat/openssl-compat.h" 41*2a01feabSEd Maste 42bc5531deSDag-Erling Smørgrav #include "sshkey.h" 43761efaa7SDag-Erling Smørgrav #include "cipher.h" 44bc5531deSDag-Erling Smørgrav #include "digest.h" 45d0c8c0bcSDag-Erling Smørgrav #include "kex.h" 46d0c8c0bcSDag-Erling Smørgrav #include "log.h" 47d0c8c0bcSDag-Erling Smørgrav #include "packet.h" 48d0c8c0bcSDag-Erling Smørgrav #include "dh.h" 49d0c8c0bcSDag-Erling Smørgrav #include "ssh2.h" 50d0c8c0bcSDag-Erling Smørgrav #include "compat.h" 51bc5531deSDag-Erling Smørgrav #include "dispatch.h" 52bc5531deSDag-Erling Smørgrav #include "ssherr.h" 53bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 54ca86bcf2SDag-Erling Smørgrav #include "misc.h" 55d0c8c0bcSDag-Erling Smørgrav 564f52dfbbSDag-Erling Smørgrav static int input_kex_dh_gex_group(int, u_int32_t, struct ssh *); 574f52dfbbSDag-Erling Smørgrav static int input_kex_dh_gex_reply(int, u_int32_t, struct ssh *); 58bc5531deSDag-Erling Smørgrav 59bc5531deSDag-Erling Smørgrav int 60bc5531deSDag-Erling Smørgrav kexgex_client(struct ssh *ssh) 61d0c8c0bcSDag-Erling Smørgrav { 62bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 63bc5531deSDag-Erling Smørgrav int r; 64bc5531deSDag-Erling Smørgrav u_int nbits; 65d0c8c0bcSDag-Erling Smørgrav 66f7167e0eSDag-Erling Smørgrav nbits = dh_estimate(kex->dh_need * 8); 67d0c8c0bcSDag-Erling Smørgrav 68bc5531deSDag-Erling Smørgrav kex->min = DH_GRP_MIN; 69bc5531deSDag-Erling Smørgrav kex->max = DH_GRP_MAX; 70bc5531deSDag-Erling Smørgrav kex->nbits = nbits; 71557f75e5SDag-Erling Smørgrav if (datafellows & SSH_BUG_DHGEX_LARGE) 72ca86bcf2SDag-Erling Smørgrav kex->nbits = MINIMUM(kex->nbits, 4096); 73d0c8c0bcSDag-Erling Smørgrav /* New GEX request */ 74bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 || 75bc5531deSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, kex->min)) != 0 || 76bc5531deSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || 77bc5531deSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, kex->max)) != 0 || 78bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 79bc5531deSDag-Erling Smørgrav goto out; 80efcad6b7SDag-Erling Smørgrav debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent", 81bc5531deSDag-Erling Smørgrav kex->min, kex->nbits, kex->max); 82d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH 83d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", 84bc5531deSDag-Erling Smørgrav kex->min, kex->nbits, kex->max); 85d0c8c0bcSDag-Erling Smørgrav #endif 86bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, 87bc5531deSDag-Erling Smørgrav &input_kex_dh_gex_group); 88bc5531deSDag-Erling Smørgrav r = 0; 89bc5531deSDag-Erling Smørgrav out: 90bc5531deSDag-Erling Smørgrav return r; 91bc5531deSDag-Erling Smørgrav } 92d0c8c0bcSDag-Erling Smørgrav 93bc5531deSDag-Erling Smørgrav static int 944f52dfbbSDag-Erling Smørgrav input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh) 95bc5531deSDag-Erling Smørgrav { 96bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 97bc5531deSDag-Erling Smørgrav BIGNUM *p = NULL, *g = NULL; 98*2a01feabSEd Maste const BIGNUM *pub_key; 99bc5531deSDag-Erling Smørgrav int r, bits; 100d0c8c0bcSDag-Erling Smørgrav 101bc5531deSDag-Erling Smørgrav debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); 102d0c8c0bcSDag-Erling Smørgrav 103bc5531deSDag-Erling Smørgrav if ((p = BN_new()) == NULL || 104bc5531deSDag-Erling Smørgrav (g = BN_new()) == NULL) { 105bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 106bc5531deSDag-Erling Smørgrav goto out; 107bc5531deSDag-Erling Smørgrav } 108bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_bignum2(ssh, p)) != 0 || 109bc5531deSDag-Erling Smørgrav (r = sshpkt_get_bignum2(ssh, g)) != 0 || 110bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 111bc5531deSDag-Erling Smørgrav goto out; 112bc5531deSDag-Erling Smørgrav if ((bits = BN_num_bits(p)) < 0 || 113bc5531deSDag-Erling Smørgrav (u_int)bits < kex->min || (u_int)bits > kex->max) { 114bc5531deSDag-Erling Smørgrav r = SSH_ERR_DH_GEX_OUT_OF_RANGE; 115bc5531deSDag-Erling Smørgrav goto out; 116bc5531deSDag-Erling Smørgrav } 117bc5531deSDag-Erling Smørgrav if ((kex->dh = dh_new_group(g, p)) == NULL) { 118bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 119bc5531deSDag-Erling Smørgrav goto out; 120bc5531deSDag-Erling Smørgrav } 121bc5531deSDag-Erling Smørgrav p = g = NULL; /* belong to kex->dh now */ 122d0c8c0bcSDag-Erling Smørgrav 123bc5531deSDag-Erling Smørgrav /* generate and send 'e', client DH public key */ 124*2a01feabSEd Maste if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) 125*2a01feabSEd Maste goto out; 126*2a01feabSEd Maste DH_get0_key(kex->dh, &pub_key, NULL); 127*2a01feabSEd Maste if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 || 128*2a01feabSEd Maste (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || 129bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 130bc5531deSDag-Erling Smørgrav goto out; 131bc5531deSDag-Erling Smørgrav debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); 132d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH 133bc5531deSDag-Erling Smørgrav DHparams_print_fp(stderr, kex->dh); 134d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "pub= "); 135*2a01feabSEd Maste BN_print_fp(stderr, pub_key); 136d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "\n"); 137d0c8c0bcSDag-Erling Smørgrav #endif 138bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL); 139bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply); 140bc5531deSDag-Erling Smørgrav r = 0; 141bc5531deSDag-Erling Smørgrav out: 142bc5531deSDag-Erling Smørgrav BN_clear_free(p); 143bc5531deSDag-Erling Smørgrav BN_clear_free(g); 144bc5531deSDag-Erling Smørgrav return r; 145bc5531deSDag-Erling Smørgrav } 146d0c8c0bcSDag-Erling Smørgrav 147bc5531deSDag-Erling Smørgrav static int 1484f52dfbbSDag-Erling Smørgrav input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) 149bc5531deSDag-Erling Smørgrav { 150bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 151bc5531deSDag-Erling Smørgrav BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 152*2a01feabSEd Maste const BIGNUM *pub_key, *dh_p, *dh_g; 153bc5531deSDag-Erling Smørgrav struct sshkey *server_host_key = NULL; 154bc5531deSDag-Erling Smørgrav u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; 155bc5531deSDag-Erling Smørgrav u_char hash[SSH_DIGEST_MAX_LENGTH]; 156bc5531deSDag-Erling Smørgrav size_t klen = 0, slen, sbloblen, hashlen; 157bc5531deSDag-Erling Smørgrav int kout, r; 158d0c8c0bcSDag-Erling Smørgrav 159bc5531deSDag-Erling Smørgrav debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); 160bc5531deSDag-Erling Smørgrav if (kex->verify_host_key == NULL) { 161bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_ARGUMENT; 162bc5531deSDag-Erling Smørgrav goto out; 163bc5531deSDag-Erling Smørgrav } 164d0c8c0bcSDag-Erling Smørgrav /* key, cert */ 165bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_string(ssh, &server_host_key_blob, 166bc5531deSDag-Erling Smørgrav &sbloblen)) != 0 || 167bc5531deSDag-Erling Smørgrav (r = sshkey_from_blob(server_host_key_blob, sbloblen, 168bc5531deSDag-Erling Smørgrav &server_host_key)) != 0) 169bc5531deSDag-Erling Smørgrav goto out; 170bc5531deSDag-Erling Smørgrav if (server_host_key->type != kex->hostkey_type || 171bc5531deSDag-Erling Smørgrav (kex->hostkey_type == KEY_ECDSA && 172bc5531deSDag-Erling Smørgrav server_host_key->ecdsa_nid != kex->hostkey_nid)) { 173bc5531deSDag-Erling Smørgrav r = SSH_ERR_KEY_TYPE_MISMATCH; 174bc5531deSDag-Erling Smørgrav goto out; 175bc5531deSDag-Erling Smørgrav } 176bc5531deSDag-Erling Smørgrav if (kex->verify_host_key(server_host_key, ssh) == -1) { 177bc5531deSDag-Erling Smørgrav r = SSH_ERR_SIGNATURE_INVALID; 178bc5531deSDag-Erling Smørgrav goto out; 179bc5531deSDag-Erling Smørgrav } 180761efaa7SDag-Erling Smørgrav /* DH parameter f, server public DH key */ 181bc5531deSDag-Erling Smørgrav if ((dh_server_pub = BN_new()) == NULL) { 182bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 183bc5531deSDag-Erling Smørgrav goto out; 184bc5531deSDag-Erling Smørgrav } 185bc5531deSDag-Erling Smørgrav /* signed H */ 186bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || 187bc5531deSDag-Erling Smørgrav (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || 188bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 189bc5531deSDag-Erling Smørgrav goto out; 190d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH 191d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "dh_server_pub= "); 192d0c8c0bcSDag-Erling Smørgrav BN_print_fp(stderr, dh_server_pub); 193d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "\n"); 194d0c8c0bcSDag-Erling Smørgrav debug("bits %d", BN_num_bits(dh_server_pub)); 195d0c8c0bcSDag-Erling Smørgrav #endif 196bc5531deSDag-Erling Smørgrav if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { 197bc5531deSDag-Erling Smørgrav sshpkt_disconnect(ssh, "bad server public DH value"); 198bc5531deSDag-Erling Smørgrav r = SSH_ERR_MESSAGE_INCOMPLETE; 199bc5531deSDag-Erling Smørgrav goto out; 200bc5531deSDag-Erling Smørgrav } 201d0c8c0bcSDag-Erling Smørgrav 202bc5531deSDag-Erling Smørgrav klen = DH_size(kex->dh); 203bc5531deSDag-Erling Smørgrav if ((kbuf = malloc(klen)) == NULL || 204bc5531deSDag-Erling Smørgrav (shared_secret = BN_new()) == NULL) { 205bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 206bc5531deSDag-Erling Smørgrav goto out; 207bc5531deSDag-Erling Smørgrav } 208bc5531deSDag-Erling Smørgrav if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || 209bc5531deSDag-Erling Smørgrav BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 210bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 211bc5531deSDag-Erling Smørgrav goto out; 212bc5531deSDag-Erling Smørgrav } 213d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH 214d0c8c0bcSDag-Erling Smørgrav dump_digest("shared secret", kbuf, kout); 215d0c8c0bcSDag-Erling Smørgrav #endif 216bc5531deSDag-Erling Smørgrav if (ssh->compat & SSH_OLD_DHGEX) 217bc5531deSDag-Erling Smørgrav kex->min = kex->max = -1; 218d0c8c0bcSDag-Erling Smørgrav 219d0c8c0bcSDag-Erling Smørgrav /* calc and verify H */ 220*2a01feabSEd Maste DH_get0_key(kex->dh, &pub_key, NULL); 221*2a01feabSEd Maste DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); 222bc5531deSDag-Erling Smørgrav hashlen = sizeof(hash); 223bc5531deSDag-Erling Smørgrav if ((r = kexgex_hash( 224f7167e0eSDag-Erling Smørgrav kex->hash_alg, 225d0c8c0bcSDag-Erling Smørgrav kex->client_version_string, 226d0c8c0bcSDag-Erling Smørgrav kex->server_version_string, 227bc5531deSDag-Erling Smørgrav sshbuf_ptr(kex->my), sshbuf_len(kex->my), 228bc5531deSDag-Erling Smørgrav sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 229d0c8c0bcSDag-Erling Smørgrav server_host_key_blob, sbloblen, 230bc5531deSDag-Erling Smørgrav kex->min, kex->nbits, kex->max, 231*2a01feabSEd Maste dh_p, dh_g, 232*2a01feabSEd Maste pub_key, 233d0c8c0bcSDag-Erling Smørgrav dh_server_pub, 234021d409fSDag-Erling Smørgrav shared_secret, 235bc5531deSDag-Erling Smørgrav hash, &hashlen)) != 0) 236bc5531deSDag-Erling Smørgrav goto out; 237021d409fSDag-Erling Smørgrav 238bc5531deSDag-Erling Smørgrav if ((r = sshkey_verify(server_host_key, signature, slen, hash, 23947dd1d1bSDag-Erling Smørgrav hashlen, kex->hostkey_alg, ssh->compat)) != 0) 240bc5531deSDag-Erling Smørgrav goto out; 241d0c8c0bcSDag-Erling Smørgrav 242d0c8c0bcSDag-Erling Smørgrav /* save session id */ 243d0c8c0bcSDag-Erling Smørgrav if (kex->session_id == NULL) { 244021d409fSDag-Erling Smørgrav kex->session_id_len = hashlen; 245bc5531deSDag-Erling Smørgrav kex->session_id = malloc(kex->session_id_len); 246bc5531deSDag-Erling Smørgrav if (kex->session_id == NULL) { 247bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 248bc5531deSDag-Erling Smørgrav goto out; 249bc5531deSDag-Erling Smørgrav } 250d0c8c0bcSDag-Erling Smørgrav memcpy(kex->session_id, hash, kex->session_id_len); 251d0c8c0bcSDag-Erling Smørgrav } 252d0c8c0bcSDag-Erling Smørgrav 253bc5531deSDag-Erling Smørgrav if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) 254bc5531deSDag-Erling Smørgrav r = kex_send_newkeys(ssh); 255bc5531deSDag-Erling Smørgrav out: 256bc5531deSDag-Erling Smørgrav explicit_bzero(hash, sizeof(hash)); 257bc5531deSDag-Erling Smørgrav DH_free(kex->dh); 258bc5531deSDag-Erling Smørgrav kex->dh = NULL; 259bc5531deSDag-Erling Smørgrav BN_clear_free(dh_server_pub); 260bc5531deSDag-Erling Smørgrav if (kbuf) { 261bc5531deSDag-Erling Smørgrav explicit_bzero(kbuf, klen); 262bc5531deSDag-Erling Smørgrav free(kbuf); 263d0c8c0bcSDag-Erling Smørgrav } 264bc5531deSDag-Erling Smørgrav BN_clear_free(shared_secret); 265bc5531deSDag-Erling Smørgrav sshkey_free(server_host_key); 266bc5531deSDag-Erling Smørgrav free(server_host_key_blob); 267bc5531deSDag-Erling Smørgrav free(signature); 268bc5531deSDag-Erling Smørgrav return r; 269bc5531deSDag-Erling Smørgrav } 270bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 271