1 /* $OpenBSD: kexc25519s.c,v 1.10 2015/12/04 16:41:28 markus Exp $ */ 2 /* 3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved. 5 * Copyright (c) 2013 Aris Adamantiadis. All rights reserved. 6 * 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "includes.h" 28 29 #include <sys/types.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <signal.h> 33 34 #include "sshkey.h" 35 #include "cipher.h" 36 #include "digest.h" 37 #include "kex.h" 38 #include "log.h" 39 #include "packet.h" 40 #include "ssh2.h" 41 #include "sshbuf.h" 42 #include "ssherr.h" 43 44 static int input_kex_c25519_init(int, u_int32_t, void *); 45 46 int 47 kexc25519_server(struct ssh *ssh) 48 { 49 debug("expecting SSH2_MSG_KEX_ECDH_INIT"); 50 ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_c25519_init); 51 return 0; 52 } 53 54 static int 55 input_kex_c25519_init(int type, u_int32_t seq, void *ctxt) 56 { 57 struct ssh *ssh = ctxt; 58 struct kex *kex = ssh->kex; 59 struct sshkey *server_host_private, *server_host_public; 60 struct sshbuf *shared_secret = NULL; 61 u_char *server_host_key_blob = NULL, *signature = NULL; 62 u_char server_key[CURVE25519_SIZE]; 63 u_char *client_pubkey = NULL; 64 u_char server_pubkey[CURVE25519_SIZE]; 65 u_char hash[SSH_DIGEST_MAX_LENGTH]; 66 size_t slen, pklen, sbloblen, hashlen; 67 int r; 68 69 /* generate private key */ 70 kexc25519_keygen(server_key, server_pubkey); 71 #ifdef DEBUG_KEXECDH 72 dump_digest("server private key:", server_key, sizeof(server_key)); 73 #endif 74 if (kex->load_host_public_key == NULL || 75 kex->load_host_private_key == NULL) { 76 r = SSH_ERR_INVALID_ARGUMENT; 77 goto out; 78 } 79 server_host_public = kex->load_host_public_key(kex->hostkey_type, 80 kex->hostkey_nid, ssh); 81 server_host_private = kex->load_host_private_key(kex->hostkey_type, 82 kex->hostkey_nid, ssh); 83 if (server_host_public == NULL) { 84 r = SSH_ERR_NO_HOSTKEY_LOADED; 85 goto out; 86 } 87 88 if ((r = sshpkt_get_string(ssh, &client_pubkey, &pklen)) != 0 || 89 (r = sshpkt_get_end(ssh)) != 0) 90 goto out; 91 if (pklen != CURVE25519_SIZE) { 92 r = SSH_ERR_SIGNATURE_INVALID; 93 goto out; 94 } 95 #ifdef DEBUG_KEXECDH 96 dump_digest("client public key:", client_pubkey, CURVE25519_SIZE); 97 #endif 98 99 if ((shared_secret = sshbuf_new()) == NULL) { 100 r = SSH_ERR_ALLOC_FAIL; 101 goto out; 102 } 103 if ((r = kexc25519_shared_key(server_key, client_pubkey, 104 shared_secret)) < 0) 105 goto out; 106 107 /* calc H */ 108 if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, 109 &sbloblen)) != 0) 110 goto out; 111 hashlen = sizeof(hash); 112 if ((r = kex_c25519_hash( 113 kex->hash_alg, 114 kex->client_version_string, 115 kex->server_version_string, 116 sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 117 sshbuf_ptr(kex->my), sshbuf_len(kex->my), 118 server_host_key_blob, sbloblen, 119 client_pubkey, 120 server_pubkey, 121 sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), 122 hash, &hashlen)) < 0) 123 goto out; 124 125 /* save session id := H */ 126 if (kex->session_id == NULL) { 127 kex->session_id_len = hashlen; 128 kex->session_id = malloc(kex->session_id_len); 129 if (kex->session_id == NULL) { 130 r = SSH_ERR_ALLOC_FAIL; 131 goto out; 132 } 133 memcpy(kex->session_id, hash, kex->session_id_len); 134 } 135 136 /* sign H */ 137 if ((r = kex->sign(server_host_private, server_host_public, &signature, 138 &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0) 139 goto out; 140 141 /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ 142 if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || 143 (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || 144 (r = sshpkt_put_string(ssh, server_pubkey, sizeof(server_pubkey))) != 0 || 145 (r = sshpkt_put_string(ssh, signature, slen)) != 0 || 146 (r = sshpkt_send(ssh)) != 0) 147 goto out; 148 149 if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) 150 r = kex_send_newkeys(ssh); 151 out: 152 explicit_bzero(hash, sizeof(hash)); 153 explicit_bzero(server_key, sizeof(server_key)); 154 free(server_host_key_blob); 155 free(signature); 156 free(client_pubkey); 157 sshbuf_free(shared_secret); 158 return r; 159 } 160