1166124Srafan/* $OpenBSD: kexc25519s.c,v 1.10 2015/12/04 16:41:28 markus Exp $ */ 250276Speter/* 3166124Srafan * Copyright (c) 2001 Markus Friedl. All rights reserved. 450276Speter * Copyright (c) 2010 Damien Miller. All rights reserved. 550276Speter * Copyright (c) 2013 Aris Adamantiadis. All rights reserved. 650276Speter * 750276Speter * modification, are permitted provided that the following conditions 850276Speter * are met: 950276Speter * 1. Redistributions of source code must retain the above copyright 1050276Speter * notice, this list of conditions and the following disclaimer. 1150276Speter * 2. Redistributions in binary form must reproduce the above copyright 1250276Speter * notice, this list of conditions and the following disclaimer in the 1350276Speter * documentation and/or other materials provided with the distribution. 1450276Speter * 1550276Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1650276Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1750276Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1850276Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1950276Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2050276Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2150276Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2250276Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2350276Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2450276Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2550276Speter */ 2650276Speter 2750276Speter#include "includes.h" 2850276Speter 2950276Speter#include <sys/types.h> 30166124Srafan#include <stdio.h> 3150276Speter#include <string.h> 3250276Speter#include <signal.h> 3350276Speter 3450276Speter#include "sshkey.h" 3550276Speter#include "cipher.h" 3650276Speter#include "digest.h" 3750276Speter#include "kex.h" 3850276Speter#include "log.h" 39166124Srafan#include "packet.h" 4050276Speter#include "ssh2.h" 4150276Speter#include "sshbuf.h" 4250276Speter#include "ssherr.h" 43166124Srafan 44166124Srafanstatic int input_kex_c25519_init(int, u_int32_t, void *); 45166124Srafan 46166124Srafanint 4750276Speterkexc25519_server(struct ssh *ssh) 4850276Speter{ 4950276Speter debug("expecting SSH2_MSG_KEX_ECDH_INIT"); 5050276Speter ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_c25519_init); 5150276Speter return 0; 5250276Speter} 5350276Speter 5450276Speterstatic int 5550276Speterinput_kex_c25519_init(int type, u_int32_t seq, void *ctxt) 5650276Speter{ 5750276Speter struct ssh *ssh = ctxt; 5850276Speter struct kex *kex = ssh->kex; 5950276Speter struct sshkey *server_host_private, *server_host_public; 6050276Speter struct sshbuf *shared_secret = NULL; 6150276Speter u_char *server_host_key_blob = NULL, *signature = NULL; 6250276Speter u_char server_key[CURVE25519_SIZE]; 6350276Speter u_char *client_pubkey = NULL; 6450276Speter u_char server_pubkey[CURVE25519_SIZE]; 6550276Speter u_char hash[SSH_DIGEST_MAX_LENGTH]; 6650276Speter size_t slen, pklen, sbloblen, hashlen; 6750276Speter int r; 68166124Srafan 69166124Srafan /* generate private key */ 70166124Srafan kexc25519_keygen(server_key, server_pubkey); 71166124Srafan#ifdef DEBUG_KEXECDH 72166124Srafan dump_digest("server private key:", server_key, sizeof(server_key)); 73166124Srafan#endif 74166124Srafan if (kex->load_host_public_key == NULL || 75166124Srafan kex->load_host_private_key == NULL) { 7650276Speter r = SSH_ERR_INVALID_ARGUMENT; 7750276Speter goto out; 7850276Speter } 7950276Speter server_host_public = kex->load_host_public_key(kex->hostkey_type, 8050276Speter kex->hostkey_nid, ssh); 8162449Speter server_host_private = kex->load_host_private_key(kex->hostkey_type, 8262449Speter kex->hostkey_nid, ssh); 8362449Speter if (server_host_public == NULL) { 8462449Speter r = SSH_ERR_NO_HOSTKEY_LOADED; 8562449Speter goto out; 8662449Speter } 8762449Speter 8862449Speter if ((r = sshpkt_get_string(ssh, &client_pubkey, &pklen)) != 0 || 8950276Speter (r = sshpkt_get_end(ssh)) != 0) 9050276Speter goto out; 9150276Speter if (pklen != CURVE25519_SIZE) { 9250276Speter r = SSH_ERR_SIGNATURE_INVALID; 9350276Speter goto out; 9450276Speter } 9550276Speter#ifdef DEBUG_KEXECDH 9650276Speter dump_digest("client public key:", client_pubkey, CURVE25519_SIZE); 97166124Srafan#endif 9850276Speter 9950276Speter if ((shared_secret = sshbuf_new()) == NULL) { 10050276Speter r = SSH_ERR_ALLOC_FAIL; 101166124Srafan goto out; 10250276Speter } 103166124Srafan if ((r = kexc25519_shared_key(server_key, client_pubkey, 10450276Speter shared_secret)) < 0) 10550276Speter goto out; 10650276Speter 10750276Speter /* calc H */ 10850276Speter if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, 10950276Speter &sbloblen)) != 0) 11050276Speter goto out; 11150276Speter hashlen = sizeof(hash); 112166124Srafan if ((r = kex_c25519_hash( 113166124Srafan kex->hash_alg, 114166124Srafan kex->client_version_string, 115166124Srafan kex->server_version_string, 116166124Srafan sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), 117166124Srafan sshbuf_ptr(kex->my), sshbuf_len(kex->my), 118166124Srafan server_host_key_blob, sbloblen, 119166124Srafan client_pubkey, 120166124Srafan server_pubkey, 121166124Srafan sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), 122166124Srafan hash, &hashlen)) < 0) 123166124Srafan goto out; 124166124Srafan 125166124Srafan /* save session id := H */ 12650276Speter if (kex->session_id == NULL) { 12750276Speter kex->session_id_len = hashlen; 12850276Speter kex->session_id = malloc(kex->session_id_len); 12950276Speter if (kex->session_id == NULL) { 130166124Srafan r = SSH_ERR_ALLOC_FAIL; 131166124Srafan goto out; 132166124Srafan } 133166124Srafan memcpy(kex->session_id, hash, kex->session_id_len); 134166124Srafan } 135166124Srafan 136166124Srafan /* sign H */ 13750276Speter if ((r = kex->sign(server_host_private, server_host_public, &signature, 13850276Speter &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0) 13950276Speter goto out; 14050276Speter 14150276Speter /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ 14250276Speter if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || 14350276Speter (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || 14450276Speter (r = sshpkt_put_string(ssh, server_pubkey, sizeof(server_pubkey))) != 0 || 14550276Speter (r = sshpkt_put_string(ssh, signature, slen)) != 0 || 14650276Speter (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); 151out: 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