1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
5*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
6*0Sstevel@tonic-gate  * are met:
7*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
8*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
9*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
10*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
11*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16*0Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17*0Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19*0Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20*0Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21*0Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22*0Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*0Sstevel@tonic-gate  *
24*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
25*0Sstevel@tonic-gate  * Use is subject to license terms.
26*0Sstevel@tonic-gate  */
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate #include "includes.h"
29*0Sstevel@tonic-gate RCSID("$OpenBSD: kex.c,v 1.51 2002/06/24 14:55:38 markus Exp $");
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <locale.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <openssl/crypto.h>
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include "ssh2.h"
38*0Sstevel@tonic-gate #include "xmalloc.h"
39*0Sstevel@tonic-gate #include "buffer.h"
40*0Sstevel@tonic-gate #include "bufaux.h"
41*0Sstevel@tonic-gate #include "packet.h"
42*0Sstevel@tonic-gate #include "compat.h"
43*0Sstevel@tonic-gate #include "cipher.h"
44*0Sstevel@tonic-gate #include "kex.h"
45*0Sstevel@tonic-gate #include "key.h"
46*0Sstevel@tonic-gate #include "log.h"
47*0Sstevel@tonic-gate #include "mac.h"
48*0Sstevel@tonic-gate #include "match.h"
49*0Sstevel@tonic-gate #include "dispatch.h"
50*0Sstevel@tonic-gate #include "monitor.h"
51*0Sstevel@tonic-gate #include "g11n.h"
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #ifdef GSSAPI
54*0Sstevel@tonic-gate #include "ssh-gss.h"
55*0Sstevel@tonic-gate #endif
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #define KEX_COOKIE_LEN	16
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /* Use privilege separation for sshd */
60*0Sstevel@tonic-gate int use_privsep;
61*0Sstevel@tonic-gate struct monitor *pmonitor;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate char *session_lang = NULL;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate /* prototype */
67*0Sstevel@tonic-gate static void kex_do_hook(Kex *kex);
68*0Sstevel@tonic-gate static void kex_kexinit_finish(Kex *);
69*0Sstevel@tonic-gate static void kex_choose_conf(Kex *);
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate /* put algorithm proposal into buffer */
72*0Sstevel@tonic-gate static
73*0Sstevel@tonic-gate void
74*0Sstevel@tonic-gate kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	int i;
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	buffer_clear(b);
79*0Sstevel@tonic-gate 	/*
80*0Sstevel@tonic-gate 	 * add a dummy cookie, the cookie will be overwritten by
81*0Sstevel@tonic-gate 	 * kex_send_kexinit(), each time a kexinit is set
82*0Sstevel@tonic-gate 	 */
83*0Sstevel@tonic-gate 	for (i = 0; i < KEX_COOKIE_LEN; i++)
84*0Sstevel@tonic-gate 		buffer_put_char(b, 0);
85*0Sstevel@tonic-gate 	for (i = 0; i < PROPOSAL_MAX; i++)
86*0Sstevel@tonic-gate 		buffer_put_cstring(b, proposal[i]);
87*0Sstevel@tonic-gate 	buffer_put_char(b, 0);			/* first_kex_packet_follows */
88*0Sstevel@tonic-gate 	buffer_put_int(b, 0);			/* uint32 reserved */
89*0Sstevel@tonic-gate }
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate /* parse buffer and return algorithm proposal */
92*0Sstevel@tonic-gate static
93*0Sstevel@tonic-gate char **
94*0Sstevel@tonic-gate kex_buf2prop(Buffer *raw, int *first_kex_follows)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	Buffer b;
97*0Sstevel@tonic-gate 	int i;
98*0Sstevel@tonic-gate 	char **proposal;
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	proposal = xmalloc(PROPOSAL_MAX * sizeof(char *));
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	buffer_init(&b);
103*0Sstevel@tonic-gate 	buffer_append(&b, buffer_ptr(raw), buffer_len(raw));
104*0Sstevel@tonic-gate 	/* skip cookie */
105*0Sstevel@tonic-gate 	for (i = 0; i < KEX_COOKIE_LEN; i++)
106*0Sstevel@tonic-gate 		buffer_get_char(&b);
107*0Sstevel@tonic-gate 	/* extract kex init proposal strings */
108*0Sstevel@tonic-gate 	for (i = 0; i < PROPOSAL_MAX; i++) {
109*0Sstevel@tonic-gate 		proposal[i] = buffer_get_string(&b,NULL);
110*0Sstevel@tonic-gate 		debug2("kex_parse_kexinit: %s", proposal[i]);
111*0Sstevel@tonic-gate 	}
112*0Sstevel@tonic-gate 	/* first kex follows / reserved */
113*0Sstevel@tonic-gate 	i = buffer_get_char(&b);
114*0Sstevel@tonic-gate 	if (first_kex_follows != NULL)
115*0Sstevel@tonic-gate 		*first_kex_follows = i;
116*0Sstevel@tonic-gate 	debug2("kex_parse_kexinit: first_kex_follows %d ", i);
117*0Sstevel@tonic-gate 	i = buffer_get_int(&b);
118*0Sstevel@tonic-gate 	debug2("kex_parse_kexinit: reserved %d ", i);
119*0Sstevel@tonic-gate 	buffer_free(&b);
120*0Sstevel@tonic-gate 	return proposal;
121*0Sstevel@tonic-gate }
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate static
124*0Sstevel@tonic-gate void
125*0Sstevel@tonic-gate kex_prop_free(char **proposal)
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	int i;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	for (i = 0; i < PROPOSAL_MAX; i++)
130*0Sstevel@tonic-gate 		xfree(proposal[i]);
131*0Sstevel@tonic-gate 	xfree(proposal);
132*0Sstevel@tonic-gate }
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate static void
135*0Sstevel@tonic-gate kex_protocol_error(int type, u_int32_t seq, void *ctxt)
136*0Sstevel@tonic-gate {
137*0Sstevel@tonic-gate 	error("Hm, kex protocol error: type %d seq %u", type, seq);
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate static void
141*0Sstevel@tonic-gate kex_reset_dispatch(void)
142*0Sstevel@tonic-gate {
143*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
144*0Sstevel@tonic-gate 	/* unprivileged sshd has a kex packet handler that must not be reset */
145*0Sstevel@tonic-gate 	debug3("kex_reset_dispatch -- should we dispatch_set(KEXINIT) here? %d && !%d",
146*0Sstevel@tonic-gate 		packet_is_server(), packet_is_monitor());
147*0Sstevel@tonic-gate 	if (packet_is_server() && !packet_is_monitor()) {
148*0Sstevel@tonic-gate 		debug3("kex_reset_dispatch -- skipping dispatch_set(KEXINIT) in unpriv proc");
149*0Sstevel@tonic-gate 		return;
150*0Sstevel@tonic-gate 	}
151*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	dispatch_range(SSH2_MSG_TRANSPORT_MIN,
154*0Sstevel@tonic-gate 	    SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
155*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate void
159*0Sstevel@tonic-gate kex_finish(Kex *kex)
160*0Sstevel@tonic-gate {
161*0Sstevel@tonic-gate 	kex_reset_dispatch();
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_NEWKEYS);
164*0Sstevel@tonic-gate 	packet_send();
165*0Sstevel@tonic-gate 	/* packet_write_wait(); */
166*0Sstevel@tonic-gate 	debug("SSH2_MSG_NEWKEYS sent");
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
169*0Sstevel@tonic-gate 	if (packet_is_monitor())
170*0Sstevel@tonic-gate 		goto skip_newkeys;
171*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
172*0Sstevel@tonic-gate 	debug("expecting SSH2_MSG_NEWKEYS");
173*0Sstevel@tonic-gate 	packet_read_expect(SSH2_MSG_NEWKEYS);
174*0Sstevel@tonic-gate 	packet_check_eom();
175*0Sstevel@tonic-gate 	debug("SSH2_MSG_NEWKEYS received");
176*0Sstevel@tonic-gate #ifdef ALTPRIVSEP
177*0Sstevel@tonic-gate skip_newkeys:
178*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	kex->done = 1;
181*0Sstevel@tonic-gate 	kex->initial_kex_done = 1; /* never to be cleared once set */
182*0Sstevel@tonic-gate 	buffer_clear(&kex->peer);
183*0Sstevel@tonic-gate 	/* buffer_clear(&kex->my); */
184*0Sstevel@tonic-gate 	kex->flags &= ~KEX_INIT_SENT;
185*0Sstevel@tonic-gate #if 0
186*0Sstevel@tonic-gate 	/* Must have this name for use in sshd (audit_save_kex())... */
187*0Sstevel@tonic-gate 	xfree(kex->name);
188*0Sstevel@tonic-gate 	kex->name = NULL;
189*0Sstevel@tonic-gate #endif
190*0Sstevel@tonic-gate }
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate void
193*0Sstevel@tonic-gate kex_send_kexinit(Kex *kex)
194*0Sstevel@tonic-gate {
195*0Sstevel@tonic-gate 	u_int32_t rand = 0;
196*0Sstevel@tonic-gate 	u_char *cookie;
197*0Sstevel@tonic-gate 	int i;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if (kex == NULL) {
200*0Sstevel@tonic-gate 		error("kex_send_kexinit: no kex, cannot rekey");
201*0Sstevel@tonic-gate 		return;
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 	if (kex->flags & KEX_INIT_SENT) {
204*0Sstevel@tonic-gate 		debug("KEX_INIT_SENT");
205*0Sstevel@tonic-gate 		return;
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 	kex->done = 0;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	/* update my proposal -- e.g., add/remove GSS kexalgs */
210*0Sstevel@tonic-gate 	kex_do_hook(kex);
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/* generate a random cookie */
213*0Sstevel@tonic-gate 	if (buffer_len(&kex->my) < KEX_COOKIE_LEN)
214*0Sstevel@tonic-gate 		fatal("kex_send_kexinit: kex proposal too short");
215*0Sstevel@tonic-gate 	cookie = buffer_ptr(&kex->my);
216*0Sstevel@tonic-gate 	for (i = 0; i < KEX_COOKIE_LEN; i++) {
217*0Sstevel@tonic-gate 		if (i % 4 == 0)
218*0Sstevel@tonic-gate 			rand = arc4random();
219*0Sstevel@tonic-gate 		cookie[i] = rand;
220*0Sstevel@tonic-gate 		rand >>= 8;
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_KEXINIT);
223*0Sstevel@tonic-gate 	packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my));
224*0Sstevel@tonic-gate 	packet_send();
225*0Sstevel@tonic-gate 	debug("SSH2_MSG_KEXINIT sent");
226*0Sstevel@tonic-gate 	kex->flags |= KEX_INIT_SENT;
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate void
230*0Sstevel@tonic-gate kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
231*0Sstevel@tonic-gate {
232*0Sstevel@tonic-gate 	char *ptr;
233*0Sstevel@tonic-gate 	u_int dlen;
234*0Sstevel@tonic-gate 	int i;
235*0Sstevel@tonic-gate 	Kex *kex = (Kex *)ctxt;
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	debug("SSH2_MSG_KEXINIT received");
238*0Sstevel@tonic-gate 	if (kex == NULL)
239*0Sstevel@tonic-gate 		fatal("kex_input_kexinit: no kex, cannot rekey");
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	ptr = packet_get_raw(&dlen);
242*0Sstevel@tonic-gate 	buffer_append(&kex->peer, ptr, dlen);
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	/* discard packet */
245*0Sstevel@tonic-gate 	for (i = 0; i < KEX_COOKIE_LEN; i++)
246*0Sstevel@tonic-gate 		packet_get_char();
247*0Sstevel@tonic-gate 	for (i = 0; i < PROPOSAL_MAX; i++)
248*0Sstevel@tonic-gate 		xfree(packet_get_string(NULL));
249*0Sstevel@tonic-gate 	(void) packet_get_char();
250*0Sstevel@tonic-gate 	(void) packet_get_int();
251*0Sstevel@tonic-gate 	packet_check_eom();
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	kex_kexinit_finish(kex);
254*0Sstevel@tonic-gate }
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate /*
257*0Sstevel@tonic-gate  * This is for GSS keyex, where actual KEX offer can change at rekey
258*0Sstevel@tonic-gate  * time due to credential expiration/renewal...
259*0Sstevel@tonic-gate  */
260*0Sstevel@tonic-gate static
261*0Sstevel@tonic-gate void
262*0Sstevel@tonic-gate kex_do_hook(Kex *kex)
263*0Sstevel@tonic-gate {
264*0Sstevel@tonic-gate 	char    **prop;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (kex->kex_hook == NULL)
267*0Sstevel@tonic-gate 		return;
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	/* Unmarshall my proposal, let the hook modify it, remarshall it */
270*0Sstevel@tonic-gate 	prop = kex_buf2prop(&kex->my, NULL);
271*0Sstevel@tonic-gate 	buffer_clear(&kex->my);
272*0Sstevel@tonic-gate 	(kex->kex_hook)(kex, prop);
273*0Sstevel@tonic-gate 	kex_prop2buf(&kex->my, prop);
274*0Sstevel@tonic-gate 	kex_prop_free(prop);
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate Kex *
278*0Sstevel@tonic-gate kex_setup(const char *host, char *proposal[PROPOSAL_MAX], Kex_hook_func hook)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	Kex	*kex;
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	kex = xmalloc(sizeof(*kex));
283*0Sstevel@tonic-gate 	memset(kex, 0, sizeof(*kex));
284*0Sstevel@tonic-gate 	buffer_init(&kex->peer);
285*0Sstevel@tonic-gate 	buffer_init(&kex->my);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	kex->kex_hook = hook; /* called by kex_send_kexinit() */
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	if (host != NULL && *host != '\0')
290*0Sstevel@tonic-gate 		kex->serverhost = xstrdup(host);
291*0Sstevel@tonic-gate 	else
292*0Sstevel@tonic-gate 		kex->server = 1;
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	kex_prop2buf(&kex->my, proposal);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	kex_send_kexinit(kex);
297*0Sstevel@tonic-gate 	kex_reset_dispatch();
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	return kex;
300*0Sstevel@tonic-gate }
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate static void
303*0Sstevel@tonic-gate kex_kexinit_finish(Kex *kex)
304*0Sstevel@tonic-gate {
305*0Sstevel@tonic-gate 	if (!(kex->flags & KEX_INIT_SENT))
306*0Sstevel@tonic-gate 		kex_send_kexinit(kex);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	kex_choose_conf(kex);
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX &&
311*0Sstevel@tonic-gate 	    kex->kex[kex->kex_type] != NULL)
312*0Sstevel@tonic-gate 		(kex->kex[kex->kex_type])(kex);
313*0Sstevel@tonic-gate 	else
314*0Sstevel@tonic-gate 		fatal("Unsupported key exchange %d", kex->kex_type);
315*0Sstevel@tonic-gate }
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate static void
318*0Sstevel@tonic-gate choose_lang(char **lang, char *client, char *server)
319*0Sstevel@tonic-gate {
320*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS)
321*0Sstevel@tonic-gate 		*lang = match_list(client, server, NULL);
322*0Sstevel@tonic-gate 	else
323*0Sstevel@tonic-gate 		*lang = g11n_srvr_locale_negotiate(client, NULL);
324*0Sstevel@tonic-gate }
325*0Sstevel@tonic-gate static void
326*0Sstevel@tonic-gate choose_enc(Enc *enc, char *client, char *server)
327*0Sstevel@tonic-gate {
328*0Sstevel@tonic-gate 	char *name = match_list(client, server, NULL);
329*0Sstevel@tonic-gate 	if (name == NULL)
330*0Sstevel@tonic-gate 		fatal("no matching cipher found: client %s server %s", client, server);
331*0Sstevel@tonic-gate 	if ((enc->cipher = cipher_by_name(name)) == NULL)
332*0Sstevel@tonic-gate 		fatal("matching cipher is not supported: %s", name);
333*0Sstevel@tonic-gate 	enc->name = name;
334*0Sstevel@tonic-gate 	enc->enabled = 0;
335*0Sstevel@tonic-gate 	enc->iv = NULL;
336*0Sstevel@tonic-gate 	enc->key = NULL;
337*0Sstevel@tonic-gate 	enc->key_len = cipher_keylen(enc->cipher);
338*0Sstevel@tonic-gate 	enc->block_size = cipher_blocksize(enc->cipher);
339*0Sstevel@tonic-gate }
340*0Sstevel@tonic-gate static void
341*0Sstevel@tonic-gate choose_mac(Mac *mac, char *client, char *server)
342*0Sstevel@tonic-gate {
343*0Sstevel@tonic-gate 	char *name = match_list(client, server, NULL);
344*0Sstevel@tonic-gate 	if (name == NULL)
345*0Sstevel@tonic-gate 		fatal("no matching mac found: client %s server %s", client, server);
346*0Sstevel@tonic-gate 	if (mac_init(mac, name) < 0)
347*0Sstevel@tonic-gate 		fatal("unsupported mac %s", name);
348*0Sstevel@tonic-gate 	/* truncate the key */
349*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_HMAC)
350*0Sstevel@tonic-gate 		mac->key_len = 16;
351*0Sstevel@tonic-gate 	mac->name = name;
352*0Sstevel@tonic-gate 	mac->key = NULL;
353*0Sstevel@tonic-gate 	mac->enabled = 0;
354*0Sstevel@tonic-gate }
355*0Sstevel@tonic-gate static void
356*0Sstevel@tonic-gate choose_comp(Comp *comp, char *client, char *server)
357*0Sstevel@tonic-gate {
358*0Sstevel@tonic-gate 	char *name = match_list(client, server, NULL);
359*0Sstevel@tonic-gate 	if (name == NULL)
360*0Sstevel@tonic-gate 		fatal("no matching comp found: client %s server %s", client, server);
361*0Sstevel@tonic-gate 	if (strcmp(name, "zlib") == 0) {
362*0Sstevel@tonic-gate 		comp->type = 1;
363*0Sstevel@tonic-gate 	} else if (strcmp(name, "none") == 0) {
364*0Sstevel@tonic-gate 		comp->type = 0;
365*0Sstevel@tonic-gate 	} else {
366*0Sstevel@tonic-gate 		fatal("unsupported comp %s", name);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 	comp->name = name;
369*0Sstevel@tonic-gate }
370*0Sstevel@tonic-gate static void
371*0Sstevel@tonic-gate choose_kex(Kex *k, char *client, char *server)
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate 	k->name = match_list(client, server, NULL);
374*0Sstevel@tonic-gate 	if (k->name == NULL)
375*0Sstevel@tonic-gate 		fatal("no kex alg");
376*0Sstevel@tonic-gate 	/* XXX Finish 3.6/7 merge of kex stuff -- choose_kex() done */
377*0Sstevel@tonic-gate 	if (strcmp(k->name, KEX_DH1) == 0) {
378*0Sstevel@tonic-gate 		k->kex_type = KEX_DH_GRP1_SHA1;
379*0Sstevel@tonic-gate 	} else if (strcmp(k->name, KEX_DHGEX) == 0) {
380*0Sstevel@tonic-gate 		k->kex_type = KEX_DH_GEX_SHA1;
381*0Sstevel@tonic-gate #ifdef GSSAPI
382*0Sstevel@tonic-gate 	} else if (strncmp(k->name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) == 0) {
383*0Sstevel@tonic-gate 		k->kex_type = KEX_GSS_GRP1_SHA1;
384*0Sstevel@tonic-gate #endif
385*0Sstevel@tonic-gate 	} else
386*0Sstevel@tonic-gate 		fatal("bad kex alg %s", k->name);
387*0Sstevel@tonic-gate }
388*0Sstevel@tonic-gate static void
389*0Sstevel@tonic-gate choose_hostkeyalg(Kex *k, char *client, char *server)
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate 	char *hostkeyalg = match_list(client, server, NULL);
392*0Sstevel@tonic-gate 	if (hostkeyalg == NULL)
393*0Sstevel@tonic-gate 		fatal("no hostkey alg");
394*0Sstevel@tonic-gate 	k->hostkey_type = key_type_from_name(hostkeyalg);
395*0Sstevel@tonic-gate 	if (k->hostkey_type == KEY_UNSPEC)
396*0Sstevel@tonic-gate 		fatal("bad hostkey alg '%s'", hostkeyalg);
397*0Sstevel@tonic-gate 	xfree(hostkeyalg);
398*0Sstevel@tonic-gate }
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate static int
401*0Sstevel@tonic-gate proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
402*0Sstevel@tonic-gate {
403*0Sstevel@tonic-gate 	static int check[] = {
404*0Sstevel@tonic-gate 		PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
405*0Sstevel@tonic-gate 	};
406*0Sstevel@tonic-gate 	int *idx;
407*0Sstevel@tonic-gate 	char *p;
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	for (idx = &check[0]; *idx != -1; idx++) {
410*0Sstevel@tonic-gate 		if ((p = strchr(my[*idx], ',')) != NULL)
411*0Sstevel@tonic-gate 			*p = '\0';
412*0Sstevel@tonic-gate 		if ((p = strchr(peer[*idx], ',')) != NULL)
413*0Sstevel@tonic-gate 			*p = '\0';
414*0Sstevel@tonic-gate 		if (strcmp(my[*idx], peer[*idx]) != 0) {
415*0Sstevel@tonic-gate 			debug2("proposal mismatch: my %s peer %s",
416*0Sstevel@tonic-gate 			    my[*idx], peer[*idx]);
417*0Sstevel@tonic-gate 			return (0);
418*0Sstevel@tonic-gate 		}
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 	debug2("proposals match");
421*0Sstevel@tonic-gate 	return (1);
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate static void
425*0Sstevel@tonic-gate kex_choose_conf(Kex *kex)
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	Newkeys *newkeys;
428*0Sstevel@tonic-gate 	char **my, **peer;
429*0Sstevel@tonic-gate 	char **cprop, **sprop;
430*0Sstevel@tonic-gate 	char *p_langs_c2s, *p_langs_s2c; /* peer's langs */
431*0Sstevel@tonic-gate 	char *plangs = NULL;		 /* peer's langs*/
432*0Sstevel@tonic-gate 	char *mlangs = NULL;		 /* my langs */
433*0Sstevel@tonic-gate 	int nenc, nmac, ncomp;
434*0Sstevel@tonic-gate 	int mode;
435*0Sstevel@tonic-gate 	int ctos;				/* direction: if true client-to-server */
436*0Sstevel@tonic-gate 	int need;
437*0Sstevel@tonic-gate 	int first_kex_follows, type;
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	my   = kex_buf2prop(&kex->my, NULL);
440*0Sstevel@tonic-gate 	peer = kex_buf2prop(&kex->peer, &first_kex_follows);
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	if (kex->server) {
443*0Sstevel@tonic-gate 		cprop=peer;
444*0Sstevel@tonic-gate 		sprop=my;
445*0Sstevel@tonic-gate 	} else {
446*0Sstevel@tonic-gate 		cprop=my;
447*0Sstevel@tonic-gate 		sprop=peer;
448*0Sstevel@tonic-gate 	}
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	/* Algorithm Negotiation */
451*0Sstevel@tonic-gate 	for (mode = 0; mode < MODE_MAX; mode++) {
452*0Sstevel@tonic-gate 		newkeys = xmalloc(sizeof(*newkeys));
453*0Sstevel@tonic-gate 		memset(newkeys, 0, sizeof(*newkeys));
454*0Sstevel@tonic-gate 		kex->newkeys[mode] = newkeys;
455*0Sstevel@tonic-gate 		ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
456*0Sstevel@tonic-gate 		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
457*0Sstevel@tonic-gate 		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
458*0Sstevel@tonic-gate 		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
459*0Sstevel@tonic-gate 		choose_enc (&newkeys->enc,  cprop[nenc],  sprop[nenc]);
460*0Sstevel@tonic-gate 		choose_mac (&newkeys->mac,  cprop[nmac],  sprop[nmac]);
461*0Sstevel@tonic-gate 		choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]);
462*0Sstevel@tonic-gate 		debug("kex: %s %s %s %s",
463*0Sstevel@tonic-gate 		    ctos ? "client->server" : "server->client",
464*0Sstevel@tonic-gate 		    newkeys->enc.name,
465*0Sstevel@tonic-gate 		    newkeys->mac.name,
466*0Sstevel@tonic-gate 		    newkeys->comp.name);
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate 	choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
469*0Sstevel@tonic-gate 	choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
470*0Sstevel@tonic-gate 	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
471*0Sstevel@tonic-gate 	need = 0;
472*0Sstevel@tonic-gate 	for (mode = 0; mode < MODE_MAX; mode++) {
473*0Sstevel@tonic-gate 		newkeys = kex->newkeys[mode];
474*0Sstevel@tonic-gate 		if (need < newkeys->enc.key_len)
475*0Sstevel@tonic-gate 			need = newkeys->enc.key_len;
476*0Sstevel@tonic-gate 		if (need < newkeys->enc.block_size)
477*0Sstevel@tonic-gate 			need = newkeys->enc.block_size;
478*0Sstevel@tonic-gate 		if (need < newkeys->mac.key_len)
479*0Sstevel@tonic-gate 			need = newkeys->mac.key_len;
480*0Sstevel@tonic-gate 	}
481*0Sstevel@tonic-gate 	/* XXX need runden? */
482*0Sstevel@tonic-gate 	kex->we_need = need;
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	/* ignore the next message if the proposals do not match */
485*0Sstevel@tonic-gate 	if (first_kex_follows && !proposals_match(my, peer) &&
486*0Sstevel@tonic-gate 	    !(datafellows & SSH_BUG_FIRSTKEX)) {
487*0Sstevel@tonic-gate 		type = packet_read();
488*0Sstevel@tonic-gate 		debug2("skipping next packet (type %u)", type);
489*0Sstevel@tonic-gate 	}
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	/* Language/locale negotiation -- not worth doing on re-key */
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	if (!kex->initial_kex_done) {
494*0Sstevel@tonic-gate 		p_langs_c2s = peer[PROPOSAL_LANG_CTOS];
495*0Sstevel@tonic-gate 		p_langs_s2c = peer[PROPOSAL_LANG_STOC];
496*0Sstevel@tonic-gate 		debug("Peer sent proposed langtags, ctos: %s", p_langs_c2s);
497*0Sstevel@tonic-gate 		debug("Peer sent proposed langtags, stoc: %s", p_langs_s2c);
498*0Sstevel@tonic-gate 		plangs = NULL;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 		/* We propose the same langs for each protocol direction */
501*0Sstevel@tonic-gate 		mlangs = my[PROPOSAL_LANG_STOC];
502*0Sstevel@tonic-gate 		debug("We proposed langtags, ctos: %s", my[PROPOSAL_LANG_CTOS]);
503*0Sstevel@tonic-gate 		debug("We proposed langtags, stoc: %s", mlangs);
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 		/*
506*0Sstevel@tonic-gate 		 * Why oh why did they bother with negotiating langs for
507*0Sstevel@tonic-gate 		 * each protocol direction?!
508*0Sstevel@tonic-gate 		 *
509*0Sstevel@tonic-gate 		 * The semantics of this are vaguely specified, but one can
510*0Sstevel@tonic-gate 		 * imagine using one language (locale) for the whole session and
511*0Sstevel@tonic-gate 		 * a different one for message localization (e.g., 'en_US.UTF-8'
512*0Sstevel@tonic-gate 		 * overall and 'fr' for messages).  Weird?  Maybe.  But lang
513*0Sstevel@tonic-gate 		 * tags don't include codeset info, like locales do...
514*0Sstevel@tonic-gate 		 *
515*0Sstevel@tonic-gate 		 * So, server-side we want:
516*0Sstevel@tonic-gate 		 *  - setlocale(LC_ALL, c2s_locale);
517*0Sstevel@tonic-gate 		 *  and
518*0Sstevel@tonic-gate 		 *  - setlocale(LC_MESSAGES, s2c_locale);
519*0Sstevel@tonic-gate 		 *
520*0Sstevel@tonic-gate 		 * Client-side we don't really care.  But we could do:
521*0Sstevel@tonic-gate 		 *
522*0Sstevel@tonic-gate 		 *  - when very verbose, tell the use what lang the server's
523*0Sstevel@tonic-gate 		 *    messages are in, if left out in the protocol
524*0Sstevel@tonic-gate 		 *  - when sending messages to the server, and if applicable, we
525*0Sstevel@tonic-gate 		 *    can localize them according to the language negotiated for
526*0Sstevel@tonic-gate 		 *    that direction.
527*0Sstevel@tonic-gate 		 *
528*0Sstevel@tonic-gate 		 * But for now we do nothing on the client side.
529*0Sstevel@tonic-gate 		 */
530*0Sstevel@tonic-gate 		if ((p_langs_c2s && *p_langs_c2s) && !(p_langs_s2c && *p_langs_s2c))
531*0Sstevel@tonic-gate 			plangs = p_langs_c2s;
532*0Sstevel@tonic-gate 		else if ((p_langs_s2c && *p_langs_s2c) && !(p_langs_c2s && *p_langs_c2s))
533*0Sstevel@tonic-gate 			plangs = p_langs_s2c;
534*0Sstevel@tonic-gate 		else
535*0Sstevel@tonic-gate 			plangs = p_langs_c2s;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 		if (kex->server) {
538*0Sstevel@tonic-gate 			if (plangs && mlangs && *plangs && *mlangs) {
539*0Sstevel@tonic-gate 				char *locale;
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 				choose_lang(&locale, plangs, mlangs);
542*0Sstevel@tonic-gate 				if (locale) {
543*0Sstevel@tonic-gate 					g11n_setlocale(LC_ALL, locale);
544*0Sstevel@tonic-gate 					debug("Negotiated main locale: %s", locale);
545*0Sstevel@tonic-gate 					packet_send_debug("Negotiated main locale: %s", locale);
546*0Sstevel@tonic-gate 				}
547*0Sstevel@tonic-gate 				if (plangs != p_langs_s2c &&
548*0Sstevel@tonic-gate 				    p_langs_s2c && *p_langs_s2c) {
549*0Sstevel@tonic-gate 					choose_lang(&locale, p_langs_s2c, mlangs);
550*0Sstevel@tonic-gate 					if (locale) {
551*0Sstevel@tonic-gate 						g11n_setlocale(LC_MESSAGES, locale);
552*0Sstevel@tonic-gate 						debug("Negotiated messages locale: %s", locale);
553*0Sstevel@tonic-gate 						packet_send_debug("Negotiated messages locale: %s", locale);
554*0Sstevel@tonic-gate 					}
555*0Sstevel@tonic-gate 				}
556*0Sstevel@tonic-gate 				/*
557*0Sstevel@tonic-gate 				 * Should we free locale? Or does setlocale
558*0Sstevel@tonic-gate 				 * retain a reference?
559*0Sstevel@tonic-gate 				 */
560*0Sstevel@tonic-gate 				/*xfree(locale);*/
561*0Sstevel@tonic-gate 			}
562*0Sstevel@tonic-gate 		}
563*0Sstevel@tonic-gate 		else {
564*0Sstevel@tonic-gate 			if (plangs && mlangs && *plangs && *mlangs &&
565*0Sstevel@tonic-gate 			    !(datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS)) {
566*0Sstevel@tonic-gate 				char *lang;
567*0Sstevel@tonic-gate 				lang = g11n_clnt_langtag_negotiate(mlangs, plangs);
568*0Sstevel@tonic-gate 				if (lang) {
569*0Sstevel@tonic-gate 					session_lang = lang;
570*0Sstevel@tonic-gate 					debug("Negotiated lang: %s", lang);
571*0Sstevel@tonic-gate 				}
572*0Sstevel@tonic-gate 			}
573*0Sstevel@tonic-gate 		}
574*0Sstevel@tonic-gate 	}
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	kex_prop_free(my);
577*0Sstevel@tonic-gate 	kex_prop_free(peer);
578*0Sstevel@tonic-gate }
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate static u_char *
581*0Sstevel@tonic-gate derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
582*0Sstevel@tonic-gate {
583*0Sstevel@tonic-gate 	Buffer b;
584*0Sstevel@tonic-gate 	const EVP_MD *evp_md = EVP_sha1();
585*0Sstevel@tonic-gate 	EVP_MD_CTX md;
586*0Sstevel@tonic-gate 	char c = id;
587*0Sstevel@tonic-gate 	int have;
588*0Sstevel@tonic-gate 	int mdsz = EVP_MD_size(evp_md);
589*0Sstevel@tonic-gate 	u_char *digest = xmalloc(roundup(need, mdsz));
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 	buffer_init(&b);
592*0Sstevel@tonic-gate 	buffer_put_bignum2(&b, shared_secret);
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	/* K1 = HASH(K || H || "A" || session_id) */
595*0Sstevel@tonic-gate 	EVP_DigestInit(&md, evp_md);
596*0Sstevel@tonic-gate 	if (!(datafellows & SSH_BUG_DERIVEKEY))
597*0Sstevel@tonic-gate 		EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
598*0Sstevel@tonic-gate 	EVP_DigestUpdate(&md, hash, mdsz);
599*0Sstevel@tonic-gate 	EVP_DigestUpdate(&md, &c, 1);
600*0Sstevel@tonic-gate 	EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len);
601*0Sstevel@tonic-gate 	EVP_DigestFinal(&md, digest, NULL);
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/*
604*0Sstevel@tonic-gate 	 * expand key:
605*0Sstevel@tonic-gate 	 * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
606*0Sstevel@tonic-gate 	 * Key = K1 || K2 || ... || Kn
607*0Sstevel@tonic-gate 	 */
608*0Sstevel@tonic-gate 	for (have = mdsz; need > have; have += mdsz) {
609*0Sstevel@tonic-gate 		EVP_DigestInit(&md, evp_md);
610*0Sstevel@tonic-gate 		if (!(datafellows & SSH_BUG_DERIVEKEY))
611*0Sstevel@tonic-gate 			EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
612*0Sstevel@tonic-gate 		EVP_DigestUpdate(&md, hash, mdsz);
613*0Sstevel@tonic-gate 		EVP_DigestUpdate(&md, digest, have);
614*0Sstevel@tonic-gate 		EVP_DigestFinal(&md, digest + have, NULL);
615*0Sstevel@tonic-gate 	}
616*0Sstevel@tonic-gate 	buffer_free(&b);
617*0Sstevel@tonic-gate #ifdef DEBUG_KEX
618*0Sstevel@tonic-gate 	fprintf(stderr, "key '%c'== ", c);
619*0Sstevel@tonic-gate 	dump_digest("key", digest, need);
620*0Sstevel@tonic-gate #endif
621*0Sstevel@tonic-gate 	return digest;
622*0Sstevel@tonic-gate }
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate Newkeys *current_keys[MODE_MAX];
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate #define NKEYS	6
627*0Sstevel@tonic-gate void
628*0Sstevel@tonic-gate kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret)
629*0Sstevel@tonic-gate {
630*0Sstevel@tonic-gate 	u_char *keys[NKEYS];
631*0Sstevel@tonic-gate 	int i, mode, ctos;
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	for (i = 0; i < NKEYS; i++)
634*0Sstevel@tonic-gate 		keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret);
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	debug2("kex_derive_keys");
637*0Sstevel@tonic-gate 	for (mode = 0; mode < MODE_MAX; mode++) {
638*0Sstevel@tonic-gate 		current_keys[mode] = kex->newkeys[mode];
639*0Sstevel@tonic-gate 		kex->newkeys[mode] = NULL;
640*0Sstevel@tonic-gate 		ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
641*0Sstevel@tonic-gate 		current_keys[mode]->enc.iv  = keys[ctos ? 0 : 1];
642*0Sstevel@tonic-gate 		current_keys[mode]->enc.key = keys[ctos ? 2 : 3];
643*0Sstevel@tonic-gate 		current_keys[mode]->mac.key = keys[ctos ? 4 : 5];
644*0Sstevel@tonic-gate 	}
645*0Sstevel@tonic-gate }
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate Newkeys *
648*0Sstevel@tonic-gate kex_get_newkeys(int mode)
649*0Sstevel@tonic-gate {
650*0Sstevel@tonic-gate 	Newkeys *ret;
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	ret = current_keys[mode];
653*0Sstevel@tonic-gate 	current_keys[mode] = NULL;
654*0Sstevel@tonic-gate 	return ret;
655*0Sstevel@tonic-gate }
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
658*0Sstevel@tonic-gate void
659*0Sstevel@tonic-gate dump_digest(char *msg, u_char *digest, int len)
660*0Sstevel@tonic-gate {
661*0Sstevel@tonic-gate 	int i;
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	fprintf(stderr, "%s\n", msg);
664*0Sstevel@tonic-gate 	for (i = 0; i< len; i++) {
665*0Sstevel@tonic-gate 		fprintf(stderr, "%02x", digest[i]);
666*0Sstevel@tonic-gate 		if (i%32 == 31)
667*0Sstevel@tonic-gate 			fprintf(stderr, "\n");
668*0Sstevel@tonic-gate 		else if (i%8 == 7)
669*0Sstevel@tonic-gate 			fprintf(stderr, " ");
670*0Sstevel@tonic-gate 	}
671*0Sstevel@tonic-gate 	fprintf(stderr, "\n");
672*0Sstevel@tonic-gate }
673*0Sstevel@tonic-gate #endif
674