]> andersk Git - openssh.git/blame - kex.c
- (djm) OpenBSD CVS updates:
[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.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
089fbbd2 31RCSID("$OpenBSD: kex.c,v 1.9 2000/07/10 16:30:25 ho Exp $");
4f8c6159 32
33#include "ssh.h"
34#include "ssh2.h"
35#include "xmalloc.h"
36#include "buffer.h"
37#include "bufaux.h"
71276795 38#include "packet.h"
4f8c6159 39#include "cipher.h"
40#include "compat.h"
41
42#include <openssl/bn.h>
43#include <openssl/dh.h>
44
45#include <openssl/crypto.h>
46#include <openssl/bio.h>
47#include <openssl/bn.h>
48#include <openssl/dh.h>
49#include <openssl/pem.h>
50
51#include "kex.h"
52
71276795 53#define KEX_COOKIE_LEN 16
54
4f8c6159 55Buffer *
56kex_init(char *myproposal[PROPOSAL_MAX])
57{
71276795 58 int first_kex_packet_follows = 0;
59 unsigned char cookie[KEX_COOKIE_LEN];
4f8c6159 60 u_int32_t rand = 0;
61 int i;
62 Buffer *ki = xmalloc(sizeof(*ki));
71276795 63 for (i = 0; i < KEX_COOKIE_LEN; i++) {
4f8c6159 64 if (i % 4 == 0)
65 rand = arc4random();
66 cookie[i] = rand & 0xff;
67 rand >>= 8;
68 }
69 buffer_init(ki);
70 buffer_append(ki, (char *)cookie, sizeof cookie);
71 for (i = 0; i < PROPOSAL_MAX; i++)
72 buffer_put_cstring(ki, myproposal[i]);
71276795 73 buffer_put_char(ki, first_kex_packet_follows);
74 buffer_put_int(ki, 0); /* uint32 reserved */
4f8c6159 75 return ki;
76}
77
71276795 78/* send kexinit, parse and save reply */
79void
80kex_exchange_kexinit(
81 Buffer *my_kexinit, Buffer *peer_kexint,
82 char *peer_proposal[PROPOSAL_MAX])
83{
84 int i;
85 char *ptr;
86 int plen;
87
88 debug("send KEXINIT");
89 packet_start(SSH2_MSG_KEXINIT);
90 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
91 packet_send();
92 packet_write_wait();
93 debug("done");
94
95 /*
96 * read and save raw KEXINIT payload in buffer. this is used during
97 * computation of the session_id and the session keys.
98 */
99 debug("wait KEXINIT");
100 packet_read_expect(&plen, SSH2_MSG_KEXINIT);
101 ptr = packet_get_raw(&plen);
102 buffer_append(peer_kexint, ptr, plen);
103
104 /* parse packet and save algorithm proposal */
105 /* skip cookie */
106 for (i = 0; i < KEX_COOKIE_LEN; i++)
107 packet_get_char();
108 /* extract kex init proposal strings */
109 for (i = 0; i < PROPOSAL_MAX; i++) {
110 peer_proposal[i] = packet_get_string(NULL);
111 debug("got kexinit: %s", peer_proposal[i]);
112 }
113 /* first kex follow / reserved */
114 i = packet_get_char();
115 debug("first kex follow: %d ", i);
116 i = packet_get_int();
117 debug("reserved: %d ", i);
118 packet_done();
119 debug("done");
120}
121
4f8c6159 122/* diffie-hellman-group1-sha1 */
123
124int
125dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
126{
127 int i;
128 int n = BN_num_bits(dh_pub);
129 int bits_set = 0;
130
131 /* we only accept g==2 */
132 if (!BN_is_word(dh->g, 2)) {
133 log("invalid DH base != 2");
134 return 0;
135 }
136 if (dh_pub->neg) {
137 log("invalid public DH value: negativ");
138 return 0;
139 }
140 for (i = 0; i <= n; i++)
141 if (BN_is_bit_set(dh_pub, i))
142 bits_set++;
143 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
144
145 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
146 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
147 return 1;
148 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
149 return 0;
150}
151
152DH *
153dh_new_group1()
154{
155 static char *group1 =
156 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
157 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
158 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
159 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
160 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
161 "FFFFFFFF" "FFFFFFFF";
162 DH *dh;
163 int ret, tries = 0;
164 dh = DH_new();
165 if(dh == NULL)
166 fatal("DH_new");
167 ret = BN_hex2bn(&dh->p, group1);
168 if(ret<0)
169 fatal("BN_hex2bn");
170 dh->g = BN_new();
171 if(dh->g == NULL)
172 fatal("DH_new g");
173 BN_set_word(dh->g, 2);
174 do {
175 if (DH_generate_key(dh) == 0)
176 fatal("DH_generate_key");
177 if (tries++ > 10)
178 fatal("dh_new_group1: too many bad keys: giving up");
179 } while (!dh_pub_is_valid(dh, dh->pub_key));
180 return dh;
181}
182
4f8c6159 183void
184dump_digest(unsigned char *digest, int len)
185{
186 int i;
187 for (i = 0; i< len; i++){
188 fprintf(stderr, "%02x", digest[i]);
189 if(i%2!=0)
190 fprintf(stderr, " ");
191 }
192 fprintf(stderr, "\n");
193}
194
195unsigned char *
196kex_hash(
197 char *client_version_string,
198 char *server_version_string,
199 char *ckexinit, int ckexinitlen,
200 char *skexinit, int skexinitlen,
201 char *serverhostkeyblob, int sbloblen,
202 BIGNUM *client_dh_pub,
203 BIGNUM *server_dh_pub,
204 BIGNUM *shared_secret)
205{
206 Buffer b;
207 static unsigned char digest[EVP_MAX_MD_SIZE];
208 EVP_MD *evp_md = EVP_sha1();
209 EVP_MD_CTX md;
210
211 buffer_init(&b);
212 buffer_put_string(&b, client_version_string, strlen(client_version_string));
213 buffer_put_string(&b, server_version_string, strlen(server_version_string));
214
215 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
216 buffer_put_int(&b, ckexinitlen+1);
217 buffer_put_char(&b, SSH2_MSG_KEXINIT);
218 buffer_append(&b, ckexinit, ckexinitlen);
219 buffer_put_int(&b, skexinitlen+1);
220 buffer_put_char(&b, SSH2_MSG_KEXINIT);
221 buffer_append(&b, skexinit, skexinitlen);
222
223 buffer_put_string(&b, serverhostkeyblob, sbloblen);
224 buffer_put_bignum2(&b, client_dh_pub);
225 buffer_put_bignum2(&b, server_dh_pub);
226 buffer_put_bignum2(&b, shared_secret);
227
228#ifdef DEBUG_KEX
229 buffer_dump(&b);
230#endif
231
232 EVP_DigestInit(&md, evp_md);
233 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
234 EVP_DigestFinal(&md, digest, NULL);
235
236 buffer_free(&b);
237
238#ifdef DEBUG_KEX
239 dump_digest(digest, evp_md->md_size);
240#endif
241 return digest;
242}
243
244unsigned char *
245derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
246{
247 Buffer b;
248 EVP_MD *evp_md = EVP_sha1();
249 EVP_MD_CTX md;
250 char c = id;
251 int have;
252 int mdsz = evp_md->md_size;
253 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
254
255 buffer_init(&b);
256 buffer_put_bignum2(&b, shared_secret);
257
258 EVP_DigestInit(&md, evp_md);
259 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
260 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
261 EVP_DigestUpdate(&md, &c, 1); /* key id */
262 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
263 EVP_DigestFinal(&md, digest, NULL);
264
265 /* expand */
266 for (have = mdsz; need > have; have += mdsz) {
267 EVP_DigestInit(&md, evp_md);
268 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
269 EVP_DigestUpdate(&md, hash, mdsz);
270 EVP_DigestUpdate(&md, digest, have);
271 EVP_DigestFinal(&md, digest + have, NULL);
272 }
273 buffer_free(&b);
274#ifdef DEBUG_KEX
275 fprintf(stderr, "Digest '%c'== ", c);
276 dump_digest(digest, need);
277#endif
278 return digest;
279}
280
281#define NKEYS 6
282
283#define MAX_PROP 20
284#define SEP ","
285
286char *
287get_match(char *client, char *server)
288{
289 char *sproposals[MAX_PROP];
089fbbd2 290 char *c, *s, *p, *ret, *cp, *sp;
4f8c6159 291 int i, j, nproposals;
292
089fbbd2 293 c = cp = xstrdup(client);
294 s = sp = xstrdup(server);
71276795 295
089fbbd2 296 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
297 (p = strsep(&sp, SEP)), i++) {
4f8c6159 298 if (i < MAX_PROP)
299 sproposals[i] = p;
300 else
301 break;
302 }
303 nproposals = i;
304
089fbbd2 305 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
306 (p = strsep(&cp, SEP)), i++) {
71276795 307 for (j = 0; j < nproposals; j++) {
308 if (strcmp(p, sproposals[j]) == 0) {
309 ret = xstrdup(p);
310 xfree(c);
311 xfree(s);
312 return ret;
313 }
314 }
4f8c6159 315 }
71276795 316 xfree(c);
317 xfree(s);
4f8c6159 318 return NULL;
319}
320void
321choose_enc(Enc *enc, char *client, char *server)
322{
323 char *name = get_match(client, server);
324 if (name == NULL)
325 fatal("no matching cipher found: client %s server %s", client, server);
326 enc->type = cipher_number(name);
327
328 switch (enc->type) {
329 case SSH_CIPHER_3DES_CBC:
330 enc->key_len = 24;
331 enc->iv_len = 8;
332 enc->block_size = 8;
333 break;
334 case SSH_CIPHER_BLOWFISH_CBC:
335 case SSH_CIPHER_CAST128_CBC:
336 enc->key_len = 16;
337 enc->iv_len = 8;
338 enc->block_size = 8;
339 break;
340 case SSH_CIPHER_ARCFOUR:
341 enc->key_len = 16;
342 enc->iv_len = 0;
343 enc->block_size = 8;
344 break;
345 default:
346 fatal("unsupported cipher %s", name);
347 }
348 enc->name = name;
349 enc->enabled = 0;
350 enc->iv = NULL;
351 enc->key = NULL;
352}
353void
354choose_mac(Mac *mac, char *client, char *server)
355{
356 char *name = get_match(client, server);
357 if (name == NULL)
358 fatal("no matching mac found: client %s server %s", client, server);
359 if (strcmp(name, "hmac-md5") == 0) {
360 mac->md = EVP_md5();
361 } else if (strcmp(name, "hmac-sha1") == 0) {
362 mac->md = EVP_sha1();
363 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
364 mac->md = EVP_ripemd160();
365 } else {
366 fatal("unsupported mac %s", name);
367 }
368 mac->name = name;
369 mac->mac_len = mac->md->md_size;
d0c832f3 370 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
4f8c6159 371 mac->key = NULL;
372 mac->enabled = 0;
373}
374void
375choose_comp(Comp *comp, char *client, char *server)
376{
377 char *name = get_match(client, server);
378 if (name == NULL)
379 fatal("no matching comp found: client %s server %s", client, server);
380 if (strcmp(name, "zlib") == 0) {
381 comp->type = 1;
382 } else if (strcmp(name, "none") == 0) {
383 comp->type = 0;
384 } else {
385 fatal("unsupported comp %s", name);
386 }
387 comp->name = name;
388}
389void
390choose_kex(Kex *k, char *client, char *server)
391{
392 k->name = get_match(client, server);
393 if (k->name == NULL)
394 fatal("no kex alg");
395 if (strcmp(k->name, KEX_DH1) != 0)
396 fatal("bad kex alg %s", k->name);
397}
398void
399choose_hostkeyalg(Kex *k, char *client, char *server)
400{
401 k->hostkeyalg = get_match(client, server);
402 if (k->hostkeyalg == NULL)
403 fatal("no hostkey alg");
404 if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
405 fatal("bad hostkey alg %s", k->hostkeyalg);
406}
407
408Kex *
409kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
410{
4f8c6159 411 int mode;
412 int ctos; /* direction: if true client-to-server */
413 int need;
414 Kex *k;
415
416 k = xmalloc(sizeof(*k));
417 memset(k, 0, sizeof(*k));
418 k->server = server;
419
420 for (mode = 0; mode < MODE_MAX; mode++) {
421 int nenc, nmac, ncomp;
422 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
423 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
424 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
425 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
426 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
427 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
428 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
429 debug("kex: %s %s %s %s",
430 ctos ? "client->server" : "server->client",
431 k->enc[mode].name,
432 k->mac[mode].name,
433 k->comp[mode].name);
434 }
435 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
436 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
437 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
4f8c6159 438 need = 0;
439 for (mode = 0; mode < MODE_MAX; mode++) {
440 if (need < k->enc[mode].key_len)
441 need = k->enc[mode].key_len;
442 if (need < k->enc[mode].iv_len)
443 need = k->enc[mode].iv_len;
444 if (need < k->mac[mode].key_len)
445 need = k->mac[mode].key_len;
446 }
71276795 447 /* XXX need runden? */
4f8c6159 448 k->we_need = need;
449 return k;
450}
451
452int
453kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
454{
455 int i;
456 int mode;
457 int ctos;
458 unsigned char *keys[NKEYS];
459
460 for (i = 0; i < NKEYS; i++)
461 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
462
463 for (mode = 0; mode < MODE_MAX; mode++) {
464 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
465 k->enc[mode].iv = keys[ctos ? 0 : 1];
466 k->enc[mode].key = keys[ctos ? 2 : 3];
467 k->mac[mode].key = keys[ctos ? 4 : 5];
468 }
469 return 0;
470}
This page took 1.166744 seconds and 5 git commands to generate.