1323124Sdes/* $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 28295367Sdes#ifdef WITH_OPENSSL 29295367Sdes 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 39295367Sdes#include "sshkey.h" 40162852Sdes#include "cipher.h" 41295367Sdes#include "digest.h" 42113908Sdes#include "kex.h" 43113908Sdes#include "log.h" 44113908Sdes#include "packet.h" 45113908Sdes#include "dh.h" 46113908Sdes#include "ssh2.h" 47295367Sdes#include "dispatch.h" 48295367Sdes#include "compat.h" 49295367Sdes#include "ssherr.h" 50295367Sdes#include "sshbuf.h" 51113908Sdes 52295367Sdesstatic int input_kex_dh(int, u_int32_t, void *); 53295367Sdes 54295367Sdesint 55295367Sdeskexdh_client(struct ssh *ssh) 56113908Sdes{ 57295367Sdes struct kex *kex = ssh->kex; 58295367Sdes int r; 59113908Sdes 60113908Sdes /* generate and send 'e', client DH public key */ 61137015Sdes switch (kex->kex_type) { 62137015Sdes case KEX_DH_GRP1_SHA1: 63295367Sdes kex->dh = dh_new_group1(); 64137015Sdes break; 65137015Sdes case KEX_DH_GRP14_SHA1: 66323124Sdes case KEX_DH_GRP14_SHA256: 67295367Sdes kex->dh = dh_new_group14(); 68137015Sdes break; 69323124Sdes case KEX_DH_GRP16_SHA512: 70323124Sdes kex->dh = dh_new_group16(); 71323124Sdes break; 72323124Sdes case KEX_DH_GRP18_SHA512: 73323124Sdes kex->dh = dh_new_group18(); 74323124Sdes break; 75137015Sdes default: 76295367Sdes r = SSH_ERR_INVALID_ARGUMENT; 77295367Sdes goto out; 78137015Sdes } 79295367Sdes if (kex->dh == NULL) { 80295367Sdes r = SSH_ERR_ALLOC_FAIL; 81295367Sdes goto out; 82295367Sdes } 83113908Sdes debug("sending SSH2_MSG_KEXDH_INIT"); 84295367Sdes if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || 85295367Sdes (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 || 86295367Sdes (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || 87295367Sdes (r = sshpkt_send(ssh)) != 0) 88295367Sdes goto out; 89113908Sdes#ifdef DEBUG_KEXDH 90295367Sdes DHparams_print_fp(stderr, kex->dh); 91113908Sdes fprintf(stderr, "pub= "); 92295367Sdes BN_print_fp(stderr, kex->dh->pub_key); 93113908Sdes fprintf(stderr, "\n"); 94113908Sdes#endif 95113908Sdes debug("expecting SSH2_MSG_KEXDH_REPLY"); 96295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh); 97295367Sdes r = 0; 98295367Sdes out: 99295367Sdes return r; 100295367Sdes} 101113908Sdes 102295367Sdesstatic int 103295367Sdesinput_kex_dh(int type, u_int32_t seq, void *ctxt) 104295367Sdes{ 105295367Sdes struct ssh *ssh = ctxt; 106295367Sdes struct kex *kex = ssh->kex; 107295367Sdes BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 108295367Sdes struct sshkey *server_host_key = NULL; 109295367Sdes u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL; 110295367Sdes u_char hash[SSH_DIGEST_MAX_LENGTH]; 111295367Sdes size_t klen = 0, slen, sbloblen, hashlen; 112295367Sdes int kout, r; 113295367Sdes 114295367Sdes if (kex->verify_host_key == NULL) { 115295367Sdes r = SSH_ERR_INVALID_ARGUMENT; 116295367Sdes goto out; 117295367Sdes } 118113908Sdes /* key, cert */ 119295367Sdes if ((r = sshpkt_get_string(ssh, &server_host_key_blob, 120295367Sdes &sbloblen)) != 0 || 121295367Sdes (r = sshkey_from_blob(server_host_key_blob, sbloblen, 122295367Sdes &server_host_key)) != 0) 123295367Sdes goto out; 124295367Sdes if (server_host_key->type != kex->hostkey_type || 125295367Sdes (kex->hostkey_type == KEY_ECDSA && 126295367Sdes server_host_key->ecdsa_nid != kex->hostkey_nid)) { 127295367Sdes r = SSH_ERR_KEY_TYPE_MISMATCH; 128295367Sdes goto out; 129295367Sdes } 130295367Sdes if (kex->verify_host_key(server_host_key, ssh) == -1) { 131295367Sdes r = SSH_ERR_SIGNATURE_INVALID; 132295367Sdes goto out; 133295367Sdes } 134162852Sdes /* DH parameter f, server public DH key */ 135295367Sdes if ((dh_server_pub = BN_new()) == NULL) { 136295367Sdes r = SSH_ERR_ALLOC_FAIL; 137295367Sdes goto out; 138295367Sdes } 139295367Sdes /* signed H */ 140295367Sdes if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || 141295367Sdes (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || 142295367Sdes (r = sshpkt_get_end(ssh)) != 0) 143295367Sdes 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 150295367Sdes if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { 151295367Sdes sshpkt_disconnect(ssh, "bad server public DH value"); 152295367Sdes r = SSH_ERR_MESSAGE_INCOMPLETE; 153295367Sdes goto out; 154295367Sdes } 155113908Sdes 156295367Sdes klen = DH_size(kex->dh); 157295367Sdes if ((kbuf = malloc(klen)) == NULL || 158295367Sdes (shared_secret = BN_new()) == NULL) { 159295367Sdes r = SSH_ERR_ALLOC_FAIL; 160295367Sdes goto out; 161295367Sdes } 162295367Sdes if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || 163295367Sdes BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 164295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 165295367Sdes goto out; 166295367Sdes } 167113908Sdes#ifdef DEBUG_KEXDH 168113908Sdes dump_digest("shared secret", kbuf, kout); 169113908Sdes#endif 170113908Sdes 171113908Sdes /* calc and verify H */ 172295367Sdes hashlen = sizeof(hash); 173295367Sdes if ((r = kex_dh_hash( 174323124Sdes kex->hash_alg, 175113908Sdes kex->client_version_string, 176113908Sdes kex->server_version_string, 177295367Sdes sshbuf_ptr(kex->my), sshbuf_len(kex->my), 178295367Sdes sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 179113908Sdes server_host_key_blob, sbloblen, 180295367Sdes kex->dh->pub_key, 181113908Sdes dh_server_pub, 182157016Sdes shared_secret, 183295367Sdes hash, &hashlen)) != 0) 184295367Sdes goto out; 185113908Sdes 186295367Sdes if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, 187295367Sdes ssh->compat)) != 0) 188295367Sdes goto out; 189113908Sdes 190113908Sdes /* save session id */ 191113908Sdes if (kex->session_id == NULL) { 192157016Sdes kex->session_id_len = hashlen; 193295367Sdes kex->session_id = malloc(kex->session_id_len); 194295367Sdes if (kex->session_id == NULL) { 195295367Sdes r = SSH_ERR_ALLOC_FAIL; 196295367Sdes goto out; 197295367Sdes } 198113908Sdes memcpy(kex->session_id, hash, kex->session_id_len); 199113908Sdes } 200113908Sdes 201295367Sdes if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) 202295367Sdes r = kex_send_newkeys(ssh); 203295367Sdes out: 204295367Sdes explicit_bzero(hash, sizeof(hash)); 205295367Sdes DH_free(kex->dh); 206295367Sdes kex->dh = NULL; 207295367Sdes if (dh_server_pub) 208295367Sdes BN_clear_free(dh_server_pub); 209295367Sdes if (kbuf) { 210295367Sdes explicit_bzero(kbuf, klen); 211295367Sdes free(kbuf); 212295367Sdes } 213295367Sdes if (shared_secret) 214295367Sdes BN_clear_free(shared_secret); 215295367Sdes sshkey_free(server_host_key); 216295367Sdes free(server_host_key_blob); 217295367Sdes free(signature); 218295367Sdes return r; 219113908Sdes} 220295367Sdes#endif /* WITH_OPENSSL */ 221