]> andersk Git - openssh.git/blob - kex.c
- markus@cvs.openbsd.org 2003/02/02 10:56:08
[openssh.git] / kex.c
1 /*
2  * Copyright (c) 2000, 2001 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"
26 RCSID("$OpenBSD: kex.c,v 1.53 2003/02/02 10:56:08 markus Exp $");
27
28 #include <openssl/crypto.h>
29
30 #include "ssh2.h"
31 #include "xmalloc.h"
32 #include "buffer.h"
33 #include "bufaux.h"
34 #include "packet.h"
35 #include "compat.h"
36 #include "cipher.h"
37 #include "kex.h"
38 #include "key.h"
39 #include "log.h"
40 #include "mac.h"
41 #include "match.h"
42 #include "dispatch.h"
43 #include "monitor.h"
44
45 #define KEX_COOKIE_LEN  16
46
47 /* Use privilege separation for sshd */
48 int use_privsep;
49 struct monitor *pmonitor;
50
51
52 /* prototype */
53 static void kex_kexinit_finish(Kex *);
54 static void kex_choose_conf(Kex *);
55
56 /* put algorithm proposal into buffer */
57 static void
58 kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
59 {
60         int i;
61
62         buffer_clear(b);
63         /*
64          * add a dummy cookie, the cookie will be overwritten by
65          * kex_send_kexinit(), each time a kexinit is set
66          */
67         for (i = 0; i < KEX_COOKIE_LEN; i++)
68                 buffer_put_char(b, 0);
69         for (i = 0; i < PROPOSAL_MAX; i++)
70                 buffer_put_cstring(b, proposal[i]);
71         buffer_put_char(b, 0);                  /* first_kex_packet_follows */
72         buffer_put_int(b, 0);                   /* uint32 reserved */
73 }
74
75 /* parse buffer and return algorithm proposal */
76 static char **
77 kex_buf2prop(Buffer *raw, int *first_kex_follows)
78 {
79         Buffer b;
80         int i;
81         char **proposal;
82
83         proposal = xmalloc(PROPOSAL_MAX * sizeof(char *));
84
85         buffer_init(&b);
86         buffer_append(&b, buffer_ptr(raw), buffer_len(raw));
87         /* skip cookie */
88         for (i = 0; i < KEX_COOKIE_LEN; i++)
89                 buffer_get_char(&b);
90         /* extract kex init proposal strings */
91         for (i = 0; i < PROPOSAL_MAX; i++) {
92                 proposal[i] = buffer_get_string(&b,NULL);
93                 debug2("kex_parse_kexinit: %s", proposal[i]);
94         }
95         /* first kex follows / reserved */
96         i = buffer_get_char(&b);
97         if (first_kex_follows != NULL)
98                 *first_kex_follows = i;
99         debug2("kex_parse_kexinit: first_kex_follows %d ", i);
100         i = buffer_get_int(&b);
101         debug2("kex_parse_kexinit: reserved %d ", i);
102         buffer_free(&b);
103         return proposal;
104 }
105
106 static void
107 kex_prop_free(char **proposal)
108 {
109         int i;
110
111         for (i = 0; i < PROPOSAL_MAX; i++)
112                 xfree(proposal[i]);
113         xfree(proposal);
114 }
115
116 static void
117 kex_protocol_error(int type, u_int32_t seq, void *ctxt)
118 {
119         error("Hm, kex protocol error: type %d seq %u", type, seq);
120 }
121
122 static void
123 kex_reset_dispatch(void)
124 {
125         dispatch_range(SSH2_MSG_TRANSPORT_MIN,
126             SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
127         dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
128 }
129
130 void
131 kex_finish(Kex *kex)
132 {
133         kex_reset_dispatch();
134
135         packet_start(SSH2_MSG_NEWKEYS);
136         packet_send();
137         /* packet_write_wait(); */
138         debug("SSH2_MSG_NEWKEYS sent");
139
140         debug("expecting SSH2_MSG_NEWKEYS");
141         packet_read_expect(SSH2_MSG_NEWKEYS);
142         packet_check_eom();
143         debug("SSH2_MSG_NEWKEYS received");
144
145         kex->done = 1;
146         buffer_clear(&kex->peer);
147         /* buffer_clear(&kex->my); */
148         kex->flags &= ~KEX_INIT_SENT;
149         xfree(kex->name);
150         kex->name = NULL;
151 }
152
153 void
154 kex_send_kexinit(Kex *kex)
155 {
156         u_int32_t rand = 0;
157         u_char *cookie;
158         int i;
159
160         if (kex == NULL) {
161                 error("kex_send_kexinit: no kex, cannot rekey");
162                 return;
163         }
164         if (kex->flags & KEX_INIT_SENT) {
165                 debug("KEX_INIT_SENT");
166                 return;
167         }
168         kex->done = 0;
169
170         /* generate a random cookie */
171         if (buffer_len(&kex->my) < KEX_COOKIE_LEN)
172                 fatal("kex_send_kexinit: kex proposal too short");
173         cookie = buffer_ptr(&kex->my);
174         for (i = 0; i < KEX_COOKIE_LEN; i++) {
175                 if (i % 4 == 0)
176                         rand = arc4random();
177                 cookie[i] = rand;
178                 rand >>= 8;
179         }
180         packet_start(SSH2_MSG_KEXINIT);
181         packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my));
182         packet_send();
183         debug("SSH2_MSG_KEXINIT sent");
184         kex->flags |= KEX_INIT_SENT;
185 }
186
187 void
188 kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
189 {
190         char *ptr;
191         int dlen;
192         int i;
193         Kex *kex = (Kex *)ctxt;
194
195         debug("SSH2_MSG_KEXINIT received");
196         if (kex == NULL)
197                 fatal("kex_input_kexinit: no kex, cannot rekey");
198
199         ptr = packet_get_raw(&dlen);
200         buffer_append(&kex->peer, ptr, dlen);
201
202         /* discard packet */
203         for (i = 0; i < KEX_COOKIE_LEN; i++)
204                 packet_get_char();
205         for (i = 0; i < PROPOSAL_MAX; i++)
206                 xfree(packet_get_string(NULL));
207         (void) packet_get_char();
208         (void) packet_get_int();
209         packet_check_eom();
210
211         kex_kexinit_finish(kex);
212 }
213
214 Kex *
215 kex_setup(char *proposal[PROPOSAL_MAX])
216 {
217         Kex *kex;
218
219         kex = xmalloc(sizeof(*kex));
220         memset(kex, 0, sizeof(*kex));
221         buffer_init(&kex->peer);
222         buffer_init(&kex->my);
223         kex_prop2buf(&kex->my, proposal);
224         kex->done = 0;
225
226         kex_send_kexinit(kex);                                  /* we start */
227         kex_reset_dispatch();
228
229         return kex;
230 }
231
232 static void
233 kex_kexinit_finish(Kex *kex)
234 {
235         if (!(kex->flags & KEX_INIT_SENT))
236                 kex_send_kexinit(kex);
237
238         kex_choose_conf(kex);
239
240         switch (kex->kex_type) {
241         case DH_GRP1_SHA1:
242                 kexdh(kex);
243                 break;
244         case DH_GEX_SHA1:
245                 kexgex(kex);
246                 break;
247         default:
248                 fatal("Unsupported key exchange %d", kex->kex_type);
249         }
250 }
251
252 static void
253 choose_enc(Enc *enc, char *client, char *server)
254 {
255         char *name = match_list(client, server, NULL);
256         if (name == NULL)
257                 fatal("no matching cipher found: client %s server %s", client, server);
258         if ((enc->cipher = cipher_by_name(name)) == NULL)
259                 fatal("matching cipher is not supported: %s", name);
260         enc->name = name;
261         enc->enabled = 0;
262         enc->iv = NULL;
263         enc->key = NULL;
264         enc->key_len = cipher_keylen(enc->cipher);
265         enc->block_size = cipher_blocksize(enc->cipher);
266 }
267 static void
268 choose_mac(Mac *mac, char *client, char *server)
269 {
270         char *name = match_list(client, server, NULL);
271         if (name == NULL)
272                 fatal("no matching mac found: client %s server %s", client, server);
273         if (mac_init(mac, name) < 0)
274                 fatal("unsupported mac %s", name);
275         /* truncate the key */
276         if (datafellows & SSH_BUG_HMAC)
277                 mac->key_len = 16;
278         mac->name = name;
279         mac->key = NULL;
280         mac->enabled = 0;
281 }
282 static void
283 choose_comp(Comp *comp, char *client, char *server)
284 {
285         char *name = match_list(client, server, NULL);
286         if (name == NULL)
287                 fatal("no matching comp found: client %s server %s", client, server);
288         if (strcmp(name, "zlib") == 0) {
289                 comp->type = 1;
290         } else if (strcmp(name, "none") == 0) {
291                 comp->type = 0;
292         } else {
293                 fatal("unsupported comp %s", name);
294         }
295         comp->name = name;
296 }
297 static void
298 choose_kex(Kex *k, char *client, char *server)
299 {
300         k->name = match_list(client, server, NULL);
301         if (k->name == NULL)
302                 fatal("no kex alg");
303         if (strcmp(k->name, KEX_DH1) == 0) {
304                 k->kex_type = DH_GRP1_SHA1;
305         } else if (strcmp(k->name, KEX_DHGEX) == 0) {
306                 k->kex_type = DH_GEX_SHA1;
307         } else
308                 fatal("bad kex alg %s", k->name);
309 }
310 static void
311 choose_hostkeyalg(Kex *k, char *client, char *server)
312 {
313         char *hostkeyalg = match_list(client, server, NULL);
314         if (hostkeyalg == NULL)
315                 fatal("no hostkey alg");
316         k->hostkey_type = key_type_from_name(hostkeyalg);
317         if (k->hostkey_type == KEY_UNSPEC)
318                 fatal("bad hostkey alg '%s'", hostkeyalg);
319         xfree(hostkeyalg);
320 }
321
322 static int 
323 proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
324 {
325         static int check[] = {
326                 PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
327         };
328         int *idx;
329         char *p;
330
331         for (idx = &check[0]; *idx != -1; idx++) {
332                 if ((p = strchr(my[*idx], ',')) != NULL)
333                         *p = '\0';
334                 if ((p = strchr(peer[*idx], ',')) != NULL)
335                         *p = '\0';
336                 if (strcmp(my[*idx], peer[*idx]) != 0) {
337                         debug2("proposal mismatch: my %s peer %s",
338                             my[*idx], peer[*idx]);
339                         return (0);
340                 }
341         }
342         debug2("proposals match");
343         return (1);
344 }
345
346 static void
347 kex_choose_conf(Kex *kex)
348 {
349         Newkeys *newkeys;
350         char **my, **peer;
351         char **cprop, **sprop;
352         int nenc, nmac, ncomp;
353         int mode;
354         int ctos;                               /* direction: if true client-to-server */
355         int need;
356         int first_kex_follows, type;
357
358         my   = kex_buf2prop(&kex->my, NULL);
359         peer = kex_buf2prop(&kex->peer, &first_kex_follows);
360
361         if (kex->server) {
362                 cprop=peer;
363                 sprop=my;
364         } else {
365                 cprop=my;
366                 sprop=peer;
367         }
368
369         /* Algorithm Negotiation */
370         for (mode = 0; mode < MODE_MAX; mode++) {
371                 newkeys = xmalloc(sizeof(*newkeys));
372                 memset(newkeys, 0, sizeof(*newkeys));
373                 kex->newkeys[mode] = newkeys;
374                 ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
375                 nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
376                 nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
377                 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
378                 choose_enc (&newkeys->enc,  cprop[nenc],  sprop[nenc]);
379                 choose_mac (&newkeys->mac,  cprop[nmac],  sprop[nmac]);
380                 choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]);
381                 debug("kex: %s %s %s %s",
382                     ctos ? "client->server" : "server->client",
383                     newkeys->enc.name,
384                     newkeys->mac.name,
385                     newkeys->comp.name);
386         }
387         choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
388         choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
389             sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
390         need = 0;
391         for (mode = 0; mode < MODE_MAX; mode++) {
392                 newkeys = kex->newkeys[mode];
393                 if (need < newkeys->enc.key_len)
394                         need = newkeys->enc.key_len;
395                 if (need < newkeys->enc.block_size)
396                         need = newkeys->enc.block_size;
397                 if (need < newkeys->mac.key_len)
398                         need = newkeys->mac.key_len;
399         }
400         /* XXX need runden? */
401         kex->we_need = need;
402
403         /* ignore the next message if the proposals do not match */
404         if (first_kex_follows && !proposals_match(my, peer)) {
405                 type = packet_read();
406                 debug2("skipping next packet (type %u)", type);
407         }
408
409         kex_prop_free(my);
410         kex_prop_free(peer);
411 }
412
413 static u_char *
414 derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
415 {
416         Buffer b;
417         const EVP_MD *evp_md = EVP_sha1();
418         EVP_MD_CTX md;
419         char c = id;
420         int have;
421         int mdsz = EVP_MD_size(evp_md);
422         u_char *digest = xmalloc(roundup(need, mdsz));
423
424         buffer_init(&b);
425         buffer_put_bignum2(&b, shared_secret);
426
427         /* K1 = HASH(K || H || "A" || session_id) */
428         EVP_DigestInit(&md, evp_md);
429         if (!(datafellows & SSH_BUG_DERIVEKEY))
430                 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
431         EVP_DigestUpdate(&md, hash, mdsz);
432         EVP_DigestUpdate(&md, &c, 1);
433         EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len);
434         EVP_DigestFinal(&md, digest, NULL);
435
436         /*
437          * expand key:
438          * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
439          * Key = K1 || K2 || ... || Kn
440          */
441         for (have = mdsz; need > have; have += mdsz) {
442                 EVP_DigestInit(&md, evp_md);
443                 if (!(datafellows & SSH_BUG_DERIVEKEY))
444                         EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
445                 EVP_DigestUpdate(&md, hash, mdsz);
446                 EVP_DigestUpdate(&md, digest, have);
447                 EVP_DigestFinal(&md, digest + have, NULL);
448         }
449         buffer_free(&b);
450 #ifdef DEBUG_KEX
451         fprintf(stderr, "key '%c'== ", c);
452         dump_digest("key", digest, need);
453 #endif
454         return digest;
455 }
456
457 Newkeys *current_keys[MODE_MAX];
458
459 #define NKEYS   6
460 void
461 kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret)
462 {
463         u_char *keys[NKEYS];
464         int i, mode, ctos;
465
466         for (i = 0; i < NKEYS; i++)
467                 keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret);
468
469         debug2("kex_derive_keys");
470         for (mode = 0; mode < MODE_MAX; mode++) {
471                 current_keys[mode] = kex->newkeys[mode];
472                 kex->newkeys[mode] = NULL;
473                 ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
474                 current_keys[mode]->enc.iv  = keys[ctos ? 0 : 1];
475                 current_keys[mode]->enc.key = keys[ctos ? 2 : 3];
476                 current_keys[mode]->mac.key = keys[ctos ? 4 : 5];
477         }
478 }
479
480 Newkeys *
481 kex_get_newkeys(int mode)
482 {
483         Newkeys *ret;
484
485         ret = current_keys[mode];
486         current_keys[mode] = NULL;
487         return ret;
488 }
489
490 #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
491 void
492 dump_digest(char *msg, u_char *digest, int len)
493 {
494         int i;
495
496         fprintf(stderr, "%s\n", msg);
497         for (i = 0; i< len; i++) {
498                 fprintf(stderr, "%02x", digest[i]);
499                 if (i%32 == 31)
500                         fprintf(stderr, "\n");
501                 else if (i%8 == 7)
502                         fprintf(stderr, " ");
503         }
504         fprintf(stderr, "\n");
505 }
506 #endif
This page took 0.067505 seconds and 5 git commands to generate.