1/* $NetBSD$ */ 2/* $OpenBSD: kexecdhs.c,v 1.2 2010/09/22 05:01:29 djm Exp $ */ 3/* 4 * Copyright (c) 2001 Markus Friedl. All rights reserved. 5 * Copyright (c) 2010 Damien Miller. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "includes.h" 29__RCSID("$NetBSD: progressmeter.c,v 1.3 2011/06/20 09:11:16 mrg Exp $"); 30#include <sys/types.h> 31#include <string.h> 32#include <signal.h> 33 34#include <openssl/ecdh.h> 35 36#include "xmalloc.h" 37#include "buffer.h" 38#include "key.h" 39#include "cipher.h" 40#include "kex.h" 41#include "log.h" 42#include "packet.h" 43#include "dh.h" 44#include "ssh2.h" 45#ifdef GSSAPI 46#include "ssh-gss.h" 47#endif 48#include "monitor_wrap.h" 49 50void 51kexecdh_server(Kex *kex) 52{ 53 EC_POINT *client_public; 54 EC_KEY *server_key; 55 const EC_GROUP *group; 56 BIGNUM *shared_secret; 57 Key *server_host_private, *server_host_public; 58 u_char *server_host_key_blob = NULL, *signature = NULL; 59 u_char *kbuf, *hash; 60 u_int klen, slen, sbloblen, hashlen; 61 int curve_nid; 62 63 if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1) 64 fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name); 65 if ((server_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL) 66 fatal("%s: EC_KEY_new_by_curve_name failed", __func__); 67 if (EC_KEY_generate_key(server_key) != 1) 68 fatal("%s: EC_KEY_generate_key failed", __func__); 69 group = EC_KEY_get0_group(server_key); 70 71#ifdef DEBUG_KEXECDH 72 fputs("server private key:\n", stderr); 73 key_dump_ec_key(server_key); 74#endif 75 76 if (kex->load_host_public_key == NULL || 77 kex->load_host_private_key == NULL) 78 fatal("Cannot load hostkey"); 79 server_host_public = kex->load_host_public_key(kex->hostkey_type); 80 if (server_host_public == NULL) 81 fatal("Unsupported hostkey type %d", kex->hostkey_type); 82 server_host_private = kex->load_host_private_key(kex->hostkey_type); 83 if (server_host_private == NULL) 84 fatal("Missing private key for hostkey type %d", 85 kex->hostkey_type); 86 87 debug("expecting SSH2_MSG_KEX_ECDH_INIT"); 88 packet_read_expect(SSH2_MSG_KEX_ECDH_INIT); 89 if ((client_public = EC_POINT_new(group)) == NULL) 90 fatal("%s: EC_POINT_new failed", __func__); 91 packet_get_ecpoint(group, client_public); 92 packet_check_eom(); 93 94 if (key_ec_validate_public(group, client_public) != 0) 95 fatal("%s: invalid client public key", __func__); 96 97#ifdef DEBUG_KEXECDH 98 fputs("client public key:\n", stderr); 99 key_dump_ec_point(group, client_public); 100#endif 101 102 /* Calculate shared_secret */ 103 klen = (EC_GROUP_get_degree(group) + 7) / 8; 104 kbuf = xmalloc(klen); 105 if (ECDH_compute_key(kbuf, klen, client_public, 106 server_key, NULL) != (int)klen) 107 fatal("%s: ECDH_compute_key failed", __func__); 108 109#ifdef DEBUG_KEXDH 110 dump_digest("shared secret", kbuf, klen); 111#endif 112 if ((shared_secret = BN_new()) == NULL) 113 fatal("%s: BN_new failed", __func__); 114 if (BN_bin2bn(kbuf, klen, shared_secret) == NULL) 115 fatal("%s: BN_bin2bn failed", __func__); 116 memset(kbuf, 0, klen); 117 xfree(kbuf); 118 119 /* calc H */ 120 key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); 121 kex_ecdh_hash( 122 kex->evp_md, 123 group, 124 kex->client_version_string, 125 kex->server_version_string, 126 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 127 buffer_ptr(&kex->my), buffer_len(&kex->my), 128 server_host_key_blob, sbloblen, 129 client_public, 130 EC_KEY_get0_public_key(server_key), 131 shared_secret, 132 &hash, &hashlen 133 ); 134 EC_POINT_clear_free(client_public); 135 136 /* save session id := H */ 137 if (kex->session_id == NULL) { 138 kex->session_id_len = hashlen; 139 kex->session_id = xmalloc(kex->session_id_len); 140 memcpy(kex->session_id, hash, kex->session_id_len); 141 } 142 143 /* sign H */ 144 if (PRIVSEP(key_sign(server_host_private, &signature, &slen, 145 hash, hashlen)) < 0) 146 fatal("kexdh_server: key_sign failed"); 147 148 /* destroy_sensitive_data(); */ 149 150 /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ 151 packet_start(SSH2_MSG_KEX_ECDH_REPLY); 152 packet_put_string(server_host_key_blob, sbloblen); 153 packet_put_ecpoint(group, EC_KEY_get0_public_key(server_key)); 154 packet_put_string(signature, slen); 155 packet_send(); 156 157 xfree(signature); 158 xfree(server_host_key_blob); 159 /* have keys, free server key */ 160 EC_KEY_free(server_key); 161 162 kex_derive_keys(kex, hash, hashlen, shared_secret); 163 BN_clear_free(shared_secret); 164 kex_finish(kex); 165} 166