1*190cef3dSDag-Erling Smørgrav /* $OpenBSD: kexgexs.c,v 1.33 2018/04/10 00:10:49 djm 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 32761efaa7SDag-Erling Smørgrav #include <stdarg.h> 33761efaa7SDag-Erling Smørgrav #include <stdio.h> 34761efaa7SDag-Erling Smørgrav #include <string.h> 35761efaa7SDag-Erling Smørgrav #include <signal.h> 36d0c8c0bcSDag-Erling Smørgrav 374a421b63SDag-Erling Smørgrav #include <openssl/dh.h> 384a421b63SDag-Erling Smørgrav 39bc5531deSDag-Erling Smørgrav #include "sshkey.h" 40761efaa7SDag-Erling Smørgrav #include "cipher.h" 41bc5531deSDag-Erling Smørgrav #include "digest.h" 42d0c8c0bcSDag-Erling Smørgrav #include "kex.h" 43d0c8c0bcSDag-Erling Smørgrav #include "log.h" 44d0c8c0bcSDag-Erling Smørgrav #include "packet.h" 45d0c8c0bcSDag-Erling Smørgrav #include "dh.h" 46d0c8c0bcSDag-Erling Smørgrav #include "ssh2.h" 47d0c8c0bcSDag-Erling Smørgrav #include "compat.h" 48761efaa7SDag-Erling Smørgrav #ifdef GSSAPI 49761efaa7SDag-Erling Smørgrav #include "ssh-gss.h" 50761efaa7SDag-Erling Smørgrav #endif 51d0c8c0bcSDag-Erling Smørgrav #include "monitor_wrap.h" 52bc5531deSDag-Erling Smørgrav #include "dispatch.h" 53bc5531deSDag-Erling Smørgrav #include "ssherr.h" 54bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 55ca86bcf2SDag-Erling Smørgrav #include "misc.h" 56d0c8c0bcSDag-Erling Smørgrav 574f52dfbbSDag-Erling Smørgrav static int input_kex_dh_gex_request(int, u_int32_t, struct ssh *); 584f52dfbbSDag-Erling Smørgrav static int input_kex_dh_gex_init(int, u_int32_t, struct ssh *); 59bc5531deSDag-Erling Smørgrav 60bc5531deSDag-Erling Smørgrav int 61bc5531deSDag-Erling Smørgrav kexgex_server(struct ssh *ssh) 62d0c8c0bcSDag-Erling Smørgrav { 63bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST, 64bc5531deSDag-Erling Smørgrav &input_kex_dh_gex_request); 65bc5531deSDag-Erling Smørgrav debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST"); 66bc5531deSDag-Erling Smørgrav return 0; 67bc5531deSDag-Erling Smørgrav } 68d0c8c0bcSDag-Erling Smørgrav 69bc5531deSDag-Erling Smørgrav static int 704f52dfbbSDag-Erling Smørgrav input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh) 71bc5531deSDag-Erling Smørgrav { 72bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 73bc5531deSDag-Erling Smørgrav int r; 74bc5531deSDag-Erling Smørgrav u_int min = 0, max = 0, nbits = 0; 75d0c8c0bcSDag-Erling Smørgrav 76d0c8c0bcSDag-Erling Smørgrav debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); 77bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u32(ssh, &min)) != 0 || 78bc5531deSDag-Erling Smørgrav (r = sshpkt_get_u32(ssh, &nbits)) != 0 || 79bc5531deSDag-Erling Smørgrav (r = sshpkt_get_u32(ssh, &max)) != 0 || 80bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 81bc5531deSDag-Erling Smørgrav goto out; 82bc5531deSDag-Erling Smørgrav kex->nbits = nbits; 83bc5531deSDag-Erling Smørgrav kex->min = min; 84bc5531deSDag-Erling Smørgrav kex->max = max; 85ca86bcf2SDag-Erling Smørgrav min = MAXIMUM(DH_GRP_MIN, min); 86ca86bcf2SDag-Erling Smørgrav max = MINIMUM(DH_GRP_MAX, max); 87ca86bcf2SDag-Erling Smørgrav nbits = MAXIMUM(DH_GRP_MIN, nbits); 88ca86bcf2SDag-Erling Smørgrav nbits = MINIMUM(DH_GRP_MAX, nbits); 89d0c8c0bcSDag-Erling Smørgrav 90bc5531deSDag-Erling Smørgrav if (kex->max < kex->min || kex->nbits < kex->min || 91076ad2f8SDag-Erling Smørgrav kex->max < kex->nbits || kex->max < DH_GRP_MIN) { 92bc5531deSDag-Erling Smørgrav r = SSH_ERR_DH_GEX_OUT_OF_RANGE; 93bc5531deSDag-Erling Smørgrav goto out; 94bc5531deSDag-Erling Smørgrav } 95d0c8c0bcSDag-Erling Smørgrav 96d0c8c0bcSDag-Erling Smørgrav /* Contact privileged parent */ 97bc5531deSDag-Erling Smørgrav kex->dh = PRIVSEP(choose_dh(min, nbits, max)); 98bc5531deSDag-Erling Smørgrav if (kex->dh == NULL) { 99bc5531deSDag-Erling Smørgrav sshpkt_disconnect(ssh, "no matching DH grp found"); 100bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 101bc5531deSDag-Erling Smørgrav goto out; 102bc5531deSDag-Erling Smørgrav } 103d0c8c0bcSDag-Erling Smørgrav debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 104bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 || 105bc5531deSDag-Erling Smørgrav (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 || 106bc5531deSDag-Erling Smørgrav (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 || 107bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 108bc5531deSDag-Erling Smørgrav goto out; 109d0c8c0bcSDag-Erling Smørgrav 110d0c8c0bcSDag-Erling Smørgrav /* Compute our exchange value in parallel with the client */ 111bc5531deSDag-Erling Smørgrav if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) 112bc5531deSDag-Erling Smørgrav goto out; 113bc5531deSDag-Erling Smørgrav 114d0c8c0bcSDag-Erling Smørgrav debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); 115bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init); 116bc5531deSDag-Erling Smørgrav r = 0; 117bc5531deSDag-Erling Smørgrav out: 118bc5531deSDag-Erling Smørgrav return r; 119bc5531deSDag-Erling Smørgrav } 120bc5531deSDag-Erling Smørgrav 121bc5531deSDag-Erling Smørgrav static int 1224f52dfbbSDag-Erling Smørgrav input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh) 123bc5531deSDag-Erling Smørgrav { 124bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 125bc5531deSDag-Erling Smørgrav BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; 126bc5531deSDag-Erling Smørgrav struct sshkey *server_host_public, *server_host_private; 127bc5531deSDag-Erling Smørgrav u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; 128bc5531deSDag-Erling Smørgrav u_char hash[SSH_DIGEST_MAX_LENGTH]; 129bc5531deSDag-Erling Smørgrav size_t sbloblen, slen; 130bc5531deSDag-Erling Smørgrav size_t klen = 0, hashlen; 131bc5531deSDag-Erling Smørgrav int kout, r; 132bc5531deSDag-Erling Smørgrav 133bc5531deSDag-Erling Smørgrav if (kex->load_host_public_key == NULL || 134bc5531deSDag-Erling Smørgrav kex->load_host_private_key == NULL) { 135bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_ARGUMENT; 136bc5531deSDag-Erling Smørgrav goto out; 137bc5531deSDag-Erling Smørgrav } 138bc5531deSDag-Erling Smørgrav server_host_public = kex->load_host_public_key(kex->hostkey_type, 139bc5531deSDag-Erling Smørgrav kex->hostkey_nid, ssh); 140bc5531deSDag-Erling Smørgrav server_host_private = kex->load_host_private_key(kex->hostkey_type, 141bc5531deSDag-Erling Smørgrav kex->hostkey_nid, ssh); 142bc5531deSDag-Erling Smørgrav if (server_host_public == NULL) { 143bc5531deSDag-Erling Smørgrav r = SSH_ERR_NO_HOSTKEY_LOADED; 144bc5531deSDag-Erling Smørgrav goto out; 145bc5531deSDag-Erling Smørgrav } 146d0c8c0bcSDag-Erling Smørgrav 147d0c8c0bcSDag-Erling Smørgrav /* key, cert */ 148bc5531deSDag-Erling Smørgrav if ((dh_client_pub = BN_new()) == NULL) { 149bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 150bc5531deSDag-Erling Smørgrav goto out; 151bc5531deSDag-Erling Smørgrav } 152bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 || 153bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 154bc5531deSDag-Erling Smørgrav goto out; 155d0c8c0bcSDag-Erling Smørgrav 156d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH 157d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "dh_client_pub= "); 158d0c8c0bcSDag-Erling Smørgrav BN_print_fp(stderr, dh_client_pub); 159d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "\n"); 160d0c8c0bcSDag-Erling Smørgrav debug("bits %d", BN_num_bits(dh_client_pub)); 161d0c8c0bcSDag-Erling Smørgrav #endif 162d0c8c0bcSDag-Erling Smørgrav 163d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH 164bc5531deSDag-Erling Smørgrav DHparams_print_fp(stderr, kex->dh); 165d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "pub= "); 166bc5531deSDag-Erling Smørgrav BN_print_fp(stderr, kex->dh->pub_key); 167d0c8c0bcSDag-Erling Smørgrav fprintf(stderr, "\n"); 168d0c8c0bcSDag-Erling Smørgrav #endif 169bc5531deSDag-Erling Smørgrav if (!dh_pub_is_valid(kex->dh, dh_client_pub)) { 170bc5531deSDag-Erling Smørgrav sshpkt_disconnect(ssh, "bad client public DH value"); 171bc5531deSDag-Erling Smørgrav r = SSH_ERR_MESSAGE_INCOMPLETE; 172bc5531deSDag-Erling Smørgrav goto out; 173bc5531deSDag-Erling Smørgrav } 174d0c8c0bcSDag-Erling Smørgrav 175bc5531deSDag-Erling Smørgrav klen = DH_size(kex->dh); 176bc5531deSDag-Erling Smørgrav if ((kbuf = malloc(klen)) == NULL || 177bc5531deSDag-Erling Smørgrav (shared_secret = BN_new()) == NULL) { 178bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 179bc5531deSDag-Erling Smørgrav goto out; 180bc5531deSDag-Erling Smørgrav } 181bc5531deSDag-Erling Smørgrav if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 || 182bc5531deSDag-Erling Smørgrav BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 183bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 184bc5531deSDag-Erling Smørgrav goto out; 185bc5531deSDag-Erling Smørgrav } 186d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH 187d0c8c0bcSDag-Erling Smørgrav dump_digest("shared secret", kbuf, kout); 188d0c8c0bcSDag-Erling Smørgrav #endif 189bc5531deSDag-Erling Smørgrav if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, 190bc5531deSDag-Erling Smørgrav &sbloblen)) != 0) 191bc5531deSDag-Erling Smørgrav goto out; 192021d409fSDag-Erling Smørgrav /* calc H */ 193bc5531deSDag-Erling Smørgrav hashlen = sizeof(hash); 194bc5531deSDag-Erling Smørgrav if ((r = kexgex_hash( 195f7167e0eSDag-Erling Smørgrav kex->hash_alg, 196d0c8c0bcSDag-Erling Smørgrav kex->client_version_string, 197d0c8c0bcSDag-Erling Smørgrav kex->server_version_string, 198bc5531deSDag-Erling Smørgrav sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 199bc5531deSDag-Erling Smørgrav sshbuf_ptr(kex->my), sshbuf_len(kex->my), 200d0c8c0bcSDag-Erling Smørgrav server_host_key_blob, sbloblen, 201bc5531deSDag-Erling Smørgrav kex->min, kex->nbits, kex->max, 202bc5531deSDag-Erling Smørgrav kex->dh->p, kex->dh->g, 203d0c8c0bcSDag-Erling Smørgrav dh_client_pub, 204bc5531deSDag-Erling Smørgrav kex->dh->pub_key, 205021d409fSDag-Erling Smørgrav shared_secret, 206bc5531deSDag-Erling Smørgrav hash, &hashlen)) != 0) 207bc5531deSDag-Erling Smørgrav goto out; 208d0c8c0bcSDag-Erling Smørgrav 209d0c8c0bcSDag-Erling Smørgrav /* save session id := H */ 210d0c8c0bcSDag-Erling Smørgrav if (kex->session_id == NULL) { 211021d409fSDag-Erling Smørgrav kex->session_id_len = hashlen; 212bc5531deSDag-Erling Smørgrav kex->session_id = malloc(kex->session_id_len); 213bc5531deSDag-Erling Smørgrav if (kex->session_id == NULL) { 214bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 215bc5531deSDag-Erling Smørgrav goto out; 216bc5531deSDag-Erling Smørgrav } 217d0c8c0bcSDag-Erling Smørgrav memcpy(kex->session_id, hash, kex->session_id_len); 218d0c8c0bcSDag-Erling Smørgrav } 219d0c8c0bcSDag-Erling Smørgrav 220d0c8c0bcSDag-Erling Smørgrav /* sign H */ 221acc1a9efSDag-Erling Smørgrav if ((r = kex->sign(server_host_private, server_host_public, &signature, 222acc1a9efSDag-Erling Smørgrav &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0) 223bc5531deSDag-Erling Smørgrav goto out; 224d0c8c0bcSDag-Erling Smørgrav 225d0c8c0bcSDag-Erling Smørgrav /* destroy_sensitive_data(); */ 226d0c8c0bcSDag-Erling Smørgrav 227*190cef3dSDag-Erling Smørgrav /* send server hostkey, DH pubkey 'f' and signed H */ 228bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || 229bc5531deSDag-Erling Smørgrav (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || 230bc5531deSDag-Erling Smørgrav (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ 231bc5531deSDag-Erling Smørgrav (r = sshpkt_put_string(ssh, signature, slen)) != 0 || 232bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 233bc5531deSDag-Erling Smørgrav goto out; 234d0c8c0bcSDag-Erling Smørgrav 235bc5531deSDag-Erling Smørgrav if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) 236bc5531deSDag-Erling Smørgrav r = kex_send_newkeys(ssh); 237bc5531deSDag-Erling Smørgrav out: 238bc5531deSDag-Erling Smørgrav DH_free(kex->dh); 239bc5531deSDag-Erling Smørgrav kex->dh = NULL; 240bc5531deSDag-Erling Smørgrav BN_clear_free(dh_client_pub); 241bc5531deSDag-Erling Smørgrav if (kbuf) { 242bc5531deSDag-Erling Smørgrav explicit_bzero(kbuf, klen); 243bc5531deSDag-Erling Smørgrav free(kbuf); 244d0c8c0bcSDag-Erling Smørgrav } 245bc5531deSDag-Erling Smørgrav BN_clear_free(shared_secret); 246bc5531deSDag-Erling Smørgrav free(server_host_key_blob); 247bc5531deSDag-Erling Smørgrav free(signature); 248bc5531deSDag-Erling Smørgrav return r; 249bc5531deSDag-Erling Smørgrav } 250bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 251