blob: 308ffb1b66f320547045c3f18aeea5005cc2b98a [file] [log] [blame]
Damien Millera664e872000-04-16 11:52:47 +10001/*
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.
Damien Millera664e872000-04-16 11:52:47 +100012 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +000026RCSID("$OpenBSD: kex.c,v 1.22 2001/03/05 17:17:20 markus Exp $");
Damien Millera664e872000-04-16 11:52:47 +100027
28#include <openssl/crypto.h>
29#include <openssl/bio.h>
30#include <openssl/bn.h>
31#include <openssl/dh.h>
32#include <openssl/pem.h>
33
Ben Lindstrom226cfa02001-01-22 05:34:40 +000034#include "ssh2.h"
35#include "xmalloc.h"
36#include "buffer.h"
37#include "bufaux.h"
38#include "packet.h"
39#include "compat.h"
40#include "cipher.h"
Damien Millera664e872000-04-16 11:52:47 +100041#include "kex.h"
Damien Miller0bc1bd82000-11-13 22:57:25 +110042#include "key.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000043#include "log.h"
Ben Lindstrom06b33aa2001-02-15 03:01:59 +000044#include "mac.h"
Damien Millera664e872000-04-16 11:52:47 +100045
Damien Millerb1715dc2000-05-30 13:44:51 +100046#define KEX_COOKIE_LEN 16
47
Damien Millera664e872000-04-16 11:52:47 +100048Buffer *
49kex_init(char *myproposal[PROPOSAL_MAX])
50{
Damien Millerb1715dc2000-05-30 13:44:51 +100051 int first_kex_packet_follows = 0;
Ben Lindstrom46c16222000-12-22 01:43:59 +000052 u_char cookie[KEX_COOKIE_LEN];
Damien Millera664e872000-04-16 11:52:47 +100053 u_int32_t rand = 0;
54 int i;
55 Buffer *ki = xmalloc(sizeof(*ki));
Damien Millerb1715dc2000-05-30 13:44:51 +100056 for (i = 0; i < KEX_COOKIE_LEN; i++) {
Damien Millera664e872000-04-16 11:52:47 +100057 if (i % 4 == 0)
58 rand = arc4random();
59 cookie[i] = rand & 0xff;
60 rand >>= 8;
61 }
62 buffer_init(ki);
63 buffer_append(ki, (char *)cookie, sizeof cookie);
64 for (i = 0; i < PROPOSAL_MAX; i++)
65 buffer_put_cstring(ki, myproposal[i]);
Damien Millerb1715dc2000-05-30 13:44:51 +100066 buffer_put_char(ki, first_kex_packet_follows);
67 buffer_put_int(ki, 0); /* uint32 reserved */
Damien Millera664e872000-04-16 11:52:47 +100068 return ki;
69}
70
Damien Millerb1715dc2000-05-30 13:44:51 +100071/* send kexinit, parse and save reply */
72void
73kex_exchange_kexinit(
74 Buffer *my_kexinit, Buffer *peer_kexint,
75 char *peer_proposal[PROPOSAL_MAX])
76{
77 int i;
78 char *ptr;
79 int plen;
80
81 debug("send KEXINIT");
82 packet_start(SSH2_MSG_KEXINIT);
Kevin Stevesef4eea92001-02-05 12:42:17 +000083 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
Damien Millerb1715dc2000-05-30 13:44:51 +100084 packet_send();
85 packet_write_wait();
86 debug("done");
87
88 /*
89 * read and save raw KEXINIT payload in buffer. this is used during
90 * computation of the session_id and the session keys.
91 */
92 debug("wait KEXINIT");
93 packet_read_expect(&plen, SSH2_MSG_KEXINIT);
94 ptr = packet_get_raw(&plen);
95 buffer_append(peer_kexint, ptr, plen);
96
97 /* parse packet and save algorithm proposal */
98 /* skip cookie */
99 for (i = 0; i < KEX_COOKIE_LEN; i++)
100 packet_get_char();
101 /* extract kex init proposal strings */
102 for (i = 0; i < PROPOSAL_MAX; i++) {
103 peer_proposal[i] = packet_get_string(NULL);
104 debug("got kexinit: %s", peer_proposal[i]);
105 }
106 /* first kex follow / reserved */
107 i = packet_get_char();
108 debug("first kex follow: %d ", i);
109 i = packet_get_int();
110 debug("reserved: %d ", i);
111 packet_done();
112 debug("done");
113}
114
Damien Millera664e872000-04-16 11:52:47 +1000115/* diffie-hellman-group1-sha1 */
116
117int
118dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
119{
120 int i;
121 int n = BN_num_bits(dh_pub);
122 int bits_set = 0;
123
Damien Millera664e872000-04-16 11:52:47 +1000124 if (dh_pub->neg) {
125 log("invalid public DH value: negativ");
126 return 0;
127 }
128 for (i = 0; i <= n; i++)
129 if (BN_is_bit_set(dh_pub, i))
130 bits_set++;
131 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
132
133 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
134 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
135 return 1;
136 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
137 return 0;
138}
139
Kevin Steves6b875862000-12-15 23:31:01 +0000140void
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000141dh_gen_key(DH *dh, int need)
Damien Millera664e872000-04-16 11:52:47 +1000142{
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000143 int i, bits_set = 0, tries = 0;
Damien Miller874d77b2000-10-14 16:23:11 +1100144
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000145 if (dh->p == NULL)
146 fatal("dh_gen_key: dh->p == NULL");
147 if (2*need >= BN_num_bits(dh->p))
148 fatal("dh_gen_key: group too small: %d (2*need %d)",
149 BN_num_bits(dh->p), 2*need);
Damien Millera664e872000-04-16 11:52:47 +1000150 do {
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000151 if (dh->priv_key != NULL)
152 BN_free(dh->priv_key);
153 dh->priv_key = BN_new();
154 if (dh->priv_key == NULL)
155 fatal("dh_gen_key: BN_new failed");
156 /* generate a 2*need bits random private exponent */
157 if (!BN_rand(dh->priv_key, 2*need, 0, 0))
158 fatal("dh_gen_key: BN_rand failed");
Damien Millera664e872000-04-16 11:52:47 +1000159 if (DH_generate_key(dh) == 0)
160 fatal("DH_generate_key");
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000161 for (i = 0; i <= BN_num_bits(dh->priv_key); i++)
162 if (BN_is_bit_set(dh->priv_key, i))
163 bits_set++;
164 debug("dh_gen_key: priv key bits set: %d/%d",
165 bits_set, BN_num_bits(dh->priv_key));
Damien Millera664e872000-04-16 11:52:47 +1000166 if (tries++ > 10)
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000167 fatal("dh_gen_key: too many bad keys: giving up");
Damien Millera664e872000-04-16 11:52:47 +1000168 } while (!dh_pub_is_valid(dh, dh->pub_key));
Damien Millera664e872000-04-16 11:52:47 +1000169}
170
Damien Miller874d77b2000-10-14 16:23:11 +1100171DH *
172dh_new_group_asc(const char *gen, const char *modulus)
173{
174 DH *dh;
175 int ret;
176
177 dh = DH_new();
178 if (dh == NULL)
179 fatal("DH_new");
180
181 if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
182 fatal("BN_hex2bn p");
183 if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
184 fatal("BN_hex2bn g");
185
Kevin Steves6b875862000-12-15 23:31:01 +0000186 return (dh);
Damien Miller874d77b2000-10-14 16:23:11 +1100187}
188
Kevin Steves6b875862000-12-15 23:31:01 +0000189/*
190 * This just returns the group, we still need to generate the exchange
191 * value.
192 */
193
Damien Miller874d77b2000-10-14 16:23:11 +1100194DH *
195dh_new_group(BIGNUM *gen, BIGNUM *modulus)
196{
197 DH *dh;
198
199 dh = DH_new();
200 if (dh == NULL)
201 fatal("DH_new");
202 dh->p = modulus;
203 dh->g = gen;
204
Kevin Steves6b875862000-12-15 23:31:01 +0000205 return (dh);
Damien Miller874d77b2000-10-14 16:23:11 +1100206}
207
208DH *
Ben Lindstrom46c16222000-12-22 01:43:59 +0000209dh_new_group1(void)
Damien Miller874d77b2000-10-14 16:23:11 +1100210{
211 static char *gen = "2", *group1 =
212 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
213 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
214 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
215 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
216 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
217 "FFFFFFFF" "FFFFFFFF";
218
219 return (dh_new_group_asc(gen, group1));
220}
221
Ben Lindstrom31ca54a2001-02-09 02:11:24 +0000222#ifdef DEBUG_KEX
Damien Millera664e872000-04-16 11:52:47 +1000223void
Ben Lindstrom46c16222000-12-22 01:43:59 +0000224dump_digest(u_char *digest, int len)
Damien Millera664e872000-04-16 11:52:47 +1000225{
226 int i;
227 for (i = 0; i< len; i++){
228 fprintf(stderr, "%02x", digest[i]);
229 if(i%2!=0)
230 fprintf(stderr, " ");
231 }
232 fprintf(stderr, "\n");
233}
Ben Lindstrom31ca54a2001-02-09 02:11:24 +0000234#endif
Damien Millera664e872000-04-16 11:52:47 +1000235
Ben Lindstrom46c16222000-12-22 01:43:59 +0000236u_char *
Damien Millera664e872000-04-16 11:52:47 +1000237kex_hash(
238 char *client_version_string,
239 char *server_version_string,
240 char *ckexinit, int ckexinitlen,
241 char *skexinit, int skexinitlen,
242 char *serverhostkeyblob, int sbloblen,
243 BIGNUM *client_dh_pub,
244 BIGNUM *server_dh_pub,
245 BIGNUM *shared_secret)
246{
247 Buffer b;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000248 static u_char digest[EVP_MAX_MD_SIZE];
Damien Millera664e872000-04-16 11:52:47 +1000249 EVP_MD *evp_md = EVP_sha1();
250 EVP_MD_CTX md;
251
252 buffer_init(&b);
253 buffer_put_string(&b, client_version_string, strlen(client_version_string));
254 buffer_put_string(&b, server_version_string, strlen(server_version_string));
255
256 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
257 buffer_put_int(&b, ckexinitlen+1);
258 buffer_put_char(&b, SSH2_MSG_KEXINIT);
259 buffer_append(&b, ckexinit, ckexinitlen);
260 buffer_put_int(&b, skexinitlen+1);
261 buffer_put_char(&b, SSH2_MSG_KEXINIT);
262 buffer_append(&b, skexinit, skexinitlen);
263
264 buffer_put_string(&b, serverhostkeyblob, sbloblen);
265 buffer_put_bignum2(&b, client_dh_pub);
266 buffer_put_bignum2(&b, server_dh_pub);
267 buffer_put_bignum2(&b, shared_secret);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000268
Damien Millera664e872000-04-16 11:52:47 +1000269#ifdef DEBUG_KEX
270 buffer_dump(&b);
271#endif
272
273 EVP_DigestInit(&md, evp_md);
274 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
275 EVP_DigestFinal(&md, digest, NULL);
276
277 buffer_free(&b);
278
279#ifdef DEBUG_KEX
280 dump_digest(digest, evp_md->md_size);
281#endif
282 return digest;
283}
284
Ben Lindstrom46c16222000-12-22 01:43:59 +0000285u_char *
Damien Miller874d77b2000-10-14 16:23:11 +1100286kex_hash_gex(
287 char *client_version_string,
288 char *server_version_string,
289 char *ckexinit, int ckexinitlen,
290 char *skexinit, int skexinitlen,
291 char *serverhostkeyblob, int sbloblen,
292 int minbits, BIGNUM *prime, BIGNUM *gen,
293 BIGNUM *client_dh_pub,
294 BIGNUM *server_dh_pub,
295 BIGNUM *shared_secret)
296{
297 Buffer b;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000298 static u_char digest[EVP_MAX_MD_SIZE];
Damien Miller874d77b2000-10-14 16:23:11 +1100299 EVP_MD *evp_md = EVP_sha1();
300 EVP_MD_CTX md;
301
302 buffer_init(&b);
303 buffer_put_string(&b, client_version_string, strlen(client_version_string));
304 buffer_put_string(&b, server_version_string, strlen(server_version_string));
305
306 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
307 buffer_put_int(&b, ckexinitlen+1);
308 buffer_put_char(&b, SSH2_MSG_KEXINIT);
309 buffer_append(&b, ckexinit, ckexinitlen);
310 buffer_put_int(&b, skexinitlen+1);
311 buffer_put_char(&b, SSH2_MSG_KEXINIT);
312 buffer_append(&b, skexinit, skexinitlen);
313
314 buffer_put_string(&b, serverhostkeyblob, sbloblen);
315 buffer_put_int(&b, minbits);
316 buffer_put_bignum2(&b, prime);
317 buffer_put_bignum2(&b, gen);
318 buffer_put_bignum2(&b, client_dh_pub);
319 buffer_put_bignum2(&b, server_dh_pub);
320 buffer_put_bignum2(&b, shared_secret);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000321
Damien Miller874d77b2000-10-14 16:23:11 +1100322#ifdef DEBUG_KEX
323 buffer_dump(&b);
324#endif
325
326 EVP_DigestInit(&md, evp_md);
327 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
328 EVP_DigestFinal(&md, digest, NULL);
329
330 buffer_free(&b);
331
332#ifdef DEBUG_KEX
333 dump_digest(digest, evp_md->md_size);
334#endif
335 return digest;
336}
337
Ben Lindstrom46c16222000-12-22 01:43:59 +0000338u_char *
339derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
Damien Millera664e872000-04-16 11:52:47 +1000340{
341 Buffer b;
342 EVP_MD *evp_md = EVP_sha1();
343 EVP_MD_CTX md;
344 char c = id;
345 int have;
346 int mdsz = evp_md->md_size;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000347 u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
Damien Millera664e872000-04-16 11:52:47 +1000348
349 buffer_init(&b);
350 buffer_put_bignum2(&b, shared_secret);
351
352 EVP_DigestInit(&md, evp_md);
353 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
354 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
355 EVP_DigestUpdate(&md, &c, 1); /* key id */
356 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
357 EVP_DigestFinal(&md, digest, NULL);
358
359 /* expand */
360 for (have = mdsz; need > have; have += mdsz) {
361 EVP_DigestInit(&md, evp_md);
362 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
363 EVP_DigestUpdate(&md, hash, mdsz);
364 EVP_DigestUpdate(&md, digest, have);
365 EVP_DigestFinal(&md, digest + have, NULL);
366 }
367 buffer_free(&b);
368#ifdef DEBUG_KEX
369 fprintf(stderr, "Digest '%c'== ", c);
370 dump_digest(digest, need);
371#endif
372 return digest;
373}
374
375#define NKEYS 6
376
377#define MAX_PROP 20
378#define SEP ","
379
380char *
381get_match(char *client, char *server)
382{
383 char *sproposals[MAX_PROP];
Damien Miller37023962000-07-11 17:31:38 +1000384 char *c, *s, *p, *ret, *cp, *sp;
Damien Millera664e872000-04-16 11:52:47 +1000385 int i, j, nproposals;
386
Damien Miller37023962000-07-11 17:31:38 +1000387 c = cp = xstrdup(client);
388 s = sp = xstrdup(server);
Damien Millerb1715dc2000-05-30 13:44:51 +1000389
Kevin Stevesef4eea92001-02-05 12:42:17 +0000390 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
Damien Miller37023962000-07-11 17:31:38 +1000391 (p = strsep(&sp, SEP)), i++) {
Damien Millera664e872000-04-16 11:52:47 +1000392 if (i < MAX_PROP)
393 sproposals[i] = p;
394 else
395 break;
396 }
397 nproposals = i;
398
Kevin Stevesef4eea92001-02-05 12:42:17 +0000399 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
Damien Miller37023962000-07-11 17:31:38 +1000400 (p = strsep(&cp, SEP)), i++) {
Damien Millerb1715dc2000-05-30 13:44:51 +1000401 for (j = 0; j < nproposals; j++) {
402 if (strcmp(p, sproposals[j]) == 0) {
403 ret = xstrdup(p);
404 xfree(c);
405 xfree(s);
406 return ret;
407 }
408 }
Damien Millera664e872000-04-16 11:52:47 +1000409 }
Damien Millerb1715dc2000-05-30 13:44:51 +1000410 xfree(c);
411 xfree(s);
Damien Millera664e872000-04-16 11:52:47 +1000412 return NULL;
413}
414void
415choose_enc(Enc *enc, char *client, char *server)
416{
417 char *name = get_match(client, server);
418 if (name == NULL)
419 fatal("no matching cipher found: client %s server %s", client, server);
Damien Miller874d77b2000-10-14 16:23:11 +1100420 enc->cipher = cipher_by_name(name);
421 if (enc->cipher == NULL)
422 fatal("matching cipher is not supported: %s", name);
Damien Millera664e872000-04-16 11:52:47 +1000423 enc->name = name;
424 enc->enabled = 0;
425 enc->iv = NULL;
426 enc->key = NULL;
427}
428void
429choose_mac(Mac *mac, char *client, char *server)
430{
431 char *name = get_match(client, server);
432 if (name == NULL)
433 fatal("no matching mac found: client %s server %s", client, server);
Ben Lindstrom06b33aa2001-02-15 03:01:59 +0000434 if (mac_init(mac, name) < 0)
Damien Millera664e872000-04-16 11:52:47 +1000435 fatal("unsupported mac %s", name);
Ben Lindstrom06b33aa2001-02-15 03:01:59 +0000436 /* truncate the key */
437 if (datafellows & SSH_BUG_HMAC)
438 mac->key_len = 16;
Damien Millera664e872000-04-16 11:52:47 +1000439 mac->name = name;
Damien Millera664e872000-04-16 11:52:47 +1000440 mac->key = NULL;
441 mac->enabled = 0;
442}
443void
444choose_comp(Comp *comp, char *client, char *server)
445{
446 char *name = get_match(client, server);
447 if (name == NULL)
448 fatal("no matching comp found: client %s server %s", client, server);
449 if (strcmp(name, "zlib") == 0) {
450 comp->type = 1;
451 } else if (strcmp(name, "none") == 0) {
452 comp->type = 0;
453 } else {
454 fatal("unsupported comp %s", name);
455 }
456 comp->name = name;
457}
458void
459choose_kex(Kex *k, char *client, char *server)
460{
461 k->name = get_match(client, server);
462 if (k->name == NULL)
463 fatal("no kex alg");
Damien Miller874d77b2000-10-14 16:23:11 +1100464 if (strcmp(k->name, KEX_DH1) == 0) {
465 k->kex_type = DH_GRP1_SHA1;
466 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
467 k->kex_type = DH_GEX_SHA1;
468 } else
Damien Millera664e872000-04-16 11:52:47 +1000469 fatal("bad kex alg %s", k->name);
470}
471void
472choose_hostkeyalg(Kex *k, char *client, char *server)
473{
Damien Miller0bc1bd82000-11-13 22:57:25 +1100474 char *hostkeyalg = get_match(client, server);
475 if (hostkeyalg == NULL)
Damien Millera664e872000-04-16 11:52:47 +1000476 fatal("no hostkey alg");
Damien Miller0bc1bd82000-11-13 22:57:25 +1100477 k->hostkey_type = key_type_from_name(hostkeyalg);
478 if (k->hostkey_type == KEY_UNSPEC)
479 fatal("bad hostkey alg '%s'", hostkeyalg);
Ben Lindstrom48bd7c12001-01-09 00:35:42 +0000480 xfree(hostkeyalg);
Damien Millera664e872000-04-16 11:52:47 +1000481}
482
483Kex *
484kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
485{
Damien Millera664e872000-04-16 11:52:47 +1000486 int mode;
487 int ctos; /* direction: if true client-to-server */
488 int need;
489 Kex *k;
490
491 k = xmalloc(sizeof(*k));
492 memset(k, 0, sizeof(*k));
493 k->server = server;
494
495 for (mode = 0; mode < MODE_MAX; mode++) {
496 int nenc, nmac, ncomp;
497 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
498 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
499 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
500 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
501 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
502 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
503 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
504 debug("kex: %s %s %s %s",
505 ctos ? "client->server" : "server->client",
506 k->enc[mode].name,
507 k->mac[mode].name,
508 k->comp[mode].name);
509 }
510 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
511 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
512 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
Damien Millera664e872000-04-16 11:52:47 +1000513 need = 0;
514 for (mode = 0; mode < MODE_MAX; mode++) {
Damien Miller874d77b2000-10-14 16:23:11 +1100515 if (need < k->enc[mode].cipher->key_len)
516 need = k->enc[mode].cipher->key_len;
517 if (need < k->enc[mode].cipher->block_size)
518 need = k->enc[mode].cipher->block_size;
Damien Millera664e872000-04-16 11:52:47 +1000519 if (need < k->mac[mode].key_len)
520 need = k->mac[mode].key_len;
521 }
Damien Millerb1715dc2000-05-30 13:44:51 +1000522 /* XXX need runden? */
Damien Millera664e872000-04-16 11:52:47 +1000523 k->we_need = need;
524 return k;
525}
526
527int
Ben Lindstrom46c16222000-12-22 01:43:59 +0000528kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
Damien Millera664e872000-04-16 11:52:47 +1000529{
530 int i;
531 int mode;
532 int ctos;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000533 u_char *keys[NKEYS];
Damien Millera664e872000-04-16 11:52:47 +1000534
535 for (i = 0; i < NKEYS; i++)
536 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
537
538 for (mode = 0; mode < MODE_MAX; mode++) {
539 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
540 k->enc[mode].iv = keys[ctos ? 0 : 1];
541 k->enc[mode].key = keys[ctos ? 2 : 3];
542 k->mac[mode].key = keys[ctos ? 4 : 5];
543 }
544 return 0;
545}