1d059297112922cabb0c674840589be8db821fd9aAdam Langley/* $OpenBSD: kexdhc.c,v 1.18 2015/01/26 06:10:03 djm Exp $ */ 2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2001 Markus Friedl. All rights reserved. 4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without 6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions 7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met: 8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright 9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer. 10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright 11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer in the 12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * documentation and/or other materials provided with the distribution. 13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h" 27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 28d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL 29d059297112922cabb0c674840589be8db821fd9aAdam Langley 30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h> 31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <openssl/dh.h> 33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h> 35bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdio.h> 36bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h> 37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <signal.h> 38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 39d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshkey.h" 40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "cipher.h" 41d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "digest.h" 42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "kex.h" 43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h" 44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "packet.h" 45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "dh.h" 46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh2.h" 47d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "dispatch.h" 48d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "compat.h" 49d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h" 50d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h" 51d059297112922cabb0c674840589be8db821fd9aAdam Langley 52d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int input_kex_dh(int, u_int32_t, void *); 53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 54d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 55d059297112922cabb0c674840589be8db821fd9aAdam Langleykexdh_client(struct ssh *ssh) 56bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 57d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 58d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 60bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* generate and send 'e', client DH public key */ 61bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman switch (kex->kex_type) { 62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case KEX_DH_GRP1_SHA1: 63d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->dh = dh_new_group1(); 64bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case KEX_DH_GRP14_SHA1: 66d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->dh = dh_new_group14(); 67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 68bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman default: 69d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_INVALID_ARGUMENT; 70d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 71d059297112922cabb0c674840589be8db821fd9aAdam Langley } 72d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->dh == NULL) { 73d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 74d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 75bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 76bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("sending SSH2_MSG_KEXDH_INIT"); 77d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || 78d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 || 79d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || 80d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_send(ssh)) != 0) 81d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 82bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEXDH 83d059297112922cabb0c674840589be8db821fd9aAdam Langley DHparams_print_fp(stderr, kex->dh); 84bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fprintf(stderr, "pub= "); 85d059297112922cabb0c674840589be8db821fd9aAdam Langley BN_print_fp(stderr, kex->dh->pub_key); 86bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fprintf(stderr, "\n"); 87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 88bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("expecting SSH2_MSG_KEXDH_REPLY"); 89d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh); 90d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 91d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 92d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 93d059297112922cabb0c674840589be8db821fd9aAdam Langley} 94bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 95d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 96d059297112922cabb0c674840589be8db821fd9aAdam Langleyinput_kex_dh(int type, u_int32_t seq, void *ctxt) 97d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 98d059297112922cabb0c674840589be8db821fd9aAdam Langley struct ssh *ssh = ctxt; 99d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 100d059297112922cabb0c674840589be8db821fd9aAdam Langley BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 101d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sshkey *server_host_key = NULL; 102d059297112922cabb0c674840589be8db821fd9aAdam Langley u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL; 103d059297112922cabb0c674840589be8db821fd9aAdam Langley u_char hash[SSH_DIGEST_MAX_LENGTH]; 104d059297112922cabb0c674840589be8db821fd9aAdam Langley size_t klen = 0, slen, sbloblen, hashlen; 105d059297112922cabb0c674840589be8db821fd9aAdam Langley int kout, r; 106d059297112922cabb0c674840589be8db821fd9aAdam Langley 107d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->verify_host_key == NULL) { 108d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_INVALID_ARGUMENT; 109d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 110d059297112922cabb0c674840589be8db821fd9aAdam Langley } 111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* key, cert */ 112d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_get_string(ssh, &server_host_key_blob, 113d059297112922cabb0c674840589be8db821fd9aAdam Langley &sbloblen)) != 0 || 114d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshkey_from_blob(server_host_key_blob, sbloblen, 115d059297112922cabb0c674840589be8db821fd9aAdam Langley &server_host_key)) != 0) 116d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 117d059297112922cabb0c674840589be8db821fd9aAdam Langley if (server_host_key->type != kex->hostkey_type || 118d059297112922cabb0c674840589be8db821fd9aAdam Langley (kex->hostkey_type == KEY_ECDSA && 119d059297112922cabb0c674840589be8db821fd9aAdam Langley server_host_key->ecdsa_nid != kex->hostkey_nid)) { 120d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_KEY_TYPE_MISMATCH; 121d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 122d059297112922cabb0c674840589be8db821fd9aAdam Langley } 123d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->verify_host_key(server_host_key, ssh) == -1) { 124d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_SIGNATURE_INVALID; 125d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 126d059297112922cabb0c674840589be8db821fd9aAdam Langley } 127bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* DH parameter f, server public DH key */ 128d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((dh_server_pub = BN_new()) == NULL) { 129d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 130d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 131d059297112922cabb0c674840589be8db821fd9aAdam Langley } 132d059297112922cabb0c674840589be8db821fd9aAdam Langley /* signed H */ 133d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || 134d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || 135d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_get_end(ssh)) != 0) 136d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEXDH 138bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fprintf(stderr, "dh_server_pub= "); 139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman BN_print_fp(stderr, dh_server_pub); 140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fprintf(stderr, "\n"); 141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("bits %d", BN_num_bits(dh_server_pub)); 142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 143d059297112922cabb0c674840589be8db821fd9aAdam Langley if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { 144d059297112922cabb0c674840589be8db821fd9aAdam Langley sshpkt_disconnect(ssh, "bad server public DH value"); 145d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_MESSAGE_INCOMPLETE; 146d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 147d059297112922cabb0c674840589be8db821fd9aAdam Langley } 148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 149d059297112922cabb0c674840589be8db821fd9aAdam Langley klen = DH_size(kex->dh); 150d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((kbuf = malloc(klen)) == NULL || 151d059297112922cabb0c674840589be8db821fd9aAdam Langley (shared_secret = BN_new()) == NULL) { 152d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 153d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 154d059297112922cabb0c674840589be8db821fd9aAdam Langley } 155d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || 156d059297112922cabb0c674840589be8db821fd9aAdam Langley BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 157d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_LIBCRYPTO_ERROR; 158d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 159d059297112922cabb0c674840589be8db821fd9aAdam Langley } 160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEXDH 161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman dump_digest("shared secret", kbuf, kout); 162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* calc and verify H */ 165d059297112922cabb0c674840589be8db821fd9aAdam Langley hashlen = sizeof(hash); 166d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_dh_hash( 167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->client_version_string, 168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->server_version_string, 169d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_ptr(kex->my), sshbuf_len(kex->my), 170d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman server_host_key_blob, sbloblen, 172d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->dh->pub_key, 173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman dh_server_pub, 174bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman shared_secret, 175d059297112922cabb0c674840589be8db821fd9aAdam Langley hash, &hashlen)) != 0) 176d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 178d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, 179d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh->compat)) != 0) 180d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* save session id */ 183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (kex->session_id == NULL) { 184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->session_id_len = hashlen; 185d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->session_id = malloc(kex->session_id_len); 186d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->session_id == NULL) { 187d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 188d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 189d059297112922cabb0c674840589be8db821fd9aAdam Langley } 190bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman memcpy(kex->session_id, hash, kex->session_id_len); 191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 193d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) 194d059297112922cabb0c674840589be8db821fd9aAdam Langley r = kex_send_newkeys(ssh); 195d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 196d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(hash, sizeof(hash)); 197d059297112922cabb0c674840589be8db821fd9aAdam Langley DH_free(kex->dh); 198d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->dh = NULL; 199d059297112922cabb0c674840589be8db821fd9aAdam Langley if (dh_server_pub) 200d059297112922cabb0c674840589be8db821fd9aAdam Langley BN_clear_free(dh_server_pub); 201d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kbuf) { 202d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(kbuf, klen); 203d059297112922cabb0c674840589be8db821fd9aAdam Langley free(kbuf); 204d059297112922cabb0c674840589be8db821fd9aAdam Langley } 205d059297112922cabb0c674840589be8db821fd9aAdam Langley if (shared_secret) 206d059297112922cabb0c674840589be8db821fd9aAdam Langley BN_clear_free(shared_secret); 207d059297112922cabb0c674840589be8db821fd9aAdam Langley sshkey_free(server_host_key); 208d059297112922cabb0c674840589be8db821fd9aAdam Langley free(server_host_key_blob); 209d059297112922cabb0c674840589be8db821fd9aAdam Langley free(signature); 210d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 212d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_OPENSSL */ 213