1/* $OpenBSD: kexc25519s.c,v 1.11 2017/05/31 04:19:28 djm 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 44static int input_kex_c25519_init(int, u_int32_t, struct ssh *); 45 46int 47kexc25519_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 54static int 55input_kex_c25519_init(int type, u_int32_t seq, struct ssh *ssh) 56{ 57 struct kex *kex = ssh->kex; 58 struct sshkey *server_host_private, *server_host_public; 59 struct sshbuf *shared_secret = NULL; 60 u_char *server_host_key_blob = NULL, *signature = NULL; 61 u_char server_key[CURVE25519_SIZE]; 62 u_char *client_pubkey = NULL; 63 u_char server_pubkey[CURVE25519_SIZE]; 64 u_char hash[SSH_DIGEST_MAX_LENGTH]; 65 size_t slen, pklen, sbloblen, hashlen; 66 int r; 67 68 /* generate private key */ 69 kexc25519_keygen(server_key, server_pubkey); 70#ifdef DEBUG_KEXECDH 71 dump_digest("server private key:", server_key, sizeof(server_key)); 72#endif 73 if (kex->load_host_public_key == NULL || 74 kex->load_host_private_key == NULL) { 75 r = SSH_ERR_INVALID_ARGUMENT; 76 goto out; 77 } 78 server_host_public = kex->load_host_public_key(kex->hostkey_type, 79 kex->hostkey_nid, ssh); 80 server_host_private = kex->load_host_private_key(kex->hostkey_type, 81 kex->hostkey_nid, ssh); 82 if (server_host_public == NULL) { 83 r = SSH_ERR_NO_HOSTKEY_LOADED; 84 goto out; 85 } 86 87 if ((r = sshpkt_get_string(ssh, &client_pubkey, &pklen)) != 0 || 88 (r = sshpkt_get_end(ssh)) != 0) 89 goto out; 90 if (pklen != CURVE25519_SIZE) { 91 r = SSH_ERR_SIGNATURE_INVALID; 92 goto out; 93 } 94#ifdef DEBUG_KEXECDH 95 dump_digest("client public key:", client_pubkey, CURVE25519_SIZE); 96#endif 97 98 if ((shared_secret = sshbuf_new()) == NULL) { 99 r = SSH_ERR_ALLOC_FAIL; 100 goto out; 101 } 102 if ((r = kexc25519_shared_key(server_key, client_pubkey, 103 shared_secret)) < 0) 104 goto out; 105 106 /* calc H */ 107 if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, 108 &sbloblen)) != 0) 109 goto out; 110 hashlen = sizeof(hash); 111 if ((r = kex_c25519_hash( 112 kex->hash_alg, 113 kex->client_version_string, 114 kex->server_version_string, 115 sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 116 sshbuf_ptr(kex->my), sshbuf_len(kex->my), 117 server_host_key_blob, sbloblen, 118 client_pubkey, 119 server_pubkey, 120 sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), 121 hash, &hashlen)) < 0) 122 goto out; 123 124 /* save session id := H */ 125 if (kex->session_id == NULL) { 126 kex->session_id_len = hashlen; 127 kex->session_id = malloc(kex->session_id_len); 128 if (kex->session_id == NULL) { 129 r = SSH_ERR_ALLOC_FAIL; 130 goto out; 131 } 132 memcpy(kex->session_id, hash, kex->session_id_len); 133 } 134 135 /* sign H */ 136 if ((r = kex->sign(server_host_private, server_host_public, &signature, 137 &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0) 138 goto out; 139 140 /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ 141 if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || 142 (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || 143 (r = sshpkt_put_string(ssh, server_pubkey, sizeof(server_pubkey))) != 0 || 144 (r = sshpkt_put_string(ssh, signature, slen)) != 0 || 145 (r = sshpkt_send(ssh)) != 0) 146 goto out; 147 148 if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) 149 r = kex_send_newkeys(ssh); 150out: 151 explicit_bzero(hash, sizeof(hash)); 152 explicit_bzero(server_key, sizeof(server_key)); 153 free(server_host_key_blob); 154 free(signature); 155 free(client_pubkey); 156 sshbuf_free(shared_secret); 157 return r; 158} 159