19768ca48f57aaf035f508a473421d210b5145e99Greg Hartman/* $OpenBSD: kexecdhs.c,v 1.15 2015/12/04 16:41:28 markus Exp $ */ 2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2001 Markus Friedl. All rights reserved. 4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2010 Damien Miller. All rights reserved. 5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without 7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions 8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met: 9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright 10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer. 11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright 12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer in the 13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * documentation and/or other materials provided with the distribution. 14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h" 28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 29d059297112922cabb0c674840589be8db821fd9aAdam Langley#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) 30d059297112922cabb0c674840589be8db821fd9aAdam Langley 31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h> 32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h> 33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <signal.h> 34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 35d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <openssl/ecdh.h> 36d059297112922cabb0c674840589be8db821fd9aAdam Langley 37d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshkey.h" 38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "cipher.h" 39d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "digest.h" 40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "kex.h" 41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h" 42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "packet.h" 43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh2.h" 44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 45d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "dispatch.h" 46d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "compat.h" 47d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h" 48d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h" 49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 50d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int input_kex_ecdh_init(int, u_int32_t, void *); 51d059297112922cabb0c674840589be8db821fd9aAdam Langley 52d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 53d059297112922cabb0c674840589be8db821fd9aAdam Langleykexecdh_server(struct ssh *ssh) 54d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 55d059297112922cabb0c674840589be8db821fd9aAdam Langley debug("expecting SSH2_MSG_KEX_ECDH_INIT"); 56d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_ecdh_init); 57d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 58d059297112922cabb0c674840589be8db821fd9aAdam Langley} 59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 60d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 61d059297112922cabb0c674840589be8db821fd9aAdam Langleyinput_kex_ecdh_init(int type, u_int32_t seq, void *ctxt) 62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 63d059297112922cabb0c674840589be8db821fd9aAdam Langley struct ssh *ssh = ctxt; 64d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman EC_POINT *client_public; 66d059297112922cabb0c674840589be8db821fd9aAdam Langley EC_KEY *server_key = NULL; 67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const EC_GROUP *group; 68d059297112922cabb0c674840589be8db821fd9aAdam Langley const EC_POINT *public_key; 69d059297112922cabb0c674840589be8db821fd9aAdam Langley BIGNUM *shared_secret = NULL; 70d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sshkey *server_host_private, *server_host_public; 71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_char *server_host_key_blob = NULL, *signature = NULL; 72d059297112922cabb0c674840589be8db821fd9aAdam Langley u_char *kbuf = NULL; 73d059297112922cabb0c674840589be8db821fd9aAdam Langley u_char hash[SSH_DIGEST_MAX_LENGTH]; 74d059297112922cabb0c674840589be8db821fd9aAdam Langley size_t slen, sbloblen; 75d059297112922cabb0c674840589be8db821fd9aAdam Langley size_t klen = 0, hashlen; 76d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 77d059297112922cabb0c674840589be8db821fd9aAdam Langley 78d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { 79d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 80d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 81d059297112922cabb0c674840589be8db821fd9aAdam Langley } 82d059297112922cabb0c674840589be8db821fd9aAdam Langley if (EC_KEY_generate_key(server_key) != 1) { 83d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_LIBCRYPTO_ERROR; 84d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 85d059297112922cabb0c674840589be8db821fd9aAdam Langley } 86bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman group = EC_KEY_get0_group(server_key); 87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 88bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEXECDH 89bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fputs("server private key:\n", stderr); 90d059297112922cabb0c674840589be8db821fd9aAdam Langley sshkey_dump_ec_key(server_key); 91bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 92bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 93bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (kex->load_host_public_key == NULL || 94d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->load_host_private_key == NULL) { 95d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_INVALID_ARGUMENT; 96d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 97d059297112922cabb0c674840589be8db821fd9aAdam Langley } 98d059297112922cabb0c674840589be8db821fd9aAdam Langley server_host_public = kex->load_host_public_key(kex->hostkey_type, 99d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->hostkey_nid, ssh); 100d059297112922cabb0c674840589be8db821fd9aAdam Langley server_host_private = kex->load_host_private_key(kex->hostkey_type, 101d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->hostkey_nid, ssh); 102d059297112922cabb0c674840589be8db821fd9aAdam Langley if (server_host_public == NULL) { 103d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_NO_HOSTKEY_LOADED; 104d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 105d059297112922cabb0c674840589be8db821fd9aAdam Langley } 106d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((client_public = EC_POINT_new(group)) == NULL) { 107d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 108d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 109d059297112922cabb0c674840589be8db821fd9aAdam Langley } 110d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_get_ec(ssh, client_public, group)) != 0 || 111d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_get_end(ssh)) != 0) 112d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 114bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEXECDH 115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fputs("client public key:\n", stderr); 116d059297112922cabb0c674840589be8db821fd9aAdam Langley sshkey_dump_ec_point(group, client_public); 117bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 118d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sshkey_ec_validate_public(group, client_public) != 0) { 119d059297112922cabb0c674840589be8db821fd9aAdam Langley sshpkt_disconnect(ssh, "invalid client public key"); 120d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_MESSAGE_INCOMPLETE; 121d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 122d059297112922cabb0c674840589be8db821fd9aAdam Langley } 123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Calculate shared_secret */ 125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman klen = (EC_GROUP_get_degree(group) + 7) / 8; 126d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((kbuf = malloc(klen)) == NULL || 127d059297112922cabb0c674840589be8db821fd9aAdam Langley (shared_secret = BN_new()) == NULL) { 128d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 129d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 130d059297112922cabb0c674840589be8db821fd9aAdam Langley } 131bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (ECDH_compute_key(kbuf, klen, client_public, 132d059297112922cabb0c674840589be8db821fd9aAdam Langley server_key, NULL) != (int)klen || 133d059297112922cabb0c674840589be8db821fd9aAdam Langley BN_bin2bn(kbuf, klen, shared_secret) == NULL) { 134d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_LIBCRYPTO_ERROR; 135d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 136d059297112922cabb0c674840589be8db821fd9aAdam Langley } 137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 138d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef DEBUG_KEXECDH 139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman dump_digest("shared secret", kbuf, klen); 140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* calc H */ 142d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, 143d059297112922cabb0c674840589be8db821fd9aAdam Langley &sbloblen)) != 0) 144d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 145d059297112922cabb0c674840589be8db821fd9aAdam Langley hashlen = sizeof(hash); 146d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_ecdh_hash( 147d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->hash_alg, 148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman group, 149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->client_version_string, 150bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->server_version_string, 151d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 152d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_ptr(kex->my), sshbuf_len(kex->my), 153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman server_host_key_blob, sbloblen, 154bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman client_public, 155bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman EC_KEY_get0_public_key(server_key), 156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman shared_secret, 157d059297112922cabb0c674840589be8db821fd9aAdam Langley hash, &hashlen)) != 0) 158d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* save session id := H */ 161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (kex->session_id == NULL) { 162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->session_id_len = hashlen; 163d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->session_id = malloc(kex->session_id_len); 164d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->session_id == NULL) { 165d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 166d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 167d059297112922cabb0c674840589be8db821fd9aAdam Langley } 168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman memcpy(kex->session_id, hash, kex->session_id_len); 169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* sign H */ 1729768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if ((r = kex->sign(server_host_private, server_host_public, &signature, 1739768ca48f57aaf035f508a473421d210b5145e99Greg Hartman &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0) 174d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* destroy_sensitive_data(); */ 177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 178d059297112922cabb0c674840589be8db821fd9aAdam Langley public_key = EC_KEY_get0_public_key(server_key); 179bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ 180d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || 181d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || 182d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_put_ec(ssh, public_key, group)) != 0 || 183d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_put_string(ssh, signature, slen)) != 0 || 184d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_send(ssh)) != 0) 185d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 186d059297112922cabb0c674840589be8db821fd9aAdam Langley 187d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) 188d059297112922cabb0c674840589be8db821fd9aAdam Langley r = kex_send_newkeys(ssh); 189d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 190d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(hash, sizeof(hash)); 191d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->ec_client_key) { 192d059297112922cabb0c674840589be8db821fd9aAdam Langley EC_KEY_free(kex->ec_client_key); 193d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->ec_client_key = NULL; 194d059297112922cabb0c674840589be8db821fd9aAdam Langley } 195d059297112922cabb0c674840589be8db821fd9aAdam Langley if (server_key) 196d059297112922cabb0c674840589be8db821fd9aAdam Langley EC_KEY_free(server_key); 197d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kbuf) { 198d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(kbuf, klen); 199d059297112922cabb0c674840589be8db821fd9aAdam Langley free(kbuf); 200d059297112922cabb0c674840589be8db821fd9aAdam Langley } 201d059297112922cabb0c674840589be8db821fd9aAdam Langley if (shared_secret) 202d059297112922cabb0c674840589be8db821fd9aAdam Langley BN_clear_free(shared_secret); 203d059297112922cabb0c674840589be8db821fd9aAdam Langley free(server_host_key_blob); 204d059297112922cabb0c674840589be8db821fd9aAdam Langley free(signature); 205d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 207d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ 208d059297112922cabb0c674840589be8db821fd9aAdam Langley 209