blob: 78e108e90c157e5b14dce622b099631be0c82f9e [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 Lindstromb9be60a2001-03-11 01:49:19 +000026RCSID("$OpenBSD: kex.c,v 1.23 2001/03/10 17:51:04 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"
Ben Lindstromb9be60a2001-03-11 01:49:19 +000045#include "match.h"
Damien Millera664e872000-04-16 11:52:47 +100046
Damien Millerb1715dc2000-05-30 13:44:51 +100047#define KEX_COOKIE_LEN 16
48
Damien Millera664e872000-04-16 11:52:47 +100049Buffer *
50kex_init(char *myproposal[PROPOSAL_MAX])
51{
Damien Millerb1715dc2000-05-30 13:44:51 +100052 int first_kex_packet_follows = 0;
Ben Lindstrom46c16222000-12-22 01:43:59 +000053 u_char cookie[KEX_COOKIE_LEN];
Damien Millera664e872000-04-16 11:52:47 +100054 u_int32_t rand = 0;
55 int i;
56 Buffer *ki = xmalloc(sizeof(*ki));
Damien Millerb1715dc2000-05-30 13:44:51 +100057 for (i = 0; i < KEX_COOKIE_LEN; i++) {
Damien Millera664e872000-04-16 11:52:47 +100058 if (i % 4 == 0)
59 rand = arc4random();
60 cookie[i] = rand & 0xff;
61 rand >>= 8;
62 }
63 buffer_init(ki);
64 buffer_append(ki, (char *)cookie, sizeof cookie);
65 for (i = 0; i < PROPOSAL_MAX; i++)
66 buffer_put_cstring(ki, myproposal[i]);
Damien Millerb1715dc2000-05-30 13:44:51 +100067 buffer_put_char(ki, first_kex_packet_follows);
68 buffer_put_int(ki, 0); /* uint32 reserved */
Damien Millera664e872000-04-16 11:52:47 +100069 return ki;
70}
71
Damien Millerb1715dc2000-05-30 13:44:51 +100072/* send kexinit, parse and save reply */
73void
74kex_exchange_kexinit(
75 Buffer *my_kexinit, Buffer *peer_kexint,
76 char *peer_proposal[PROPOSAL_MAX])
77{
78 int i;
79 char *ptr;
80 int plen;
81
82 debug("send KEXINIT");
83 packet_start(SSH2_MSG_KEXINIT);
Kevin Stevesef4eea92001-02-05 12:42:17 +000084 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
Damien Millerb1715dc2000-05-30 13:44:51 +100085 packet_send();
86 packet_write_wait();
87 debug("done");
88
89 /*
90 * read and save raw KEXINIT payload in buffer. this is used during
91 * computation of the session_id and the session keys.
92 */
93 debug("wait KEXINIT");
94 packet_read_expect(&plen, SSH2_MSG_KEXINIT);
95 ptr = packet_get_raw(&plen);
96 buffer_append(peer_kexint, ptr, plen);
97
98 /* parse packet and save algorithm proposal */
99 /* skip cookie */
100 for (i = 0; i < KEX_COOKIE_LEN; i++)
101 packet_get_char();
102 /* extract kex init proposal strings */
103 for (i = 0; i < PROPOSAL_MAX; i++) {
104 peer_proposal[i] = packet_get_string(NULL);
105 debug("got kexinit: %s", peer_proposal[i]);
106 }
107 /* first kex follow / reserved */
108 i = packet_get_char();
109 debug("first kex follow: %d ", i);
110 i = packet_get_int();
111 debug("reserved: %d ", i);
112 packet_done();
113 debug("done");
114}
115
Damien Millera664e872000-04-16 11:52:47 +1000116/* diffie-hellman-group1-sha1 */
117
118int
119dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
120{
121 int i;
122 int n = BN_num_bits(dh_pub);
123 int bits_set = 0;
124
Damien Millera664e872000-04-16 11:52:47 +1000125 if (dh_pub->neg) {
126 log("invalid public DH value: negativ");
127 return 0;
128 }
129 for (i = 0; i <= n; i++)
130 if (BN_is_bit_set(dh_pub, i))
131 bits_set++;
132 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
133
134 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
135 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
136 return 1;
137 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
138 return 0;
139}
140
Kevin Steves6b875862000-12-15 23:31:01 +0000141void
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000142dh_gen_key(DH *dh, int need)
Damien Millera664e872000-04-16 11:52:47 +1000143{
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000144 int i, bits_set = 0, tries = 0;
Damien Miller874d77b2000-10-14 16:23:11 +1100145
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000146 if (dh->p == NULL)
147 fatal("dh_gen_key: dh->p == NULL");
148 if (2*need >= BN_num_bits(dh->p))
149 fatal("dh_gen_key: group too small: %d (2*need %d)",
150 BN_num_bits(dh->p), 2*need);
Damien Millera664e872000-04-16 11:52:47 +1000151 do {
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000152 if (dh->priv_key != NULL)
153 BN_free(dh->priv_key);
154 dh->priv_key = BN_new();
155 if (dh->priv_key == NULL)
156 fatal("dh_gen_key: BN_new failed");
157 /* generate a 2*need bits random private exponent */
158 if (!BN_rand(dh->priv_key, 2*need, 0, 0))
159 fatal("dh_gen_key: BN_rand failed");
Damien Millera664e872000-04-16 11:52:47 +1000160 if (DH_generate_key(dh) == 0)
161 fatal("DH_generate_key");
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000162 for (i = 0; i <= BN_num_bits(dh->priv_key); i++)
163 if (BN_is_bit_set(dh->priv_key, i))
164 bits_set++;
165 debug("dh_gen_key: priv key bits set: %d/%d",
166 bits_set, BN_num_bits(dh->priv_key));
Damien Millera664e872000-04-16 11:52:47 +1000167 if (tries++ > 10)
Ben Lindstrom4c4f05e2001-03-06 01:09:20 +0000168 fatal("dh_gen_key: too many bad keys: giving up");
Damien Millera664e872000-04-16 11:52:47 +1000169 } while (!dh_pub_is_valid(dh, dh->pub_key));
Damien Millera664e872000-04-16 11:52:47 +1000170}
171
Damien Miller874d77b2000-10-14 16:23:11 +1100172DH *
173dh_new_group_asc(const char *gen, const char *modulus)
174{
175 DH *dh;
176 int ret;
177
178 dh = DH_new();
179 if (dh == NULL)
180 fatal("DH_new");
181
182 if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
183 fatal("BN_hex2bn p");
184 if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
185 fatal("BN_hex2bn g");
186
Kevin Steves6b875862000-12-15 23:31:01 +0000187 return (dh);
Damien Miller874d77b2000-10-14 16:23:11 +1100188}
189
Kevin Steves6b875862000-12-15 23:31:01 +0000190/*
191 * This just returns the group, we still need to generate the exchange
192 * value.
193 */
194
Damien Miller874d77b2000-10-14 16:23:11 +1100195DH *
196dh_new_group(BIGNUM *gen, BIGNUM *modulus)
197{
198 DH *dh;
199
200 dh = DH_new();
201 if (dh == NULL)
202 fatal("DH_new");
203 dh->p = modulus;
204 dh->g = gen;
205
Kevin Steves6b875862000-12-15 23:31:01 +0000206 return (dh);
Damien Miller874d77b2000-10-14 16:23:11 +1100207}
208
209DH *
Ben Lindstrom46c16222000-12-22 01:43:59 +0000210dh_new_group1(void)
Damien Miller874d77b2000-10-14 16:23:11 +1100211{
212 static char *gen = "2", *group1 =
213 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
214 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
215 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
216 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
217 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
218 "FFFFFFFF" "FFFFFFFF";
219
220 return (dh_new_group_asc(gen, group1));
221}
222
Ben Lindstrom31ca54a2001-02-09 02:11:24 +0000223#ifdef DEBUG_KEX
Damien Millera664e872000-04-16 11:52:47 +1000224void
Ben Lindstrom46c16222000-12-22 01:43:59 +0000225dump_digest(u_char *digest, int len)
Damien Millera664e872000-04-16 11:52:47 +1000226{
227 int i;
228 for (i = 0; i< len; i++){
229 fprintf(stderr, "%02x", digest[i]);
230 if(i%2!=0)
231 fprintf(stderr, " ");
232 }
233 fprintf(stderr, "\n");
234}
Ben Lindstrom31ca54a2001-02-09 02:11:24 +0000235#endif
Damien Millera664e872000-04-16 11:52:47 +1000236
Ben Lindstrom46c16222000-12-22 01:43:59 +0000237u_char *
Damien Millera664e872000-04-16 11:52:47 +1000238kex_hash(
239 char *client_version_string,
240 char *server_version_string,
241 char *ckexinit, int ckexinitlen,
242 char *skexinit, int skexinitlen,
243 char *serverhostkeyblob, int sbloblen,
244 BIGNUM *client_dh_pub,
245 BIGNUM *server_dh_pub,
246 BIGNUM *shared_secret)
247{
248 Buffer b;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000249 static u_char digest[EVP_MAX_MD_SIZE];
Damien Millera664e872000-04-16 11:52:47 +1000250 EVP_MD *evp_md = EVP_sha1();
251 EVP_MD_CTX md;
252
253 buffer_init(&b);
254 buffer_put_string(&b, client_version_string, strlen(client_version_string));
255 buffer_put_string(&b, server_version_string, strlen(server_version_string));
256
257 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
258 buffer_put_int(&b, ckexinitlen+1);
259 buffer_put_char(&b, SSH2_MSG_KEXINIT);
260 buffer_append(&b, ckexinit, ckexinitlen);
261 buffer_put_int(&b, skexinitlen+1);
262 buffer_put_char(&b, SSH2_MSG_KEXINIT);
263 buffer_append(&b, skexinit, skexinitlen);
264
265 buffer_put_string(&b, serverhostkeyblob, sbloblen);
266 buffer_put_bignum2(&b, client_dh_pub);
267 buffer_put_bignum2(&b, server_dh_pub);
268 buffer_put_bignum2(&b, shared_secret);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000269
Damien Millera664e872000-04-16 11:52:47 +1000270#ifdef DEBUG_KEX
271 buffer_dump(&b);
272#endif
273
274 EVP_DigestInit(&md, evp_md);
275 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
276 EVP_DigestFinal(&md, digest, NULL);
277
278 buffer_free(&b);
279
280#ifdef DEBUG_KEX
281 dump_digest(digest, evp_md->md_size);
282#endif
283 return digest;
284}
285
Ben Lindstrom46c16222000-12-22 01:43:59 +0000286u_char *
Damien Miller874d77b2000-10-14 16:23:11 +1100287kex_hash_gex(
288 char *client_version_string,
289 char *server_version_string,
290 char *ckexinit, int ckexinitlen,
291 char *skexinit, int skexinitlen,
292 char *serverhostkeyblob, int sbloblen,
293 int minbits, BIGNUM *prime, BIGNUM *gen,
294 BIGNUM *client_dh_pub,
295 BIGNUM *server_dh_pub,
296 BIGNUM *shared_secret)
297{
298 Buffer b;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000299 static u_char digest[EVP_MAX_MD_SIZE];
Damien Miller874d77b2000-10-14 16:23:11 +1100300 EVP_MD *evp_md = EVP_sha1();
301 EVP_MD_CTX md;
302
303 buffer_init(&b);
304 buffer_put_string(&b, client_version_string, strlen(client_version_string));
305 buffer_put_string(&b, server_version_string, strlen(server_version_string));
306
307 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
308 buffer_put_int(&b, ckexinitlen+1);
309 buffer_put_char(&b, SSH2_MSG_KEXINIT);
310 buffer_append(&b, ckexinit, ckexinitlen);
311 buffer_put_int(&b, skexinitlen+1);
312 buffer_put_char(&b, SSH2_MSG_KEXINIT);
313 buffer_append(&b, skexinit, skexinitlen);
314
315 buffer_put_string(&b, serverhostkeyblob, sbloblen);
316 buffer_put_int(&b, minbits);
317 buffer_put_bignum2(&b, prime);
318 buffer_put_bignum2(&b, gen);
319 buffer_put_bignum2(&b, client_dh_pub);
320 buffer_put_bignum2(&b, server_dh_pub);
321 buffer_put_bignum2(&b, shared_secret);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000322
Damien Miller874d77b2000-10-14 16:23:11 +1100323#ifdef DEBUG_KEX
324 buffer_dump(&b);
325#endif
326
327 EVP_DigestInit(&md, evp_md);
328 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
329 EVP_DigestFinal(&md, digest, NULL);
330
331 buffer_free(&b);
332
333#ifdef DEBUG_KEX
334 dump_digest(digest, evp_md->md_size);
335#endif
336 return digest;
337}
338
Ben Lindstrom46c16222000-12-22 01:43:59 +0000339u_char *
340derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
Damien Millera664e872000-04-16 11:52:47 +1000341{
342 Buffer b;
343 EVP_MD *evp_md = EVP_sha1();
344 EVP_MD_CTX md;
345 char c = id;
346 int have;
347 int mdsz = evp_md->md_size;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000348 u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
Damien Millera664e872000-04-16 11:52:47 +1000349
350 buffer_init(&b);
351 buffer_put_bignum2(&b, shared_secret);
352
353 EVP_DigestInit(&md, evp_md);
354 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
355 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
356 EVP_DigestUpdate(&md, &c, 1); /* key id */
357 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
358 EVP_DigestFinal(&md, digest, NULL);
359
360 /* expand */
361 for (have = mdsz; need > have; have += mdsz) {
362 EVP_DigestInit(&md, evp_md);
363 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
364 EVP_DigestUpdate(&md, hash, mdsz);
365 EVP_DigestUpdate(&md, digest, have);
366 EVP_DigestFinal(&md, digest + have, NULL);
367 }
368 buffer_free(&b);
369#ifdef DEBUG_KEX
370 fprintf(stderr, "Digest '%c'== ", c);
371 dump_digest(digest, need);
372#endif
373 return digest;
374}
375
Damien Millera664e872000-04-16 11:52:47 +1000376void
377choose_enc(Enc *enc, char *client, char *server)
378{
Ben Lindstromb9be60a2001-03-11 01:49:19 +0000379 char *name = match_list(client, server, NULL);
Damien Millera664e872000-04-16 11:52:47 +1000380 if (name == NULL)
381 fatal("no matching cipher found: client %s server %s", client, server);
Damien Miller874d77b2000-10-14 16:23:11 +1100382 enc->cipher = cipher_by_name(name);
383 if (enc->cipher == NULL)
384 fatal("matching cipher is not supported: %s", name);
Damien Millera664e872000-04-16 11:52:47 +1000385 enc->name = name;
386 enc->enabled = 0;
387 enc->iv = NULL;
388 enc->key = NULL;
389}
390void
391choose_mac(Mac *mac, char *client, char *server)
392{
Ben Lindstromb9be60a2001-03-11 01:49:19 +0000393 char *name = match_list(client, server, NULL);
Damien Millera664e872000-04-16 11:52:47 +1000394 if (name == NULL)
395 fatal("no matching mac found: client %s server %s", client, server);
Ben Lindstrom06b33aa2001-02-15 03:01:59 +0000396 if (mac_init(mac, name) < 0)
Damien Millera664e872000-04-16 11:52:47 +1000397 fatal("unsupported mac %s", name);
Ben Lindstrom06b33aa2001-02-15 03:01:59 +0000398 /* truncate the key */
399 if (datafellows & SSH_BUG_HMAC)
400 mac->key_len = 16;
Damien Millera664e872000-04-16 11:52:47 +1000401 mac->name = name;
Damien Millera664e872000-04-16 11:52:47 +1000402 mac->key = NULL;
403 mac->enabled = 0;
404}
405void
406choose_comp(Comp *comp, char *client, char *server)
407{
Ben Lindstromb9be60a2001-03-11 01:49:19 +0000408 char *name = match_list(client, server, NULL);
Damien Millera664e872000-04-16 11:52:47 +1000409 if (name == NULL)
410 fatal("no matching comp found: client %s server %s", client, server);
411 if (strcmp(name, "zlib") == 0) {
412 comp->type = 1;
413 } else if (strcmp(name, "none") == 0) {
414 comp->type = 0;
415 } else {
416 fatal("unsupported comp %s", name);
417 }
418 comp->name = name;
419}
420void
421choose_kex(Kex *k, char *client, char *server)
422{
Ben Lindstromb9be60a2001-03-11 01:49:19 +0000423 k->name = match_list(client, server, NULL);
Damien Millera664e872000-04-16 11:52:47 +1000424 if (k->name == NULL)
425 fatal("no kex alg");
Damien Miller874d77b2000-10-14 16:23:11 +1100426 if (strcmp(k->name, KEX_DH1) == 0) {
427 k->kex_type = DH_GRP1_SHA1;
428 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
429 k->kex_type = DH_GEX_SHA1;
430 } else
Damien Millera664e872000-04-16 11:52:47 +1000431 fatal("bad kex alg %s", k->name);
432}
433void
434choose_hostkeyalg(Kex *k, char *client, char *server)
435{
Ben Lindstromb9be60a2001-03-11 01:49:19 +0000436 char *hostkeyalg = match_list(client, server, NULL);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100437 if (hostkeyalg == NULL)
Damien Millera664e872000-04-16 11:52:47 +1000438 fatal("no hostkey alg");
Damien Miller0bc1bd82000-11-13 22:57:25 +1100439 k->hostkey_type = key_type_from_name(hostkeyalg);
440 if (k->hostkey_type == KEY_UNSPEC)
441 fatal("bad hostkey alg '%s'", hostkeyalg);
Ben Lindstrom48bd7c12001-01-09 00:35:42 +0000442 xfree(hostkeyalg);
Damien Millera664e872000-04-16 11:52:47 +1000443}
444
445Kex *
446kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
447{
Damien Millera664e872000-04-16 11:52:47 +1000448 int mode;
449 int ctos; /* direction: if true client-to-server */
450 int need;
451 Kex *k;
452
453 k = xmalloc(sizeof(*k));
454 memset(k, 0, sizeof(*k));
455 k->server = server;
456
457 for (mode = 0; mode < MODE_MAX; mode++) {
458 int nenc, nmac, ncomp;
459 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
460 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
461 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
462 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
463 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
464 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
465 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
466 debug("kex: %s %s %s %s",
467 ctos ? "client->server" : "server->client",
468 k->enc[mode].name,
469 k->mac[mode].name,
470 k->comp[mode].name);
471 }
472 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
473 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
474 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
Damien Millera664e872000-04-16 11:52:47 +1000475 need = 0;
476 for (mode = 0; mode < MODE_MAX; mode++) {
Damien Miller874d77b2000-10-14 16:23:11 +1100477 if (need < k->enc[mode].cipher->key_len)
478 need = k->enc[mode].cipher->key_len;
479 if (need < k->enc[mode].cipher->block_size)
480 need = k->enc[mode].cipher->block_size;
Damien Millera664e872000-04-16 11:52:47 +1000481 if (need < k->mac[mode].key_len)
482 need = k->mac[mode].key_len;
483 }
Damien Millerb1715dc2000-05-30 13:44:51 +1000484 /* XXX need runden? */
Damien Millera664e872000-04-16 11:52:47 +1000485 k->we_need = need;
486 return k;
487}
488
Ben Lindstromb9be60a2001-03-11 01:49:19 +0000489#define NKEYS 6
Damien Millera664e872000-04-16 11:52:47 +1000490int
Ben Lindstrom46c16222000-12-22 01:43:59 +0000491kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
Damien Millera664e872000-04-16 11:52:47 +1000492{
493 int i;
494 int mode;
495 int ctos;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000496 u_char *keys[NKEYS];
Damien Millera664e872000-04-16 11:52:47 +1000497
498 for (i = 0; i < NKEYS; i++)
499 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
500
501 for (mode = 0; mode < MODE_MAX; mode++) {
502 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
503 k->enc[mode].iv = keys[ctos ? 0 : 1];
504 k->enc[mode].key = keys[ctos ? 2 : 3];
505 k->mac[mode].key = keys[ctos ? 4 : 5];
506 }
507 return 0;
508}