1323136Sdes/* $OpenBSD: kex.c,v 1.131 2017/03/15 07:07:39 markus 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
28162852Sdes
29162852Sdes#include <signal.h>
30162852Sdes#include <stdarg.h>
31162852Sdes#include <stdio.h>
32162852Sdes#include <stdlib.h>
33162852Sdes#include <string.h>
34162852Sdes
35294328Sdes#ifdef WITH_OPENSSL
3676259Sgreen#include <openssl/crypto.h>
37323129Sdes#include <openssl/dh.h>
38294328Sdes#endif
3976259Sgreen
4060573Skris#include "ssh2.h"
4161209Skris#include "packet.h"
4260573Skris#include "compat.h"
4376259Sgreen#include "cipher.h"
44294332Sdes#include "sshkey.h"
4560573Skris#include "kex.h"
4676259Sgreen#include "log.h"
4776259Sgreen#include "mac.h"
4876259Sgreen#include "match.h"
49294332Sdes#include "misc.h"
5076259Sgreen#include "dispatch.h"
5198675Sdes#include "monitor.h"
52294332Sdes
53294332Sdes#include "ssherr.h"
54294332Sdes#include "sshbuf.h"
55261320Sdes#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 */
66294332Sdesstatic int kex_choose_conf(struct ssh *);
67294332Sdesstatic int kex_input_newkeys(int, u_int32_t, void *);
6876259Sgreen
69296633Sdesstatic const char *proposal_names[PROPOSAL_MAX] = {
70296633Sdes	"KEX algorithms",
71296633Sdes	"host key algorithms",
72296633Sdes	"ciphers ctos",
73296633Sdes	"ciphers stoc",
74296633Sdes	"MACs ctos",
75296633Sdes	"MACs stoc",
76296633Sdes	"compression ctos",
77296633Sdes	"compression stoc",
78296633Sdes	"languages ctos",
79296633Sdes	"languages stoc",
80296633Sdes};
81296633Sdes
82255767Sdesstruct kexalg {
83255767Sdes	char *name;
84294332Sdes	u_int type;
85255767Sdes	int ec_nid;
86261320Sdes	int hash_alg;
87255767Sdes};
88255767Sdesstatic const struct kexalg kexalgs[] = {
89294328Sdes#ifdef WITH_OPENSSL
90261320Sdes	{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
91323129Sdes	{ KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
92323129Sdes	{ KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 },
93323129Sdes	{ KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },
94323129Sdes	{ KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 },
95261320Sdes	{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
96255767Sdes#ifdef HAVE_EVP_SHA256
97261320Sdes	{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
98294328Sdes#endif /* HAVE_EVP_SHA256 */
99255767Sdes#ifdef OPENSSL_HAS_ECC
100261320Sdes	{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
101261320Sdes	    NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
102261320Sdes	{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
103261320Sdes	    SSH_DIGEST_SHA384 },
104261320Sdes# ifdef OPENSSL_HAS_NISTP521
105261320Sdes	{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
106261320Sdes	    SSH_DIGEST_SHA512 },
107294328Sdes# endif /* OPENSSL_HAS_NISTP521 */
108294328Sdes#endif /* OPENSSL_HAS_ECC */
109294328Sdes#endif /* WITH_OPENSSL */
110294332Sdes#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
111261320Sdes	{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
112323134Sdes	{ KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
113294332Sdes#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
114261320Sdes	{ NULL, -1, -1, -1},
115255767Sdes};
116255767Sdes
117255767Sdeschar *
118261320Sdeskex_alg_list(char sep)
119255767Sdes{
120294332Sdes	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)
126261320Sdes			ret[rlen++] = sep;
127255767Sdes		nlen = strlen(k->name);
128294332Sdes		if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
129294332Sdes			free(ret);
130294332Sdes			return NULL;
131294332Sdes		}
132294332Sdes		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;
159294332Sdes	if ((s = cp = strdup(names)) == NULL)
160294332Sdes		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
174294464Sdes/*
175294464Sdes * Concatenate algorithm names, avoiding duplicates in the process.
176294464Sdes * Caller must free returned string.
177294464Sdes */
178294464Sdeschar *
179294464Sdeskex_names_cat(const char *a, const char *b)
180294464Sdes{
181323136Sdes	char *ret = NULL, *tmp = NULL, *cp, *p, *m;
182294464Sdes	size_t len;
183294464Sdes
184294464Sdes	if (a == NULL || *a == '\0')
185294464Sdes		return NULL;
186294464Sdes	if (b == NULL || *b == '\0')
187294464Sdes		return strdup(a);
188294464Sdes	if (strlen(b) > 1024*1024)
189294464Sdes		return NULL;
190294464Sdes	len = strlen(a) + strlen(b) + 2;
191294464Sdes	if ((tmp = cp = strdup(b)) == NULL ||
192294464Sdes	    (ret = calloc(1, len)) == NULL) {
193294464Sdes		free(tmp);
194294464Sdes		return NULL;
195294464Sdes	}
196294464Sdes	strlcpy(ret, a, len);
197294464Sdes	for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
198323136Sdes		if ((m = match_list(ret, p, NULL)) != NULL) {
199323136Sdes			free(m);
200294464Sdes			continue; /* Algorithm already present */
201323136Sdes		}
202294464Sdes		if (strlcat(ret, ",", len) >= len ||
203294464Sdes		    strlcat(ret, p, len) >= len) {
204294464Sdes			free(tmp);
205294464Sdes			free(ret);
206294464Sdes			return NULL; /* Shouldn't happen */
207294464Sdes		}
208294464Sdes	}
209294464Sdes	free(tmp);
210294464Sdes	return ret;
211294464Sdes}
212294464Sdes
213294464Sdes/*
214294464Sdes * Assemble a list of algorithms from a default list and a string from a
215294464Sdes * configuration file. The user-provided string may begin with '+' to
216323136Sdes * indicate that it should be appended to the default or '-' that the
217323136Sdes * specified names should be removed.
218294464Sdes */
219294464Sdesint
220294464Sdeskex_assemble_names(const char *def, char **list)
221294464Sdes{
222294464Sdes	char *ret;
223294464Sdes
224294464Sdes	if (list == NULL || *list == NULL || **list == '\0') {
225294464Sdes		*list = strdup(def);
226294464Sdes		return 0;
227294464Sdes	}
228323136Sdes	if (**list == '+') {
229323136Sdes		if ((ret = kex_names_cat(def, *list + 1)) == NULL)
230323136Sdes			return SSH_ERR_ALLOC_FAIL;
231323136Sdes		free(*list);
232323136Sdes		*list = ret;
233323136Sdes	} else if (**list == '-') {
234323136Sdes		if ((ret = match_filter_list(def, *list + 1)) == NULL)
235323136Sdes			return SSH_ERR_ALLOC_FAIL;
236323136Sdes		free(*list);
237323136Sdes		*list = ret;
238294464Sdes	}
239294464Sdes
240294464Sdes	return 0;
241294464Sdes}
242294464Sdes
243291198Sdes/* put algorithm proposal into buffer */
244294332Sdesint
245294332Sdeskex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
24660573Skris{
247149749Sdes	u_int i;
248294332Sdes	int r;
24976259Sgreen
250294332Sdes	sshbuf_reset(b);
251294332Sdes
25298675Sdes	/*
25398675Sdes	 * add a dummy cookie, the cookie will be overwritten by
25498675Sdes	 * kex_send_kexinit(), each time a kexinit is set
25598675Sdes	 */
256294332Sdes	for (i = 0; i < KEX_COOKIE_LEN; i++) {
257294332Sdes		if ((r = sshbuf_put_u8(b, 0)) != 0)
258294332Sdes			return r;
259294332Sdes	}
260294332Sdes	for (i = 0; i < PROPOSAL_MAX; i++) {
261294332Sdes		if ((r = sshbuf_put_cstring(b, proposal[i])) != 0)
262294332Sdes			return r;
263294332Sdes	}
264294332Sdes	if ((r = sshbuf_put_u8(b, 0)) != 0 ||	/* first_kex_packet_follows */
265294332Sdes	    (r = sshbuf_put_u32(b, 0)) != 0)	/* uint32 reserved */
266294332Sdes		return r;
267294332Sdes	return 0;
26860573Skris}
26960573Skris
27076259Sgreen/* parse buffer and return algorithm proposal */
271294332Sdesint
272294332Sdeskex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
27361209Skris{
274294332Sdes	struct sshbuf *b = NULL;
275294332Sdes	u_char v;
276181111Sdes	u_int i;
277294332Sdes	char **proposal = NULL;
278294332Sdes	int r;
27961209Skris
280294332Sdes	*propp = NULL;
281294332Sdes	if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL)
282294332Sdes		return SSH_ERR_ALLOC_FAIL;
283294332Sdes	if ((b = sshbuf_fromb(raw)) == NULL) {
284294332Sdes		r = SSH_ERR_ALLOC_FAIL;
285294332Sdes		goto out;
286294332Sdes	}
287294332Sdes	if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */
288294332Sdes		goto out;
28961209Skris	/* extract kex init proposal strings */
29061209Skris	for (i = 0; i < PROPOSAL_MAX; i++) {
291294332Sdes		if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
292294332Sdes			goto out;
293296633Sdes		debug2("%s: %s", proposal_names[i], proposal[i]);
29461209Skris	}
29576259Sgreen	/* first kex follows / reserved */
296294496Sdes	if ((r = sshbuf_get_u8(b, &v)) != 0 ||	/* first_kex_follows */
297294496Sdes	    (r = sshbuf_get_u32(b, &i)) != 0)	/* reserved */
298294332Sdes		goto out;
299113908Sdes	if (first_kex_follows != NULL)
300294496Sdes		*first_kex_follows = v;
301294496Sdes	debug2("first_kex_follows %d ", v);
302294496Sdes	debug2("reserved %u ", i);
303294332Sdes	r = 0;
304294332Sdes	*propp = proposal;
305294332Sdes out:
306294332Sdes	if (r != 0 && proposal != NULL)
307294332Sdes		kex_prop_free(proposal);
308294332Sdes	sshbuf_free(b);
309294332Sdes	return r;
31061209Skris}
31161209Skris
312294332Sdesvoid
31376259Sgreenkex_prop_free(char **proposal)
31460573Skris{
315149749Sdes	u_int i;
31660573Skris
317294336Sdes	if (proposal == NULL)
318294336Sdes		return;
31976259Sgreen	for (i = 0; i < PROPOSAL_MAX; i++)
320255767Sdes		free(proposal[i]);
321255767Sdes	free(proposal);
32260573Skris}
32360573Skris
324181111Sdes/* ARGSUSED */
325294332Sdesstatic int
32692555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt)
32760573Skris{
328296633Sdes	struct ssh *ssh = active_state; /* XXX */
329296633Sdes	int r;
330296633Sdes
331296633Sdes	error("kex protocol error: type %d seq %u", type, seq);
332296633Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
333296633Sdes	    (r = sshpkt_put_u32(ssh, seq)) != 0 ||
334296633Sdes	    (r = sshpkt_send(ssh)) != 0)
335296633Sdes		return r;
336294332Sdes	return 0;
33760573Skris}
33860573Skris
33992555Sdesstatic void
340294332Sdeskex_reset_dispatch(struct ssh *ssh)
34169587Sgreen{
342294332Sdes	ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
34392555Sdes	    SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
34469587Sgreen}
34569587Sgreen
346296633Sdesstatic int
347296633Sdeskex_send_ext_info(struct ssh *ssh)
348296633Sdes{
349296633Sdes	int r;
350323134Sdes	char *algs;
351296633Sdes
352323136Sdes	if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
353323134Sdes		return SSH_ERR_ALLOC_FAIL;
354296633Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
355296633Sdes	    (r = sshpkt_put_u32(ssh, 1)) != 0 ||
356296633Sdes	    (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
357323134Sdes	    (r = sshpkt_put_cstring(ssh, algs)) != 0 ||
358296633Sdes	    (r = sshpkt_send(ssh)) != 0)
359323134Sdes		goto out;
360323134Sdes	/* success */
361323134Sdes	r = 0;
362323134Sdes out:
363323134Sdes	free(algs);
364323134Sdes	return r;
365296633Sdes}
366296633Sdes
367294332Sdesint
368294332Sdeskex_send_newkeys(struct ssh *ssh)
36969587Sgreen{
370294332Sdes	int r;
37169587Sgreen
372294332Sdes	kex_reset_dispatch(ssh);
373294332Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
374294332Sdes	    (r = sshpkt_send(ssh)) != 0)
375294332Sdes		return r;
37676259Sgreen	debug("SSH2_MSG_NEWKEYS sent");
377294332Sdes	debug("expecting SSH2_MSG_NEWKEYS");
378294332Sdes	ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
379296633Sdes	if (ssh->kex->ext_info_c)
380296633Sdes		if ((r = kex_send_ext_info(ssh)) != 0)
381296633Sdes			return r;
382294332Sdes	return 0;
383294332Sdes}
38469587Sgreen
385296633Sdesint
386296633Sdeskex_input_ext_info(int type, u_int32_t seq, void *ctxt)
387296633Sdes{
388296633Sdes	struct ssh *ssh = ctxt;
389296633Sdes	struct kex *kex = ssh->kex;
390296633Sdes	u_int32_t i, ninfo;
391296633Sdes	char *name, *val, *found;
392296633Sdes	int r;
393296633Sdes
394296633Sdes	debug("SSH2_MSG_EXT_INFO received");
395296633Sdes	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
396296633Sdes	if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
397296633Sdes		return r;
398296633Sdes	for (i = 0; i < ninfo; i++) {
399296633Sdes		if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
400296633Sdes			return r;
401296633Sdes		if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) {
402296633Sdes			free(name);
403296633Sdes			return r;
404296633Sdes		}
405296633Sdes		debug("%s: %s=<%s>", __func__, name, val);
406296633Sdes		if (strcmp(name, "server-sig-algs") == 0) {
407296633Sdes			found = match_list("rsa-sha2-256", val, NULL);
408296633Sdes			if (found) {
409296633Sdes				kex->rsa_sha2 = 256;
410296633Sdes				free(found);
411296633Sdes			}
412296633Sdes			found = match_list("rsa-sha2-512", val, NULL);
413296633Sdes			if (found) {
414296633Sdes				kex->rsa_sha2 = 512;
415296633Sdes				free(found);
416296633Sdes			}
417296633Sdes		}
418296633Sdes		free(name);
419296633Sdes		free(val);
420296633Sdes	}
421296633Sdes	return sshpkt_get_end(ssh);
422296633Sdes}
423296633Sdes
424294332Sdesstatic int
425294332Sdeskex_input_newkeys(int type, u_int32_t seq, void *ctxt)
426294332Sdes{
427294332Sdes	struct ssh *ssh = ctxt;
428294332Sdes	struct kex *kex = ssh->kex;
429294332Sdes	int r;
430294332Sdes
43176259Sgreen	debug("SSH2_MSG_NEWKEYS received");
432294332Sdes	ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
433323136Sdes	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
434294332Sdes	if ((r = sshpkt_get_end(ssh)) != 0)
435294332Sdes		return r;
436323134Sdes	if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0)
437323134Sdes		return r;
43876259Sgreen	kex->done = 1;
439294332Sdes	sshbuf_reset(kex->peer);
440294332Sdes	/* sshbuf_reset(kex->my); */
44176259Sgreen	kex->flags &= ~KEX_INIT_SENT;
442255767Sdes	free(kex->name);
44376259Sgreen	kex->name = NULL;
444294332Sdes	return 0;
44569587Sgreen}
44669587Sgreen
447294332Sdesint
448294332Sdeskex_send_kexinit(struct ssh *ssh)
44960573Skris{
45098675Sdes	u_char *cookie;
451294332Sdes	struct kex *kex = ssh->kex;
452294332Sdes	int r;
45398675Sdes
454294332Sdes	if (kex == NULL)
455294332Sdes		return SSH_ERR_INTERNAL_ERROR;
456294332Sdes	if (kex->flags & KEX_INIT_SENT)
457294332Sdes		return 0;
45876259Sgreen	kex->done = 0;
45998675Sdes
46098675Sdes	/* generate a random cookie */
461294332Sdes	if (sshbuf_len(kex->my) < KEX_COOKIE_LEN)
462294332Sdes		return SSH_ERR_INVALID_FORMAT;
463294332Sdes	if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL)
464294332Sdes		return SSH_ERR_INTERNAL_ERROR;
465294332Sdes	arc4random_buf(cookie, KEX_COOKIE_LEN);
466294332Sdes
467294332Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
468294332Sdes	    (r = sshpkt_putb(ssh, kex->my)) != 0 ||
469294332Sdes	    (r = sshpkt_send(ssh)) != 0)
470294332Sdes		return r;
47176259Sgreen	debug("SSH2_MSG_KEXINIT sent");
47276259Sgreen	kex->flags |= KEX_INIT_SENT;
473294332Sdes	return 0;
47460573Skris}
47560573Skris
476181111Sdes/* ARGSUSED */
477294332Sdesint
47892555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt)
47960573Skris{
480294332Sdes	struct ssh *ssh = ctxt;
481294332Sdes	struct kex *kex = ssh->kex;
482294332Sdes	const u_char *ptr;
483294332Sdes	u_int i;
484294332Sdes	size_t dlen;
485294332Sdes	int r;
48660573Skris
48776259Sgreen	debug("SSH2_MSG_KEXINIT received");
48876259Sgreen	if (kex == NULL)
489294332Sdes		return SSH_ERR_INVALID_ARGUMENT;
49060573Skris
491323134Sdes	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
492294332Sdes	ptr = sshpkt_ptr(ssh, &dlen);
493294332Sdes	if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
494294332Sdes		return r;
49560573Skris
49676259Sgreen	/* discard packet */
49776259Sgreen	for (i = 0; i < KEX_COOKIE_LEN; i++)
498294332Sdes		if ((r = sshpkt_get_u8(ssh, NULL)) != 0)
499294332Sdes			return r;
50076259Sgreen	for (i = 0; i < PROPOSAL_MAX; i++)
501294332Sdes		if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
502294332Sdes			return r;
503248619Sdes	/*
504248619Sdes	 * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
505248619Sdes	 * KEX method has the server move first, but a server might be using
506248619Sdes	 * a custom method or one that we otherwise don't support. We should
507248619Sdes	 * be prepared to remember first_kex_follows here so we can eat a
508248619Sdes	 * packet later.
509248619Sdes	 * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
510248619Sdes	 * for cases where the server *doesn't* go first. I guess we should
511248619Sdes	 * ignore it when it is set for these cases, which is what we do now.
512248619Sdes	 */
513294332Sdes	if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||	/* first_kex_follows */
514294332Sdes	    (r = sshpkt_get_u32(ssh, NULL)) != 0 ||	/* reserved */
515294332Sdes	    (r = sshpkt_get_end(ssh)) != 0)
516294332Sdes			return r;
51760573Skris
518294332Sdes	if (!(kex->flags & KEX_INIT_SENT))
519294332Sdes		if ((r = kex_send_kexinit(ssh)) != 0)
520294332Sdes			return r;
521294332Sdes	if ((r = kex_choose_conf(ssh)) != 0)
522294332Sdes		return r;
523294332Sdes
524294332Sdes	if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
525294332Sdes		return (kex->kex[kex->kex_type])(ssh);
526294332Sdes
527294332Sdes	return SSH_ERR_INTERNAL_ERROR;
52860573Skris}
52960573Skris
530294332Sdesint
531294332Sdeskex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
53269587Sgreen{
533294332Sdes	struct kex *kex;
534294332Sdes	int r;
53569587Sgreen
536294332Sdes	*kexp = NULL;
537294332Sdes	if ((kex = calloc(1, sizeof(*kex))) == NULL)
538294332Sdes		return SSH_ERR_ALLOC_FAIL;
539294332Sdes	if ((kex->peer = sshbuf_new()) == NULL ||
540294332Sdes	    (kex->my = sshbuf_new()) == NULL) {
541294332Sdes		r = SSH_ERR_ALLOC_FAIL;
542294332Sdes		goto out;
543294332Sdes	}
544294332Sdes	if ((r = kex_prop2buf(kex->my, proposal)) != 0)
545294332Sdes		goto out;
54676259Sgreen	kex->done = 0;
547294332Sdes	kex_reset_dispatch(ssh);
548323136Sdes	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
549294332Sdes	r = 0;
550294332Sdes	*kexp = kex;
551294332Sdes out:
552294332Sdes	if (r != 0)
553294332Sdes		kex_free(kex);
554294332Sdes	return r;
555294332Sdes}
55669587Sgreen
557294332Sdesvoid
558294332Sdeskex_free_newkeys(struct newkeys *newkeys)
559294332Sdes{
560294332Sdes	if (newkeys == NULL)
561294332Sdes		return;
562294332Sdes	if (newkeys->enc.key) {
563294332Sdes		explicit_bzero(newkeys->enc.key, newkeys->enc.key_len);
564294332Sdes		free(newkeys->enc.key);
565294332Sdes		newkeys->enc.key = NULL;
566294332Sdes	}
567294332Sdes	if (newkeys->enc.iv) {
568296633Sdes		explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
569294332Sdes		free(newkeys->enc.iv);
570294332Sdes		newkeys->enc.iv = NULL;
571294332Sdes	}
572294332Sdes	free(newkeys->enc.name);
573294332Sdes	explicit_bzero(&newkeys->enc, sizeof(newkeys->enc));
574294332Sdes	free(newkeys->comp.name);
575294332Sdes	explicit_bzero(&newkeys->comp, sizeof(newkeys->comp));
576294332Sdes	mac_clear(&newkeys->mac);
577294332Sdes	if (newkeys->mac.key) {
578294332Sdes		explicit_bzero(newkeys->mac.key, newkeys->mac.key_len);
579294332Sdes		free(newkeys->mac.key);
580294332Sdes		newkeys->mac.key = NULL;
581294332Sdes	}
582294332Sdes	free(newkeys->mac.name);
583294332Sdes	explicit_bzero(&newkeys->mac, sizeof(newkeys->mac));
584294332Sdes	explicit_bzero(newkeys, sizeof(*newkeys));
585294332Sdes	free(newkeys);
586294332Sdes}
58769587Sgreen
588294332Sdesvoid
589294332Sdeskex_free(struct kex *kex)
590294332Sdes{
591294332Sdes	u_int mode;
592294332Sdes
593294332Sdes#ifdef WITH_OPENSSL
594294332Sdes	if (kex->dh)
595294332Sdes		DH_free(kex->dh);
596294332Sdes#ifdef OPENSSL_HAS_ECC
597294332Sdes	if (kex->ec_client_key)
598294332Sdes		EC_KEY_free(kex->ec_client_key);
599294332Sdes#endif /* OPENSSL_HAS_ECC */
600294332Sdes#endif /* WITH_OPENSSL */
601294332Sdes	for (mode = 0; mode < MODE_MAX; mode++) {
602294332Sdes		kex_free_newkeys(kex->newkeys[mode]);
603294332Sdes		kex->newkeys[mode] = NULL;
604294332Sdes	}
605294332Sdes	sshbuf_free(kex->peer);
606294332Sdes	sshbuf_free(kex->my);
607294332Sdes	free(kex->session_id);
608294332Sdes	free(kex->client_version_string);
609294332Sdes	free(kex->server_version_string);
610294464Sdes	free(kex->failed_choice);
611296633Sdes	free(kex->hostkey_alg);
612296633Sdes	free(kex->name);
613294332Sdes	free(kex);
61469587Sgreen}
61569587Sgreen
616294332Sdesint
617294332Sdeskex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
61860573Skris{
619294332Sdes	int r;
62060573Skris
621294332Sdes	if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0)
622294332Sdes		return r;
623294332Sdes	if ((r = kex_send_kexinit(ssh)) != 0) {		/* we start */
624294332Sdes		kex_free(ssh->kex);
625294332Sdes		ssh->kex = NULL;
626294332Sdes		return r;
62760573Skris	}
628294332Sdes	return 0;
62960573Skris}
63060573Skris
631296633Sdes/*
632296633Sdes * Request key re-exchange, returns 0 on success or a ssherr.h error
633296633Sdes * code otherwise. Must not be called if KEX is incomplete or in-progress.
634296633Sdes */
635296633Sdesint
636296633Sdeskex_start_rekex(struct ssh *ssh)
637296633Sdes{
638296633Sdes	if (ssh->kex == NULL) {
639296633Sdes		error("%s: no kex", __func__);
640296633Sdes		return SSH_ERR_INTERNAL_ERROR;
641296633Sdes	}
642296633Sdes	if (ssh->kex->done == 0) {
643296633Sdes		error("%s: requested twice", __func__);
644296633Sdes		return SSH_ERR_INTERNAL_ERROR;
645296633Sdes	}
646296633Sdes	ssh->kex->done = 0;
647296633Sdes	return kex_send_kexinit(ssh);
648296633Sdes}
649296633Sdes
650294332Sdesstatic int
651294332Sdeschoose_enc(struct sshenc *enc, char *client, char *server)
65260573Skris{
65376259Sgreen	char *name = match_list(client, server, NULL);
654294332Sdes
65560573Skris	if (name == NULL)
656294332Sdes		return SSH_ERR_NO_CIPHER_ALG_MATCH;
657323136Sdes	if ((enc->cipher = cipher_by_name(name)) == NULL) {
658323136Sdes		free(name);
659294332Sdes		return SSH_ERR_INTERNAL_ERROR;
660323136Sdes	}
66160573Skris	enc->name = name;
66260573Skris	enc->enabled = 0;
66360573Skris	enc->iv = NULL;
664248619Sdes	enc->iv_len = cipher_ivlen(enc->cipher);
66560573Skris	enc->key = NULL;
66692555Sdes	enc->key_len = cipher_keylen(enc->cipher);
66792555Sdes	enc->block_size = cipher_blocksize(enc->cipher);
668294332Sdes	return 0;
66960573Skris}
670162852Sdes
671294332Sdesstatic int
672294332Sdeschoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
67360573Skris{
67476259Sgreen	char *name = match_list(client, server, NULL);
675294332Sdes
67660573Skris	if (name == NULL)
677294332Sdes		return SSH_ERR_NO_MAC_ALG_MATCH;
678323136Sdes	if (mac_setup(mac, name) < 0) {
679323136Sdes		free(name);
680294332Sdes		return SSH_ERR_INTERNAL_ERROR;
681323136Sdes	}
68276259Sgreen	/* truncate the key */
683294332Sdes	if (ssh->compat & SSH_BUG_HMAC)
68476259Sgreen		mac->key_len = 16;
68560573Skris	mac->name = name;
68660573Skris	mac->key = NULL;
68760573Skris	mac->enabled = 0;
688294332Sdes	return 0;
68960573Skris}
690162852Sdes
691294332Sdesstatic int
692294332Sdeschoose_comp(struct sshcomp *comp, char *client, char *server)
69360573Skris{
69476259Sgreen	char *name = match_list(client, server, NULL);
695294332Sdes
69660573Skris	if (name == NULL)
697294332Sdes		return SSH_ERR_NO_COMPRESS_ALG_MATCH;
698149749Sdes	if (strcmp(name, "zlib@openssh.com") == 0) {
699149749Sdes		comp->type = COMP_DELAYED;
700149749Sdes	} else if (strcmp(name, "zlib") == 0) {
701149749Sdes		comp->type = COMP_ZLIB;
70260573Skris	} else if (strcmp(name, "none") == 0) {
703149749Sdes		comp->type = COMP_NONE;
70460573Skris	} else {
705323136Sdes		free(name);
706294332Sdes		return SSH_ERR_INTERNAL_ERROR;
70760573Skris	}
70860573Skris	comp->name = name;
709294332Sdes	return 0;
71060573Skris}
711162852Sdes
712294332Sdesstatic int
713294332Sdeschoose_kex(struct kex *k, char *client, char *server)
71460573Skris{
715255767Sdes	const struct kexalg *kexalg;
716255767Sdes
71776259Sgreen	k->name = match_list(client, server, NULL);
718294332Sdes
719296633Sdes	debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
72060573Skris	if (k->name == NULL)
721294332Sdes		return SSH_ERR_NO_KEX_ALG_MATCH;
722255767Sdes	if ((kexalg = kex_alg_by_name(k->name)) == NULL)
723294332Sdes		return SSH_ERR_INTERNAL_ERROR;
724255767Sdes	k->kex_type = kexalg->type;
725261320Sdes	k->hash_alg = kexalg->hash_alg;
726255767Sdes	k->ec_nid = kexalg->ec_nid;
727294332Sdes	return 0;
72860573Skris}
729157016Sdes
730294332Sdesstatic int
731294332Sdeschoose_hostkeyalg(struct kex *k, char *client, char *server)
73260573Skris{
733296633Sdes	k->hostkey_alg = match_list(client, server, NULL);
734294332Sdes
735296633Sdes	debug("kex: host key algorithm: %s",
736296633Sdes	    k->hostkey_alg ? k->hostkey_alg : "(no match)");
737296633Sdes	if (k->hostkey_alg == NULL)
738294332Sdes		return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
739296633Sdes	k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
74076259Sgreen	if (k->hostkey_type == KEY_UNSPEC)
741294332Sdes		return SSH_ERR_INTERNAL_ERROR;
742296633Sdes	k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
743294332Sdes	return 0;
74460573Skris}
74560573Skris
746126274Sdesstatic int
747113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
748113908Sdes{
749113908Sdes	static int check[] = {
750113908Sdes		PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
751113908Sdes	};
752113908Sdes	int *idx;
753113908Sdes	char *p;
754113908Sdes
755113908Sdes	for (idx = &check[0]; *idx != -1; idx++) {
756113908Sdes		if ((p = strchr(my[*idx], ',')) != NULL)
757113908Sdes			*p = '\0';
758113908Sdes		if ((p = strchr(peer[*idx], ',')) != NULL)
759113908Sdes			*p = '\0';
760113908Sdes		if (strcmp(my[*idx], peer[*idx]) != 0) {
761113908Sdes			debug2("proposal mismatch: my %s peer %s",
762113908Sdes			    my[*idx], peer[*idx]);
763113908Sdes			return (0);
764113908Sdes		}
765113908Sdes	}
766113908Sdes	debug2("proposals match");
767113908Sdes	return (1);
768113908Sdes}
769113908Sdes
770294332Sdesstatic int
771294332Sdeskex_choose_conf(struct ssh *ssh)
77260573Skris{
773294332Sdes	struct kex *kex = ssh->kex;
774294332Sdes	struct newkeys *newkeys;
775294332Sdes	char **my = NULL, **peer = NULL;
77676259Sgreen	char **cprop, **sprop;
77776259Sgreen	int nenc, nmac, ncomp;
778261320Sdes	u_int mode, ctos, need, dh_need, authlen;
779294332Sdes	int r, first_kex_follows;
78060573Skris
781296633Sdes	debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
782296633Sdes	if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
783294332Sdes		goto out;
784296633Sdes	debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
785296633Sdes	if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
786296633Sdes		goto out;
78760573Skris
78876259Sgreen	if (kex->server) {
78976259Sgreen		cprop=peer;
79076259Sgreen		sprop=my;
79176259Sgreen	} else {
79276259Sgreen		cprop=my;
79376259Sgreen		sprop=peer;
79476259Sgreen	}
79576259Sgreen
796296633Sdes	/* Check whether client supports ext_info_c */
797296633Sdes	if (kex->server) {
798296633Sdes		char *ext;
799294332Sdes
800296633Sdes		ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
801323134Sdes		kex->ext_info_c = (ext != NULL);
802323134Sdes		free(ext);
803204917Sdes	}
804204917Sdes
80576259Sgreen	/* Algorithm Negotiation */
806296633Sdes	if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
807296633Sdes	    sprop[PROPOSAL_KEX_ALGS])) != 0) {
808296633Sdes		kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
809296633Sdes		peer[PROPOSAL_KEX_ALGS] = NULL;
810296633Sdes		goto out;
811296633Sdes	}
812296633Sdes	if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
813296633Sdes	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
814296633Sdes		kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
815296633Sdes		peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
816296633Sdes		goto out;
817296633Sdes	}
81860573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
819294332Sdes		if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
820294332Sdes			r = SSH_ERR_ALLOC_FAIL;
821294332Sdes			goto out;
822294332Sdes		}
82376259Sgreen		kex->newkeys[mode] = newkeys;
824181111Sdes		ctos = (!kex->server && mode == MODE_OUT) ||
825181111Sdes		    (kex->server && mode == MODE_IN);
82660573Skris		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
82760573Skris		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
82860573Skris		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
829294332Sdes		if ((r = choose_enc(&newkeys->enc, cprop[nenc],
830294464Sdes		    sprop[nenc])) != 0) {
831294464Sdes			kex->failed_choice = peer[nenc];
832294464Sdes			peer[nenc] = NULL;
833294332Sdes			goto out;
834294464Sdes		}
835294332Sdes		authlen = cipher_authlen(newkeys->enc.cipher);
836248619Sdes		/* ignore mac for authenticated encryption */
837294332Sdes		if (authlen == 0 &&
838294332Sdes		    (r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
839294464Sdes		    sprop[nmac])) != 0) {
840294464Sdes			kex->failed_choice = peer[nmac];
841294464Sdes			peer[nmac] = NULL;
842294332Sdes			goto out;
843294464Sdes		}
844294332Sdes		if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
845294464Sdes		    sprop[ncomp])) != 0) {
846294464Sdes			kex->failed_choice = peer[ncomp];
847294464Sdes			peer[ncomp] = NULL;
848294332Sdes			goto out;
849294464Sdes		}
850296633Sdes		debug("kex: %s cipher: %s MAC: %s compression: %s",
85160573Skris		    ctos ? "client->server" : "server->client",
85276259Sgreen		    newkeys->enc.name,
853248619Sdes		    authlen == 0 ? newkeys->mac.name : "<implicit>",
85476259Sgreen		    newkeys->comp.name);
85560573Skris	}
856261320Sdes	need = dh_need = 0;
85760573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
85876259Sgreen		newkeys = kex->newkeys[mode];
859323134Sdes		need = MAXIMUM(need, newkeys->enc.key_len);
860323134Sdes		need = MAXIMUM(need, newkeys->enc.block_size);
861323134Sdes		need = MAXIMUM(need, newkeys->enc.iv_len);
862323134Sdes		need = MAXIMUM(need, newkeys->mac.key_len);
863323134Sdes		dh_need = MAXIMUM(dh_need, cipher_seclen(newkeys->enc.cipher));
864323134Sdes		dh_need = MAXIMUM(dh_need, newkeys->enc.block_size);
865323134Sdes		dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len);
866323134Sdes		dh_need = MAXIMUM(dh_need, newkeys->mac.key_len);
86760573Skris	}
86861209Skris	/* XXX need runden? */
86976259Sgreen	kex->we_need = need;
870261320Sdes	kex->dh_need = dh_need;
87176259Sgreen
872113908Sdes	/* ignore the next message if the proposals do not match */
873126274Sdes	if (first_kex_follows && !proposals_match(my, peer) &&
874294332Sdes	    !(ssh->compat & SSH_BUG_FIRSTKEX))
875294332Sdes		ssh->dispatch_skip_packets = 1;
876294332Sdes	r = 0;
877294332Sdes out:
87876259Sgreen	kex_prop_free(my);
87976259Sgreen	kex_prop_free(peer);
880294332Sdes	return r;
88160573Skris}
88260573Skris
883294332Sdesstatic int
884294332Sdesderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
885294332Sdes    const struct sshbuf *shared_secret, u_char **keyp)
88660573Skris{
887294332Sdes	struct kex *kex = ssh->kex;
888294332Sdes	struct ssh_digest_ctx *hashctx = NULL;
88976259Sgreen	char c = id;
890149749Sdes	u_int have;
891261320Sdes	size_t mdsz;
892149749Sdes	u_char *digest;
893294332Sdes	int r;
89460573Skris
895261320Sdes	if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
896294332Sdes		return SSH_ERR_INVALID_ARGUMENT;
897323134Sdes	if ((digest = calloc(1, ROUNDUP(need, mdsz))) == NULL) {
898294332Sdes		r = SSH_ERR_ALLOC_FAIL;
899294332Sdes		goto out;
900294332Sdes	}
901149749Sdes
90276259Sgreen	/* K1 = HASH(K || H || "A" || session_id) */
903294332Sdes	if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
904294332Sdes	    ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
905261320Sdes	    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
906261320Sdes	    ssh_digest_update(hashctx, &c, 1) != 0 ||
907261320Sdes	    ssh_digest_update(hashctx, kex->session_id,
908294332Sdes	    kex->session_id_len) != 0 ||
909294332Sdes	    ssh_digest_final(hashctx, digest, mdsz) != 0) {
910294332Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
911294332Sdes		goto out;
912294332Sdes	}
913261320Sdes	ssh_digest_free(hashctx);
914294332Sdes	hashctx = NULL;
91576259Sgreen
91676259Sgreen	/*
91776259Sgreen	 * expand key:
91876259Sgreen	 * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
91976259Sgreen	 * Key = K1 || K2 || ... || Kn
92076259Sgreen	 */
92176259Sgreen	for (have = mdsz; need > have; have += mdsz) {
922294332Sdes		if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
923294332Sdes		    ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
924261320Sdes		    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
925294332Sdes		    ssh_digest_update(hashctx, digest, have) != 0 ||
926294332Sdes		    ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
927294332Sdes			r = SSH_ERR_LIBCRYPTO_ERROR;
928294332Sdes			goto out;
929294332Sdes		}
930261320Sdes		ssh_digest_free(hashctx);
931294332Sdes		hashctx = NULL;
93276259Sgreen	}
93376259Sgreen#ifdef DEBUG_KEX
93476259Sgreen	fprintf(stderr, "key '%c'== ", c);
93576259Sgreen	dump_digest("key", digest, need);
93676259Sgreen#endif
937294332Sdes	*keyp = digest;
938294332Sdes	digest = NULL;
939294332Sdes	r = 0;
940294332Sdes out:
941296633Sdes	free(digest);
942294332Sdes	ssh_digest_free(hashctx);
943294332Sdes	return r;
94476259Sgreen}
94576259Sgreen
94676259Sgreen#define NKEYS	6
947294332Sdesint
948294332Sdeskex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
949294332Sdes    const struct sshbuf *shared_secret)
95076259Sgreen{
951294332Sdes	struct kex *kex = ssh->kex;
95276259Sgreen	u_char *keys[NKEYS];
953294332Sdes	u_int i, j, mode, ctos;
954294332Sdes	int r;
95576259Sgreen
956157016Sdes	for (i = 0; i < NKEYS; i++) {
957294332Sdes		if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
958294332Sdes		    shared_secret, &keys[i])) != 0) {
959294332Sdes			for (j = 0; j < i; j++)
960294332Sdes				free(keys[j]);
961294332Sdes			return r;
962294332Sdes		}
963157016Sdes	}
96460573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
965162852Sdes		ctos = (!kex->server && mode == MODE_OUT) ||
966162852Sdes		    (kex->server && mode == MODE_IN);
967294332Sdes		kex->newkeys[mode]->enc.iv  = keys[ctos ? 0 : 1];
968294332Sdes		kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
969294332Sdes		kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
97060573Skris	}
971294332Sdes	return 0;
97260573Skris}
97376259Sgreen
974294328Sdes#ifdef WITH_OPENSSL
975294332Sdesint
976294332Sdeskex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
977294332Sdes    const BIGNUM *secret)
978261320Sdes{
979294332Sdes	struct sshbuf *shared_secret;
980294332Sdes	int r;
981261320Sdes
982294332Sdes	if ((shared_secret = sshbuf_new()) == NULL)
983294332Sdes		return SSH_ERR_ALLOC_FAIL;
984294332Sdes	if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0)
985294332Sdes		r = kex_derive_keys(ssh, hash, hashlen, shared_secret);
986294332Sdes	sshbuf_free(shared_secret);
987294332Sdes	return r;
988261320Sdes}
989294328Sdes#endif
990261320Sdes
991294328Sdes#ifdef WITH_SSH1
992294332Sdesint
993137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
994137015Sdes    u_int8_t cookie[8], u_int8_t id[16])
995137015Sdes{
996294332Sdes	u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
997294332Sdes	struct ssh_digest_ctx *hashctx = NULL;
998294332Sdes	size_t hlen, slen;
999294332Sdes	int r;
1000137015Sdes
1001294332Sdes	hlen = BN_num_bytes(host_modulus);
1002294332Sdes	slen = BN_num_bytes(server_modulus);
1003294332Sdes	if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) ||
1004294332Sdes	    slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
1005294332Sdes		return SSH_ERR_KEY_BITS_MISMATCH;
1006294332Sdes	if (BN_bn2bin(host_modulus, hbuf) <= 0 ||
1007294332Sdes	    BN_bn2bin(server_modulus, sbuf) <= 0) {
1008294332Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
1009294332Sdes		goto out;
1010294332Sdes	}
1011294332Sdes	if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) {
1012294332Sdes		r = SSH_ERR_ALLOC_FAIL;
1013294332Sdes		goto out;
1014294332Sdes	}
1015294332Sdes	if (ssh_digest_update(hashctx, hbuf, hlen) != 0 ||
1016294332Sdes	    ssh_digest_update(hashctx, sbuf, slen) != 0 ||
1017294332Sdes	    ssh_digest_update(hashctx, cookie, 8) != 0 ||
1018294332Sdes	    ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
1019294332Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
1020294332Sdes		goto out;
1021294332Sdes	}
1022261320Sdes	memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
1023294332Sdes	r = 0;
1024294332Sdes out:
1025294332Sdes	ssh_digest_free(hashctx);
1026294332Sdes	explicit_bzero(hbuf, sizeof(hbuf));
1027294332Sdes	explicit_bzero(sbuf, sizeof(sbuf));
1028263712Sdes	explicit_bzero(obuf, sizeof(obuf));
1029294332Sdes	return r;
1030137015Sdes}
1031294328Sdes#endif
1032137015Sdes
1033221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
103476259Sgreenvoid
103576259Sgreendump_digest(char *msg, u_char *digest, int len)
103676259Sgreen{
103776259Sgreen	fprintf(stderr, "%s\n", msg);
1038294332Sdes	sshbuf_dump_data(digest, len, stderr);
103976259Sgreen}
104076259Sgreen#endif
1041