]> andersk Git - openssh.git/blame - kex.c
- (djm) Merge OpenBSD changes:
[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"
bcbf86ec 26RCSID("$OpenBSD: kex.c,v 1.10 2000/09/07 20:27:51 deraadt 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 "cipher.h"
35#include "compat.h"
36
37#include <openssl/bn.h>
38#include <openssl/dh.h>
39
40#include <openssl/crypto.h>
41#include <openssl/bio.h>
42#include <openssl/bn.h>
43#include <openssl/dh.h>
44#include <openssl/pem.h>
45
46#include "kex.h"
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;
54 unsigned 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
126 /* we only accept g==2 */
127 if (!BN_is_word(dh->g, 2)) {
128 log("invalid DH base != 2");
129 return 0;
130 }
131 if (dh_pub->neg) {
132 log("invalid public DH value: negativ");
133 return 0;
134 }
135 for (i = 0; i <= n; i++)
136 if (BN_is_bit_set(dh_pub, i))
137 bits_set++;
138 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
139
140 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
141 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
142 return 1;
143 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
144 return 0;
145}
146
147DH *
148dh_new_group1()
149{
150 static char *group1 =
151 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
152 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
153 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
154 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
155 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
156 "FFFFFFFF" "FFFFFFFF";
157 DH *dh;
158 int ret, tries = 0;
159 dh = DH_new();
160 if(dh == NULL)
161 fatal("DH_new");
162 ret = BN_hex2bn(&dh->p, group1);
163 if(ret<0)
164 fatal("BN_hex2bn");
165 dh->g = BN_new();
166 if(dh->g == NULL)
167 fatal("DH_new g");
168 BN_set_word(dh->g, 2);
169 do {
170 if (DH_generate_key(dh) == 0)
171 fatal("DH_generate_key");
172 if (tries++ > 10)
173 fatal("dh_new_group1: too many bad keys: giving up");
174 } while (!dh_pub_is_valid(dh, dh->pub_key));
175 return dh;
176}
177
4f8c6159 178void
179dump_digest(unsigned char *digest, int len)
180{
181 int i;
182 for (i = 0; i< len; i++){
183 fprintf(stderr, "%02x", digest[i]);
184 if(i%2!=0)
185 fprintf(stderr, " ");
186 }
187 fprintf(stderr, "\n");
188}
189
190unsigned char *
191kex_hash(
192 char *client_version_string,
193 char *server_version_string,
194 char *ckexinit, int ckexinitlen,
195 char *skexinit, int skexinitlen,
196 char *serverhostkeyblob, int sbloblen,
197 BIGNUM *client_dh_pub,
198 BIGNUM *server_dh_pub,
199 BIGNUM *shared_secret)
200{
201 Buffer b;
202 static unsigned char digest[EVP_MAX_MD_SIZE];
203 EVP_MD *evp_md = EVP_sha1();
204 EVP_MD_CTX md;
205
206 buffer_init(&b);
207 buffer_put_string(&b, client_version_string, strlen(client_version_string));
208 buffer_put_string(&b, server_version_string, strlen(server_version_string));
209
210 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
211 buffer_put_int(&b, ckexinitlen+1);
212 buffer_put_char(&b, SSH2_MSG_KEXINIT);
213 buffer_append(&b, ckexinit, ckexinitlen);
214 buffer_put_int(&b, skexinitlen+1);
215 buffer_put_char(&b, SSH2_MSG_KEXINIT);
216 buffer_append(&b, skexinit, skexinitlen);
217
218 buffer_put_string(&b, serverhostkeyblob, sbloblen);
219 buffer_put_bignum2(&b, client_dh_pub);
220 buffer_put_bignum2(&b, server_dh_pub);
221 buffer_put_bignum2(&b, shared_secret);
222
223#ifdef DEBUG_KEX
224 buffer_dump(&b);
225#endif
226
227 EVP_DigestInit(&md, evp_md);
228 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
229 EVP_DigestFinal(&md, digest, NULL);
230
231 buffer_free(&b);
232
233#ifdef DEBUG_KEX
234 dump_digest(digest, evp_md->md_size);
235#endif
236 return digest;
237}
238
239unsigned char *
240derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
241{
242 Buffer b;
243 EVP_MD *evp_md = EVP_sha1();
244 EVP_MD_CTX md;
245 char c = id;
246 int have;
247 int mdsz = evp_md->md_size;
248 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
249
250 buffer_init(&b);
251 buffer_put_bignum2(&b, shared_secret);
252
253 EVP_DigestInit(&md, evp_md);
254 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
255 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
256 EVP_DigestUpdate(&md, &c, 1); /* key id */
257 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
258 EVP_DigestFinal(&md, digest, NULL);
259
260 /* expand */
261 for (have = mdsz; need > have; have += mdsz) {
262 EVP_DigestInit(&md, evp_md);
263 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
264 EVP_DigestUpdate(&md, hash, mdsz);
265 EVP_DigestUpdate(&md, digest, have);
266 EVP_DigestFinal(&md, digest + have, NULL);
267 }
268 buffer_free(&b);
269#ifdef DEBUG_KEX
270 fprintf(stderr, "Digest '%c'== ", c);
271 dump_digest(digest, need);
272#endif
273 return digest;
274}
275
276#define NKEYS 6
277
278#define MAX_PROP 20
279#define SEP ","
280
281char *
282get_match(char *client, char *server)
283{
284 char *sproposals[MAX_PROP];
089fbbd2 285 char *c, *s, *p, *ret, *cp, *sp;
4f8c6159 286 int i, j, nproposals;
287
089fbbd2 288 c = cp = xstrdup(client);
289 s = sp = xstrdup(server);
71276795 290
089fbbd2 291 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
292 (p = strsep(&sp, SEP)), i++) {
4f8c6159 293 if (i < MAX_PROP)
294 sproposals[i] = p;
295 else
296 break;
297 }
298 nproposals = i;
299
089fbbd2 300 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
301 (p = strsep(&cp, SEP)), i++) {
71276795 302 for (j = 0; j < nproposals; j++) {
303 if (strcmp(p, sproposals[j]) == 0) {
304 ret = xstrdup(p);
305 xfree(c);
306 xfree(s);
307 return ret;
308 }
309 }
4f8c6159 310 }
71276795 311 xfree(c);
312 xfree(s);
4f8c6159 313 return NULL;
314}
315void
316choose_enc(Enc *enc, char *client, char *server)
317{
318 char *name = get_match(client, server);
319 if (name == NULL)
320 fatal("no matching cipher found: client %s server %s", client, server);
321 enc->type = cipher_number(name);
322
323 switch (enc->type) {
324 case SSH_CIPHER_3DES_CBC:
325 enc->key_len = 24;
326 enc->iv_len = 8;
327 enc->block_size = 8;
328 break;
329 case SSH_CIPHER_BLOWFISH_CBC:
330 case SSH_CIPHER_CAST128_CBC:
331 enc->key_len = 16;
332 enc->iv_len = 8;
333 enc->block_size = 8;
334 break;
335 case SSH_CIPHER_ARCFOUR:
336 enc->key_len = 16;
337 enc->iv_len = 0;
338 enc->block_size = 8;
339 break;
340 default:
341 fatal("unsupported cipher %s", name);
342 }
343 enc->name = name;
344 enc->enabled = 0;
345 enc->iv = NULL;
346 enc->key = NULL;
347}
348void
349choose_mac(Mac *mac, char *client, char *server)
350{
351 char *name = get_match(client, server);
352 if (name == NULL)
353 fatal("no matching mac found: client %s server %s", client, server);
354 if (strcmp(name, "hmac-md5") == 0) {
355 mac->md = EVP_md5();
356 } else if (strcmp(name, "hmac-sha1") == 0) {
357 mac->md = EVP_sha1();
358 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
359 mac->md = EVP_ripemd160();
360 } else {
361 fatal("unsupported mac %s", name);
362 }
363 mac->name = name;
364 mac->mac_len = mac->md->md_size;
d0c832f3 365 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
4f8c6159 366 mac->key = NULL;
367 mac->enabled = 0;
368}
369void
370choose_comp(Comp *comp, char *client, char *server)
371{
372 char *name = get_match(client, server);
373 if (name == NULL)
374 fatal("no matching comp found: client %s server %s", client, server);
375 if (strcmp(name, "zlib") == 0) {
376 comp->type = 1;
377 } else if (strcmp(name, "none") == 0) {
378 comp->type = 0;
379 } else {
380 fatal("unsupported comp %s", name);
381 }
382 comp->name = name;
383}
384void
385choose_kex(Kex *k, char *client, char *server)
386{
387 k->name = get_match(client, server);
388 if (k->name == NULL)
389 fatal("no kex alg");
390 if (strcmp(k->name, KEX_DH1) != 0)
391 fatal("bad kex alg %s", k->name);
392}
393void
394choose_hostkeyalg(Kex *k, char *client, char *server)
395{
396 k->hostkeyalg = get_match(client, server);
397 if (k->hostkeyalg == NULL)
398 fatal("no hostkey alg");
399 if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
400 fatal("bad hostkey alg %s", k->hostkeyalg);
401}
402
403Kex *
404kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
405{
4f8c6159 406 int mode;
407 int ctos; /* direction: if true client-to-server */
408 int need;
409 Kex *k;
410
411 k = xmalloc(sizeof(*k));
412 memset(k, 0, sizeof(*k));
413 k->server = server;
414
415 for (mode = 0; mode < MODE_MAX; mode++) {
416 int nenc, nmac, ncomp;
417 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
418 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
419 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
420 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
421 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
422 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
423 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
424 debug("kex: %s %s %s %s",
425 ctos ? "client->server" : "server->client",
426 k->enc[mode].name,
427 k->mac[mode].name,
428 k->comp[mode].name);
429 }
430 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
431 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
432 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
4f8c6159 433 need = 0;
434 for (mode = 0; mode < MODE_MAX; mode++) {
435 if (need < k->enc[mode].key_len)
436 need = k->enc[mode].key_len;
437 if (need < k->enc[mode].iv_len)
438 need = k->enc[mode].iv_len;
439 if (need < k->mac[mode].key_len)
440 need = k->mac[mode].key_len;
441 }
71276795 442 /* XXX need runden? */
4f8c6159 443 k->we_need = need;
444 return k;
445}
446
447int
448kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
449{
450 int i;
451 int mode;
452 int ctos;
453 unsigned char *keys[NKEYS];
454
455 for (i = 0; i < NKEYS; i++)
456 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
457
458 for (mode = 0; mode < MODE_MAX; mode++) {
459 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
460 k->enc[mode].iv = keys[ctos ? 0 : 1];
461 k->enc[mode].key = keys[ctos ? 2 : 3];
462 k->mac[mode].key = keys[ctos ? 4 : 5];
463 }
464 return 0;
465}
This page took 0.135091 seconds and 5 git commands to generate.