xref: /freebsd/crypto/openssh/kex.c (revision 64db83a8ab2d1f72a9b2174b39d2ef42b5b0580c)
1 /*
2  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Markus Friedl.
15  * 4. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "includes.h"
31 RCSID("$Id: kex.c,v 1.6 2000/05/08 17:42:25 markus Exp $");
32 
33 #include "ssh.h"
34 #include "ssh2.h"
35 #include "xmalloc.h"
36 #include "buffer.h"
37 #include "bufaux.h"
38 #include "cipher.h"
39 #include "compat.h"
40 
41 #include <openssl/bn.h>
42 #include <openssl/dh.h>
43 
44 #include <openssl/crypto.h>
45 #include <openssl/bio.h>
46 #include <openssl/bn.h>
47 #include <openssl/dh.h>
48 #include <openssl/pem.h>
49 
50 #include "kex.h"
51 
52 Buffer *
53 kex_init(char *myproposal[PROPOSAL_MAX])
54 {
55 	char c = 0;
56 	unsigned char cookie[16];
57 	u_int32_t rand = 0;
58 	int i;
59 	Buffer *ki = xmalloc(sizeof(*ki));
60 	for (i = 0; i < 16; i++) {
61 		if (i % 4 == 0)
62 			rand = arc4random();
63 		cookie[i] = rand & 0xff;
64 		rand >>= 8;
65 	}
66 	buffer_init(ki);
67 	buffer_append(ki, (char *)cookie, sizeof cookie);
68 	for (i = 0; i < PROPOSAL_MAX; i++)
69 		buffer_put_cstring(ki, myproposal[i]);
70 	buffer_append(ki, &c, 1); /* boolean   first_kex_packet_follows */
71 	buffer_put_int(ki, 0);    /* uint32    0 (reserved for future extension) */
72 	return ki;
73 }
74 
75 /* diffie-hellman-group1-sha1 */
76 
77 int
78 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
79 {
80 	int i;
81 	int n = BN_num_bits(dh_pub);
82 	int bits_set = 0;
83 
84 	/* we only accept g==2 */
85 	if (!BN_is_word(dh->g, 2)) {
86 		log("invalid DH base != 2");
87 		return 0;
88 	}
89 	if (dh_pub->neg) {
90 		log("invalid public DH value: negativ");
91 		return 0;
92 	}
93 	for (i = 0; i <= n; i++)
94 		if (BN_is_bit_set(dh_pub, i))
95 			bits_set++;
96 	debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
97 
98 	/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
99 	if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
100 		return 1;
101 	log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
102 	return 0;
103 }
104 
105 DH *
106 dh_new_group1()
107 {
108 	static char *group1 =
109 	    "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
110 	    "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
111 	    "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
112 	    "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
113 	    "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
114 	    "FFFFFFFF" "FFFFFFFF";
115 	DH *dh;
116 	int ret, tries = 0;
117 	dh = DH_new();
118 	if(dh == NULL)
119 		fatal("DH_new");
120 	ret = BN_hex2bn(&dh->p, group1);
121 	if(ret<0)
122 		fatal("BN_hex2bn");
123 	dh->g = BN_new();
124 	if(dh->g == NULL)
125 		fatal("DH_new g");
126 	BN_set_word(dh->g, 2);
127 	do {
128 		if (DH_generate_key(dh) == 0)
129 			fatal("DH_generate_key");
130 		if (tries++ > 10)
131 			fatal("dh_new_group1: too many bad keys: giving up");
132 	} while (!dh_pub_is_valid(dh, dh->pub_key));
133 	return dh;
134 }
135 
136 void
137 bignum_print(BIGNUM *b)
138 {
139 	BN_print_fp(stderr,b);
140 }
141 
142 void
143 dump_digest(unsigned char *digest, int len)
144 {
145 	int i;
146 	for (i = 0; i< len; i++){
147 		fprintf(stderr, "%02x", digest[i]);
148 		if(i%2!=0)
149 			fprintf(stderr, " ");
150 	}
151 	fprintf(stderr, "\n");
152 }
153 
154 unsigned char *
155 kex_hash(
156     char *client_version_string,
157     char *server_version_string,
158     char *ckexinit, int ckexinitlen,
159     char *skexinit, int skexinitlen,
160     char *serverhostkeyblob, int sbloblen,
161     BIGNUM *client_dh_pub,
162     BIGNUM *server_dh_pub,
163     BIGNUM *shared_secret)
164 {
165 	Buffer b;
166 	static unsigned char digest[EVP_MAX_MD_SIZE];
167 	EVP_MD *evp_md = EVP_sha1();
168 	EVP_MD_CTX md;
169 
170 	buffer_init(&b);
171 	buffer_put_string(&b, client_version_string, strlen(client_version_string));
172 	buffer_put_string(&b, server_version_string, strlen(server_version_string));
173 
174 	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
175 	buffer_put_int(&b, ckexinitlen+1);
176 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
177 	buffer_append(&b, ckexinit, ckexinitlen);
178 	buffer_put_int(&b, skexinitlen+1);
179 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
180 	buffer_append(&b, skexinit, skexinitlen);
181 
182 	buffer_put_string(&b, serverhostkeyblob, sbloblen);
183 	buffer_put_bignum2(&b, client_dh_pub);
184 	buffer_put_bignum2(&b, server_dh_pub);
185 	buffer_put_bignum2(&b, shared_secret);
186 
187 #ifdef DEBUG_KEX
188 	buffer_dump(&b);
189 #endif
190 
191 	EVP_DigestInit(&md, evp_md);
192 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
193 	EVP_DigestFinal(&md, digest, NULL);
194 
195 	buffer_free(&b);
196 
197 #ifdef DEBUG_KEX
198 	dump_digest(digest, evp_md->md_size);
199 #endif
200 	return digest;
201 }
202 
203 unsigned char *
204 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
205 {
206 	Buffer b;
207 	EVP_MD *evp_md = EVP_sha1();
208 	EVP_MD_CTX md;
209 	char c = id;
210 	int have;
211 	int mdsz = evp_md->md_size;
212 	unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
213 
214 	buffer_init(&b);
215 	buffer_put_bignum2(&b, shared_secret);
216 
217 	EVP_DigestInit(&md, evp_md);
218 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));	/* shared_secret K */
219 	EVP_DigestUpdate(&md, hash, mdsz);		/* transport-06 */
220 	EVP_DigestUpdate(&md, &c, 1);			/* key id */
221 	EVP_DigestUpdate(&md, hash, mdsz);		/* session id */
222 	EVP_DigestFinal(&md, digest, NULL);
223 
224 	/* expand */
225 	for (have = mdsz; need > have; have += mdsz) {
226 		EVP_DigestInit(&md, evp_md);
227 		EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
228 		EVP_DigestUpdate(&md, hash, mdsz);
229 		EVP_DigestUpdate(&md, digest, have);
230 		EVP_DigestFinal(&md, digest + have, NULL);
231 	}
232 	buffer_free(&b);
233 #ifdef DEBUG_KEX
234 	fprintf(stderr, "Digest '%c'== ", c);
235 	dump_digest(digest, need);
236 #endif
237 	return digest;
238 }
239 
240 #define NKEYS	6
241 
242 #define	MAX_PROP	20
243 #define	SEP	","
244 
245 char *
246 get_match(char *client, char *server)
247 {
248 	char *sproposals[MAX_PROP];
249 	char *p;
250 	int i, j, nproposals;
251 
252 	for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
253 		if (i < MAX_PROP)
254 			sproposals[i] = p;
255 		else
256 			break;
257 	}
258 	nproposals = i;
259 
260 	for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
261 		for (j = 0; j < nproposals; j++)
262 			if (strcmp(p, sproposals[j]) == 0)
263 				return xstrdup(p);
264 	}
265 	return NULL;
266 }
267 void
268 choose_enc(Enc *enc, char *client, char *server)
269 {
270 	char *name = get_match(client, server);
271 	if (name == NULL)
272 		fatal("no matching cipher found: client %s server %s", client, server);
273 	enc->type = cipher_number(name);
274 
275 	switch (enc->type) {
276 	case SSH_CIPHER_3DES_CBC:
277 		enc->key_len = 24;
278 		enc->iv_len = 8;
279 		enc->block_size = 8;
280 		break;
281 	case SSH_CIPHER_BLOWFISH_CBC:
282 	case SSH_CIPHER_CAST128_CBC:
283 		enc->key_len = 16;
284 		enc->iv_len = 8;
285 		enc->block_size = 8;
286 		break;
287 	case SSH_CIPHER_ARCFOUR:
288 		enc->key_len = 16;
289 		enc->iv_len = 0;
290 		enc->block_size = 8;
291 		break;
292 	default:
293 		fatal("unsupported cipher %s", name);
294 	}
295 	enc->name = name;
296 	enc->enabled = 0;
297 	enc->iv = NULL;
298 	enc->key = NULL;
299 }
300 void
301 choose_mac(Mac *mac, char *client, char *server)
302 {
303 	char *name = get_match(client, server);
304 	if (name == NULL)
305 		fatal("no matching mac found: client %s server %s", client, server);
306 	if (strcmp(name, "hmac-md5") == 0) {
307 		mac->md = EVP_md5();
308 	} else if (strcmp(name, "hmac-sha1") == 0) {
309 		mac->md = EVP_sha1();
310 	} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
311 		mac->md = EVP_ripemd160();
312 	} else {
313 		fatal("unsupported mac %s", name);
314 	}
315 	mac->name = name;
316 	mac->mac_len = mac->md->md_size;
317 	mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
318 	mac->key = NULL;
319 	mac->enabled = 0;
320 }
321 void
322 choose_comp(Comp *comp, char *client, char *server)
323 {
324 	char *name = get_match(client, server);
325 	if (name == NULL)
326 		fatal("no matching comp found: client %s server %s", client, server);
327 	if (strcmp(name, "zlib") == 0) {
328 		comp->type = 1;
329 	} else if (strcmp(name, "none") == 0) {
330 		comp->type = 0;
331 	} else {
332 		fatal("unsupported comp %s", name);
333 	}
334 	comp->name = name;
335 }
336 void
337 choose_kex(Kex *k, char *client, char *server)
338 {
339 	k->name = get_match(client, server);
340 	if (k->name == NULL)
341 		fatal("no kex alg");
342 	if (strcmp(k->name, KEX_DH1) != 0)
343 		fatal("bad kex alg %s", k->name);
344 }
345 void
346 choose_hostkeyalg(Kex *k, char *client, char *server)
347 {
348 	k->hostkeyalg = get_match(client, server);
349 	if (k->hostkeyalg == NULL)
350 		fatal("no hostkey alg");
351 	if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
352 		fatal("bad hostkey alg %s", k->hostkeyalg);
353 }
354 
355 Kex *
356 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
357 {
358 	int i;
359 	int mode;
360 	int ctos;				/* direction: if true client-to-server */
361 	int need;
362 	Kex *k;
363 
364 	k = xmalloc(sizeof(*k));
365 	memset(k, 0, sizeof(*k));
366 	k->server = server;
367 
368 	for (mode = 0; mode < MODE_MAX; mode++) {
369 		int nenc, nmac, ncomp;
370 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
371 		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
372 		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
373 		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
374 		choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
375 		choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
376 		choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
377 		debug("kex: %s %s %s %s",
378 		    ctos ? "client->server" : "server->client",
379 		    k->enc[mode].name,
380 		    k->mac[mode].name,
381 		    k->comp[mode].name);
382 	}
383 	choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
384 	choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
385 	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
386 	for (i = 0; i < PROPOSAL_MAX; i++) {
387 		xfree(cprop[i]);
388 		xfree(sprop[i]);
389 	}
390 	need = 0;
391 	for (mode = 0; mode < MODE_MAX; mode++) {
392 	    if (need < k->enc[mode].key_len)
393 		    need = k->enc[mode].key_len;
394 	    if (need < k->enc[mode].iv_len)
395 		    need = k->enc[mode].iv_len;
396 	    if (need < k->mac[mode].key_len)
397 		    need = k->mac[mode].key_len;
398 	}
399 	/* need runden? */
400 #define WE_NEED 32
401 	k->we_need = WE_NEED;
402 	k->we_need = need;
403 	return k;
404 }
405 
406 int
407 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
408 {
409 	int i;
410 	int mode;
411 	int ctos;
412 	unsigned char *keys[NKEYS];
413 
414 	for (i = 0; i < NKEYS; i++)
415 		keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
416 
417 	for (mode = 0; mode < MODE_MAX; mode++) {
418 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
419 		k->enc[mode].iv  = keys[ctos ? 0 : 1];
420 		k->enc[mode].key = keys[ctos ? 2 : 3];
421 		k->mac[mode].key = keys[ctos ? 4 : 5];
422 	}
423 	return 0;
424 }
425