]> andersk Git - openssh.git/blame - kex.c
- (stevesk) auth1.c: free should be after WITH_AIXAUTHENTICATE
[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"
1e3b8b07 26RCSID("$OpenBSD: kex.c,v 1.16 2000/12/20 19:37:22 markus Exp $");
4f8c6159 27
28#include "ssh.h"
29#include "ssh2.h"
30#include "xmalloc.h"
31#include "buffer.h"
32#include "bufaux.h"
71276795 33#include "packet.h"
4f8c6159 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"
fa08c86b 46#include "key.h"
4f8c6159 47
71276795 48#define KEX_COOKIE_LEN 16
49
4f8c6159 50Buffer *
51kex_init(char *myproposal[PROPOSAL_MAX])
52{
71276795 53 int first_kex_packet_follows = 0;
1e3b8b07 54 u_char cookie[KEX_COOKIE_LEN];
4f8c6159 55 u_int32_t rand = 0;
56 int i;
57 Buffer *ki = xmalloc(sizeof(*ki));
71276795 58 for (i = 0; i < KEX_COOKIE_LEN; i++) {
4f8c6159 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]);
71276795 68 buffer_put_char(ki, first_kex_packet_follows);
69 buffer_put_int(ki, 0); /* uint32 reserved */
4f8c6159 70 return ki;
71}
72
71276795 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
4f8c6159 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
4f8c6159 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
3e1caa83 142void
94ec8c6b 143dh_gen_key(DH *dh)
4f8c6159 144{
94ec8c6b 145 int tries = 0;
146
4f8c6159 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));
4f8c6159 153}
154
94ec8c6b 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
3e1caa83 170 return (dh);
94ec8c6b 171}
172
3e1caa83 173/*
174 * This just returns the group, we still need to generate the exchange
175 * value.
176 */
177
94ec8c6b 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
3e1caa83 189 return (dh);
94ec8c6b 190}
191
192DH *
1e3b8b07 193dh_new_group1(void)
94ec8c6b 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
4f8c6159 206void
1e3b8b07 207dump_digest(u_char *digest, int len)
4f8c6159 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
1e3b8b07 218u_char *
4f8c6159 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;
1e3b8b07 230 static u_char digest[EVP_MAX_MD_SIZE];
4f8c6159 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
1e3b8b07 267u_char *
94ec8c6b 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;
1e3b8b07 280 static u_char digest[EVP_MAX_MD_SIZE];
94ec8c6b 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
1e3b8b07 320u_char *
321derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
4f8c6159 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;
1e3b8b07 329 u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
4f8c6159 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];
089fbbd2 366 char *c, *s, *p, *ret, *cp, *sp;
4f8c6159 367 int i, j, nproposals;
368
089fbbd2 369 c = cp = xstrdup(client);
370 s = sp = xstrdup(server);
71276795 371
089fbbd2 372 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
373 (p = strsep(&sp, SEP)), i++) {
4f8c6159 374 if (i < MAX_PROP)
375 sproposals[i] = p;
376 else
377 break;
378 }
379 nproposals = i;
380
089fbbd2 381 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
382 (p = strsep(&cp, SEP)), i++) {
71276795 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 }
4f8c6159 391 }
71276795 392 xfree(c);
393 xfree(s);
4f8c6159 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);
94ec8c6b 402 enc->cipher = cipher_by_name(name);
403 if (enc->cipher == NULL)
404 fatal("matching cipher is not supported: %s", name);
4f8c6159 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;
d0c832f3 427 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
4f8c6159 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");
94ec8c6b 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
4f8c6159 457 fatal("bad kex alg %s", k->name);
458}
459void
460choose_hostkeyalg(Kex *k, char *client, char *server)
461{
fa08c86b 462 char *hostkeyalg = get_match(client, server);
463 if (hostkeyalg == NULL)
4f8c6159 464 fatal("no hostkey alg");
fa08c86b 465 k->hostkey_type = key_type_from_name(hostkeyalg);
466 if (k->hostkey_type == KEY_UNSPEC)
467 fatal("bad hostkey alg '%s'", hostkeyalg);
4f8c6159 468}
469
470Kex *
471kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
472{
4f8c6159 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]);
4f8c6159 500 need = 0;
501 for (mode = 0; mode < MODE_MAX; mode++) {
94ec8c6b 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;
4f8c6159 506 if (need < k->mac[mode].key_len)
507 need = k->mac[mode].key_len;
508 }
71276795 509 /* XXX need runden? */
4f8c6159 510 k->we_need = need;
511 return k;
512}
513
514int
1e3b8b07 515kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
4f8c6159 516{
517 int i;
518 int mode;
519 int ctos;
1e3b8b07 520 u_char *keys[NKEYS];
4f8c6159 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.23597 seconds and 5 git commands to generate.