1296853Sdes/* $OpenBSD: kex.c,v 1.117 2016/02/08 10:57:07 djm Exp $ */
260573Skris/*
392555Sdes * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
460573Skris *
560573Skris * Redistribution and use in source and binary forms, with or without
660573Skris * modification, are permitted provided that the following conditions
760573Skris * are met:
860573Skris * 1. Redistributions of source code must retain the above copyright
960573Skris *    notice, this list of conditions and the following disclaimer.
1060573Skris * 2. Redistributions in binary form must reproduce the above copyright
1160573Skris *    notice, this list of conditions and the following disclaimer in the
1260573Skris *    documentation and/or other materials provided with the distribution.
1360573Skris *
1460573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1560573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1660573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1760573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1860573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1960573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2060573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2160573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2260573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2360573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2460573Skris */
2560573Skris
2660573Skris#include "includes.h"
2760573Skris
28295367Sdes#include <sys/param.h>	/* MAX roundup */
29162852Sdes
30162852Sdes#include <signal.h>
31162852Sdes#include <stdarg.h>
32162852Sdes#include <stdio.h>
33162852Sdes#include <stdlib.h>
34162852Sdes#include <string.h>
35162852Sdes
36295367Sdes#ifdef WITH_OPENSSL
3776259Sgreen#include <openssl/crypto.h>
38295367Sdes#endif
3976259Sgreen
4060573Skris#include "ssh2.h"
4161209Skris#include "packet.h"
4260573Skris#include "compat.h"
4376259Sgreen#include "cipher.h"
44295367Sdes#include "sshkey.h"
4560573Skris#include "kex.h"
4676259Sgreen#include "log.h"
4776259Sgreen#include "mac.h"
4876259Sgreen#include "match.h"
49295367Sdes#include "misc.h"
5076259Sgreen#include "dispatch.h"
5198675Sdes#include "monitor.h"
52295367Sdes
53295367Sdes#include "ssherr.h"
54295367Sdes#include "sshbuf.h"
55262566Sdes#include "digest.h"
5660573Skris
57162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L
58162852Sdes# if defined(HAVE_EVP_SHA256)
59162852Sdes# define evp_ssh_sha256 EVP_sha256
60162852Sdes# else
61162852Sdesextern const EVP_MD *evp_ssh_sha256(void);
62162852Sdes# endif
63162852Sdes#endif
64162852Sdes
6592555Sdes/* prototype */
66295367Sdesstatic int kex_choose_conf(struct ssh *);
67295367Sdesstatic int kex_input_newkeys(int, u_int32_t, void *);
6876259Sgreen
69296853Sdesstatic const char *proposal_names[PROPOSAL_MAX] = {
70296853Sdes	"KEX algorithms",
71296853Sdes	"host key algorithms",
72296853Sdes	"ciphers ctos",
73296853Sdes	"ciphers stoc",
74296853Sdes	"MACs ctos",
75296853Sdes	"MACs stoc",
76296853Sdes	"compression ctos",
77296853Sdes	"compression stoc",
78296853Sdes	"languages ctos",
79296853Sdes	"languages stoc",
80296853Sdes};
81296853Sdes
82255767Sdesstruct kexalg {
83255767Sdes	char *name;
84295367Sdes	u_int type;
85255767Sdes	int ec_nid;
86262566Sdes	int hash_alg;
87255767Sdes};
88255767Sdesstatic const struct kexalg kexalgs[] = {
89295367Sdes#ifdef WITH_OPENSSL
90262566Sdes	{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
91262566Sdes	{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
92262566Sdes	{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
93255767Sdes#ifdef HAVE_EVP_SHA256
94262566Sdes	{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
95295367Sdes#endif /* HAVE_EVP_SHA256 */
96255767Sdes#ifdef OPENSSL_HAS_ECC
97262566Sdes	{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
98262566Sdes	    NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
99262566Sdes	{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
100262566Sdes	    SSH_DIGEST_SHA384 },
101262566Sdes# ifdef OPENSSL_HAS_NISTP521
102262566Sdes	{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
103262566Sdes	    SSH_DIGEST_SHA512 },
104295367Sdes# endif /* OPENSSL_HAS_NISTP521 */
105295367Sdes#endif /* OPENSSL_HAS_ECC */
106295367Sdes#endif /* WITH_OPENSSL */
107295367Sdes#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
108262566Sdes	{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
109295367Sdes#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
110262566Sdes	{ NULL, -1, -1, -1},
111255767Sdes};
112255767Sdes
113255767Sdeschar *
114262566Sdeskex_alg_list(char sep)
115255767Sdes{
116295367Sdes	char *ret = NULL, *tmp;
117255767Sdes	size_t nlen, rlen = 0;
118255767Sdes	const struct kexalg *k;
119255767Sdes
120255767Sdes	for (k = kexalgs; k->name != NULL; k++) {
121255767Sdes		if (ret != NULL)
122262566Sdes			ret[rlen++] = sep;
123255767Sdes		nlen = strlen(k->name);
124295367Sdes		if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
125295367Sdes			free(ret);
126295367Sdes			return NULL;
127295367Sdes		}
128295367Sdes		ret = tmp;
129255767Sdes		memcpy(ret + rlen, k->name, nlen + 1);
130255767Sdes		rlen += nlen;
131255767Sdes	}
132255767Sdes	return ret;
133255767Sdes}
134255767Sdes
135255767Sdesstatic const struct kexalg *
136255767Sdeskex_alg_by_name(const char *name)
137255767Sdes{
138255767Sdes	const struct kexalg *k;
139255767Sdes
140255767Sdes	for (k = kexalgs; k->name != NULL; k++) {
141255767Sdes		if (strcmp(k->name, name) == 0)
142255767Sdes			return k;
143255767Sdes	}
144255767Sdes	return NULL;
145255767Sdes}
146255767Sdes
147221420Sdes/* Validate KEX method name list */
148221420Sdesint
149221420Sdeskex_names_valid(const char *names)
150221420Sdes{
151221420Sdes	char *s, *cp, *p;
152221420Sdes
153221420Sdes	if (names == NULL || strcmp(names, "") == 0)
154221420Sdes		return 0;
155295367Sdes	if ((s = cp = strdup(names)) == NULL)
156295367Sdes		return 0;
157221420Sdes	for ((p = strsep(&cp, ",")); p && *p != '\0';
158221420Sdes	    (p = strsep(&cp, ","))) {
159255767Sdes		if (kex_alg_by_name(p) == NULL) {
160221420Sdes			error("Unsupported KEX algorithm \"%.100s\"", p);
161255767Sdes			free(s);
162221420Sdes			return 0;
163221420Sdes		}
164221420Sdes	}
165221420Sdes	debug3("kex names ok: [%s]", names);
166255767Sdes	free(s);
167221420Sdes	return 1;
168221420Sdes}
169221420Sdes
170295367Sdes/*
171295367Sdes * Concatenate algorithm names, avoiding duplicates in the process.
172295367Sdes * Caller must free returned string.
173295367Sdes */
174295367Sdeschar *
175295367Sdeskex_names_cat(const char *a, const char *b)
176295367Sdes{
177295367Sdes	char *ret = NULL, *tmp = NULL, *cp, *p;
178295367Sdes	size_t len;
179295367Sdes
180295367Sdes	if (a == NULL || *a == '\0')
181295367Sdes		return NULL;
182295367Sdes	if (b == NULL || *b == '\0')
183295367Sdes		return strdup(a);
184295367Sdes	if (strlen(b) > 1024*1024)
185295367Sdes		return NULL;
186295367Sdes	len = strlen(a) + strlen(b) + 2;
187295367Sdes	if ((tmp = cp = strdup(b)) == NULL ||
188295367Sdes	    (ret = calloc(1, len)) == NULL) {
189295367Sdes		free(tmp);
190295367Sdes		return NULL;
191295367Sdes	}
192295367Sdes	strlcpy(ret, a, len);
193295367Sdes	for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
194295367Sdes		if (match_list(ret, p, NULL) != NULL)
195295367Sdes			continue; /* Algorithm already present */
196295367Sdes		if (strlcat(ret, ",", len) >= len ||
197295367Sdes		    strlcat(ret, p, len) >= len) {
198295367Sdes			free(tmp);
199295367Sdes			free(ret);
200295367Sdes			return NULL; /* Shouldn't happen */
201295367Sdes		}
202295367Sdes	}
203295367Sdes	free(tmp);
204295367Sdes	return ret;
205295367Sdes}
206295367Sdes
207295367Sdes/*
208295367Sdes * Assemble a list of algorithms from a default list and a string from a
209295367Sdes * configuration file. The user-provided string may begin with '+' to
210295367Sdes * indicate that it should be appended to the default.
211295367Sdes */
212295367Sdesint
213295367Sdeskex_assemble_names(const char *def, char **list)
214295367Sdes{
215295367Sdes	char *ret;
216295367Sdes
217295367Sdes	if (list == NULL || *list == NULL || **list == '\0') {
218295367Sdes		*list = strdup(def);
219295367Sdes		return 0;
220295367Sdes	}
221295367Sdes	if (**list != '+') {
222295367Sdes		return 0;
223295367Sdes	}
224295367Sdes
225295367Sdes	if ((ret = kex_names_cat(def, *list + 1)) == NULL)
226295367Sdes		return SSH_ERR_ALLOC_FAIL;
227295367Sdes	free(*list);
228295367Sdes	*list = ret;
229295367Sdes	return 0;
230295367Sdes}
231295367Sdes
232294693Sdes/* put algorithm proposal into buffer */
233295367Sdesint
234295367Sdeskex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
23560573Skris{
236149749Sdes	u_int i;
237295367Sdes	int r;
23876259Sgreen
239295367Sdes	sshbuf_reset(b);
240295367Sdes
24198675Sdes	/*
24298675Sdes	 * add a dummy cookie, the cookie will be overwritten by
24398675Sdes	 * kex_send_kexinit(), each time a kexinit is set
24498675Sdes	 */
245295367Sdes	for (i = 0; i < KEX_COOKIE_LEN; i++) {
246295367Sdes		if ((r = sshbuf_put_u8(b, 0)) != 0)
247295367Sdes			return r;
248295367Sdes	}
249295367Sdes	for (i = 0; i < PROPOSAL_MAX; i++) {
250295367Sdes		if ((r = sshbuf_put_cstring(b, proposal[i])) != 0)
251295367Sdes			return r;
252295367Sdes	}
253295367Sdes	if ((r = sshbuf_put_u8(b, 0)) != 0 ||	/* first_kex_packet_follows */
254295367Sdes	    (r = sshbuf_put_u32(b, 0)) != 0)	/* uint32 reserved */
255295367Sdes		return r;
256295367Sdes	return 0;
25760573Skris}
25860573Skris
25976259Sgreen/* parse buffer and return algorithm proposal */
260295367Sdesint
261295367Sdeskex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
26261209Skris{
263295367Sdes	struct sshbuf *b = NULL;
264295367Sdes	u_char v;
265181111Sdes	u_int i;
266295367Sdes	char **proposal = NULL;
267295367Sdes	int r;
26861209Skris
269295367Sdes	*propp = NULL;
270295367Sdes	if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL)
271295367Sdes		return SSH_ERR_ALLOC_FAIL;
272295367Sdes	if ((b = sshbuf_fromb(raw)) == NULL) {
273295367Sdes		r = SSH_ERR_ALLOC_FAIL;
274295367Sdes		goto out;
275295367Sdes	}
276295367Sdes	if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */
277295367Sdes		goto out;
27861209Skris	/* extract kex init proposal strings */
27961209Skris	for (i = 0; i < PROPOSAL_MAX; i++) {
280295367Sdes		if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
281295367Sdes			goto out;
282296853Sdes		debug2("%s: %s", proposal_names[i], proposal[i]);
28361209Skris	}
28476259Sgreen	/* first kex follows / reserved */
285295367Sdes	if ((r = sshbuf_get_u8(b, &v)) != 0 ||	/* first_kex_follows */
286295367Sdes	    (r = sshbuf_get_u32(b, &i)) != 0)	/* reserved */
287295367Sdes		goto out;
288113908Sdes	if (first_kex_follows != NULL)
289295367Sdes		*first_kex_follows = v;
290295367Sdes	debug2("first_kex_follows %d ", v);
291295367Sdes	debug2("reserved %u ", i);
292295367Sdes	r = 0;
293295367Sdes	*propp = proposal;
294295367Sdes out:
295295367Sdes	if (r != 0 && proposal != NULL)
296295367Sdes		kex_prop_free(proposal);
297295367Sdes	sshbuf_free(b);
298295367Sdes	return r;
29961209Skris}
30061209Skris
301295367Sdesvoid
30276259Sgreenkex_prop_free(char **proposal)
30360573Skris{
304149749Sdes	u_int i;
30560573Skris
306295367Sdes	if (proposal == NULL)
307295367Sdes		return;
30876259Sgreen	for (i = 0; i < PROPOSAL_MAX; i++)
309255767Sdes		free(proposal[i]);
310255767Sdes	free(proposal);
31160573Skris}
31260573Skris
313181111Sdes/* ARGSUSED */
314295367Sdesstatic int
31592555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt)
31660573Skris{
317296853Sdes	struct ssh *ssh = active_state; /* XXX */
318296853Sdes	int r;
319296853Sdes
320296853Sdes	error("kex protocol error: type %d seq %u", type, seq);
321296853Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
322296853Sdes	    (r = sshpkt_put_u32(ssh, seq)) != 0 ||
323296853Sdes	    (r = sshpkt_send(ssh)) != 0)
324296853Sdes		return r;
325295367Sdes	return 0;
32660573Skris}
32760573Skris
32892555Sdesstatic void
329295367Sdeskex_reset_dispatch(struct ssh *ssh)
33069587Sgreen{
331295367Sdes	ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
33292555Sdes	    SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
333295367Sdes	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
33469587Sgreen}
33569587Sgreen
336296853Sdesstatic int
337296853Sdeskex_send_ext_info(struct ssh *ssh)
338296853Sdes{
339296853Sdes	int r;
340296853Sdes
341296853Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
342296853Sdes	    (r = sshpkt_put_u32(ssh, 1)) != 0 ||
343296853Sdes	    (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
344296853Sdes	    (r = sshpkt_put_cstring(ssh, "rsa-sha2-256,rsa-sha2-512")) != 0 ||
345296853Sdes	    (r = sshpkt_send(ssh)) != 0)
346296853Sdes		return r;
347296853Sdes	return 0;
348296853Sdes}
349296853Sdes
350295367Sdesint
351295367Sdeskex_send_newkeys(struct ssh *ssh)
35269587Sgreen{
353295367Sdes	int r;
35469587Sgreen
355295367Sdes	kex_reset_dispatch(ssh);
356295367Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
357295367Sdes	    (r = sshpkt_send(ssh)) != 0)
358295367Sdes		return r;
35976259Sgreen	debug("SSH2_MSG_NEWKEYS sent");
360295367Sdes	debug("expecting SSH2_MSG_NEWKEYS");
361295367Sdes	ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
362296853Sdes	if (ssh->kex->ext_info_c)
363296853Sdes		if ((r = kex_send_ext_info(ssh)) != 0)
364296853Sdes			return r;
365295367Sdes	return 0;
366295367Sdes}
36769587Sgreen
368296853Sdesint
369296853Sdeskex_input_ext_info(int type, u_int32_t seq, void *ctxt)
370296853Sdes{
371296853Sdes	struct ssh *ssh = ctxt;
372296853Sdes	struct kex *kex = ssh->kex;
373296853Sdes	u_int32_t i, ninfo;
374296853Sdes	char *name, *val, *found;
375296853Sdes	int r;
376296853Sdes
377296853Sdes	debug("SSH2_MSG_EXT_INFO received");
378296853Sdes	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
379296853Sdes	if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
380296853Sdes		return r;
381296853Sdes	for (i = 0; i < ninfo; i++) {
382296853Sdes		if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
383296853Sdes			return r;
384296853Sdes		if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) {
385296853Sdes			free(name);
386296853Sdes			return r;
387296853Sdes		}
388296853Sdes		debug("%s: %s=<%s>", __func__, name, val);
389296853Sdes		if (strcmp(name, "server-sig-algs") == 0) {
390296853Sdes			found = match_list("rsa-sha2-256", val, NULL);
391296853Sdes			if (found) {
392296853Sdes				kex->rsa_sha2 = 256;
393296853Sdes				free(found);
394296853Sdes			}
395296853Sdes			found = match_list("rsa-sha2-512", val, NULL);
396296853Sdes			if (found) {
397296853Sdes				kex->rsa_sha2 = 512;
398296853Sdes				free(found);
399296853Sdes			}
400296853Sdes		}
401296853Sdes		free(name);
402296853Sdes		free(val);
403296853Sdes	}
404296853Sdes	return sshpkt_get_end(ssh);
405296853Sdes}
406296853Sdes
407295367Sdesstatic int
408295367Sdeskex_input_newkeys(int type, u_int32_t seq, void *ctxt)
409295367Sdes{
410295367Sdes	struct ssh *ssh = ctxt;
411295367Sdes	struct kex *kex = ssh->kex;
412295367Sdes	int r;
413295367Sdes
41476259Sgreen	debug("SSH2_MSG_NEWKEYS received");
415295367Sdes	ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
416295367Sdes	if ((r = sshpkt_get_end(ssh)) != 0)
417295367Sdes		return r;
41876259Sgreen	kex->done = 1;
419295367Sdes	sshbuf_reset(kex->peer);
420295367Sdes	/* sshbuf_reset(kex->my); */
42176259Sgreen	kex->flags &= ~KEX_INIT_SENT;
422255767Sdes	free(kex->name);
42376259Sgreen	kex->name = NULL;
424295367Sdes	return 0;
42569587Sgreen}
42669587Sgreen
427295367Sdesint
428295367Sdeskex_send_kexinit(struct ssh *ssh)
42960573Skris{
43098675Sdes	u_char *cookie;
431295367Sdes	struct kex *kex = ssh->kex;
432295367Sdes	int r;
43398675Sdes
434295367Sdes	if (kex == NULL)
435295367Sdes		return SSH_ERR_INTERNAL_ERROR;
436295367Sdes	if (kex->flags & KEX_INIT_SENT)
437295367Sdes		return 0;
43876259Sgreen	kex->done = 0;
43998675Sdes
44098675Sdes	/* generate a random cookie */
441295367Sdes	if (sshbuf_len(kex->my) < KEX_COOKIE_LEN)
442295367Sdes		return SSH_ERR_INVALID_FORMAT;
443295367Sdes	if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL)
444295367Sdes		return SSH_ERR_INTERNAL_ERROR;
445295367Sdes	arc4random_buf(cookie, KEX_COOKIE_LEN);
446295367Sdes
447295367Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
448295367Sdes	    (r = sshpkt_putb(ssh, kex->my)) != 0 ||
449295367Sdes	    (r = sshpkt_send(ssh)) != 0)
450295367Sdes		return r;
45176259Sgreen	debug("SSH2_MSG_KEXINIT sent");
45276259Sgreen	kex->flags |= KEX_INIT_SENT;
453295367Sdes	return 0;
45460573Skris}
45560573Skris
456181111Sdes/* ARGSUSED */
457295367Sdesint
45892555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt)
45960573Skris{
460295367Sdes	struct ssh *ssh = ctxt;
461295367Sdes	struct kex *kex = ssh->kex;
462295367Sdes	const u_char *ptr;
463295367Sdes	u_int i;
464295367Sdes	size_t dlen;
465295367Sdes	int r;
46660573Skris
46776259Sgreen	debug("SSH2_MSG_KEXINIT received");
46876259Sgreen	if (kex == NULL)
469295367Sdes		return SSH_ERR_INVALID_ARGUMENT;
47060573Skris
471308203Sdelphij	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
472295367Sdes	ptr = sshpkt_ptr(ssh, &dlen);
473295367Sdes	if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
474295367Sdes		return r;
47560573Skris
47676259Sgreen	/* discard packet */
47776259Sgreen	for (i = 0; i < KEX_COOKIE_LEN; i++)
478295367Sdes		if ((r = sshpkt_get_u8(ssh, NULL)) != 0)
479295367Sdes			return r;
48076259Sgreen	for (i = 0; i < PROPOSAL_MAX; i++)
481295367Sdes		if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
482295367Sdes			return r;
483248619Sdes	/*
484248619Sdes	 * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
485248619Sdes	 * KEX method has the server move first, but a server might be using
486248619Sdes	 * a custom method or one that we otherwise don't support. We should
487248619Sdes	 * be prepared to remember first_kex_follows here so we can eat a
488248619Sdes	 * packet later.
489248619Sdes	 * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
490248619Sdes	 * for cases where the server *doesn't* go first. I guess we should
491248619Sdes	 * ignore it when it is set for these cases, which is what we do now.
492248619Sdes	 */
493295367Sdes	if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||	/* first_kex_follows */
494295367Sdes	    (r = sshpkt_get_u32(ssh, NULL)) != 0 ||	/* reserved */
495295367Sdes	    (r = sshpkt_get_end(ssh)) != 0)
496295367Sdes			return r;
49760573Skris
498295367Sdes	if (!(kex->flags & KEX_INIT_SENT))
499295367Sdes		if ((r = kex_send_kexinit(ssh)) != 0)
500295367Sdes			return r;
501295367Sdes	if ((r = kex_choose_conf(ssh)) != 0)
502295367Sdes		return r;
503295367Sdes
504295367Sdes	if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
505295367Sdes		return (kex->kex[kex->kex_type])(ssh);
506295367Sdes
507295367Sdes	return SSH_ERR_INTERNAL_ERROR;
50860573Skris}
50960573Skris
510295367Sdesint
511295367Sdeskex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
51269587Sgreen{
513295367Sdes	struct kex *kex;
514295367Sdes	int r;
51569587Sgreen
516295367Sdes	*kexp = NULL;
517295367Sdes	if ((kex = calloc(1, sizeof(*kex))) == NULL)
518295367Sdes		return SSH_ERR_ALLOC_FAIL;
519295367Sdes	if ((kex->peer = sshbuf_new()) == NULL ||
520295367Sdes	    (kex->my = sshbuf_new()) == NULL) {
521295367Sdes		r = SSH_ERR_ALLOC_FAIL;
522295367Sdes		goto out;
523295367Sdes	}
524295367Sdes	if ((r = kex_prop2buf(kex->my, proposal)) != 0)
525295367Sdes		goto out;
52676259Sgreen	kex->done = 0;
527295367Sdes	kex_reset_dispatch(ssh);
528295367Sdes	r = 0;
529295367Sdes	*kexp = kex;
530295367Sdes out:
531295367Sdes	if (r != 0)
532295367Sdes		kex_free(kex);
533295367Sdes	return r;
534295367Sdes}
53569587Sgreen
536295367Sdesvoid
537295367Sdeskex_free_newkeys(struct newkeys *newkeys)
538295367Sdes{
539295367Sdes	if (newkeys == NULL)
540295367Sdes		return;
541295367Sdes	if (newkeys->enc.key) {
542295367Sdes		explicit_bzero(newkeys->enc.key, newkeys->enc.key_len);
543295367Sdes		free(newkeys->enc.key);
544295367Sdes		newkeys->enc.key = NULL;
545295367Sdes	}
546295367Sdes	if (newkeys->enc.iv) {
547296853Sdes		explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
548295367Sdes		free(newkeys->enc.iv);
549295367Sdes		newkeys->enc.iv = NULL;
550295367Sdes	}
551295367Sdes	free(newkeys->enc.name);
552295367Sdes	explicit_bzero(&newkeys->enc, sizeof(newkeys->enc));
553295367Sdes	free(newkeys->comp.name);
554295367Sdes	explicit_bzero(&newkeys->comp, sizeof(newkeys->comp));
555295367Sdes	mac_clear(&newkeys->mac);
556295367Sdes	if (newkeys->mac.key) {
557295367Sdes		explicit_bzero(newkeys->mac.key, newkeys->mac.key_len);
558295367Sdes		free(newkeys->mac.key);
559295367Sdes		newkeys->mac.key = NULL;
560295367Sdes	}
561295367Sdes	free(newkeys->mac.name);
562295367Sdes	explicit_bzero(&newkeys->mac, sizeof(newkeys->mac));
563295367Sdes	explicit_bzero(newkeys, sizeof(*newkeys));
564295367Sdes	free(newkeys);
565295367Sdes}
56669587Sgreen
567295367Sdesvoid
568295367Sdeskex_free(struct kex *kex)
569295367Sdes{
570295367Sdes	u_int mode;
571295367Sdes
572295367Sdes#ifdef WITH_OPENSSL
573295367Sdes	if (kex->dh)
574295367Sdes		DH_free(kex->dh);
575295367Sdes#ifdef OPENSSL_HAS_ECC
576295367Sdes	if (kex->ec_client_key)
577295367Sdes		EC_KEY_free(kex->ec_client_key);
578295367Sdes#endif /* OPENSSL_HAS_ECC */
579295367Sdes#endif /* WITH_OPENSSL */
580295367Sdes	for (mode = 0; mode < MODE_MAX; mode++) {
581295367Sdes		kex_free_newkeys(kex->newkeys[mode]);
582295367Sdes		kex->newkeys[mode] = NULL;
583295367Sdes	}
584295367Sdes	sshbuf_free(kex->peer);
585295367Sdes	sshbuf_free(kex->my);
586295367Sdes	free(kex->session_id);
587295367Sdes	free(kex->client_version_string);
588295367Sdes	free(kex->server_version_string);
589295367Sdes	free(kex->failed_choice);
590296853Sdes	free(kex->hostkey_alg);
591296853Sdes	free(kex->name);
592295367Sdes	free(kex);
59369587Sgreen}
59469587Sgreen
595295367Sdesint
596295367Sdeskex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
59760573Skris{
598295367Sdes	int r;
59960573Skris
600295367Sdes	if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0)
601295367Sdes		return r;
602295367Sdes	if ((r = kex_send_kexinit(ssh)) != 0) {		/* we start */
603295367Sdes		kex_free(ssh->kex);
604295367Sdes		ssh->kex = NULL;
605295367Sdes		return r;
60660573Skris	}
607295367Sdes	return 0;
60860573Skris}
60960573Skris
610296853Sdes/*
611296853Sdes * Request key re-exchange, returns 0 on success or a ssherr.h error
612296853Sdes * code otherwise. Must not be called if KEX is incomplete or in-progress.
613296853Sdes */
614296853Sdesint
615296853Sdeskex_start_rekex(struct ssh *ssh)
616296853Sdes{
617296853Sdes	if (ssh->kex == NULL) {
618296853Sdes		error("%s: no kex", __func__);
619296853Sdes		return SSH_ERR_INTERNAL_ERROR;
620296853Sdes	}
621296853Sdes	if (ssh->kex->done == 0) {
622296853Sdes		error("%s: requested twice", __func__);
623296853Sdes		return SSH_ERR_INTERNAL_ERROR;
624296853Sdes	}
625296853Sdes	ssh->kex->done = 0;
626296853Sdes	return kex_send_kexinit(ssh);
627296853Sdes}
628296853Sdes
629295367Sdesstatic int
630295367Sdeschoose_enc(struct sshenc *enc, char *client, char *server)
63160573Skris{
63276259Sgreen	char *name = match_list(client, server, NULL);
633295367Sdes
63460573Skris	if (name == NULL)
635295367Sdes		return SSH_ERR_NO_CIPHER_ALG_MATCH;
63692555Sdes	if ((enc->cipher = cipher_by_name(name)) == NULL)
637295367Sdes		return SSH_ERR_INTERNAL_ERROR;
63860573Skris	enc->name = name;
63960573Skris	enc->enabled = 0;
64060573Skris	enc->iv = NULL;
641248619Sdes	enc->iv_len = cipher_ivlen(enc->cipher);
64260573Skris	enc->key = NULL;
64392555Sdes	enc->key_len = cipher_keylen(enc->cipher);
64492555Sdes	enc->block_size = cipher_blocksize(enc->cipher);
645295367Sdes	return 0;
64660573Skris}
647162852Sdes
648295367Sdesstatic int
649295367Sdeschoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
65060573Skris{
65176259Sgreen	char *name = match_list(client, server, NULL);
652295367Sdes
65360573Skris	if (name == NULL)
654295367Sdes		return SSH_ERR_NO_MAC_ALG_MATCH;
655181111Sdes	if (mac_setup(mac, name) < 0)
656295367Sdes		return SSH_ERR_INTERNAL_ERROR;
65776259Sgreen	/* truncate the key */
658295367Sdes	if (ssh->compat & SSH_BUG_HMAC)
65976259Sgreen		mac->key_len = 16;
66060573Skris	mac->name = name;
66160573Skris	mac->key = NULL;
66260573Skris	mac->enabled = 0;
663295367Sdes	return 0;
66460573Skris}
665162852Sdes
666295367Sdesstatic int
667295367Sdeschoose_comp(struct sshcomp *comp, char *client, char *server)
66860573Skris{
66976259Sgreen	char *name = match_list(client, server, NULL);
670295367Sdes
67160573Skris	if (name == NULL)
672295367Sdes		return SSH_ERR_NO_COMPRESS_ALG_MATCH;
673149749Sdes	if (strcmp(name, "zlib@openssh.com") == 0) {
674149749Sdes		comp->type = COMP_DELAYED;
675149749Sdes	} else if (strcmp(name, "zlib") == 0) {
676149749Sdes		comp->type = COMP_ZLIB;
67760573Skris	} else if (strcmp(name, "none") == 0) {
678149749Sdes		comp->type = COMP_NONE;
67960573Skris	} else {
680295367Sdes		return SSH_ERR_INTERNAL_ERROR;
68160573Skris	}
68260573Skris	comp->name = name;
683295367Sdes	return 0;
68460573Skris}
685162852Sdes
686295367Sdesstatic int
687295367Sdeschoose_kex(struct kex *k, char *client, char *server)
68860573Skris{
689255767Sdes	const struct kexalg *kexalg;
690255767Sdes
69176259Sgreen	k->name = match_list(client, server, NULL);
692295367Sdes
693296853Sdes	debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
69460573Skris	if (k->name == NULL)
695295367Sdes		return SSH_ERR_NO_KEX_ALG_MATCH;
696255767Sdes	if ((kexalg = kex_alg_by_name(k->name)) == NULL)
697295367Sdes		return SSH_ERR_INTERNAL_ERROR;
698255767Sdes	k->kex_type = kexalg->type;
699262566Sdes	k->hash_alg = kexalg->hash_alg;
700255767Sdes	k->ec_nid = kexalg->ec_nid;
701295367Sdes	return 0;
70260573Skris}
703157016Sdes
704295367Sdesstatic int
705295367Sdeschoose_hostkeyalg(struct kex *k, char *client, char *server)
70660573Skris{
707296853Sdes	k->hostkey_alg = match_list(client, server, NULL);
708295367Sdes
709296853Sdes	debug("kex: host key algorithm: %s",
710296853Sdes	    k->hostkey_alg ? k->hostkey_alg : "(no match)");
711296853Sdes	if (k->hostkey_alg == NULL)
712295367Sdes		return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
713296853Sdes	k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
71476259Sgreen	if (k->hostkey_type == KEY_UNSPEC)
715295367Sdes		return SSH_ERR_INTERNAL_ERROR;
716296853Sdes	k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
717295367Sdes	return 0;
71860573Skris}
71960573Skris
720126274Sdesstatic int
721113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
722113908Sdes{
723113908Sdes	static int check[] = {
724113908Sdes		PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
725113908Sdes	};
726113908Sdes	int *idx;
727113908Sdes	char *p;
728113908Sdes
729113908Sdes	for (idx = &check[0]; *idx != -1; idx++) {
730113908Sdes		if ((p = strchr(my[*idx], ',')) != NULL)
731113908Sdes			*p = '\0';
732113908Sdes		if ((p = strchr(peer[*idx], ',')) != NULL)
733113908Sdes			*p = '\0';
734113908Sdes		if (strcmp(my[*idx], peer[*idx]) != 0) {
735113908Sdes			debug2("proposal mismatch: my %s peer %s",
736113908Sdes			    my[*idx], peer[*idx]);
737113908Sdes			return (0);
738113908Sdes		}
739113908Sdes	}
740113908Sdes	debug2("proposals match");
741113908Sdes	return (1);
742113908Sdes}
743113908Sdes
744295367Sdesstatic int
745295367Sdeskex_choose_conf(struct ssh *ssh)
74660573Skris{
747295367Sdes	struct kex *kex = ssh->kex;
748295367Sdes	struct newkeys *newkeys;
749295367Sdes	char **my = NULL, **peer = NULL;
75076259Sgreen	char **cprop, **sprop;
75176259Sgreen	int nenc, nmac, ncomp;
752262566Sdes	u_int mode, ctos, need, dh_need, authlen;
753295367Sdes	int r, first_kex_follows;
75460573Skris
755296853Sdes	debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
756296853Sdes	if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
757295367Sdes		goto out;
758296853Sdes	debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
759296853Sdes	if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
760296853Sdes		goto out;
76160573Skris
76276259Sgreen	if (kex->server) {
76376259Sgreen		cprop=peer;
76476259Sgreen		sprop=my;
76576259Sgreen	} else {
76676259Sgreen		cprop=my;
76776259Sgreen		sprop=peer;
76876259Sgreen	}
76976259Sgreen
770296853Sdes	/* Check whether client supports ext_info_c */
771296853Sdes	if (kex->server) {
772296853Sdes		char *ext;
773295367Sdes
774296853Sdes		ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
775296853Sdes		if (ext) {
776296853Sdes			kex->ext_info_c = 1;
777296853Sdes			free(ext);
778204917Sdes		}
779204917Sdes	}
780204917Sdes
78176259Sgreen	/* Algorithm Negotiation */
782296853Sdes	if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
783296853Sdes	    sprop[PROPOSAL_KEX_ALGS])) != 0) {
784296853Sdes		kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
785296853Sdes		peer[PROPOSAL_KEX_ALGS] = NULL;
786296853Sdes		goto out;
787296853Sdes	}
788296853Sdes	if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
789296853Sdes	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
790296853Sdes		kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
791296853Sdes		peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
792296853Sdes		goto out;
793296853Sdes	}
79460573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
795295367Sdes		if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
796295367Sdes			r = SSH_ERR_ALLOC_FAIL;
797295367Sdes			goto out;
798295367Sdes		}
79976259Sgreen		kex->newkeys[mode] = newkeys;
800181111Sdes		ctos = (!kex->server && mode == MODE_OUT) ||
801181111Sdes		    (kex->server && mode == MODE_IN);
80260573Skris		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
80360573Skris		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
80460573Skris		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
805295367Sdes		if ((r = choose_enc(&newkeys->enc, cprop[nenc],
806295367Sdes		    sprop[nenc])) != 0) {
807295367Sdes			kex->failed_choice = peer[nenc];
808295367Sdes			peer[nenc] = NULL;
809295367Sdes			goto out;
810295367Sdes		}
811295367Sdes		authlen = cipher_authlen(newkeys->enc.cipher);
812248619Sdes		/* ignore mac for authenticated encryption */
813295367Sdes		if (authlen == 0 &&
814295367Sdes		    (r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
815295367Sdes		    sprop[nmac])) != 0) {
816295367Sdes			kex->failed_choice = peer[nmac];
817295367Sdes			peer[nmac] = NULL;
818295367Sdes			goto out;
819295367Sdes		}
820295367Sdes		if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
821295367Sdes		    sprop[ncomp])) != 0) {
822295367Sdes			kex->failed_choice = peer[ncomp];
823295367Sdes			peer[ncomp] = NULL;
824295367Sdes			goto out;
825295367Sdes		}
826296853Sdes		debug("kex: %s cipher: %s MAC: %s compression: %s",
82760573Skris		    ctos ? "client->server" : "server->client",
82876259Sgreen		    newkeys->enc.name,
829248619Sdes		    authlen == 0 ? newkeys->mac.name : "<implicit>",
83076259Sgreen		    newkeys->comp.name);
83160573Skris	}
832262566Sdes	need = dh_need = 0;
83360573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
83476259Sgreen		newkeys = kex->newkeys[mode];
835262566Sdes		need = MAX(need, newkeys->enc.key_len);
836262566Sdes		need = MAX(need, newkeys->enc.block_size);
837262566Sdes		need = MAX(need, newkeys->enc.iv_len);
838262566Sdes		need = MAX(need, newkeys->mac.key_len);
839262566Sdes		dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher));
840262566Sdes		dh_need = MAX(dh_need, newkeys->enc.block_size);
841262566Sdes		dh_need = MAX(dh_need, newkeys->enc.iv_len);
842262566Sdes		dh_need = MAX(dh_need, newkeys->mac.key_len);
84360573Skris	}
84461209Skris	/* XXX need runden? */
84576259Sgreen	kex->we_need = need;
846262566Sdes	kex->dh_need = dh_need;
84776259Sgreen
848113908Sdes	/* ignore the next message if the proposals do not match */
849126274Sdes	if (first_kex_follows && !proposals_match(my, peer) &&
850295367Sdes	    !(ssh->compat & SSH_BUG_FIRSTKEX))
851295367Sdes		ssh->dispatch_skip_packets = 1;
852295367Sdes	r = 0;
853295367Sdes out:
85476259Sgreen	kex_prop_free(my);
85576259Sgreen	kex_prop_free(peer);
856295367Sdes	return r;
85760573Skris}
85860573Skris
859295367Sdesstatic int
860295367Sdesderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
861295367Sdes    const struct sshbuf *shared_secret, u_char **keyp)
86260573Skris{
863295367Sdes	struct kex *kex = ssh->kex;
864295367Sdes	struct ssh_digest_ctx *hashctx = NULL;
86576259Sgreen	char c = id;
866149749Sdes	u_int have;
867262566Sdes	size_t mdsz;
868149749Sdes	u_char *digest;
869295367Sdes	int r;
87060573Skris
871262566Sdes	if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
872295367Sdes		return SSH_ERR_INVALID_ARGUMENT;
873295367Sdes	if ((digest = calloc(1, roundup(need, mdsz))) == NULL) {
874295367Sdes		r = SSH_ERR_ALLOC_FAIL;
875295367Sdes		goto out;
876295367Sdes	}
877149749Sdes
87876259Sgreen	/* K1 = HASH(K || H || "A" || session_id) */
879295367Sdes	if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
880295367Sdes	    ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
881262566Sdes	    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
882262566Sdes	    ssh_digest_update(hashctx, &c, 1) != 0 ||
883262566Sdes	    ssh_digest_update(hashctx, kex->session_id,
884295367Sdes	    kex->session_id_len) != 0 ||
885295367Sdes	    ssh_digest_final(hashctx, digest, mdsz) != 0) {
886295367Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
887295367Sdes		goto out;
888295367Sdes	}
889262566Sdes	ssh_digest_free(hashctx);
890295367Sdes	hashctx = NULL;
89176259Sgreen
89276259Sgreen	/*
89376259Sgreen	 * expand key:
89476259Sgreen	 * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
89576259Sgreen	 * Key = K1 || K2 || ... || Kn
89676259Sgreen	 */
89776259Sgreen	for (have = mdsz; need > have; have += mdsz) {
898295367Sdes		if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
899295367Sdes		    ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
900262566Sdes		    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
901295367Sdes		    ssh_digest_update(hashctx, digest, have) != 0 ||
902295367Sdes		    ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
903295367Sdes			r = SSH_ERR_LIBCRYPTO_ERROR;
904295367Sdes			goto out;
905295367Sdes		}
906262566Sdes		ssh_digest_free(hashctx);
907295367Sdes		hashctx = NULL;
90876259Sgreen	}
90976259Sgreen#ifdef DEBUG_KEX
91076259Sgreen	fprintf(stderr, "key '%c'== ", c);
91176259Sgreen	dump_digest("key", digest, need);
91276259Sgreen#endif
913295367Sdes	*keyp = digest;
914295367Sdes	digest = NULL;
915295367Sdes	r = 0;
916295367Sdes out:
917296853Sdes	free(digest);
918295367Sdes	ssh_digest_free(hashctx);
919295367Sdes	return r;
92076259Sgreen}
92176259Sgreen
92276259Sgreen#define NKEYS	6
923295367Sdesint
924295367Sdeskex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
925295367Sdes    const struct sshbuf *shared_secret)
92676259Sgreen{
927295367Sdes	struct kex *kex = ssh->kex;
92876259Sgreen	u_char *keys[NKEYS];
929295367Sdes	u_int i, j, mode, ctos;
930295367Sdes	int r;
93176259Sgreen
932157016Sdes	for (i = 0; i < NKEYS; i++) {
933295367Sdes		if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
934295367Sdes		    shared_secret, &keys[i])) != 0) {
935295367Sdes			for (j = 0; j < i; j++)
936295367Sdes				free(keys[j]);
937295367Sdes			return r;
938295367Sdes		}
939157016Sdes	}
94060573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
941162852Sdes		ctos = (!kex->server && mode == MODE_OUT) ||
942162852Sdes		    (kex->server && mode == MODE_IN);
943295367Sdes		kex->newkeys[mode]->enc.iv  = keys[ctos ? 0 : 1];
944295367Sdes		kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
945295367Sdes		kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
94660573Skris	}
947295367Sdes	return 0;
94860573Skris}
94976259Sgreen
950295367Sdes#ifdef WITH_OPENSSL
951295367Sdesint
952295367Sdeskex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
953295367Sdes    const BIGNUM *secret)
954262566Sdes{
955295367Sdes	struct sshbuf *shared_secret;
956295367Sdes	int r;
957262566Sdes
958295367Sdes	if ((shared_secret = sshbuf_new()) == NULL)
959295367Sdes		return SSH_ERR_ALLOC_FAIL;
960295367Sdes	if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0)
961295367Sdes		r = kex_derive_keys(ssh, hash, hashlen, shared_secret);
962295367Sdes	sshbuf_free(shared_secret);
963295367Sdes	return r;
964262566Sdes}
965295367Sdes#endif
966262566Sdes
967295367Sdes#ifdef WITH_SSH1
968295367Sdesint
969137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
970137015Sdes    u_int8_t cookie[8], u_int8_t id[16])
971137015Sdes{
972295367Sdes	u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
973295367Sdes	struct ssh_digest_ctx *hashctx = NULL;
974295367Sdes	size_t hlen, slen;
975295367Sdes	int r;
976137015Sdes
977295367Sdes	hlen = BN_num_bytes(host_modulus);
978295367Sdes	slen = BN_num_bytes(server_modulus);
979295367Sdes	if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) ||
980295367Sdes	    slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
981295367Sdes		return SSH_ERR_KEY_BITS_MISMATCH;
982295367Sdes	if (BN_bn2bin(host_modulus, hbuf) <= 0 ||
983295367Sdes	    BN_bn2bin(server_modulus, sbuf) <= 0) {
984295367Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
985295367Sdes		goto out;
986295367Sdes	}
987295367Sdes	if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) {
988295367Sdes		r = SSH_ERR_ALLOC_FAIL;
989295367Sdes		goto out;
990295367Sdes	}
991295367Sdes	if (ssh_digest_update(hashctx, hbuf, hlen) != 0 ||
992295367Sdes	    ssh_digest_update(hashctx, sbuf, slen) != 0 ||
993295367Sdes	    ssh_digest_update(hashctx, cookie, 8) != 0 ||
994295367Sdes	    ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
995295367Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
996295367Sdes		goto out;
997295367Sdes	}
998262566Sdes	memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
999295367Sdes	r = 0;
1000295367Sdes out:
1001295367Sdes	ssh_digest_free(hashctx);
1002295367Sdes	explicit_bzero(hbuf, sizeof(hbuf));
1003295367Sdes	explicit_bzero(sbuf, sizeof(sbuf));
1004264377Sdes	explicit_bzero(obuf, sizeof(obuf));
1005295367Sdes	return r;
1006137015Sdes}
1007295367Sdes#endif
1008137015Sdes
1009221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
101076259Sgreenvoid
101176259Sgreendump_digest(char *msg, u_char *digest, int len)
101276259Sgreen{
101376259Sgreen	fprintf(stderr, "%s\n", msg);
1014295367Sdes	sshbuf_dump_data(digest, len, stderr);
101576259Sgreen}
101676259Sgreen#endif
1017