150a69bb5SSascha Wildner /* $OpenBSD: kexgexs.c,v 1.43 2021/01/31 22:55:29 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 29e9778795SPeter Avalos #ifdef WITH_OPENSSL 30e9778795SPeter Avalos 3118de8d7fSPeter Avalos 3218de8d7fSPeter Avalos #include <stdarg.h> 3318de8d7fSPeter Avalos #include <stdio.h> 3418de8d7fSPeter Avalos #include <string.h> 3518de8d7fSPeter Avalos #include <signal.h> 3618de8d7fSPeter Avalos 379f304aafSPeter Avalos #include <openssl/dh.h> 389f304aafSPeter Avalos 39664f4763Szrj #include "openbsd-compat/openssl-compat.h" 40664f4763Szrj 41e9778795SPeter Avalos #include "sshkey.h" 4218de8d7fSPeter Avalos #include "cipher.h" 43e9778795SPeter Avalos #include "digest.h" 4418de8d7fSPeter Avalos #include "kex.h" 4518de8d7fSPeter Avalos #include "log.h" 4618de8d7fSPeter Avalos #include "packet.h" 4718de8d7fSPeter Avalos #include "dh.h" 4818de8d7fSPeter Avalos #include "ssh2.h" 4918de8d7fSPeter Avalos #include "compat.h" 5018de8d7fSPeter Avalos #ifdef GSSAPI 5118de8d7fSPeter Avalos #include "ssh-gss.h" 5218de8d7fSPeter Avalos #endif 5318de8d7fSPeter Avalos #include "monitor_wrap.h" 54e9778795SPeter Avalos #include "dispatch.h" 55e9778795SPeter Avalos #include "ssherr.h" 56e9778795SPeter Avalos #include "sshbuf.h" 57ce74bacaSMatthew Dillon #include "misc.h" 5818de8d7fSPeter Avalos 59ce74bacaSMatthew Dillon static int input_kex_dh_gex_request(int, u_int32_t, struct ssh *); 60ce74bacaSMatthew Dillon static int input_kex_dh_gex_init(int, u_int32_t, struct ssh *); 61e9778795SPeter Avalos 62e9778795SPeter Avalos int 63e9778795SPeter Avalos kexgex_server(struct ssh *ssh) 6418de8d7fSPeter Avalos { 65e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST, 66e9778795SPeter Avalos &input_kex_dh_gex_request); 67e9778795SPeter Avalos debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST"); 68e9778795SPeter Avalos return 0; 69e9778795SPeter Avalos } 7018de8d7fSPeter Avalos 71e9778795SPeter Avalos static int 72ce74bacaSMatthew Dillon input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh) 73e9778795SPeter Avalos { 74e9778795SPeter Avalos struct kex *kex = ssh->kex; 75e9778795SPeter Avalos int r; 76e9778795SPeter Avalos u_int min = 0, max = 0, nbits = 0; 77664f4763Szrj const BIGNUM *dh_p, *dh_g; 7818de8d7fSPeter Avalos 7918de8d7fSPeter Avalos debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); 8050a69bb5SSascha Wildner ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST, &kex_protocol_error); 8150a69bb5SSascha Wildner 82e9778795SPeter Avalos if ((r = sshpkt_get_u32(ssh, &min)) != 0 || 83e9778795SPeter Avalos (r = sshpkt_get_u32(ssh, &nbits)) != 0 || 84e9778795SPeter Avalos (r = sshpkt_get_u32(ssh, &max)) != 0 || 85e9778795SPeter Avalos (r = sshpkt_get_end(ssh)) != 0) 86e9778795SPeter Avalos goto out; 87e9778795SPeter Avalos kex->nbits = nbits; 88e9778795SPeter Avalos kex->min = min; 89e9778795SPeter Avalos kex->max = max; 90ce74bacaSMatthew Dillon min = MAXIMUM(DH_GRP_MIN, min); 91ce74bacaSMatthew Dillon max = MINIMUM(DH_GRP_MAX, max); 92ce74bacaSMatthew Dillon nbits = MAXIMUM(DH_GRP_MIN, nbits); 93ce74bacaSMatthew Dillon nbits = MINIMUM(DH_GRP_MAX, nbits); 9418de8d7fSPeter Avalos 95e9778795SPeter Avalos if (kex->max < kex->min || kex->nbits < kex->min || 96e9778795SPeter Avalos kex->max < kex->nbits || kex->max < DH_GRP_MIN) { 97e9778795SPeter Avalos r = SSH_ERR_DH_GEX_OUT_OF_RANGE; 98e9778795SPeter Avalos goto out; 99e9778795SPeter Avalos } 10018de8d7fSPeter Avalos 10118de8d7fSPeter Avalos /* Contact privileged parent */ 102e9778795SPeter Avalos kex->dh = PRIVSEP(choose_dh(min, nbits, max)); 103e9778795SPeter Avalos if (kex->dh == NULL) { 104e9778795SPeter Avalos sshpkt_disconnect(ssh, "no matching DH grp found"); 105e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 106e9778795SPeter Avalos goto out; 107e9778795SPeter Avalos } 10818de8d7fSPeter Avalos debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 109664f4763Szrj DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); 110e9778795SPeter Avalos if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 || 111664f4763Szrj (r = sshpkt_put_bignum2(ssh, dh_p)) != 0 || 112664f4763Szrj (r = sshpkt_put_bignum2(ssh, dh_g)) != 0 || 113e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) 114e9778795SPeter Avalos goto out; 11518de8d7fSPeter Avalos 11618de8d7fSPeter Avalos /* Compute our exchange value in parallel with the client */ 117e9778795SPeter Avalos if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) 118e9778795SPeter Avalos goto out; 11918de8d7fSPeter Avalos 12018de8d7fSPeter Avalos debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); 121e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init); 122e9778795SPeter Avalos r = 0; 123e9778795SPeter Avalos out: 124e9778795SPeter Avalos return r; 125e9778795SPeter Avalos } 126e9778795SPeter Avalos 127e9778795SPeter Avalos static int 128ce74bacaSMatthew Dillon input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh) 129e9778795SPeter Avalos { 130e9778795SPeter Avalos struct kex *kex = ssh->kex; 131664f4763Szrj BIGNUM *dh_client_pub = NULL; 132664f4763Szrj const BIGNUM *pub_key, *dh_p, *dh_g; 133664f4763Szrj struct sshbuf *shared_secret = NULL; 134664f4763Szrj struct sshbuf *server_host_key_blob = NULL; 135e9778795SPeter Avalos struct sshkey *server_host_public, *server_host_private; 136664f4763Szrj u_char *signature = NULL; 137e9778795SPeter Avalos u_char hash[SSH_DIGEST_MAX_LENGTH]; 138664f4763Szrj size_t slen, hashlen; 139664f4763Szrj int r; 140e9778795SPeter Avalos 14150a69bb5SSascha Wildner debug("SSH2_MSG_KEX_DH_GEX_INIT received"); 14250a69bb5SSascha Wildner ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &kex_protocol_error); 14350a69bb5SSascha Wildner 144664f4763Szrj if ((r = kex_load_hostkey(ssh, &server_host_private, 145664f4763Szrj &server_host_public)) != 0) 146e9778795SPeter Avalos goto out; 14718de8d7fSPeter Avalos 14818de8d7fSPeter Avalos /* key, cert */ 149664f4763Szrj if ((r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 || 150e9778795SPeter Avalos (r = sshpkt_get_end(ssh)) != 0) 151e9778795SPeter Avalos goto out; 152664f4763Szrj if ((shared_secret = sshbuf_new()) == NULL) { 153e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 154e9778795SPeter Avalos goto out; 155e9778795SPeter Avalos } 156664f4763Szrj if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0) 157664f4763Szrj goto out; 158664f4763Szrj if ((server_host_key_blob = sshbuf_new()) == NULL) { 159664f4763Szrj r = SSH_ERR_ALLOC_FAIL; 160e9778795SPeter Avalos goto out; 161e9778795SPeter Avalos } 162664f4763Szrj if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0) 163e9778795SPeter Avalos goto out; 164664f4763Szrj 16518de8d7fSPeter Avalos /* calc H */ 166664f4763Szrj DH_get0_key(kex->dh, &pub_key, NULL); 167664f4763Szrj DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); 168e9778795SPeter Avalos hashlen = sizeof(hash); 169e9778795SPeter Avalos if ((r = kexgex_hash( 17036e94dc5SPeter Avalos kex->hash_alg, 171664f4763Szrj kex->client_version, 172664f4763Szrj kex->server_version, 173664f4763Szrj kex->peer, 174664f4763Szrj kex->my, 175664f4763Szrj server_host_key_blob, 176e9778795SPeter Avalos kex->min, kex->nbits, kex->max, 177664f4763Szrj dh_p, dh_g, 17818de8d7fSPeter Avalos dh_client_pub, 179664f4763Szrj pub_key, 180664f4763Szrj sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), 181e9778795SPeter Avalos hash, &hashlen)) != 0) 182e9778795SPeter Avalos goto out; 18318de8d7fSPeter Avalos 18418de8d7fSPeter Avalos /* sign H */ 185664f4763Szrj if ((r = kex->sign(ssh, server_host_private, server_host_public, 186664f4763Szrj &signature, &slen, hash, hashlen, kex->hostkey_alg)) < 0) 187e9778795SPeter Avalos goto out; 18818de8d7fSPeter Avalos 189664f4763Szrj /* send server hostkey, DH pubkey 'f' and signed H */ 190e9778795SPeter Avalos if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || 191664f4763Szrj (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 || 192664f4763Szrj (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || /* f */ 193e9778795SPeter Avalos (r = sshpkt_put_string(ssh, signature, slen)) != 0 || 194e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) 195e9778795SPeter Avalos goto out; 19618de8d7fSPeter Avalos 197664f4763Szrj if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) 198e9778795SPeter Avalos r = kex_send_newkeys(ssh); 199e9778795SPeter Avalos out: 200664f4763Szrj explicit_bzero(hash, sizeof(hash)); 201e9778795SPeter Avalos DH_free(kex->dh); 202e9778795SPeter Avalos kex->dh = NULL; 203e9778795SPeter Avalos BN_clear_free(dh_client_pub); 204664f4763Szrj sshbuf_free(shared_secret); 205664f4763Szrj sshbuf_free(server_host_key_blob); 206e9778795SPeter Avalos free(signature); 207e9778795SPeter Avalos return r; 208e9778795SPeter Avalos } 209e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 210