]> andersk Git - openssh.git/blame_incremental - kex.c
- (stevesk) auth1.c: free should be after WITH_AIXAUTHENTICATE
[openssh.git] / kex.c
... / ...
CommitLineData
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 *
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"
26RCSID("$OpenBSD: kex.c,v 1.16 2000/12/20 19:37:22 markus Exp $");
27
28#include "ssh.h"
29#include "ssh2.h"
30#include "xmalloc.h"
31#include "buffer.h"
32#include "bufaux.h"
33#include "packet.h"
34#include "compat.h"
35
36#include <openssl/bn.h>
37#include <openssl/dh.h>
38
39#include <openssl/crypto.h>
40#include <openssl/bio.h>
41#include <openssl/bn.h>
42#include <openssl/dh.h>
43#include <openssl/pem.h>
44
45#include "kex.h"
46#include "key.h"
47
48#define KEX_COOKIE_LEN 16
49
50Buffer *
51kex_init(char *myproposal[PROPOSAL_MAX])
52{
53 int first_kex_packet_follows = 0;
54 u_char cookie[KEX_COOKIE_LEN];
55 u_int32_t rand = 0;
56 int i;
57 Buffer *ki = xmalloc(sizeof(*ki));
58 for (i = 0; i < KEX_COOKIE_LEN; i++) {
59 if (i % 4 == 0)
60 rand = arc4random();
61 cookie[i] = rand & 0xff;
62 rand >>= 8;
63 }
64 buffer_init(ki);
65 buffer_append(ki, (char *)cookie, sizeof cookie);
66 for (i = 0; i < PROPOSAL_MAX; i++)
67 buffer_put_cstring(ki, myproposal[i]);
68 buffer_put_char(ki, first_kex_packet_follows);
69 buffer_put_int(ki, 0); /* uint32 reserved */
70 return ki;
71}
72
73/* send kexinit, parse and save reply */
74void
75kex_exchange_kexinit(
76 Buffer *my_kexinit, Buffer *peer_kexint,
77 char *peer_proposal[PROPOSAL_MAX])
78{
79 int i;
80 char *ptr;
81 int plen;
82
83 debug("send KEXINIT");
84 packet_start(SSH2_MSG_KEXINIT);
85 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
86 packet_send();
87 packet_write_wait();
88 debug("done");
89
90 /*
91 * read and save raw KEXINIT payload in buffer. this is used during
92 * computation of the session_id and the session keys.
93 */
94 debug("wait KEXINIT");
95 packet_read_expect(&plen, SSH2_MSG_KEXINIT);
96 ptr = packet_get_raw(&plen);
97 buffer_append(peer_kexint, ptr, plen);
98
99 /* parse packet and save algorithm proposal */
100 /* skip cookie */
101 for (i = 0; i < KEX_COOKIE_LEN; i++)
102 packet_get_char();
103 /* extract kex init proposal strings */
104 for (i = 0; i < PROPOSAL_MAX; i++) {
105 peer_proposal[i] = packet_get_string(NULL);
106 debug("got kexinit: %s", peer_proposal[i]);
107 }
108 /* first kex follow / reserved */
109 i = packet_get_char();
110 debug("first kex follow: %d ", i);
111 i = packet_get_int();
112 debug("reserved: %d ", i);
113 packet_done();
114 debug("done");
115}
116
117/* diffie-hellman-group1-sha1 */
118
119int
120dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
121{
122 int i;
123 int n = BN_num_bits(dh_pub);
124 int bits_set = 0;
125
126 if (dh_pub->neg) {
127 log("invalid public DH value: negativ");
128 return 0;
129 }
130 for (i = 0; i <= n; i++)
131 if (BN_is_bit_set(dh_pub, i))
132 bits_set++;
133 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
134
135 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
136 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
137 return 1;
138 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
139 return 0;
140}
141
142void
143dh_gen_key(DH *dh)
144{
145 int tries = 0;
146
147 do {
148 if (DH_generate_key(dh) == 0)
149 fatal("DH_generate_key");
150 if (tries++ > 10)
151 fatal("dh_new_group1: too many bad keys: giving up");
152 } while (!dh_pub_is_valid(dh, dh->pub_key));
153}
154
155DH *
156dh_new_group_asc(const char *gen, const char *modulus)
157{
158 DH *dh;
159 int ret;
160
161 dh = DH_new();
162 if (dh == NULL)
163 fatal("DH_new");
164
165 if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
166 fatal("BN_hex2bn p");
167 if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
168 fatal("BN_hex2bn g");
169
170 return (dh);
171}
172
173/*
174 * This just returns the group, we still need to generate the exchange
175 * value.
176 */
177
178DH *
179dh_new_group(BIGNUM *gen, BIGNUM *modulus)
180{
181 DH *dh;
182
183 dh = DH_new();
184 if (dh == NULL)
185 fatal("DH_new");
186 dh->p = modulus;
187 dh->g = gen;
188
189 return (dh);
190}
191
192DH *
193dh_new_group1(void)
194{
195 static char *gen = "2", *group1 =
196 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
197 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
198 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
199 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
200 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
201 "FFFFFFFF" "FFFFFFFF";
202
203 return (dh_new_group_asc(gen, group1));
204}
205
206void
207dump_digest(u_char *digest, int len)
208{
209 int i;
210 for (i = 0; i< len; i++){
211 fprintf(stderr, "%02x", digest[i]);
212 if(i%2!=0)
213 fprintf(stderr, " ");
214 }
215 fprintf(stderr, "\n");
216}
217
218u_char *
219kex_hash(
220 char *client_version_string,
221 char *server_version_string,
222 char *ckexinit, int ckexinitlen,
223 char *skexinit, int skexinitlen,
224 char *serverhostkeyblob, int sbloblen,
225 BIGNUM *client_dh_pub,
226 BIGNUM *server_dh_pub,
227 BIGNUM *shared_secret)
228{
229 Buffer b;
230 static u_char digest[EVP_MAX_MD_SIZE];
231 EVP_MD *evp_md = EVP_sha1();
232 EVP_MD_CTX md;
233
234 buffer_init(&b);
235 buffer_put_string(&b, client_version_string, strlen(client_version_string));
236 buffer_put_string(&b, server_version_string, strlen(server_version_string));
237
238 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
239 buffer_put_int(&b, ckexinitlen+1);
240 buffer_put_char(&b, SSH2_MSG_KEXINIT);
241 buffer_append(&b, ckexinit, ckexinitlen);
242 buffer_put_int(&b, skexinitlen+1);
243 buffer_put_char(&b, SSH2_MSG_KEXINIT);
244 buffer_append(&b, skexinit, skexinitlen);
245
246 buffer_put_string(&b, serverhostkeyblob, sbloblen);
247 buffer_put_bignum2(&b, client_dh_pub);
248 buffer_put_bignum2(&b, server_dh_pub);
249 buffer_put_bignum2(&b, shared_secret);
250
251#ifdef DEBUG_KEX
252 buffer_dump(&b);
253#endif
254
255 EVP_DigestInit(&md, evp_md);
256 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
257 EVP_DigestFinal(&md, digest, NULL);
258
259 buffer_free(&b);
260
261#ifdef DEBUG_KEX
262 dump_digest(digest, evp_md->md_size);
263#endif
264 return digest;
265}
266
267u_char *
268kex_hash_gex(
269 char *client_version_string,
270 char *server_version_string,
271 char *ckexinit, int ckexinitlen,
272 char *skexinit, int skexinitlen,
273 char *serverhostkeyblob, int sbloblen,
274 int minbits, BIGNUM *prime, BIGNUM *gen,
275 BIGNUM *client_dh_pub,
276 BIGNUM *server_dh_pub,
277 BIGNUM *shared_secret)
278{
279 Buffer b;
280 static u_char digest[EVP_MAX_MD_SIZE];
281 EVP_MD *evp_md = EVP_sha1();
282 EVP_MD_CTX md;
283
284 buffer_init(&b);
285 buffer_put_string(&b, client_version_string, strlen(client_version_string));
286 buffer_put_string(&b, server_version_string, strlen(server_version_string));
287
288 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
289 buffer_put_int(&b, ckexinitlen+1);
290 buffer_put_char(&b, SSH2_MSG_KEXINIT);
291 buffer_append(&b, ckexinit, ckexinitlen);
292 buffer_put_int(&b, skexinitlen+1);
293 buffer_put_char(&b, SSH2_MSG_KEXINIT);
294 buffer_append(&b, skexinit, skexinitlen);
295
296 buffer_put_string(&b, serverhostkeyblob, sbloblen);
297 buffer_put_int(&b, minbits);
298 buffer_put_bignum2(&b, prime);
299 buffer_put_bignum2(&b, gen);
300 buffer_put_bignum2(&b, client_dh_pub);
301 buffer_put_bignum2(&b, server_dh_pub);
302 buffer_put_bignum2(&b, shared_secret);
303
304#ifdef DEBUG_KEX
305 buffer_dump(&b);
306#endif
307
308 EVP_DigestInit(&md, evp_md);
309 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
310 EVP_DigestFinal(&md, digest, NULL);
311
312 buffer_free(&b);
313
314#ifdef DEBUG_KEX
315 dump_digest(digest, evp_md->md_size);
316#endif
317 return digest;
318}
319
320u_char *
321derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
322{
323 Buffer b;
324 EVP_MD *evp_md = EVP_sha1();
325 EVP_MD_CTX md;
326 char c = id;
327 int have;
328 int mdsz = evp_md->md_size;
329 u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
330
331 buffer_init(&b);
332 buffer_put_bignum2(&b, shared_secret);
333
334 EVP_DigestInit(&md, evp_md);
335 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
336 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
337 EVP_DigestUpdate(&md, &c, 1); /* key id */
338 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
339 EVP_DigestFinal(&md, digest, NULL);
340
341 /* expand */
342 for (have = mdsz; need > have; have += mdsz) {
343 EVP_DigestInit(&md, evp_md);
344 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
345 EVP_DigestUpdate(&md, hash, mdsz);
346 EVP_DigestUpdate(&md, digest, have);
347 EVP_DigestFinal(&md, digest + have, NULL);
348 }
349 buffer_free(&b);
350#ifdef DEBUG_KEX
351 fprintf(stderr, "Digest '%c'== ", c);
352 dump_digest(digest, need);
353#endif
354 return digest;
355}
356
357#define NKEYS 6
358
359#define MAX_PROP 20
360#define SEP ","
361
362char *
363get_match(char *client, char *server)
364{
365 char *sproposals[MAX_PROP];
366 char *c, *s, *p, *ret, *cp, *sp;
367 int i, j, nproposals;
368
369 c = cp = xstrdup(client);
370 s = sp = xstrdup(server);
371
372 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
373 (p = strsep(&sp, SEP)), i++) {
374 if (i < MAX_PROP)
375 sproposals[i] = p;
376 else
377 break;
378 }
379 nproposals = i;
380
381 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
382 (p = strsep(&cp, SEP)), i++) {
383 for (j = 0; j < nproposals; j++) {
384 if (strcmp(p, sproposals[j]) == 0) {
385 ret = xstrdup(p);
386 xfree(c);
387 xfree(s);
388 return ret;
389 }
390 }
391 }
392 xfree(c);
393 xfree(s);
394 return NULL;
395}
396void
397choose_enc(Enc *enc, char *client, char *server)
398{
399 char *name = get_match(client, server);
400 if (name == NULL)
401 fatal("no matching cipher found: client %s server %s", client, server);
402 enc->cipher = cipher_by_name(name);
403 if (enc->cipher == NULL)
404 fatal("matching cipher is not supported: %s", name);
405 enc->name = name;
406 enc->enabled = 0;
407 enc->iv = NULL;
408 enc->key = NULL;
409}
410void
411choose_mac(Mac *mac, char *client, char *server)
412{
413 char *name = get_match(client, server);
414 if (name == NULL)
415 fatal("no matching mac found: client %s server %s", client, server);
416 if (strcmp(name, "hmac-md5") == 0) {
417 mac->md = EVP_md5();
418 } else if (strcmp(name, "hmac-sha1") == 0) {
419 mac->md = EVP_sha1();
420 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
421 mac->md = EVP_ripemd160();
422 } else {
423 fatal("unsupported mac %s", name);
424 }
425 mac->name = name;
426 mac->mac_len = mac->md->md_size;
427 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
428 mac->key = NULL;
429 mac->enabled = 0;
430}
431void
432choose_comp(Comp *comp, char *client, char *server)
433{
434 char *name = get_match(client, server);
435 if (name == NULL)
436 fatal("no matching comp found: client %s server %s", client, server);
437 if (strcmp(name, "zlib") == 0) {
438 comp->type = 1;
439 } else if (strcmp(name, "none") == 0) {
440 comp->type = 0;
441 } else {
442 fatal("unsupported comp %s", name);
443 }
444 comp->name = name;
445}
446void
447choose_kex(Kex *k, char *client, char *server)
448{
449 k->name = get_match(client, server);
450 if (k->name == NULL)
451 fatal("no kex alg");
452 if (strcmp(k->name, KEX_DH1) == 0) {
453 k->kex_type = DH_GRP1_SHA1;
454 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
455 k->kex_type = DH_GEX_SHA1;
456 } else
457 fatal("bad kex alg %s", k->name);
458}
459void
460choose_hostkeyalg(Kex *k, char *client, char *server)
461{
462 char *hostkeyalg = get_match(client, server);
463 if (hostkeyalg == NULL)
464 fatal("no hostkey alg");
465 k->hostkey_type = key_type_from_name(hostkeyalg);
466 if (k->hostkey_type == KEY_UNSPEC)
467 fatal("bad hostkey alg '%s'", hostkeyalg);
468}
469
470Kex *
471kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
472{
473 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]);
500 need = 0;
501 for (mode = 0; mode < MODE_MAX; mode++) {
502 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;
506 if (need < k->mac[mode].key_len)
507 need = k->mac[mode].key_len;
508 }
509 /* XXX need runden? */
510 k->we_need = need;
511 return k;
512}
513
514int
515kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
516{
517 int i;
518 int mode;
519 int ctos;
520 u_char *keys[NKEYS];
521
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}
This page took 0.127703 seconds and 5 git commands to generate.