1323124Sdes/* $OpenBSD: kex.c,v 1.118 2016/05/02 10:26:04 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>
38323124Sdes#include <openssl/dh.h>
39295367Sdes#endif
4076259Sgreen
4160573Skris#include "ssh2.h"
4261209Skris#include "packet.h"
4360573Skris#include "compat.h"
4476259Sgreen#include "cipher.h"
45295367Sdes#include "sshkey.h"
4660573Skris#include "kex.h"
4776259Sgreen#include "log.h"
4876259Sgreen#include "mac.h"
4976259Sgreen#include "match.h"
50295367Sdes#include "misc.h"
5176259Sgreen#include "dispatch.h"
5298675Sdes#include "monitor.h"
53295367Sdes
54295367Sdes#include "ssherr.h"
55295367Sdes#include "sshbuf.h"
56262566Sdes#include "digest.h"
5760573Skris
58162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L
59162852Sdes# if defined(HAVE_EVP_SHA256)
60162852Sdes# define evp_ssh_sha256 EVP_sha256
61162852Sdes# else
62162852Sdesextern const EVP_MD *evp_ssh_sha256(void);
63162852Sdes# endif
64162852Sdes#endif
65162852Sdes
6692555Sdes/* prototype */
67295367Sdesstatic int kex_choose_conf(struct ssh *);
68295367Sdesstatic int kex_input_newkeys(int, u_int32_t, void *);
6976259Sgreen
70296781Sdesstatic const char *proposal_names[PROPOSAL_MAX] = {
71296781Sdes	"KEX algorithms",
72296781Sdes	"host key algorithms",
73296781Sdes	"ciphers ctos",
74296781Sdes	"ciphers stoc",
75296781Sdes	"MACs ctos",
76296781Sdes	"MACs stoc",
77296781Sdes	"compression ctos",
78296781Sdes	"compression stoc",
79296781Sdes	"languages ctos",
80296781Sdes	"languages stoc",
81296781Sdes};
82296781Sdes
83255767Sdesstruct kexalg {
84255767Sdes	char *name;
85295367Sdes	u_int type;
86255767Sdes	int ec_nid;
87262566Sdes	int hash_alg;
88255767Sdes};
89255767Sdesstatic const struct kexalg kexalgs[] = {
90295367Sdes#ifdef WITH_OPENSSL
91262566Sdes	{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
92323124Sdes	{ KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
93323124Sdes	{ KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 },
94323124Sdes	{ KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },
95323124Sdes	{ KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 },
96262566Sdes	{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
97255767Sdes#ifdef HAVE_EVP_SHA256
98262566Sdes	{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
99295367Sdes#endif /* HAVE_EVP_SHA256 */
100255767Sdes#ifdef OPENSSL_HAS_ECC
101262566Sdes	{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
102262566Sdes	    NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
103262566Sdes	{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
104262566Sdes	    SSH_DIGEST_SHA384 },
105262566Sdes# ifdef OPENSSL_HAS_NISTP521
106262566Sdes	{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
107262566Sdes	    SSH_DIGEST_SHA512 },
108295367Sdes# endif /* OPENSSL_HAS_NISTP521 */
109295367Sdes#endif /* OPENSSL_HAS_ECC */
110295367Sdes#endif /* WITH_OPENSSL */
111295367Sdes#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
112262566Sdes	{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
113295367Sdes#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
114262566Sdes	{ NULL, -1, -1, -1},
115255767Sdes};
116255767Sdes
117255767Sdeschar *
118262566Sdeskex_alg_list(char sep)
119255767Sdes{
120295367Sdes	char *ret = NULL, *tmp;
121255767Sdes	size_t nlen, rlen = 0;
122255767Sdes	const struct kexalg *k;
123255767Sdes
124255767Sdes	for (k = kexalgs; k->name != NULL; k++) {
125255767Sdes		if (ret != NULL)
126262566Sdes			ret[rlen++] = sep;
127255767Sdes		nlen = strlen(k->name);
128295367Sdes		if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
129295367Sdes			free(ret);
130295367Sdes			return NULL;
131295367Sdes		}
132295367Sdes		ret = tmp;
133255767Sdes		memcpy(ret + rlen, k->name, nlen + 1);
134255767Sdes		rlen += nlen;
135255767Sdes	}
136255767Sdes	return ret;
137255767Sdes}
138255767Sdes
139255767Sdesstatic const struct kexalg *
140255767Sdeskex_alg_by_name(const char *name)
141255767Sdes{
142255767Sdes	const struct kexalg *k;
143255767Sdes
144255767Sdes	for (k = kexalgs; k->name != NULL; k++) {
145255767Sdes		if (strcmp(k->name, name) == 0)
146255767Sdes			return k;
147255767Sdes	}
148255767Sdes	return NULL;
149255767Sdes}
150255767Sdes
151221420Sdes/* Validate KEX method name list */
152221420Sdesint
153221420Sdeskex_names_valid(const char *names)
154221420Sdes{
155221420Sdes	char *s, *cp, *p;
156221420Sdes
157221420Sdes	if (names == NULL || strcmp(names, "") == 0)
158221420Sdes		return 0;
159295367Sdes	if ((s = cp = strdup(names)) == NULL)
160295367Sdes		return 0;
161221420Sdes	for ((p = strsep(&cp, ",")); p && *p != '\0';
162221420Sdes	    (p = strsep(&cp, ","))) {
163255767Sdes		if (kex_alg_by_name(p) == NULL) {
164221420Sdes			error("Unsupported KEX algorithm \"%.100s\"", p);
165255767Sdes			free(s);
166221420Sdes			return 0;
167221420Sdes		}
168221420Sdes	}
169221420Sdes	debug3("kex names ok: [%s]", names);
170255767Sdes	free(s);
171221420Sdes	return 1;
172221420Sdes}
173221420Sdes
174295367Sdes/*
175295367Sdes * Concatenate algorithm names, avoiding duplicates in the process.
176295367Sdes * Caller must free returned string.
177295367Sdes */
178295367Sdeschar *
179295367Sdeskex_names_cat(const char *a, const char *b)
180295367Sdes{
181295367Sdes	char *ret = NULL, *tmp = NULL, *cp, *p;
182295367Sdes	size_t len;
183295367Sdes
184295367Sdes	if (a == NULL || *a == '\0')
185295367Sdes		return NULL;
186295367Sdes	if (b == NULL || *b == '\0')
187295367Sdes		return strdup(a);
188295367Sdes	if (strlen(b) > 1024*1024)
189295367Sdes		return NULL;
190295367Sdes	len = strlen(a) + strlen(b) + 2;
191295367Sdes	if ((tmp = cp = strdup(b)) == NULL ||
192295367Sdes	    (ret = calloc(1, len)) == NULL) {
193295367Sdes		free(tmp);
194295367Sdes		return NULL;
195295367Sdes	}
196295367Sdes	strlcpy(ret, a, len);
197295367Sdes	for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
198295367Sdes		if (match_list(ret, p, NULL) != NULL)
199295367Sdes			continue; /* Algorithm already present */
200295367Sdes		if (strlcat(ret, ",", len) >= len ||
201295367Sdes		    strlcat(ret, p, len) >= len) {
202295367Sdes			free(tmp);
203295367Sdes			free(ret);
204295367Sdes			return NULL; /* Shouldn't happen */
205295367Sdes		}
206295367Sdes	}
207295367Sdes	free(tmp);
208295367Sdes	return ret;
209295367Sdes}
210295367Sdes
211295367Sdes/*
212295367Sdes * Assemble a list of algorithms from a default list and a string from a
213295367Sdes * configuration file. The user-provided string may begin with '+' to
214295367Sdes * indicate that it should be appended to the default.
215295367Sdes */
216295367Sdesint
217295367Sdeskex_assemble_names(const char *def, char **list)
218295367Sdes{
219295367Sdes	char *ret;
220295367Sdes
221295367Sdes	if (list == NULL || *list == NULL || **list == '\0') {
222295367Sdes		*list = strdup(def);
223295367Sdes		return 0;
224295367Sdes	}
225295367Sdes	if (**list != '+') {
226295367Sdes		return 0;
227295367Sdes	}
228295367Sdes
229295367Sdes	if ((ret = kex_names_cat(def, *list + 1)) == NULL)
230295367Sdes		return SSH_ERR_ALLOC_FAIL;
231295367Sdes	free(*list);
232295367Sdes	*list = ret;
233295367Sdes	return 0;
234295367Sdes}
235295367Sdes
236294693Sdes/* put algorithm proposal into buffer */
237295367Sdesint
238295367Sdeskex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
23960573Skris{
240149749Sdes	u_int i;
241295367Sdes	int r;
24276259Sgreen
243295367Sdes	sshbuf_reset(b);
244295367Sdes
24598675Sdes	/*
24698675Sdes	 * add a dummy cookie, the cookie will be overwritten by
24798675Sdes	 * kex_send_kexinit(), each time a kexinit is set
24898675Sdes	 */
249295367Sdes	for (i = 0; i < KEX_COOKIE_LEN; i++) {
250295367Sdes		if ((r = sshbuf_put_u8(b, 0)) != 0)
251295367Sdes			return r;
252295367Sdes	}
253295367Sdes	for (i = 0; i < PROPOSAL_MAX; i++) {
254295367Sdes		if ((r = sshbuf_put_cstring(b, proposal[i])) != 0)
255295367Sdes			return r;
256295367Sdes	}
257295367Sdes	if ((r = sshbuf_put_u8(b, 0)) != 0 ||	/* first_kex_packet_follows */
258295367Sdes	    (r = sshbuf_put_u32(b, 0)) != 0)	/* uint32 reserved */
259295367Sdes		return r;
260295367Sdes	return 0;
26160573Skris}
26260573Skris
26376259Sgreen/* parse buffer and return algorithm proposal */
264295367Sdesint
265295367Sdeskex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
26661209Skris{
267295367Sdes	struct sshbuf *b = NULL;
268295367Sdes	u_char v;
269181111Sdes	u_int i;
270295367Sdes	char **proposal = NULL;
271295367Sdes	int r;
27261209Skris
273295367Sdes	*propp = NULL;
274295367Sdes	if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL)
275295367Sdes		return SSH_ERR_ALLOC_FAIL;
276295367Sdes	if ((b = sshbuf_fromb(raw)) == NULL) {
277295367Sdes		r = SSH_ERR_ALLOC_FAIL;
278295367Sdes		goto out;
279295367Sdes	}
280295367Sdes	if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */
281295367Sdes		goto out;
28261209Skris	/* extract kex init proposal strings */
28361209Skris	for (i = 0; i < PROPOSAL_MAX; i++) {
284295367Sdes		if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
285295367Sdes			goto out;
286296781Sdes		debug2("%s: %s", proposal_names[i], proposal[i]);
28761209Skris	}
28876259Sgreen	/* first kex follows / reserved */
289295367Sdes	if ((r = sshbuf_get_u8(b, &v)) != 0 ||	/* first_kex_follows */
290295367Sdes	    (r = sshbuf_get_u32(b, &i)) != 0)	/* reserved */
291295367Sdes		goto out;
292113908Sdes	if (first_kex_follows != NULL)
293295367Sdes		*first_kex_follows = v;
294295367Sdes	debug2("first_kex_follows %d ", v);
295295367Sdes	debug2("reserved %u ", i);
296295367Sdes	r = 0;
297295367Sdes	*propp = proposal;
298295367Sdes out:
299295367Sdes	if (r != 0 && proposal != NULL)
300295367Sdes		kex_prop_free(proposal);
301295367Sdes	sshbuf_free(b);
302295367Sdes	return r;
30361209Skris}
30461209Skris
305295367Sdesvoid
30676259Sgreenkex_prop_free(char **proposal)
30760573Skris{
308149749Sdes	u_int i;
30960573Skris
310295367Sdes	if (proposal == NULL)
311295367Sdes		return;
31276259Sgreen	for (i = 0; i < PROPOSAL_MAX; i++)
313255767Sdes		free(proposal[i]);
314255767Sdes	free(proposal);
31560573Skris}
31660573Skris
317181111Sdes/* ARGSUSED */
318295367Sdesstatic int
31992555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt)
32060573Skris{
321296781Sdes	struct ssh *ssh = active_state; /* XXX */
322296781Sdes	int r;
323296781Sdes
324296781Sdes	error("kex protocol error: type %d seq %u", type, seq);
325296781Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
326296781Sdes	    (r = sshpkt_put_u32(ssh, seq)) != 0 ||
327296781Sdes	    (r = sshpkt_send(ssh)) != 0)
328296781Sdes		return r;
329295367Sdes	return 0;
33060573Skris}
33160573Skris
33292555Sdesstatic void
333295367Sdeskex_reset_dispatch(struct ssh *ssh)
33469587Sgreen{
335295367Sdes	ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
33692555Sdes	    SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
337295367Sdes	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
33869587Sgreen}
33969587Sgreen
340296781Sdesstatic int
341296781Sdeskex_send_ext_info(struct ssh *ssh)
342296781Sdes{
343296781Sdes	int r;
344296781Sdes
345296781Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
346296781Sdes	    (r = sshpkt_put_u32(ssh, 1)) != 0 ||
347296781Sdes	    (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
348296781Sdes	    (r = sshpkt_put_cstring(ssh, "rsa-sha2-256,rsa-sha2-512")) != 0 ||
349296781Sdes	    (r = sshpkt_send(ssh)) != 0)
350296781Sdes		return r;
351296781Sdes	return 0;
352296781Sdes}
353296781Sdes
354295367Sdesint
355295367Sdeskex_send_newkeys(struct ssh *ssh)
35669587Sgreen{
357295367Sdes	int r;
35869587Sgreen
359295367Sdes	kex_reset_dispatch(ssh);
360295367Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
361295367Sdes	    (r = sshpkt_send(ssh)) != 0)
362295367Sdes		return r;
36376259Sgreen	debug("SSH2_MSG_NEWKEYS sent");
364295367Sdes	debug("expecting SSH2_MSG_NEWKEYS");
365295367Sdes	ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
366296781Sdes	if (ssh->kex->ext_info_c)
367296781Sdes		if ((r = kex_send_ext_info(ssh)) != 0)
368296781Sdes			return r;
369295367Sdes	return 0;
370295367Sdes}
37169587Sgreen
372296781Sdesint
373296781Sdeskex_input_ext_info(int type, u_int32_t seq, void *ctxt)
374296781Sdes{
375296781Sdes	struct ssh *ssh = ctxt;
376296781Sdes	struct kex *kex = ssh->kex;
377296781Sdes	u_int32_t i, ninfo;
378296781Sdes	char *name, *val, *found;
379296781Sdes	int r;
380296781Sdes
381296781Sdes	debug("SSH2_MSG_EXT_INFO received");
382296781Sdes	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
383296781Sdes	if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
384296781Sdes		return r;
385296781Sdes	for (i = 0; i < ninfo; i++) {
386296781Sdes		if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
387296781Sdes			return r;
388296781Sdes		if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) {
389296781Sdes			free(name);
390296781Sdes			return r;
391296781Sdes		}
392296781Sdes		debug("%s: %s=<%s>", __func__, name, val);
393296781Sdes		if (strcmp(name, "server-sig-algs") == 0) {
394296781Sdes			found = match_list("rsa-sha2-256", val, NULL);
395296781Sdes			if (found) {
396296781Sdes				kex->rsa_sha2 = 256;
397296781Sdes				free(found);
398296781Sdes			}
399296781Sdes			found = match_list("rsa-sha2-512", val, NULL);
400296781Sdes			if (found) {
401296781Sdes				kex->rsa_sha2 = 512;
402296781Sdes				free(found);
403296781Sdes			}
404296781Sdes		}
405296781Sdes		free(name);
406296781Sdes		free(val);
407296781Sdes	}
408296781Sdes	return sshpkt_get_end(ssh);
409296781Sdes}
410296781Sdes
411295367Sdesstatic int
412295367Sdeskex_input_newkeys(int type, u_int32_t seq, void *ctxt)
413295367Sdes{
414295367Sdes	struct ssh *ssh = ctxt;
415295367Sdes	struct kex *kex = ssh->kex;
416295367Sdes	int r;
417295367Sdes
41876259Sgreen	debug("SSH2_MSG_NEWKEYS received");
419295367Sdes	ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
420295367Sdes	if ((r = sshpkt_get_end(ssh)) != 0)
421295367Sdes		return r;
42276259Sgreen	kex->done = 1;
423295367Sdes	sshbuf_reset(kex->peer);
424295367Sdes	/* sshbuf_reset(kex->my); */
42576259Sgreen	kex->flags &= ~KEX_INIT_SENT;
426255767Sdes	free(kex->name);
42776259Sgreen	kex->name = NULL;
428295367Sdes	return 0;
42969587Sgreen}
43069587Sgreen
431295367Sdesint
432295367Sdeskex_send_kexinit(struct ssh *ssh)
43360573Skris{
43498675Sdes	u_char *cookie;
435295367Sdes	struct kex *kex = ssh->kex;
436295367Sdes	int r;
43798675Sdes
438295367Sdes	if (kex == NULL)
439295367Sdes		return SSH_ERR_INTERNAL_ERROR;
440295367Sdes	if (kex->flags & KEX_INIT_SENT)
441295367Sdes		return 0;
44276259Sgreen	kex->done = 0;
44398675Sdes
44498675Sdes	/* generate a random cookie */
445295367Sdes	if (sshbuf_len(kex->my) < KEX_COOKIE_LEN)
446295367Sdes		return SSH_ERR_INVALID_FORMAT;
447295367Sdes	if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL)
448295367Sdes		return SSH_ERR_INTERNAL_ERROR;
449295367Sdes	arc4random_buf(cookie, KEX_COOKIE_LEN);
450295367Sdes
451295367Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
452295367Sdes	    (r = sshpkt_putb(ssh, kex->my)) != 0 ||
453295367Sdes	    (r = sshpkt_send(ssh)) != 0)
454295367Sdes		return r;
45576259Sgreen	debug("SSH2_MSG_KEXINIT sent");
45676259Sgreen	kex->flags |= KEX_INIT_SENT;
457295367Sdes	return 0;
45860573Skris}
45960573Skris
460181111Sdes/* ARGSUSED */
461295367Sdesint
46292555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt)
46360573Skris{
464295367Sdes	struct ssh *ssh = ctxt;
465295367Sdes	struct kex *kex = ssh->kex;
466295367Sdes	const u_char *ptr;
467295367Sdes	u_int i;
468295367Sdes	size_t dlen;
469295367Sdes	int r;
47060573Skris
47176259Sgreen	debug("SSH2_MSG_KEXINIT received");
47276259Sgreen	if (kex == NULL)
473295367Sdes		return SSH_ERR_INVALID_ARGUMENT;
47460573Skris
475295367Sdes	ptr = sshpkt_ptr(ssh, &dlen);
476295367Sdes	if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
477295367Sdes		return r;
47860573Skris
47976259Sgreen	/* discard packet */
48076259Sgreen	for (i = 0; i < KEX_COOKIE_LEN; i++)
481295367Sdes		if ((r = sshpkt_get_u8(ssh, NULL)) != 0)
482295367Sdes			return r;
48376259Sgreen	for (i = 0; i < PROPOSAL_MAX; i++)
484295367Sdes		if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
485295367Sdes			return r;
486248619Sdes	/*
487248619Sdes	 * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
488248619Sdes	 * KEX method has the server move first, but a server might be using
489248619Sdes	 * a custom method or one that we otherwise don't support. We should
490248619Sdes	 * be prepared to remember first_kex_follows here so we can eat a
491248619Sdes	 * packet later.
492248619Sdes	 * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
493248619Sdes	 * for cases where the server *doesn't* go first. I guess we should
494248619Sdes	 * ignore it when it is set for these cases, which is what we do now.
495248619Sdes	 */
496295367Sdes	if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||	/* first_kex_follows */
497295367Sdes	    (r = sshpkt_get_u32(ssh, NULL)) != 0 ||	/* reserved */
498295367Sdes	    (r = sshpkt_get_end(ssh)) != 0)
499295367Sdes			return r;
50060573Skris
501295367Sdes	if (!(kex->flags & KEX_INIT_SENT))
502295367Sdes		if ((r = kex_send_kexinit(ssh)) != 0)
503295367Sdes			return r;
504295367Sdes	if ((r = kex_choose_conf(ssh)) != 0)
505295367Sdes		return r;
506295367Sdes
507295367Sdes	if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
508295367Sdes		return (kex->kex[kex->kex_type])(ssh);
509295367Sdes
510295367Sdes	return SSH_ERR_INTERNAL_ERROR;
51160573Skris}
51260573Skris
513295367Sdesint
514295367Sdeskex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
51569587Sgreen{
516295367Sdes	struct kex *kex;
517295367Sdes	int r;
51869587Sgreen
519295367Sdes	*kexp = NULL;
520295367Sdes	if ((kex = calloc(1, sizeof(*kex))) == NULL)
521295367Sdes		return SSH_ERR_ALLOC_FAIL;
522295367Sdes	if ((kex->peer = sshbuf_new()) == NULL ||
523295367Sdes	    (kex->my = sshbuf_new()) == NULL) {
524295367Sdes		r = SSH_ERR_ALLOC_FAIL;
525295367Sdes		goto out;
526295367Sdes	}
527295367Sdes	if ((r = kex_prop2buf(kex->my, proposal)) != 0)
528295367Sdes		goto out;
52976259Sgreen	kex->done = 0;
530295367Sdes	kex_reset_dispatch(ssh);
531295367Sdes	r = 0;
532295367Sdes	*kexp = kex;
533295367Sdes out:
534295367Sdes	if (r != 0)
535295367Sdes		kex_free(kex);
536295367Sdes	return r;
537295367Sdes}
53869587Sgreen
539295367Sdesvoid
540295367Sdeskex_free_newkeys(struct newkeys *newkeys)
541295367Sdes{
542295367Sdes	if (newkeys == NULL)
543295367Sdes		return;
544295367Sdes	if (newkeys->enc.key) {
545295367Sdes		explicit_bzero(newkeys->enc.key, newkeys->enc.key_len);
546295367Sdes		free(newkeys->enc.key);
547295367Sdes		newkeys->enc.key = NULL;
548295367Sdes	}
549295367Sdes	if (newkeys->enc.iv) {
550296781Sdes		explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
551295367Sdes		free(newkeys->enc.iv);
552295367Sdes		newkeys->enc.iv = NULL;
553295367Sdes	}
554295367Sdes	free(newkeys->enc.name);
555295367Sdes	explicit_bzero(&newkeys->enc, sizeof(newkeys->enc));
556295367Sdes	free(newkeys->comp.name);
557295367Sdes	explicit_bzero(&newkeys->comp, sizeof(newkeys->comp));
558295367Sdes	mac_clear(&newkeys->mac);
559295367Sdes	if (newkeys->mac.key) {
560295367Sdes		explicit_bzero(newkeys->mac.key, newkeys->mac.key_len);
561295367Sdes		free(newkeys->mac.key);
562295367Sdes		newkeys->mac.key = NULL;
563295367Sdes	}
564295367Sdes	free(newkeys->mac.name);
565295367Sdes	explicit_bzero(&newkeys->mac, sizeof(newkeys->mac));
566295367Sdes	explicit_bzero(newkeys, sizeof(*newkeys));
567295367Sdes	free(newkeys);
568295367Sdes}
56969587Sgreen
570295367Sdesvoid
571295367Sdeskex_free(struct kex *kex)
572295367Sdes{
573295367Sdes	u_int mode;
574295367Sdes
575295367Sdes#ifdef WITH_OPENSSL
576295367Sdes	if (kex->dh)
577295367Sdes		DH_free(kex->dh);
578295367Sdes#ifdef OPENSSL_HAS_ECC
579295367Sdes	if (kex->ec_client_key)
580295367Sdes		EC_KEY_free(kex->ec_client_key);
581295367Sdes#endif /* OPENSSL_HAS_ECC */
582295367Sdes#endif /* WITH_OPENSSL */
583295367Sdes	for (mode = 0; mode < MODE_MAX; mode++) {
584295367Sdes		kex_free_newkeys(kex->newkeys[mode]);
585295367Sdes		kex->newkeys[mode] = NULL;
586295367Sdes	}
587295367Sdes	sshbuf_free(kex->peer);
588295367Sdes	sshbuf_free(kex->my);
589295367Sdes	free(kex->session_id);
590295367Sdes	free(kex->client_version_string);
591295367Sdes	free(kex->server_version_string);
592295367Sdes	free(kex->failed_choice);
593296781Sdes	free(kex->hostkey_alg);
594296781Sdes	free(kex->name);
595295367Sdes	free(kex);
59669587Sgreen}
59769587Sgreen
598295367Sdesint
599295367Sdeskex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
60060573Skris{
601295367Sdes	int r;
60260573Skris
603295367Sdes	if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0)
604295367Sdes		return r;
605295367Sdes	if ((r = kex_send_kexinit(ssh)) != 0) {		/* we start */
606295367Sdes		kex_free(ssh->kex);
607295367Sdes		ssh->kex = NULL;
608295367Sdes		return r;
60960573Skris	}
610295367Sdes	return 0;
61160573Skris}
61260573Skris
613296781Sdes/*
614296781Sdes * Request key re-exchange, returns 0 on success or a ssherr.h error
615296781Sdes * code otherwise. Must not be called if KEX is incomplete or in-progress.
616296781Sdes */
617296781Sdesint
618296781Sdeskex_start_rekex(struct ssh *ssh)
619296781Sdes{
620296781Sdes	if (ssh->kex == NULL) {
621296781Sdes		error("%s: no kex", __func__);
622296781Sdes		return SSH_ERR_INTERNAL_ERROR;
623296781Sdes	}
624296781Sdes	if (ssh->kex->done == 0) {
625296781Sdes		error("%s: requested twice", __func__);
626296781Sdes		return SSH_ERR_INTERNAL_ERROR;
627296781Sdes	}
628296781Sdes	ssh->kex->done = 0;
629296781Sdes	return kex_send_kexinit(ssh);
630296781Sdes}
631296781Sdes
632295367Sdesstatic int
633295367Sdeschoose_enc(struct sshenc *enc, char *client, char *server)
63460573Skris{
63576259Sgreen	char *name = match_list(client, server, NULL);
636295367Sdes
63760573Skris	if (name == NULL)
638295367Sdes		return SSH_ERR_NO_CIPHER_ALG_MATCH;
63992555Sdes	if ((enc->cipher = cipher_by_name(name)) == NULL)
640295367Sdes		return SSH_ERR_INTERNAL_ERROR;
64160573Skris	enc->name = name;
64260573Skris	enc->enabled = 0;
64360573Skris	enc->iv = NULL;
644248619Sdes	enc->iv_len = cipher_ivlen(enc->cipher);
64560573Skris	enc->key = NULL;
64692555Sdes	enc->key_len = cipher_keylen(enc->cipher);
64792555Sdes	enc->block_size = cipher_blocksize(enc->cipher);
648295367Sdes	return 0;
64960573Skris}
650162852Sdes
651295367Sdesstatic int
652295367Sdeschoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
65360573Skris{
65476259Sgreen	char *name = match_list(client, server, NULL);
655295367Sdes
65660573Skris	if (name == NULL)
657295367Sdes		return SSH_ERR_NO_MAC_ALG_MATCH;
658181111Sdes	if (mac_setup(mac, name) < 0)
659295367Sdes		return SSH_ERR_INTERNAL_ERROR;
66076259Sgreen	/* truncate the key */
661295367Sdes	if (ssh->compat & SSH_BUG_HMAC)
66276259Sgreen		mac->key_len = 16;
66360573Skris	mac->name = name;
66460573Skris	mac->key = NULL;
66560573Skris	mac->enabled = 0;
666295367Sdes	return 0;
66760573Skris}
668162852Sdes
669295367Sdesstatic int
670295367Sdeschoose_comp(struct sshcomp *comp, char *client, char *server)
67160573Skris{
67276259Sgreen	char *name = match_list(client, server, NULL);
673295367Sdes
67460573Skris	if (name == NULL)
675295367Sdes		return SSH_ERR_NO_COMPRESS_ALG_MATCH;
676149749Sdes	if (strcmp(name, "zlib@openssh.com") == 0) {
677149749Sdes		comp->type = COMP_DELAYED;
678149749Sdes	} else if (strcmp(name, "zlib") == 0) {
679149749Sdes		comp->type = COMP_ZLIB;
68060573Skris	} else if (strcmp(name, "none") == 0) {
681149749Sdes		comp->type = COMP_NONE;
68260573Skris	} else {
683295367Sdes		return SSH_ERR_INTERNAL_ERROR;
68460573Skris	}
68560573Skris	comp->name = name;
686295367Sdes	return 0;
68760573Skris}
688162852Sdes
689295367Sdesstatic int
690295367Sdeschoose_kex(struct kex *k, char *client, char *server)
69160573Skris{
692255767Sdes	const struct kexalg *kexalg;
693255767Sdes
69476259Sgreen	k->name = match_list(client, server, NULL);
695295367Sdes
696296781Sdes	debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
69760573Skris	if (k->name == NULL)
698295367Sdes		return SSH_ERR_NO_KEX_ALG_MATCH;
699255767Sdes	if ((kexalg = kex_alg_by_name(k->name)) == NULL)
700295367Sdes		return SSH_ERR_INTERNAL_ERROR;
701255767Sdes	k->kex_type = kexalg->type;
702262566Sdes	k->hash_alg = kexalg->hash_alg;
703255767Sdes	k->ec_nid = kexalg->ec_nid;
704295367Sdes	return 0;
70560573Skris}
706157016Sdes
707295367Sdesstatic int
708295367Sdeschoose_hostkeyalg(struct kex *k, char *client, char *server)
70960573Skris{
710296781Sdes	k->hostkey_alg = match_list(client, server, NULL);
711295367Sdes
712296781Sdes	debug("kex: host key algorithm: %s",
713296781Sdes	    k->hostkey_alg ? k->hostkey_alg : "(no match)");
714296781Sdes	if (k->hostkey_alg == NULL)
715295367Sdes		return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
716296781Sdes	k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
71776259Sgreen	if (k->hostkey_type == KEY_UNSPEC)
718295367Sdes		return SSH_ERR_INTERNAL_ERROR;
719296781Sdes	k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
720295367Sdes	return 0;
72160573Skris}
72260573Skris
723126274Sdesstatic int
724113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
725113908Sdes{
726113908Sdes	static int check[] = {
727113908Sdes		PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
728113908Sdes	};
729113908Sdes	int *idx;
730113908Sdes	char *p;
731113908Sdes
732113908Sdes	for (idx = &check[0]; *idx != -1; idx++) {
733113908Sdes		if ((p = strchr(my[*idx], ',')) != NULL)
734113908Sdes			*p = '\0';
735113908Sdes		if ((p = strchr(peer[*idx], ',')) != NULL)
736113908Sdes			*p = '\0';
737113908Sdes		if (strcmp(my[*idx], peer[*idx]) != 0) {
738113908Sdes			debug2("proposal mismatch: my %s peer %s",
739113908Sdes			    my[*idx], peer[*idx]);
740113908Sdes			return (0);
741113908Sdes		}
742113908Sdes	}
743113908Sdes	debug2("proposals match");
744113908Sdes	return (1);
745113908Sdes}
746113908Sdes
747295367Sdesstatic int
748295367Sdeskex_choose_conf(struct ssh *ssh)
74960573Skris{
750295367Sdes	struct kex *kex = ssh->kex;
751295367Sdes	struct newkeys *newkeys;
752295367Sdes	char **my = NULL, **peer = NULL;
75376259Sgreen	char **cprop, **sprop;
75476259Sgreen	int nenc, nmac, ncomp;
755262566Sdes	u_int mode, ctos, need, dh_need, authlen;
756295367Sdes	int r, first_kex_follows;
75760573Skris
758296781Sdes	debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
759296781Sdes	if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
760295367Sdes		goto out;
761296781Sdes	debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
762296781Sdes	if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
763296781Sdes		goto out;
76460573Skris
76576259Sgreen	if (kex->server) {
76676259Sgreen		cprop=peer;
76776259Sgreen		sprop=my;
76876259Sgreen	} else {
76976259Sgreen		cprop=my;
77076259Sgreen		sprop=peer;
77176259Sgreen	}
77276259Sgreen
773296781Sdes	/* Check whether client supports ext_info_c */
774296781Sdes	if (kex->server) {
775296781Sdes		char *ext;
776295367Sdes
777296781Sdes		ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
778296781Sdes		if (ext) {
779296781Sdes			kex->ext_info_c = 1;
780296781Sdes			free(ext);
781204917Sdes		}
782204917Sdes	}
783204917Sdes
78476259Sgreen	/* Algorithm Negotiation */
785296781Sdes	if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
786296781Sdes	    sprop[PROPOSAL_KEX_ALGS])) != 0) {
787296781Sdes		kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
788296781Sdes		peer[PROPOSAL_KEX_ALGS] = NULL;
789296781Sdes		goto out;
790296781Sdes	}
791296781Sdes	if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
792296781Sdes	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
793296781Sdes		kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
794296781Sdes		peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
795296781Sdes		goto out;
796296781Sdes	}
79760573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
798295367Sdes		if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
799295367Sdes			r = SSH_ERR_ALLOC_FAIL;
800295367Sdes			goto out;
801295367Sdes		}
80276259Sgreen		kex->newkeys[mode] = newkeys;
803181111Sdes		ctos = (!kex->server && mode == MODE_OUT) ||
804181111Sdes		    (kex->server && mode == MODE_IN);
80560573Skris		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
80660573Skris		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
80760573Skris		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
808295367Sdes		if ((r = choose_enc(&newkeys->enc, cprop[nenc],
809295367Sdes		    sprop[nenc])) != 0) {
810295367Sdes			kex->failed_choice = peer[nenc];
811295367Sdes			peer[nenc] = NULL;
812295367Sdes			goto out;
813295367Sdes		}
814295367Sdes		authlen = cipher_authlen(newkeys->enc.cipher);
815248619Sdes		/* ignore mac for authenticated encryption */
816295367Sdes		if (authlen == 0 &&
817295367Sdes		    (r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
818295367Sdes		    sprop[nmac])) != 0) {
819295367Sdes			kex->failed_choice = peer[nmac];
820295367Sdes			peer[nmac] = NULL;
821295367Sdes			goto out;
822295367Sdes		}
823295367Sdes		if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
824295367Sdes		    sprop[ncomp])) != 0) {
825295367Sdes			kex->failed_choice = peer[ncomp];
826295367Sdes			peer[ncomp] = NULL;
827295367Sdes			goto out;
828295367Sdes		}
829296781Sdes		debug("kex: %s cipher: %s MAC: %s compression: %s",
83060573Skris		    ctos ? "client->server" : "server->client",
83176259Sgreen		    newkeys->enc.name,
832248619Sdes		    authlen == 0 ? newkeys->mac.name : "<implicit>",
83376259Sgreen		    newkeys->comp.name);
83460573Skris	}
835262566Sdes	need = dh_need = 0;
83660573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
83776259Sgreen		newkeys = kex->newkeys[mode];
838262566Sdes		need = MAX(need, newkeys->enc.key_len);
839262566Sdes		need = MAX(need, newkeys->enc.block_size);
840262566Sdes		need = MAX(need, newkeys->enc.iv_len);
841262566Sdes		need = MAX(need, newkeys->mac.key_len);
842262566Sdes		dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher));
843262566Sdes		dh_need = MAX(dh_need, newkeys->enc.block_size);
844262566Sdes		dh_need = MAX(dh_need, newkeys->enc.iv_len);
845262566Sdes		dh_need = MAX(dh_need, newkeys->mac.key_len);
84660573Skris	}
84761209Skris	/* XXX need runden? */
84876259Sgreen	kex->we_need = need;
849262566Sdes	kex->dh_need = dh_need;
85076259Sgreen
851113908Sdes	/* ignore the next message if the proposals do not match */
852126274Sdes	if (first_kex_follows && !proposals_match(my, peer) &&
853295367Sdes	    !(ssh->compat & SSH_BUG_FIRSTKEX))
854295367Sdes		ssh->dispatch_skip_packets = 1;
855295367Sdes	r = 0;
856295367Sdes out:
85776259Sgreen	kex_prop_free(my);
85876259Sgreen	kex_prop_free(peer);
859295367Sdes	return r;
86060573Skris}
86160573Skris
862295367Sdesstatic int
863295367Sdesderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
864295367Sdes    const struct sshbuf *shared_secret, u_char **keyp)
86560573Skris{
866295367Sdes	struct kex *kex = ssh->kex;
867295367Sdes	struct ssh_digest_ctx *hashctx = NULL;
86876259Sgreen	char c = id;
869149749Sdes	u_int have;
870262566Sdes	size_t mdsz;
871149749Sdes	u_char *digest;
872295367Sdes	int r;
87360573Skris
874262566Sdes	if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
875295367Sdes		return SSH_ERR_INVALID_ARGUMENT;
876295367Sdes	if ((digest = calloc(1, roundup(need, mdsz))) == NULL) {
877295367Sdes		r = SSH_ERR_ALLOC_FAIL;
878295367Sdes		goto out;
879295367Sdes	}
880149749Sdes
88176259Sgreen	/* K1 = HASH(K || H || "A" || session_id) */
882295367Sdes	if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
883295367Sdes	    ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
884262566Sdes	    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
885262566Sdes	    ssh_digest_update(hashctx, &c, 1) != 0 ||
886262566Sdes	    ssh_digest_update(hashctx, kex->session_id,
887295367Sdes	    kex->session_id_len) != 0 ||
888295367Sdes	    ssh_digest_final(hashctx, digest, mdsz) != 0) {
889295367Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
890295367Sdes		goto out;
891295367Sdes	}
892262566Sdes	ssh_digest_free(hashctx);
893295367Sdes	hashctx = NULL;
89476259Sgreen
89576259Sgreen	/*
89676259Sgreen	 * expand key:
89776259Sgreen	 * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
89876259Sgreen	 * Key = K1 || K2 || ... || Kn
89976259Sgreen	 */
90076259Sgreen	for (have = mdsz; need > have; have += mdsz) {
901295367Sdes		if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
902295367Sdes		    ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
903262566Sdes		    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
904295367Sdes		    ssh_digest_update(hashctx, digest, have) != 0 ||
905295367Sdes		    ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
906295367Sdes			r = SSH_ERR_LIBCRYPTO_ERROR;
907295367Sdes			goto out;
908295367Sdes		}
909262566Sdes		ssh_digest_free(hashctx);
910295367Sdes		hashctx = NULL;
91176259Sgreen	}
91276259Sgreen#ifdef DEBUG_KEX
91376259Sgreen	fprintf(stderr, "key '%c'== ", c);
91476259Sgreen	dump_digest("key", digest, need);
91576259Sgreen#endif
916295367Sdes	*keyp = digest;
917295367Sdes	digest = NULL;
918295367Sdes	r = 0;
919295367Sdes out:
920296781Sdes	free(digest);
921295367Sdes	ssh_digest_free(hashctx);
922295367Sdes	return r;
92376259Sgreen}
92476259Sgreen
92576259Sgreen#define NKEYS	6
926295367Sdesint
927295367Sdeskex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
928295367Sdes    const struct sshbuf *shared_secret)
92976259Sgreen{
930295367Sdes	struct kex *kex = ssh->kex;
93176259Sgreen	u_char *keys[NKEYS];
932295367Sdes	u_int i, j, mode, ctos;
933295367Sdes	int r;
93476259Sgreen
935157016Sdes	for (i = 0; i < NKEYS; i++) {
936295367Sdes		if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
937295367Sdes		    shared_secret, &keys[i])) != 0) {
938295367Sdes			for (j = 0; j < i; j++)
939295367Sdes				free(keys[j]);
940295367Sdes			return r;
941295367Sdes		}
942157016Sdes	}
94360573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
944162852Sdes		ctos = (!kex->server && mode == MODE_OUT) ||
945162852Sdes		    (kex->server && mode == MODE_IN);
946295367Sdes		kex->newkeys[mode]->enc.iv  = keys[ctos ? 0 : 1];
947295367Sdes		kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
948295367Sdes		kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
94960573Skris	}
950295367Sdes	return 0;
95160573Skris}
95276259Sgreen
953295367Sdes#ifdef WITH_OPENSSL
954295367Sdesint
955295367Sdeskex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
956295367Sdes    const BIGNUM *secret)
957262566Sdes{
958295367Sdes	struct sshbuf *shared_secret;
959295367Sdes	int r;
960262566Sdes
961295367Sdes	if ((shared_secret = sshbuf_new()) == NULL)
962295367Sdes		return SSH_ERR_ALLOC_FAIL;
963295367Sdes	if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0)
964295367Sdes		r = kex_derive_keys(ssh, hash, hashlen, shared_secret);
965295367Sdes	sshbuf_free(shared_secret);
966295367Sdes	return r;
967262566Sdes}
968295367Sdes#endif
969262566Sdes
970295367Sdes#ifdef WITH_SSH1
971295367Sdesint
972137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
973137015Sdes    u_int8_t cookie[8], u_int8_t id[16])
974137015Sdes{
975295367Sdes	u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
976295367Sdes	struct ssh_digest_ctx *hashctx = NULL;
977295367Sdes	size_t hlen, slen;
978295367Sdes	int r;
979137015Sdes
980295367Sdes	hlen = BN_num_bytes(host_modulus);
981295367Sdes	slen = BN_num_bytes(server_modulus);
982295367Sdes	if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) ||
983295367Sdes	    slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
984295367Sdes		return SSH_ERR_KEY_BITS_MISMATCH;
985295367Sdes	if (BN_bn2bin(host_modulus, hbuf) <= 0 ||
986295367Sdes	    BN_bn2bin(server_modulus, sbuf) <= 0) {
987295367Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
988295367Sdes		goto out;
989295367Sdes	}
990295367Sdes	if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) {
991295367Sdes		r = SSH_ERR_ALLOC_FAIL;
992295367Sdes		goto out;
993295367Sdes	}
994295367Sdes	if (ssh_digest_update(hashctx, hbuf, hlen) != 0 ||
995295367Sdes	    ssh_digest_update(hashctx, sbuf, slen) != 0 ||
996295367Sdes	    ssh_digest_update(hashctx, cookie, 8) != 0 ||
997295367Sdes	    ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
998295367Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
999295367Sdes		goto out;
1000295367Sdes	}
1001262566Sdes	memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
1002295367Sdes	r = 0;
1003295367Sdes out:
1004295367Sdes	ssh_digest_free(hashctx);
1005295367Sdes	explicit_bzero(hbuf, sizeof(hbuf));
1006295367Sdes	explicit_bzero(sbuf, sizeof(sbuf));
1007264377Sdes	explicit_bzero(obuf, sizeof(obuf));
1008295367Sdes	return r;
1009137015Sdes}
1010295367Sdes#endif
1011137015Sdes
1012221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
101376259Sgreenvoid
101476259Sgreendump_digest(char *msg, u_char *digest, int len)
101576259Sgreen{
101676259Sgreen	fprintf(stderr, "%s\n", msg);
1017295367Sdes	sshbuf_dump_data(digest, len, stderr);
101876259Sgreen}
101976259Sgreen#endif
1020