1323129Sdes/* $OpenBSD: kexdhc.c,v 1.19 2016/05/02 10:26:04 djm Exp $ */ 2113908Sdes/* 3113908Sdes * Copyright (c) 2001 Markus Friedl. All rights reserved. 4113908Sdes * 5113908Sdes * Redistribution and use in source and binary forms, with or without 6113908Sdes * modification, are permitted provided that the following conditions 7113908Sdes * are met: 8113908Sdes * 1. Redistributions of source code must retain the above copyright 9113908Sdes * notice, this list of conditions and the following disclaimer. 10113908Sdes * 2. Redistributions in binary form must reproduce the above copyright 11113908Sdes * notice, this list of conditions and the following disclaimer in the 12113908Sdes * documentation and/or other materials provided with the distribution. 13113908Sdes * 14113908Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15113908Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16113908Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17113908Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18113908Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19113908Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20113908Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21113908Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22113908Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23113908Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24113908Sdes */ 25113908Sdes 26113908Sdes#include "includes.h" 27113908Sdes 28294332Sdes#ifdef WITH_OPENSSL 29294332Sdes 30162852Sdes#include <sys/types.h> 31162852Sdes 32221420Sdes#include <openssl/dh.h> 33221420Sdes 34162852Sdes#include <stdarg.h> 35162852Sdes#include <stdio.h> 36162852Sdes#include <string.h> 37162852Sdes#include <signal.h> 38162852Sdes 39294332Sdes#include "sshkey.h" 40162852Sdes#include "cipher.h" 41294332Sdes#include "digest.h" 42113908Sdes#include "kex.h" 43113908Sdes#include "log.h" 44113908Sdes#include "packet.h" 45113908Sdes#include "dh.h" 46113908Sdes#include "ssh2.h" 47294332Sdes#include "dispatch.h" 48294332Sdes#include "compat.h" 49294332Sdes#include "ssherr.h" 50294332Sdes#include "sshbuf.h" 51113908Sdes 52294332Sdesstatic int input_kex_dh(int, u_int32_t, void *); 53294332Sdes 54294332Sdesint 55294332Sdeskexdh_client(struct ssh *ssh) 56113908Sdes{ 57294332Sdes struct kex *kex = ssh->kex; 58294332Sdes int r; 59113908Sdes 60113908Sdes /* generate and send 'e', client DH public key */ 61137015Sdes switch (kex->kex_type) { 62137015Sdes case KEX_DH_GRP1_SHA1: 63294332Sdes kex->dh = dh_new_group1(); 64137015Sdes break; 65137015Sdes case KEX_DH_GRP14_SHA1: 66323129Sdes case KEX_DH_GRP14_SHA256: 67294332Sdes kex->dh = dh_new_group14(); 68137015Sdes break; 69323129Sdes case KEX_DH_GRP16_SHA512: 70323129Sdes kex->dh = dh_new_group16(); 71323129Sdes break; 72323129Sdes case KEX_DH_GRP18_SHA512: 73323129Sdes kex->dh = dh_new_group18(); 74323129Sdes break; 75137015Sdes default: 76294332Sdes r = SSH_ERR_INVALID_ARGUMENT; 77294332Sdes goto out; 78137015Sdes } 79294332Sdes if (kex->dh == NULL) { 80294332Sdes r = SSH_ERR_ALLOC_FAIL; 81294332Sdes goto out; 82294332Sdes } 83113908Sdes debug("sending SSH2_MSG_KEXDH_INIT"); 84294332Sdes if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || 85294332Sdes (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 || 86294332Sdes (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || 87294332Sdes (r = sshpkt_send(ssh)) != 0) 88294332Sdes goto out; 89113908Sdes#ifdef DEBUG_KEXDH 90294332Sdes DHparams_print_fp(stderr, kex->dh); 91113908Sdes fprintf(stderr, "pub= "); 92294332Sdes BN_print_fp(stderr, kex->dh->pub_key); 93113908Sdes fprintf(stderr, "\n"); 94113908Sdes#endif 95113908Sdes debug("expecting SSH2_MSG_KEXDH_REPLY"); 96294332Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh); 97294332Sdes r = 0; 98294332Sdes out: 99294332Sdes return r; 100294332Sdes} 101113908Sdes 102294332Sdesstatic int 103294332Sdesinput_kex_dh(int type, u_int32_t seq, void *ctxt) 104294332Sdes{ 105294332Sdes struct ssh *ssh = ctxt; 106294332Sdes struct kex *kex = ssh->kex; 107294332Sdes BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 108294332Sdes struct sshkey *server_host_key = NULL; 109294332Sdes u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL; 110294332Sdes u_char hash[SSH_DIGEST_MAX_LENGTH]; 111294332Sdes size_t klen = 0, slen, sbloblen, hashlen; 112294332Sdes int kout, r; 113294332Sdes 114294332Sdes if (kex->verify_host_key == NULL) { 115294332Sdes r = SSH_ERR_INVALID_ARGUMENT; 116294332Sdes goto out; 117294332Sdes } 118113908Sdes /* key, cert */ 119294332Sdes if ((r = sshpkt_get_string(ssh, &server_host_key_blob, 120294332Sdes &sbloblen)) != 0 || 121294332Sdes (r = sshkey_from_blob(server_host_key_blob, sbloblen, 122294332Sdes &server_host_key)) != 0) 123294332Sdes goto out; 124294332Sdes if (server_host_key->type != kex->hostkey_type || 125294332Sdes (kex->hostkey_type == KEY_ECDSA && 126294332Sdes server_host_key->ecdsa_nid != kex->hostkey_nid)) { 127294332Sdes r = SSH_ERR_KEY_TYPE_MISMATCH; 128294332Sdes goto out; 129294332Sdes } 130294332Sdes if (kex->verify_host_key(server_host_key, ssh) == -1) { 131294332Sdes r = SSH_ERR_SIGNATURE_INVALID; 132294332Sdes goto out; 133294332Sdes } 134162852Sdes /* DH parameter f, server public DH key */ 135294332Sdes if ((dh_server_pub = BN_new()) == NULL) { 136294332Sdes r = SSH_ERR_ALLOC_FAIL; 137294332Sdes goto out; 138294332Sdes } 139294332Sdes /* signed H */ 140294332Sdes if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || 141294332Sdes (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || 142294332Sdes (r = sshpkt_get_end(ssh)) != 0) 143294332Sdes goto out; 144113908Sdes#ifdef DEBUG_KEXDH 145113908Sdes fprintf(stderr, "dh_server_pub= "); 146113908Sdes BN_print_fp(stderr, dh_server_pub); 147113908Sdes fprintf(stderr, "\n"); 148113908Sdes debug("bits %d", BN_num_bits(dh_server_pub)); 149113908Sdes#endif 150294332Sdes if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { 151294332Sdes sshpkt_disconnect(ssh, "bad server public DH value"); 152294332Sdes r = SSH_ERR_MESSAGE_INCOMPLETE; 153294332Sdes goto out; 154294332Sdes } 155113908Sdes 156294332Sdes klen = DH_size(kex->dh); 157294332Sdes if ((kbuf = malloc(klen)) == NULL || 158294332Sdes (shared_secret = BN_new()) == NULL) { 159294332Sdes r = SSH_ERR_ALLOC_FAIL; 160294332Sdes goto out; 161294332Sdes } 162294332Sdes if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || 163294332Sdes BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 164294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 165294332Sdes goto out; 166294332Sdes } 167113908Sdes#ifdef DEBUG_KEXDH 168113908Sdes dump_digest("shared secret", kbuf, kout); 169113908Sdes#endif 170113908Sdes 171113908Sdes /* calc and verify H */ 172294332Sdes hashlen = sizeof(hash); 173294332Sdes if ((r = kex_dh_hash( 174323129Sdes kex->hash_alg, 175113908Sdes kex->client_version_string, 176113908Sdes kex->server_version_string, 177294332Sdes sshbuf_ptr(kex->my), sshbuf_len(kex->my), 178294332Sdes sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 179113908Sdes server_host_key_blob, sbloblen, 180294332Sdes kex->dh->pub_key, 181113908Sdes dh_server_pub, 182157016Sdes shared_secret, 183294332Sdes hash, &hashlen)) != 0) 184294332Sdes goto out; 185113908Sdes 186294332Sdes if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, 187294332Sdes ssh->compat)) != 0) 188294332Sdes goto out; 189113908Sdes 190113908Sdes /* save session id */ 191113908Sdes if (kex->session_id == NULL) { 192157016Sdes kex->session_id_len = hashlen; 193294332Sdes kex->session_id = malloc(kex->session_id_len); 194294332Sdes if (kex->session_id == NULL) { 195294332Sdes r = SSH_ERR_ALLOC_FAIL; 196294332Sdes goto out; 197294332Sdes } 198113908Sdes memcpy(kex->session_id, hash, kex->session_id_len); 199113908Sdes } 200113908Sdes 201294332Sdes if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) 202294332Sdes r = kex_send_newkeys(ssh); 203294332Sdes out: 204294332Sdes explicit_bzero(hash, sizeof(hash)); 205294332Sdes DH_free(kex->dh); 206294332Sdes kex->dh = NULL; 207294332Sdes if (dh_server_pub) 208294332Sdes BN_clear_free(dh_server_pub); 209294332Sdes if (kbuf) { 210294332Sdes explicit_bzero(kbuf, klen); 211294332Sdes free(kbuf); 212294332Sdes } 213294332Sdes if (shared_secret) 214294332Sdes BN_clear_free(shared_secret); 215294332Sdes sshkey_free(server_host_key); 216294332Sdes free(server_host_key_blob); 217294332Sdes free(signature); 218294332Sdes return r; 219113908Sdes} 220294332Sdes#endif /* WITH_OPENSSL */ 221