kexecdhc.c revision 261320
1236769Sobrien/* $OpenBSD: kexecdhc.c,v 1.6 2014/01/12 08:13:13 djm Exp $ */ 2236769Sobrien/* 3236769Sobrien * Copyright (c) 2001 Markus Friedl. All rights reserved. 4236769Sobrien * Copyright (c) 2010 Damien Miller. All rights reserved. 5236769Sobrien * 6236769Sobrien * Redistribution and use in source and binary forms, with or without 7236769Sobrien * modification, are permitted provided that the following conditions 8236769Sobrien * are met: 9236769Sobrien * 1. Redistributions of source code must retain the above copyright 10236769Sobrien * notice, this list of conditions and the following disclaimer. 11236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12236769Sobrien * notice, this list of conditions and the following disclaimer in the 13236769Sobrien * documentation and/or other materials provided with the distribution. 14236769Sobrien * 15236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16236769Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17236769Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18236769Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19236769Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20236769Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21236769Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22236769Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23236769Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24236769Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25236769Sobrien */ 26236769Sobrien 27236769Sobrien#include "includes.h" 28236769Sobrien 29236769Sobrien#include <sys/types.h> 30236769Sobrien 31236769Sobrien#include <stdio.h> 32236769Sobrien#include <string.h> 33236769Sobrien#include <signal.h> 34236769Sobrien 35236769Sobrien#include "xmalloc.h" 36236769Sobrien#include "buffer.h" 37236769Sobrien#include "key.h" 38236769Sobrien#include "cipher.h" 39236769Sobrien#include "kex.h" 40236769Sobrien#include "log.h" 41236769Sobrien#include "packet.h" 42236769Sobrien#include "dh.h" 43236769Sobrien#include "ssh2.h" 44236769Sobrien 45236769Sobrien#ifdef OPENSSL_HAS_ECC 46236769Sobrien 47236769Sobrien#include <openssl/ecdh.h> 48236769Sobrien 49236769Sobrienvoid 50236769Sobrienkexecdh_client(Kex *kex) 51236769Sobrien{ 52236769Sobrien EC_KEY *client_key; 53236769Sobrien EC_POINT *server_public; 54236769Sobrien const EC_GROUP *group; 55236769Sobrien BIGNUM *shared_secret; 56236769Sobrien Key *server_host_key; 57236769Sobrien u_char *server_host_key_blob = NULL, *signature = NULL; 58236769Sobrien u_char *kbuf, *hash; 59236769Sobrien u_int klen, slen, sbloblen, hashlen; 60236769Sobrien 61236769Sobrien if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) 62236769Sobrien fatal("%s: EC_KEY_new_by_curve_name failed", __func__); 63236769Sobrien if (EC_KEY_generate_key(client_key) != 1) 64236769Sobrien fatal("%s: EC_KEY_generate_key failed", __func__); 65236769Sobrien group = EC_KEY_get0_group(client_key); 66236769Sobrien 67236769Sobrien packet_start(SSH2_MSG_KEX_ECDH_INIT); 68236769Sobrien packet_put_ecpoint(group, EC_KEY_get0_public_key(client_key)); 69236769Sobrien packet_send(); 70236769Sobrien debug("sending SSH2_MSG_KEX_ECDH_INIT"); 71236769Sobrien 72236769Sobrien#ifdef DEBUG_KEXECDH 73236769Sobrien fputs("client private key:\n", stderr); 74236769Sobrien key_dump_ec_key(client_key); 75236769Sobrien#endif 76236769Sobrien 77236769Sobrien debug("expecting SSH2_MSG_KEX_ECDH_REPLY"); 78236769Sobrien packet_read_expect(SSH2_MSG_KEX_ECDH_REPLY); 79236769Sobrien 80236769Sobrien /* hostkey */ 81236769Sobrien server_host_key_blob = packet_get_string(&sbloblen); 82236769Sobrien server_host_key = key_from_blob(server_host_key_blob, sbloblen); 83236769Sobrien if (server_host_key == NULL) 84236769Sobrien fatal("cannot decode server_host_key_blob"); 85236769Sobrien if (server_host_key->type != kex->hostkey_type) 86236769Sobrien fatal("type mismatch for decoded server_host_key_blob"); 87236769Sobrien if (kex->verify_host_key == NULL) 88236769Sobrien fatal("cannot verify server_host_key"); 89236769Sobrien if (kex->verify_host_key(server_host_key) == -1) 90236769Sobrien fatal("server_host_key verification failed"); 91 92 /* Q_S, server public key */ 93 if ((server_public = EC_POINT_new(group)) == NULL) 94 fatal("%s: EC_POINT_new failed", __func__); 95 packet_get_ecpoint(group, server_public); 96 97 if (key_ec_validate_public(group, server_public) != 0) 98 fatal("%s: invalid server public key", __func__); 99 100#ifdef DEBUG_KEXECDH 101 fputs("server public key:\n", stderr); 102 key_dump_ec_point(group, server_public); 103#endif 104 105 /* signed H */ 106 signature = packet_get_string(&slen); 107 packet_check_eom(); 108 109 klen = (EC_GROUP_get_degree(group) + 7) / 8; 110 kbuf = xmalloc(klen); 111 if (ECDH_compute_key(kbuf, klen, server_public, 112 client_key, NULL) != (int)klen) 113 fatal("%s: ECDH_compute_key failed", __func__); 114 115#ifdef DEBUG_KEXECDH 116 dump_digest("shared secret", kbuf, klen); 117#endif 118 if ((shared_secret = BN_new()) == NULL) 119 fatal("%s: BN_new failed", __func__); 120 if (BN_bin2bn(kbuf, klen, shared_secret) == NULL) 121 fatal("%s: BN_bin2bn failed", __func__); 122 memset(kbuf, 0, klen); 123 free(kbuf); 124 125 /* calc and verify H */ 126 kex_ecdh_hash( 127 kex->hash_alg, 128 group, 129 kex->client_version_string, 130 kex->server_version_string, 131 buffer_ptr(&kex->my), buffer_len(&kex->my), 132 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 133 server_host_key_blob, sbloblen, 134 EC_KEY_get0_public_key(client_key), 135 server_public, 136 shared_secret, 137 &hash, &hashlen 138 ); 139 free(server_host_key_blob); 140 EC_POINT_clear_free(server_public); 141 EC_KEY_free(client_key); 142 143 if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) 144 fatal("key_verify failed for server_host_key"); 145 key_free(server_host_key); 146 free(signature); 147 148 /* save session id */ 149 if (kex->session_id == NULL) { 150 kex->session_id_len = hashlen; 151 kex->session_id = xmalloc(kex->session_id_len); 152 memcpy(kex->session_id, hash, kex->session_id_len); 153 } 154 155 kex_derive_keys_bn(kex, hash, hashlen, shared_secret); 156 BN_clear_free(shared_secret); 157 kex_finish(kex); 158} 159#else /* OPENSSL_HAS_ECC */ 160void 161kexecdh_client(Kex *kex) 162{ 163 fatal("ECC support is not enabled"); 164} 165#endif /* OPENSSL_HAS_ECC */ 166