blob: 7c1326ed09e67eda600992f03699392235c11821 [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 Lindstrom31ca54a2001-02-09 02:11:24 +000026RCSID("$OpenBSD: kex.c,v 1.20 2001/02/08 19:30:51 itojun 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"
Damien Millera664e872000-04-16 11:52:47 +100044
Damien Millerb1715dc2000-05-30 13:44:51 +100045#define KEX_COOKIE_LEN 16
46
Damien Millera664e872000-04-16 11:52:47 +100047Buffer *
48kex_init(char *myproposal[PROPOSAL_MAX])
49{
Damien Millerb1715dc2000-05-30 13:44:51 +100050 int first_kex_packet_follows = 0;
Ben Lindstrom46c16222000-12-22 01:43:59 +000051 u_char cookie[KEX_COOKIE_LEN];
Damien Millera664e872000-04-16 11:52:47 +100052 u_int32_t rand = 0;
53 int i;
54 Buffer *ki = xmalloc(sizeof(*ki));
Damien Millerb1715dc2000-05-30 13:44:51 +100055 for (i = 0; i < KEX_COOKIE_LEN; i++) {
Damien Millera664e872000-04-16 11:52:47 +100056 if (i % 4 == 0)
57 rand = arc4random();
58 cookie[i] = rand & 0xff;
59 rand >>= 8;
60 }
61 buffer_init(ki);
62 buffer_append(ki, (char *)cookie, sizeof cookie);
63 for (i = 0; i < PROPOSAL_MAX; i++)
64 buffer_put_cstring(ki, myproposal[i]);
Damien Millerb1715dc2000-05-30 13:44:51 +100065 buffer_put_char(ki, first_kex_packet_follows);
66 buffer_put_int(ki, 0); /* uint32 reserved */
Damien Millera664e872000-04-16 11:52:47 +100067 return ki;
68}
69
Damien Millerb1715dc2000-05-30 13:44:51 +100070/* send kexinit, parse and save reply */
71void
72kex_exchange_kexinit(
73 Buffer *my_kexinit, Buffer *peer_kexint,
74 char *peer_proposal[PROPOSAL_MAX])
75{
76 int i;
77 char *ptr;
78 int plen;
79
80 debug("send KEXINIT");
81 packet_start(SSH2_MSG_KEXINIT);
Kevin Stevesef4eea92001-02-05 12:42:17 +000082 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
Damien Millerb1715dc2000-05-30 13:44:51 +100083 packet_send();
84 packet_write_wait();
85 debug("done");
86
87 /*
88 * read and save raw KEXINIT payload in buffer. this is used during
89 * computation of the session_id and the session keys.
90 */
91 debug("wait KEXINIT");
92 packet_read_expect(&plen, SSH2_MSG_KEXINIT);
93 ptr = packet_get_raw(&plen);
94 buffer_append(peer_kexint, ptr, plen);
95
96 /* parse packet and save algorithm proposal */
97 /* skip cookie */
98 for (i = 0; i < KEX_COOKIE_LEN; i++)
99 packet_get_char();
100 /* extract kex init proposal strings */
101 for (i = 0; i < PROPOSAL_MAX; i++) {
102 peer_proposal[i] = packet_get_string(NULL);
103 debug("got kexinit: %s", peer_proposal[i]);
104 }
105 /* first kex follow / reserved */
106 i = packet_get_char();
107 debug("first kex follow: %d ", i);
108 i = packet_get_int();
109 debug("reserved: %d ", i);
110 packet_done();
111 debug("done");
112}
113
Damien Millera664e872000-04-16 11:52:47 +1000114/* diffie-hellman-group1-sha1 */
115
116int
117dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
118{
119 int i;
120 int n = BN_num_bits(dh_pub);
121 int bits_set = 0;
122
Damien Millera664e872000-04-16 11:52:47 +1000123 if (dh_pub->neg) {
124 log("invalid public DH value: negativ");
125 return 0;
126 }
127 for (i = 0; i <= n; i++)
128 if (BN_is_bit_set(dh_pub, i))
129 bits_set++;
130 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
131
132 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
133 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
134 return 1;
135 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
136 return 0;
137}
138
Kevin Steves6b875862000-12-15 23:31:01 +0000139void
Damien Miller874d77b2000-10-14 16:23:11 +1100140dh_gen_key(DH *dh)
Damien Millera664e872000-04-16 11:52:47 +1000141{
Damien Miller874d77b2000-10-14 16:23:11 +1100142 int tries = 0;
143
Damien Millera664e872000-04-16 11:52:47 +1000144 do {
145 if (DH_generate_key(dh) == 0)
146 fatal("DH_generate_key");
147 if (tries++ > 10)
148 fatal("dh_new_group1: too many bad keys: giving up");
149 } while (!dh_pub_is_valid(dh, dh->pub_key));
Damien Millera664e872000-04-16 11:52:47 +1000150}
151
Damien Miller874d77b2000-10-14 16:23:11 +1100152DH *
153dh_new_group_asc(const char *gen, const char *modulus)
154{
155 DH *dh;
156 int ret;
157
158 dh = DH_new();
159 if (dh == NULL)
160 fatal("DH_new");
161
162 if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
163 fatal("BN_hex2bn p");
164 if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
165 fatal("BN_hex2bn g");
166
Kevin Steves6b875862000-12-15 23:31:01 +0000167 return (dh);
Damien Miller874d77b2000-10-14 16:23:11 +1100168}
169
Kevin Steves6b875862000-12-15 23:31:01 +0000170/*
171 * This just returns the group, we still need to generate the exchange
172 * value.
173 */
174
Damien Miller874d77b2000-10-14 16:23:11 +1100175DH *
176dh_new_group(BIGNUM *gen, BIGNUM *modulus)
177{
178 DH *dh;
179
180 dh = DH_new();
181 if (dh == NULL)
182 fatal("DH_new");
183 dh->p = modulus;
184 dh->g = gen;
185
Kevin Steves6b875862000-12-15 23:31:01 +0000186 return (dh);
Damien Miller874d77b2000-10-14 16:23:11 +1100187}
188
189DH *
Ben Lindstrom46c16222000-12-22 01:43:59 +0000190dh_new_group1(void)
Damien Miller874d77b2000-10-14 16:23:11 +1100191{
192 static char *gen = "2", *group1 =
193 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
194 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
195 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
196 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
197 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
198 "FFFFFFFF" "FFFFFFFF";
199
200 return (dh_new_group_asc(gen, group1));
201}
202
Ben Lindstrom31ca54a2001-02-09 02:11:24 +0000203#ifdef DEBUG_KEX
Damien Millera664e872000-04-16 11:52:47 +1000204void
Ben Lindstrom46c16222000-12-22 01:43:59 +0000205dump_digest(u_char *digest, int len)
Damien Millera664e872000-04-16 11:52:47 +1000206{
207 int i;
208 for (i = 0; i< len; i++){
209 fprintf(stderr, "%02x", digest[i]);
210 if(i%2!=0)
211 fprintf(stderr, " ");
212 }
213 fprintf(stderr, "\n");
214}
Ben Lindstrom31ca54a2001-02-09 02:11:24 +0000215#endif
Damien Millera664e872000-04-16 11:52:47 +1000216
Ben Lindstrom46c16222000-12-22 01:43:59 +0000217u_char *
Damien Millera664e872000-04-16 11:52:47 +1000218kex_hash(
219 char *client_version_string,
220 char *server_version_string,
221 char *ckexinit, int ckexinitlen,
222 char *skexinit, int skexinitlen,
223 char *serverhostkeyblob, int sbloblen,
224 BIGNUM *client_dh_pub,
225 BIGNUM *server_dh_pub,
226 BIGNUM *shared_secret)
227{
228 Buffer b;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000229 static u_char digest[EVP_MAX_MD_SIZE];
Damien Millera664e872000-04-16 11:52:47 +1000230 EVP_MD *evp_md = EVP_sha1();
231 EVP_MD_CTX md;
232
233 buffer_init(&b);
234 buffer_put_string(&b, client_version_string, strlen(client_version_string));
235 buffer_put_string(&b, server_version_string, strlen(server_version_string));
236
237 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
238 buffer_put_int(&b, ckexinitlen+1);
239 buffer_put_char(&b, SSH2_MSG_KEXINIT);
240 buffer_append(&b, ckexinit, ckexinitlen);
241 buffer_put_int(&b, skexinitlen+1);
242 buffer_put_char(&b, SSH2_MSG_KEXINIT);
243 buffer_append(&b, skexinit, skexinitlen);
244
245 buffer_put_string(&b, serverhostkeyblob, sbloblen);
246 buffer_put_bignum2(&b, client_dh_pub);
247 buffer_put_bignum2(&b, server_dh_pub);
248 buffer_put_bignum2(&b, shared_secret);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000249
Damien Millera664e872000-04-16 11:52:47 +1000250#ifdef DEBUG_KEX
251 buffer_dump(&b);
252#endif
253
254 EVP_DigestInit(&md, evp_md);
255 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
256 EVP_DigestFinal(&md, digest, NULL);
257
258 buffer_free(&b);
259
260#ifdef DEBUG_KEX
261 dump_digest(digest, evp_md->md_size);
262#endif
263 return digest;
264}
265
Ben Lindstrom46c16222000-12-22 01:43:59 +0000266u_char *
Damien Miller874d77b2000-10-14 16:23:11 +1100267kex_hash_gex(
268 char *client_version_string,
269 char *server_version_string,
270 char *ckexinit, int ckexinitlen,
271 char *skexinit, int skexinitlen,
272 char *serverhostkeyblob, int sbloblen,
273 int minbits, BIGNUM *prime, BIGNUM *gen,
274 BIGNUM *client_dh_pub,
275 BIGNUM *server_dh_pub,
276 BIGNUM *shared_secret)
277{
278 Buffer b;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000279 static u_char digest[EVP_MAX_MD_SIZE];
Damien Miller874d77b2000-10-14 16:23:11 +1100280 EVP_MD *evp_md = EVP_sha1();
281 EVP_MD_CTX md;
282
283 buffer_init(&b);
284 buffer_put_string(&b, client_version_string, strlen(client_version_string));
285 buffer_put_string(&b, server_version_string, strlen(server_version_string));
286
287 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
288 buffer_put_int(&b, ckexinitlen+1);
289 buffer_put_char(&b, SSH2_MSG_KEXINIT);
290 buffer_append(&b, ckexinit, ckexinitlen);
291 buffer_put_int(&b, skexinitlen+1);
292 buffer_put_char(&b, SSH2_MSG_KEXINIT);
293 buffer_append(&b, skexinit, skexinitlen);
294
295 buffer_put_string(&b, serverhostkeyblob, sbloblen);
296 buffer_put_int(&b, minbits);
297 buffer_put_bignum2(&b, prime);
298 buffer_put_bignum2(&b, gen);
299 buffer_put_bignum2(&b, client_dh_pub);
300 buffer_put_bignum2(&b, server_dh_pub);
301 buffer_put_bignum2(&b, shared_secret);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000302
Damien Miller874d77b2000-10-14 16:23:11 +1100303#ifdef DEBUG_KEX
304 buffer_dump(&b);
305#endif
306
307 EVP_DigestInit(&md, evp_md);
308 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
309 EVP_DigestFinal(&md, digest, NULL);
310
311 buffer_free(&b);
312
313#ifdef DEBUG_KEX
314 dump_digest(digest, evp_md->md_size);
315#endif
316 return digest;
317}
318
Ben Lindstrom46c16222000-12-22 01:43:59 +0000319u_char *
320derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
Damien Millera664e872000-04-16 11:52:47 +1000321{
322 Buffer b;
323 EVP_MD *evp_md = EVP_sha1();
324 EVP_MD_CTX md;
325 char c = id;
326 int have;
327 int mdsz = evp_md->md_size;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000328 u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
Damien Millera664e872000-04-16 11:52:47 +1000329
330 buffer_init(&b);
331 buffer_put_bignum2(&b, shared_secret);
332
333 EVP_DigestInit(&md, evp_md);
334 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
335 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
336 EVP_DigestUpdate(&md, &c, 1); /* key id */
337 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
338 EVP_DigestFinal(&md, digest, NULL);
339
340 /* expand */
341 for (have = mdsz; need > have; have += mdsz) {
342 EVP_DigestInit(&md, evp_md);
343 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
344 EVP_DigestUpdate(&md, hash, mdsz);
345 EVP_DigestUpdate(&md, digest, have);
346 EVP_DigestFinal(&md, digest + have, NULL);
347 }
348 buffer_free(&b);
349#ifdef DEBUG_KEX
350 fprintf(stderr, "Digest '%c'== ", c);
351 dump_digest(digest, need);
352#endif
353 return digest;
354}
355
356#define NKEYS 6
357
358#define MAX_PROP 20
359#define SEP ","
360
361char *
362get_match(char *client, char *server)
363{
364 char *sproposals[MAX_PROP];
Damien Miller37023962000-07-11 17:31:38 +1000365 char *c, *s, *p, *ret, *cp, *sp;
Damien Millera664e872000-04-16 11:52:47 +1000366 int i, j, nproposals;
367
Damien Miller37023962000-07-11 17:31:38 +1000368 c = cp = xstrdup(client);
369 s = sp = xstrdup(server);
Damien Millerb1715dc2000-05-30 13:44:51 +1000370
Kevin Stevesef4eea92001-02-05 12:42:17 +0000371 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
Damien Miller37023962000-07-11 17:31:38 +1000372 (p = strsep(&sp, SEP)), i++) {
Damien Millera664e872000-04-16 11:52:47 +1000373 if (i < MAX_PROP)
374 sproposals[i] = p;
375 else
376 break;
377 }
378 nproposals = i;
379
Kevin Stevesef4eea92001-02-05 12:42:17 +0000380 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
Damien Miller37023962000-07-11 17:31:38 +1000381 (p = strsep(&cp, SEP)), i++) {
Damien Millerb1715dc2000-05-30 13:44:51 +1000382 for (j = 0; j < nproposals; j++) {
383 if (strcmp(p, sproposals[j]) == 0) {
384 ret = xstrdup(p);
385 xfree(c);
386 xfree(s);
387 return ret;
388 }
389 }
Damien Millera664e872000-04-16 11:52:47 +1000390 }
Damien Millerb1715dc2000-05-30 13:44:51 +1000391 xfree(c);
392 xfree(s);
Damien Millera664e872000-04-16 11:52:47 +1000393 return NULL;
394}
395void
396choose_enc(Enc *enc, char *client, char *server)
397{
398 char *name = get_match(client, server);
399 if (name == NULL)
400 fatal("no matching cipher found: client %s server %s", client, server);
Damien Miller874d77b2000-10-14 16:23:11 +1100401 enc->cipher = cipher_by_name(name);
402 if (enc->cipher == NULL)
403 fatal("matching cipher is not supported: %s", name);
Damien Millera664e872000-04-16 11:52:47 +1000404 enc->name = name;
405 enc->enabled = 0;
406 enc->iv = NULL;
407 enc->key = NULL;
408}
409void
410choose_mac(Mac *mac, char *client, char *server)
411{
412 char *name = get_match(client, server);
413 if (name == NULL)
414 fatal("no matching mac found: client %s server %s", client, server);
415 if (strcmp(name, "hmac-md5") == 0) {
416 mac->md = EVP_md5();
417 } else if (strcmp(name, "hmac-sha1") == 0) {
418 mac->md = EVP_sha1();
419 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
420 mac->md = EVP_ripemd160();
421 } else {
422 fatal("unsupported mac %s", name);
423 }
424 mac->name = name;
425 mac->mac_len = mac->md->md_size;
Damien Miller30c3d422000-05-09 11:02:59 +1000426 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
Damien Millera664e872000-04-16 11:52:47 +1000427 mac->key = NULL;
428 mac->enabled = 0;
429}
430void
431choose_comp(Comp *comp, char *client, char *server)
432{
433 char *name = get_match(client, server);
434 if (name == NULL)
435 fatal("no matching comp found: client %s server %s", client, server);
436 if (strcmp(name, "zlib") == 0) {
437 comp->type = 1;
438 } else if (strcmp(name, "none") == 0) {
439 comp->type = 0;
440 } else {
441 fatal("unsupported comp %s", name);
442 }
443 comp->name = name;
444}
445void
446choose_kex(Kex *k, char *client, char *server)
447{
448 k->name = get_match(client, server);
449 if (k->name == NULL)
450 fatal("no kex alg");
Damien Miller874d77b2000-10-14 16:23:11 +1100451 if (strcmp(k->name, KEX_DH1) == 0) {
452 k->kex_type = DH_GRP1_SHA1;
453 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
454 k->kex_type = DH_GEX_SHA1;
455 } else
Damien Millera664e872000-04-16 11:52:47 +1000456 fatal("bad kex alg %s", k->name);
457}
458void
459choose_hostkeyalg(Kex *k, char *client, char *server)
460{
Damien Miller0bc1bd82000-11-13 22:57:25 +1100461 char *hostkeyalg = get_match(client, server);
462 if (hostkeyalg == NULL)
Damien Millera664e872000-04-16 11:52:47 +1000463 fatal("no hostkey alg");
Damien Miller0bc1bd82000-11-13 22:57:25 +1100464 k->hostkey_type = key_type_from_name(hostkeyalg);
465 if (k->hostkey_type == KEY_UNSPEC)
466 fatal("bad hostkey alg '%s'", hostkeyalg);
Ben Lindstrom48bd7c12001-01-09 00:35:42 +0000467 xfree(hostkeyalg);
Damien Millera664e872000-04-16 11:52:47 +1000468}
469
470Kex *
471kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
472{
Damien Millera664e872000-04-16 11:52:47 +1000473 int mode;
474 int ctos; /* direction: if true client-to-server */
475 int need;
476 Kex *k;
477
478 k = xmalloc(sizeof(*k));
479 memset(k, 0, sizeof(*k));
480 k->server = server;
481
482 for (mode = 0; mode < MODE_MAX; mode++) {
483 int nenc, nmac, ncomp;
484 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
485 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
486 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
487 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
488 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
489 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
490 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
491 debug("kex: %s %s %s %s",
492 ctos ? "client->server" : "server->client",
493 k->enc[mode].name,
494 k->mac[mode].name,
495 k->comp[mode].name);
496 }
497 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
498 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
499 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
Damien Millera664e872000-04-16 11:52:47 +1000500 need = 0;
501 for (mode = 0; mode < MODE_MAX; mode++) {
Damien Miller874d77b2000-10-14 16:23:11 +1100502 if (need < k->enc[mode].cipher->key_len)
503 need = k->enc[mode].cipher->key_len;
504 if (need < k->enc[mode].cipher->block_size)
505 need = k->enc[mode].cipher->block_size;
Damien Millera664e872000-04-16 11:52:47 +1000506 if (need < k->mac[mode].key_len)
507 need = k->mac[mode].key_len;
508 }
Damien Millerb1715dc2000-05-30 13:44:51 +1000509 /* XXX need runden? */
Damien Millera664e872000-04-16 11:52:47 +1000510 k->we_need = need;
511 return k;
512}
513
514int
Ben Lindstrom46c16222000-12-22 01:43:59 +0000515kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
Damien Millera664e872000-04-16 11:52:47 +1000516{
517 int i;
518 int mode;
519 int ctos;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000520 u_char *keys[NKEYS];
Damien Millera664e872000-04-16 11:52:47 +1000521
522 for (i = 0; i < NKEYS; i++)
523 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
524
525 for (mode = 0; mode < MODE_MAX; mode++) {
526 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
527 k->enc[mode].iv = keys[ctos ? 0 : 1];
528 k->enc[mode].key = keys[ctos ? 2 : 3];
529 k->mac[mode].key = keys[ctos ? 4 : 5];
530 }
531 return 0;
532}