]> andersk Git - openssh.git/blame - kex.c
- markus@cvs.openbsd.org 2001/03/10 17:51:04
[openssh.git] / kex.c
CommitLineData
4f8c6159 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.
4f8c6159 12 *
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"
cab80f75 26RCSID("$OpenBSD: kex.c,v 1.23 2001/03/10 17:51:04 markus Exp $");
4f8c6159 27
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
42f11eb2 34#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"
4f8c6159 41#include "kex.h"
fa08c86b 42#include "key.h"
42f11eb2 43#include "log.h"
b2552997 44#include "mac.h"
cab80f75 45#include "match.h"
4f8c6159 46
71276795 47#define KEX_COOKIE_LEN 16
48
4f8c6159 49Buffer *
50kex_init(char *myproposal[PROPOSAL_MAX])
51{
71276795 52 int first_kex_packet_follows = 0;
1e3b8b07 53 u_char cookie[KEX_COOKIE_LEN];
4f8c6159 54 u_int32_t rand = 0;
55 int i;
56 Buffer *ki = xmalloc(sizeof(*ki));
71276795 57 for (i = 0; i < KEX_COOKIE_LEN; i++) {
4f8c6159 58 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]);
71276795 67 buffer_put_char(ki, first_kex_packet_follows);
68 buffer_put_int(ki, 0); /* uint32 reserved */
4f8c6159 69 return ki;
70}
71
71276795 72/* 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);
2b87da3b 84 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
71276795 85 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
4f8c6159 116/* 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
4f8c6159 125 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
3e1caa83 141void
7de5b06b 142dh_gen_key(DH *dh, int need)
4f8c6159 143{
7de5b06b 144 int i, bits_set = 0, tries = 0;
94ec8c6b 145
7de5b06b 146 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);
4f8c6159 151 do {
7de5b06b 152 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");
4f8c6159 160 if (DH_generate_key(dh) == 0)
161 fatal("DH_generate_key");
7de5b06b 162 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));
4f8c6159 167 if (tries++ > 10)
7de5b06b 168 fatal("dh_gen_key: too many bad keys: giving up");
4f8c6159 169 } while (!dh_pub_is_valid(dh, dh->pub_key));
4f8c6159 170}
171
94ec8c6b 172DH *
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
3e1caa83 187 return (dh);
94ec8c6b 188}
189
3e1caa83 190/*
191 * This just returns the group, we still need to generate the exchange
192 * value.
193 */
194
94ec8c6b 195DH *
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
3e1caa83 206 return (dh);
94ec8c6b 207}
208
209DH *
1e3b8b07 210dh_new_group1(void)
94ec8c6b 211{
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
5ca51e19 223#ifdef DEBUG_KEX
4f8c6159 224void
1e3b8b07 225dump_digest(u_char *digest, int len)
4f8c6159 226{
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}
5ca51e19 235#endif
4f8c6159 236
1e3b8b07 237u_char *
4f8c6159 238kex_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;
1e3b8b07 249 static u_char digest[EVP_MAX_MD_SIZE];
4f8c6159 250 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);
2b87da3b 269
4f8c6159 270#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
1e3b8b07 286u_char *
94ec8c6b 287kex_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;
1e3b8b07 299 static u_char digest[EVP_MAX_MD_SIZE];
94ec8c6b 300 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);
2b87da3b 322
94ec8c6b 323#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
1e3b8b07 339u_char *
340derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
4f8c6159 341{
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;
1e3b8b07 348 u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
4f8c6159 349
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
4f8c6159 376void
377choose_enc(Enc *enc, char *client, char *server)
378{
cab80f75 379 char *name = match_list(client, server, NULL);
4f8c6159 380 if (name == NULL)
381 fatal("no matching cipher found: client %s server %s", client, server);
94ec8c6b 382 enc->cipher = cipher_by_name(name);
383 if (enc->cipher == NULL)
384 fatal("matching cipher is not supported: %s", name);
4f8c6159 385 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{
cab80f75 393 char *name = match_list(client, server, NULL);
4f8c6159 394 if (name == NULL)
395 fatal("no matching mac found: client %s server %s", client, server);
b2552997 396 if (mac_init(mac, name) < 0)
4f8c6159 397 fatal("unsupported mac %s", name);
b2552997 398 /* truncate the key */
399 if (datafellows & SSH_BUG_HMAC)
400 mac->key_len = 16;
4f8c6159 401 mac->name = name;
4f8c6159 402 mac->key = NULL;
403 mac->enabled = 0;
404}
405void
406choose_comp(Comp *comp, char *client, char *server)
407{
cab80f75 408 char *name = match_list(client, server, NULL);
4f8c6159 409 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{
cab80f75 423 k->name = match_list(client, server, NULL);
4f8c6159 424 if (k->name == NULL)
425 fatal("no kex alg");
94ec8c6b 426 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
4f8c6159 431 fatal("bad kex alg %s", k->name);
432}
433void
434choose_hostkeyalg(Kex *k, char *client, char *server)
435{
cab80f75 436 char *hostkeyalg = match_list(client, server, NULL);
fa08c86b 437 if (hostkeyalg == NULL)
4f8c6159 438 fatal("no hostkey alg");
fa08c86b 439 k->hostkey_type = key_type_from_name(hostkeyalg);
440 if (k->hostkey_type == KEY_UNSPEC)
441 fatal("bad hostkey alg '%s'", hostkeyalg);
eea39c02 442 xfree(hostkeyalg);
4f8c6159 443}
444
445Kex *
446kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
447{
4f8c6159 448 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]);
4f8c6159 475 need = 0;
476 for (mode = 0; mode < MODE_MAX; mode++) {
94ec8c6b 477 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;
4f8c6159 481 if (need < k->mac[mode].key_len)
482 need = k->mac[mode].key_len;
483 }
71276795 484 /* XXX need runden? */
4f8c6159 485 k->we_need = need;
486 return k;
487}
488
cab80f75 489#define NKEYS 6
4f8c6159 490int
1e3b8b07 491kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
4f8c6159 492{
493 int i;
494 int mode;
495 int ctos;
1e3b8b07 496 u_char *keys[NKEYS];
4f8c6159 497
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}
This page took 0.149981 seconds and 5 git commands to generate.