1295367Sdes/* $OpenBSD: kexgexc.c,v 1.22 2015/05/26 23:23:40 dtucker Exp $ */ 2113908Sdes/* 3113908Sdes * Copyright (c) 2000 Niels Provos. All rights reserved. 4113908Sdes * Copyright (c) 2001 Markus Friedl. All rights reserved. 5113908Sdes * 6113908Sdes * Redistribution and use in source and binary forms, with or without 7113908Sdes * modification, are permitted provided that the following conditions 8113908Sdes * are met: 9113908Sdes * 1. Redistributions of source code must retain the above copyright 10113908Sdes * notice, this list of conditions and the following disclaimer. 11113908Sdes * 2. Redistributions in binary form must reproduce the above copyright 12113908Sdes * notice, this list of conditions and the following disclaimer in the 13113908Sdes * documentation and/or other materials provided with the distribution. 14113908Sdes * 15113908Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16113908Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17113908Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18113908Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19113908Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20113908Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21113908Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22113908Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23113908Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24113908Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25113908Sdes */ 26113908Sdes 27113908Sdes#include "includes.h" 28113908Sdes 29295367Sdes#ifdef WITH_OPENSSL 30295367Sdes 31295367Sdes#include <sys/param.h> 32162852Sdes#include <sys/types.h> 33162852Sdes 34221420Sdes#include <openssl/dh.h> 35221420Sdes 36162852Sdes#include <stdarg.h> 37162852Sdes#include <stdio.h> 38162852Sdes#include <string.h> 39162852Sdes#include <signal.h> 40162852Sdes 41295367Sdes#include "sshkey.h" 42162852Sdes#include "cipher.h" 43295367Sdes#include "digest.h" 44113908Sdes#include "kex.h" 45113908Sdes#include "log.h" 46113908Sdes#include "packet.h" 47113908Sdes#include "dh.h" 48113908Sdes#include "ssh2.h" 49113908Sdes#include "compat.h" 50295367Sdes#include "dispatch.h" 51295367Sdes#include "ssherr.h" 52295367Sdes#include "sshbuf.h" 53113908Sdes 54295367Sdesstatic int input_kex_dh_gex_group(int, u_int32_t, void *); 55295367Sdesstatic int input_kex_dh_gex_reply(int, u_int32_t, void *); 56295367Sdes 57295367Sdesint 58295367Sdeskexgex_client(struct ssh *ssh) 59113908Sdes{ 60295367Sdes struct kex *kex = ssh->kex; 61295367Sdes int r; 62295367Sdes u_int nbits; 63113908Sdes 64262566Sdes nbits = dh_estimate(kex->dh_need * 8); 65113908Sdes 66295367Sdes kex->min = DH_GRP_MIN; 67295367Sdes kex->max = DH_GRP_MAX; 68295367Sdes kex->nbits = nbits; 69295367Sdes if (datafellows & SSH_BUG_DHGEX_LARGE) 70295367Sdes kex->nbits = MIN(kex->nbits, 4096); 71295367Sdes /* New GEX request */ 72295367Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 || 73295367Sdes (r = sshpkt_put_u32(ssh, kex->min)) != 0 || 74295367Sdes (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || 75295367Sdes (r = sshpkt_put_u32(ssh, kex->max)) != 0 || 76295367Sdes (r = sshpkt_send(ssh)) != 0) 77295367Sdes goto out; 78295367Sdes debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent", 79295367Sdes kex->min, kex->nbits, kex->max); 80113908Sdes#ifdef DEBUG_KEXDH 81113908Sdes fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", 82295367Sdes kex->min, kex->nbits, kex->max); 83113908Sdes#endif 84295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, 85295367Sdes &input_kex_dh_gex_group); 86295367Sdes r = 0; 87295367Sdes out: 88295367Sdes return r; 89295367Sdes} 90113908Sdes 91295367Sdesstatic int 92295367Sdesinput_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt) 93295367Sdes{ 94295367Sdes struct ssh *ssh = ctxt; 95295367Sdes struct kex *kex = ssh->kex; 96295367Sdes BIGNUM *p = NULL, *g = NULL; 97295367Sdes int r, bits; 98113908Sdes 99295367Sdes debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); 100113908Sdes 101295367Sdes if ((p = BN_new()) == NULL || 102295367Sdes (g = BN_new()) == NULL) { 103295367Sdes r = SSH_ERR_ALLOC_FAIL; 104295367Sdes goto out; 105295367Sdes } 106295367Sdes if ((r = sshpkt_get_bignum2(ssh, p)) != 0 || 107295367Sdes (r = sshpkt_get_bignum2(ssh, g)) != 0 || 108295367Sdes (r = sshpkt_get_end(ssh)) != 0) 109295367Sdes goto out; 110295367Sdes if ((bits = BN_num_bits(p)) < 0 || 111295367Sdes (u_int)bits < kex->min || (u_int)bits > kex->max) { 112295367Sdes r = SSH_ERR_DH_GEX_OUT_OF_RANGE; 113295367Sdes goto out; 114295367Sdes } 115295367Sdes if ((kex->dh = dh_new_group(g, p)) == NULL) { 116295367Sdes r = SSH_ERR_ALLOC_FAIL; 117295367Sdes goto out; 118295367Sdes } 119295367Sdes p = g = NULL; /* belong to kex->dh now */ 120113908Sdes 121295367Sdes /* generate and send 'e', client DH public key */ 122295367Sdes if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || 123295367Sdes (r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 || 124295367Sdes (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || 125295367Sdes (r = sshpkt_send(ssh)) != 0) 126295367Sdes goto out; 127295367Sdes debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); 128113908Sdes#ifdef DEBUG_KEXDH 129295367Sdes DHparams_print_fp(stderr, kex->dh); 130113908Sdes fprintf(stderr, "pub= "); 131295367Sdes BN_print_fp(stderr, kex->dh->pub_key); 132113908Sdes fprintf(stderr, "\n"); 133113908Sdes#endif 134295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL); 135295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply); 136295367Sdes r = 0; 137295367Sdesout: 138295367Sdes if (p) 139295367Sdes BN_clear_free(p); 140295367Sdes if (g) 141295367Sdes BN_clear_free(g); 142295367Sdes return r; 143295367Sdes} 144113908Sdes 145295367Sdesstatic int 146295367Sdesinput_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt) 147295367Sdes{ 148295367Sdes struct ssh *ssh = ctxt; 149295367Sdes struct kex *kex = ssh->kex; 150295367Sdes BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 151295367Sdes struct sshkey *server_host_key = NULL; 152295367Sdes u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; 153295367Sdes u_char hash[SSH_DIGEST_MAX_LENGTH]; 154295367Sdes size_t klen = 0, slen, sbloblen, hashlen; 155295367Sdes int kout, r; 156113908Sdes 157295367Sdes debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); 158295367Sdes if (kex->verify_host_key == NULL) { 159295367Sdes r = SSH_ERR_INVALID_ARGUMENT; 160295367Sdes goto out; 161295367Sdes } 162113908Sdes /* key, cert */ 163295367Sdes if ((r = sshpkt_get_string(ssh, &server_host_key_blob, 164295367Sdes &sbloblen)) != 0 || 165295367Sdes (r = sshkey_from_blob(server_host_key_blob, sbloblen, 166295367Sdes &server_host_key)) != 0) 167295367Sdes goto out; 168295367Sdes if (server_host_key->type != kex->hostkey_type) { 169295367Sdes r = SSH_ERR_KEY_TYPE_MISMATCH; 170295367Sdes goto out; 171295367Sdes } 172295367Sdes if (server_host_key->type != kex->hostkey_type || 173295367Sdes (kex->hostkey_type == KEY_ECDSA && 174295367Sdes server_host_key->ecdsa_nid != kex->hostkey_nid)) { 175295367Sdes r = SSH_ERR_KEY_TYPE_MISMATCH; 176295367Sdes goto out; 177295367Sdes } 178295367Sdes if (kex->verify_host_key(server_host_key, ssh) == -1) { 179295367Sdes r = SSH_ERR_SIGNATURE_INVALID; 180295367Sdes goto out; 181295367Sdes } 182162852Sdes /* DH parameter f, server public DH key */ 183295367Sdes if ((dh_server_pub = BN_new()) == NULL) { 184295367Sdes r = SSH_ERR_ALLOC_FAIL; 185295367Sdes goto out; 186295367Sdes } 187295367Sdes /* signed H */ 188295367Sdes if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || 189295367Sdes (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || 190295367Sdes (r = sshpkt_get_end(ssh)) != 0) 191295367Sdes goto out; 192113908Sdes#ifdef DEBUG_KEXDH 193113908Sdes fprintf(stderr, "dh_server_pub= "); 194113908Sdes BN_print_fp(stderr, dh_server_pub); 195113908Sdes fprintf(stderr, "\n"); 196113908Sdes debug("bits %d", BN_num_bits(dh_server_pub)); 197113908Sdes#endif 198295367Sdes if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { 199295367Sdes sshpkt_disconnect(ssh, "bad server public DH value"); 200295367Sdes r = SSH_ERR_MESSAGE_INCOMPLETE; 201295367Sdes goto out; 202295367Sdes } 203113908Sdes 204295367Sdes klen = DH_size(kex->dh); 205295367Sdes if ((kbuf = malloc(klen)) == NULL || 206295367Sdes (shared_secret = BN_new()) == NULL) { 207295367Sdes r = SSH_ERR_ALLOC_FAIL; 208295367Sdes goto out; 209295367Sdes } 210295367Sdes if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || 211295367Sdes BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 212295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 213295367Sdes goto out; 214295367Sdes } 215113908Sdes#ifdef DEBUG_KEXDH 216113908Sdes dump_digest("shared secret", kbuf, kout); 217113908Sdes#endif 218295367Sdes if (ssh->compat & SSH_OLD_DHGEX) 219295367Sdes kex->min = kex->max = -1; 220113908Sdes 221113908Sdes /* calc and verify H */ 222295367Sdes hashlen = sizeof(hash); 223295367Sdes if ((r = kexgex_hash( 224262566Sdes kex->hash_alg, 225113908Sdes kex->client_version_string, 226113908Sdes kex->server_version_string, 227295367Sdes sshbuf_ptr(kex->my), sshbuf_len(kex->my), 228295367Sdes sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 229113908Sdes server_host_key_blob, sbloblen, 230295367Sdes kex->min, kex->nbits, kex->max, 231295367Sdes kex->dh->p, kex->dh->g, 232295367Sdes kex->dh->pub_key, 233113908Sdes dh_server_pub, 234157016Sdes shared_secret, 235295367Sdes hash, &hashlen)) != 0) 236295367Sdes goto out; 237157016Sdes 238295367Sdes if ((r = sshkey_verify(server_host_key, signature, slen, hash, 239295367Sdes hashlen, ssh->compat)) != 0) 240295367Sdes goto out; 241113908Sdes 242113908Sdes /* save session id */ 243113908Sdes if (kex->session_id == NULL) { 244157016Sdes kex->session_id_len = hashlen; 245295367Sdes kex->session_id = malloc(kex->session_id_len); 246295367Sdes if (kex->session_id == NULL) { 247295367Sdes r = SSH_ERR_ALLOC_FAIL; 248295367Sdes goto out; 249295367Sdes } 250113908Sdes memcpy(kex->session_id, hash, kex->session_id_len); 251113908Sdes } 252113908Sdes 253295367Sdes if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) 254295367Sdes r = kex_send_newkeys(ssh); 255295367Sdes out: 256295367Sdes explicit_bzero(hash, sizeof(hash)); 257295367Sdes DH_free(kex->dh); 258295367Sdes kex->dh = NULL; 259295367Sdes if (dh_server_pub) 260295367Sdes BN_clear_free(dh_server_pub); 261295367Sdes if (kbuf) { 262295367Sdes explicit_bzero(kbuf, klen); 263295367Sdes free(kbuf); 264295367Sdes } 265295367Sdes if (shared_secret) 266295367Sdes BN_clear_free(shared_secret); 267295367Sdes sshkey_free(server_host_key); 268295367Sdes free(server_host_key_blob); 269295367Sdes free(signature); 270295367Sdes return r; 271113908Sdes} 272295367Sdes#endif /* WITH_OPENSSL */ 273