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