]> andersk Git - openssh.git/blob - kex.c
- OpenBSD CVS updates.
[openssh.git] / kex.c
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"
31 RCSID("$Id$");
32
33 #include "ssh.h"
34 #include "ssh2.h"
35 #include "xmalloc.h"
36 #include "buffer.h"
37 #include "bufaux.h"
38 #include "cipher.h"
39 #include "compat.h"
40
41 #if HAVE_OPENSSL
42 # include <openssl/bn.h>
43 # include <openssl/dh.h>
44 # include <openssl/crypto.h>
45 # include <openssl/bio.h>
46 # include <openssl/pem.h>
47 #endif /* HAVE_OPENSSL */
48 #if HAVE_SSL
49 # include <ssl/bn.h>
50 # include <ssl/dh.h>
51 # include <ssl/crypto.h>
52 # include <ssl/bio.h>
53 # include <ssl/pem.h>
54 #endif /* HAVE_SSL */
55
56 #include "kex.h"
57
58 Buffer *
59 kex_init(char *myproposal[PROPOSAL_MAX])
60 {
61         char c = 0;
62         unsigned char cookie[16];
63         u_int32_t rand = 0;
64         int i;
65         Buffer *ki = xmalloc(sizeof(*ki));
66         for (i = 0; i < 16; i++) {
67                 if (i % 4 == 0)
68                         rand = arc4random();
69                 cookie[i] = rand & 0xff;
70                 rand >>= 8;
71         }
72         buffer_init(ki);
73         buffer_append(ki, (char *)cookie, sizeof cookie);
74         for (i = 0; i < PROPOSAL_MAX; i++)
75                 buffer_put_cstring(ki, myproposal[i]);
76         buffer_append(ki, &c, 1); /* boolean   first_kex_packet_follows */
77         buffer_put_int(ki, 0);    /* uint32    0 (reserved for future extension) */
78         return ki;
79 }
80
81 /* diffie-hellman-group1-sha1 */
82
83 int
84 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
85 {
86         int i;
87         int n = BN_num_bits(dh_pub);
88         int bits_set = 0;
89
90         /* we only accept g==2 */
91         if (!BN_is_word(dh->g, 2)) {
92                 log("invalid DH base != 2");
93                 return 0;
94         }
95         if (dh_pub->neg) {
96                 log("invalid public DH value: negativ");
97                 return 0;
98         }
99         for (i = 0; i <= n; i++)
100                 if (BN_is_bit_set(dh_pub, i))
101                         bits_set++;
102         debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
103
104         /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
105         if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
106                 return 1;
107         log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
108         return 0;
109 }
110
111 DH *
112 dh_new_group1()
113 {
114         static char *group1 =
115             "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
116             "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
117             "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
118             "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
119             "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
120             "FFFFFFFF" "FFFFFFFF";
121         DH *dh;
122         int ret, tries = 0;
123         dh = DH_new();
124         if(dh == NULL)
125                 fatal("DH_new");
126         ret = BN_hex2bn(&dh->p, group1);
127         if(ret<0)
128                 fatal("BN_hex2bn");
129         dh->g = BN_new();
130         if(dh->g == NULL)
131                 fatal("DH_new g");
132         BN_set_word(dh->g, 2);
133         do {
134                 if (DH_generate_key(dh) == 0)
135                         fatal("DH_generate_key");
136                 if (tries++ > 10)
137                         fatal("dh_new_group1: too many bad keys: giving up");
138         } while (!dh_pub_is_valid(dh, dh->pub_key));
139         return dh;
140 }
141
142 void
143 bignum_print(BIGNUM *b)
144 {
145         BN_print_fp(stderr,b);
146 }
147
148 void
149 dump_digest(unsigned char *digest, int len)
150 {
151         int i;
152         for (i = 0; i< len; i++){
153                 fprintf(stderr, "%02x", digest[i]);
154                 if(i%2!=0)
155                         fprintf(stderr, " ");
156         }
157         fprintf(stderr, "\n");
158 }
159
160 unsigned char *
161 kex_hash(
162     char *client_version_string,
163     char *server_version_string,
164     char *ckexinit, int ckexinitlen,
165     char *skexinit, int skexinitlen,
166     char *serverhostkeyblob, int sbloblen,
167     BIGNUM *client_dh_pub,
168     BIGNUM *server_dh_pub,
169     BIGNUM *shared_secret)
170 {
171         Buffer b;
172         static unsigned char digest[EVP_MAX_MD_SIZE];
173         EVP_MD *evp_md = EVP_sha1();
174         EVP_MD_CTX md;
175
176         buffer_init(&b);
177         buffer_put_string(&b, client_version_string, strlen(client_version_string));
178         buffer_put_string(&b, server_version_string, strlen(server_version_string));
179
180         /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
181         buffer_put_int(&b, ckexinitlen+1);
182         buffer_put_char(&b, SSH2_MSG_KEXINIT);
183         buffer_append(&b, ckexinit, ckexinitlen);
184         buffer_put_int(&b, skexinitlen+1);
185         buffer_put_char(&b, SSH2_MSG_KEXINIT);
186         buffer_append(&b, skexinit, skexinitlen);
187
188         buffer_put_string(&b, serverhostkeyblob, sbloblen);
189         buffer_put_bignum2(&b, client_dh_pub);
190         buffer_put_bignum2(&b, server_dh_pub);
191         buffer_put_bignum2(&b, shared_secret);
192         
193 #ifdef DEBUG_KEX
194         buffer_dump(&b);
195 #endif
196
197         EVP_DigestInit(&md, evp_md);
198         EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
199         EVP_DigestFinal(&md, digest, NULL);
200
201         buffer_free(&b);
202
203 #ifdef DEBUG_KEX
204         dump_digest(digest, evp_md->md_size);
205 #endif
206         return digest;
207 }
208
209 unsigned char *
210 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
211 {
212         Buffer b;
213         EVP_MD *evp_md = EVP_sha1();
214         EVP_MD_CTX md;
215         char c = id;
216         int have;
217         int mdsz = evp_md->md_size;
218         unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
219
220         buffer_init(&b);
221         buffer_put_bignum2(&b, shared_secret);
222
223         EVP_DigestInit(&md, evp_md);
224         EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));  /* shared_secret K */
225         EVP_DigestUpdate(&md, hash, mdsz);              /* transport-06 */
226         EVP_DigestUpdate(&md, &c, 1);                   /* key id */
227         EVP_DigestUpdate(&md, hash, mdsz);              /* session id */
228         EVP_DigestFinal(&md, digest, NULL);
229
230         /* expand */
231         for (have = mdsz; need > have; have += mdsz) {
232                 EVP_DigestInit(&md, evp_md);
233                 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
234                 EVP_DigestUpdate(&md, hash, mdsz);
235                 EVP_DigestUpdate(&md, digest, have);
236                 EVP_DigestFinal(&md, digest + have, NULL);
237         }
238         buffer_free(&b);
239 #ifdef DEBUG_KEX
240         fprintf(stderr, "Digest '%c'== ", c);
241         dump_digest(digest, need);
242 #endif
243         return digest;
244 }
245
246 #define NKEYS   6
247
248 #define MAX_PROP        20
249 #define SEP     ","
250
251 char *
252 get_match(char *client, char *server)
253 {
254         char *sproposals[MAX_PROP];
255         char *p;
256         int i, j, nproposals;
257
258         for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
259                 if (i < MAX_PROP)
260                         sproposals[i] = p;
261                 else
262                         break;
263         }
264         nproposals = i;
265
266         for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
267                 for (j = 0; j < nproposals; j++)
268                         if (strcmp(p, sproposals[j]) == 0)
269                                 return xstrdup(p);
270         }
271         return NULL;
272 }
273 void
274 choose_enc(Enc *enc, char *client, char *server)
275 {
276         char *name = get_match(client, server);
277         if (name == NULL)
278                 fatal("no matching cipher found: client %s server %s", client, server);
279         enc->type = cipher_number(name);
280
281         switch (enc->type) {
282         case SSH_CIPHER_3DES_CBC:
283                 enc->key_len = 24;
284                 enc->iv_len = 8;
285                 enc->block_size = 8;
286                 break;
287         case SSH_CIPHER_BLOWFISH_CBC:
288         case SSH_CIPHER_CAST128_CBC:
289                 enc->key_len = 16;
290                 enc->iv_len = 8;
291                 enc->block_size = 8;
292                 break;
293         case SSH_CIPHER_ARCFOUR:
294                 enc->key_len = 16;
295                 enc->iv_len = 0;
296                 enc->block_size = 8;
297                 break;
298         default:
299                 fatal("unsupported cipher %s", name);
300         }
301         enc->name = name;
302         enc->enabled = 0;
303         enc->iv = NULL;
304         enc->key = NULL;
305 }
306 void
307 choose_mac(Mac *mac, char *client, char *server)
308 {
309         char *name = get_match(client, server);
310         if (name == NULL)
311                 fatal("no matching mac found: client %s server %s", client, server);
312         if (strcmp(name, "hmac-md5") == 0) {
313                 mac->md = EVP_md5();
314         } else if (strcmp(name, "hmac-sha1") == 0) {
315                 mac->md = EVP_sha1();
316         } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
317                 mac->md = EVP_ripemd160();
318         } else {
319                 fatal("unsupported mac %s", name);
320         }
321         mac->name = name;
322         mac->mac_len = mac->md->md_size;
323         mac->key_len = datafellows ? 16 : mac->mac_len;
324         mac->key = NULL;
325         mac->enabled = 0;
326 }
327 void
328 choose_comp(Comp *comp, char *client, char *server)
329 {
330         char *name = get_match(client, server);
331         if (name == NULL)
332                 fatal("no matching comp found: client %s server %s", client, server);
333         if (strcmp(name, "zlib") == 0) {
334                 comp->type = 1;
335         } else if (strcmp(name, "none") == 0) {
336                 comp->type = 0;
337         } else {
338                 fatal("unsupported comp %s", name);
339         }
340         comp->name = name;
341 }
342 void
343 choose_kex(Kex *k, char *client, char *server)
344 {
345         k->name = get_match(client, server);
346         if (k->name == NULL)
347                 fatal("no kex alg");
348         if (strcmp(k->name, KEX_DH1) != 0)
349                 fatal("bad kex alg %s", k->name);
350 }
351 void
352 choose_hostkeyalg(Kex *k, char *client, char *server)
353 {
354         k->hostkeyalg = get_match(client, server);
355         if (k->hostkeyalg == NULL)
356                 fatal("no hostkey alg");
357         if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
358                 fatal("bad hostkey alg %s", k->hostkeyalg);
359 }
360
361 Kex *
362 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
363 {
364         int i;
365         int mode;
366         int ctos;                               /* direction: if true client-to-server */
367         int need;
368         Kex *k;
369
370         k = xmalloc(sizeof(*k));
371         memset(k, 0, sizeof(*k));
372         k->server = server;
373
374         for (mode = 0; mode < MODE_MAX; mode++) {
375                 int nenc, nmac, ncomp;
376                 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
377                 nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
378                 nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
379                 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
380                 choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
381                 choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
382                 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
383                 debug("kex: %s %s %s %s",
384                     ctos ? "client->server" : "server->client",
385                     k->enc[mode].name,
386                     k->mac[mode].name,
387                     k->comp[mode].name);
388         }
389         choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
390         choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
391             sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
392         for (i = 0; i < PROPOSAL_MAX; i++) {
393                 xfree(cprop[i]);
394                 xfree(sprop[i]);
395         }
396         need = 0;
397         for (mode = 0; mode < MODE_MAX; mode++) {
398             if (need < k->enc[mode].key_len)
399                     need = k->enc[mode].key_len;
400             if (need < k->enc[mode].iv_len)
401                     need = k->enc[mode].iv_len;
402             if (need < k->mac[mode].key_len)
403                     need = k->mac[mode].key_len;
404         }
405         /* need runden? */
406 #define WE_NEED 32
407         k->we_need = WE_NEED;
408         k->we_need = need;
409         return k;
410 }
411
412 int
413 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
414 {
415         int i;
416         int mode;
417         int ctos;
418         unsigned char *keys[NKEYS];
419
420         for (i = 0; i < NKEYS; i++)
421                 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
422
423         for (mode = 0; mode < MODE_MAX; mode++) {
424                 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
425                 k->enc[mode].iv  = keys[ctos ? 0 : 1];
426                 k->enc[mode].key = keys[ctos ? 2 : 3];
427                 k->mac[mode].key = keys[ctos ? 4 : 5];
428         }
429         return 0;
430 }
This page took 0.113601 seconds and 5 git commands to generate.