source: trunk/third/openssh/kexgex.c @ 18759

Revision 18759, 11.2 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000 Niels Provos.  All rights reserved.
3 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27RCSID("$OpenBSD: kexgex.c,v 1.22 2002/03/24 17:27:03 stevesk Exp $");
28
29#include <openssl/bn.h>
30
31#include "xmalloc.h"
32#include "buffer.h"
33#include "bufaux.h"
34#include "key.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "ssh2.h"
40#include "compat.h"
41#include "monitor_wrap.h"
42
43static u_char *
44kexgex_hash(
45    char *client_version_string,
46    char *server_version_string,
47    char *ckexinit, int ckexinitlen,
48    char *skexinit, int skexinitlen,
49    u_char *serverhostkeyblob, int sbloblen,
50    int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
51    BIGNUM *client_dh_pub,
52    BIGNUM *server_dh_pub,
53    BIGNUM *shared_secret)
54{
55        Buffer b;
56        static u_char digest[EVP_MAX_MD_SIZE];
57        const EVP_MD *evp_md = EVP_sha1();
58        EVP_MD_CTX md;
59
60        buffer_init(&b);
61        buffer_put_cstring(&b, client_version_string);
62        buffer_put_cstring(&b, server_version_string);
63
64        /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
65        buffer_put_int(&b, ckexinitlen+1);
66        buffer_put_char(&b, SSH2_MSG_KEXINIT);
67        buffer_append(&b, ckexinit, ckexinitlen);
68        buffer_put_int(&b, skexinitlen+1);
69        buffer_put_char(&b, SSH2_MSG_KEXINIT);
70        buffer_append(&b, skexinit, skexinitlen);
71
72        buffer_put_string(&b, serverhostkeyblob, sbloblen);
73        if (min == -1 || max == -1)
74                buffer_put_int(&b, wantbits);
75        else {
76                buffer_put_int(&b, min);
77                buffer_put_int(&b, wantbits);
78                buffer_put_int(&b, max);
79        }
80        buffer_put_bignum2(&b, prime);
81        buffer_put_bignum2(&b, gen);
82        buffer_put_bignum2(&b, client_dh_pub);
83        buffer_put_bignum2(&b, server_dh_pub);
84        buffer_put_bignum2(&b, shared_secret);
85
86#ifdef DEBUG_KEXDH
87        buffer_dump(&b);
88#endif
89        EVP_DigestInit(&md, evp_md);
90        EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
91        EVP_DigestFinal(&md, digest, NULL);
92
93        buffer_free(&b);
94
95#ifdef DEBUG_KEXDH
96        dump_digest("hash", digest, EVP_MD_size(evp_md));
97#endif
98        return digest;
99}
100
101/* client */
102
103static void
104kexgex_client(Kex *kex)
105{
106        BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
107        BIGNUM *p = NULL, *g = NULL;
108        Key *server_host_key;
109        u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
110        u_int klen, kout, slen, sbloblen;
111        int min, max, nbits;
112        DH *dh;
113
114        nbits = dh_estimate(kex->we_need * 8);
115
116        if (datafellows & SSH_OLD_DHGEX) {
117                debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
118
119                /* Old GEX request */
120                packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
121                packet_put_int(nbits);
122                min = DH_GRP_MIN;
123                max = DH_GRP_MAX;
124        } else {
125                debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
126
127                /* New GEX request */
128                min = DH_GRP_MIN;
129                max = DH_GRP_MAX;
130                packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
131                packet_put_int(min);
132                packet_put_int(nbits);
133                packet_put_int(max);
134        }
135#ifdef DEBUG_KEXDH
136        fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
137            min, nbits, max);
138#endif
139        packet_send();
140
141        debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
142        packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP);
143
144        if ((p = BN_new()) == NULL)
145                fatal("BN_new");
146        packet_get_bignum2(p);
147        if ((g = BN_new()) == NULL)
148                fatal("BN_new");
149        packet_get_bignum2(g);
150        packet_check_eom();
151
152        if (BN_num_bits(p) < min || BN_num_bits(p) > max)
153                fatal("DH_GEX group out of range: %d !< %d !< %d",
154                    min, BN_num_bits(p), max);
155
156        dh = dh_new_group(g, p);
157        dh_gen_key(dh, kex->we_need * 8);
158
159#ifdef DEBUG_KEXDH
160        DHparams_print_fp(stderr, dh);
161        fprintf(stderr, "pub= ");
162        BN_print_fp(stderr, dh->pub_key);
163        fprintf(stderr, "\n");
164#endif
165
166        debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
167        /* generate and send 'e', client DH public key */
168        packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
169        packet_put_bignum2(dh->pub_key);
170        packet_send();
171
172        debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
173        packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY);
174
175        /* key, cert */
176        server_host_key_blob = packet_get_string(&sbloblen);
177        server_host_key = key_from_blob(server_host_key_blob, sbloblen);
178        if (server_host_key == NULL)
179                fatal("cannot decode server_host_key_blob");
180        if (server_host_key->type != kex->hostkey_type)
181                fatal("type mismatch for decoded server_host_key_blob");
182        if (kex->verify_host_key == NULL)
183                fatal("cannot verify server_host_key");
184        if (kex->verify_host_key(server_host_key) == -1)
185                fatal("server_host_key verification failed");
186
187        /* DH paramter f, server public DH key */
188        if ((dh_server_pub = BN_new()) == NULL)
189                fatal("dh_server_pub == NULL");
190        packet_get_bignum2(dh_server_pub);
191
192#ifdef DEBUG_KEXDH
193        fprintf(stderr, "dh_server_pub= ");
194        BN_print_fp(stderr, dh_server_pub);
195        fprintf(stderr, "\n");
196        debug("bits %d", BN_num_bits(dh_server_pub));
197#endif
198
199        /* signed H */
200        signature = packet_get_string(&slen);
201        packet_check_eom();
202
203        if (!dh_pub_is_valid(dh, dh_server_pub))
204                packet_disconnect("bad server public DH value");
205
206        klen = DH_size(dh);
207        kbuf = xmalloc(klen);
208        kout = DH_compute_key(kbuf, dh_server_pub, dh);
209#ifdef DEBUG_KEXDH
210        dump_digest("shared secret", kbuf, kout);
211#endif
212        if ((shared_secret = BN_new()) == NULL)
213                fatal("kexgex_client: BN_new failed");
214        BN_bin2bn(kbuf, kout, shared_secret);
215        memset(kbuf, 0, klen);
216        xfree(kbuf);
217
218        if (datafellows & SSH_OLD_DHGEX)
219                min = max = -1;
220
221        /* calc and verify H */
222        hash = kexgex_hash(
223            kex->client_version_string,
224            kex->server_version_string,
225            buffer_ptr(&kex->my), buffer_len(&kex->my),
226            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
227            server_host_key_blob, sbloblen,
228            min, nbits, max,
229            dh->p, dh->g,
230            dh->pub_key,
231            dh_server_pub,
232            shared_secret
233        );
234        /* have keys, free DH */
235        DH_free(dh);
236        xfree(server_host_key_blob);
237        BN_clear_free(dh_server_pub);
238
239        if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
240                fatal("key_verify failed for server_host_key");
241        key_free(server_host_key);
242        xfree(signature);
243
244        /* save session id */
245        if (kex->session_id == NULL) {
246                kex->session_id_len = 20;
247                kex->session_id = xmalloc(kex->session_id_len);
248                memcpy(kex->session_id, hash, kex->session_id_len);
249        }
250        kex_derive_keys(kex, hash, shared_secret);
251        BN_clear_free(shared_secret);
252
253        kex_finish(kex);
254}
255
256/* server */
257
258static void
259kexgex_server(Kex *kex)
260{
261        BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
262        Key *server_host_key;
263        DH *dh;
264        u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
265        u_int sbloblen, klen, kout, slen;
266        int min = -1, max = -1, nbits = -1, type;
267
268        if (kex->load_host_key == NULL)
269                fatal("Cannot load hostkey");
270        server_host_key = kex->load_host_key(kex->hostkey_type);
271        if (server_host_key == NULL)
272                fatal("Unsupported hostkey type %d", kex->hostkey_type);
273
274        type = packet_read();
275        switch (type) {
276        case SSH2_MSG_KEX_DH_GEX_REQUEST:
277                debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
278                min = packet_get_int();
279                nbits = packet_get_int();
280                max = packet_get_int();
281                min = MAX(DH_GRP_MIN, min);
282                max = MIN(DH_GRP_MAX, max);
283                break;
284        case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
285                debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
286                nbits = packet_get_int();
287                min = DH_GRP_MIN;
288                max = DH_GRP_MAX;
289                /* unused for old GEX */
290                break;
291        default:
292                fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
293        }
294        packet_check_eom();
295
296        if (max < min || nbits < min || max < nbits)
297                fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
298                    min, nbits, max);
299
300        /* Contact privileged parent */
301        dh = PRIVSEP(choose_dh(min, nbits, max));
302        if (dh == NULL)
303                packet_disconnect("Protocol error: no matching DH grp found");
304
305        debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
306        packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
307        packet_put_bignum2(dh->p);
308        packet_put_bignum2(dh->g);
309        packet_send();
310
311        /* flush */
312        packet_write_wait();
313
314        /* Compute our exchange value in parallel with the client */
315        dh_gen_key(dh, kex->we_need * 8);
316
317        debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
318        packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT);
319
320        /* key, cert */
321        if ((dh_client_pub = BN_new()) == NULL)
322                fatal("dh_client_pub == NULL");
323        packet_get_bignum2(dh_client_pub);
324        packet_check_eom();
325
326#ifdef DEBUG_KEXDH
327        fprintf(stderr, "dh_client_pub= ");
328        BN_print_fp(stderr, dh_client_pub);
329        fprintf(stderr, "\n");
330        debug("bits %d", BN_num_bits(dh_client_pub));
331#endif
332
333#ifdef DEBUG_KEXDH
334        DHparams_print_fp(stderr, dh);
335        fprintf(stderr, "pub= ");
336        BN_print_fp(stderr, dh->pub_key);
337        fprintf(stderr, "\n");
338#endif
339        if (!dh_pub_is_valid(dh, dh_client_pub))
340                packet_disconnect("bad client public DH value");
341
342        klen = DH_size(dh);
343        kbuf = xmalloc(klen);
344        kout = DH_compute_key(kbuf, dh_client_pub, dh);
345#ifdef DEBUG_KEXDH
346        dump_digest("shared secret", kbuf, kout);
347#endif
348        if ((shared_secret = BN_new()) == NULL)
349                fatal("kexgex_server: BN_new failed");
350        BN_bin2bn(kbuf, kout, shared_secret);
351        memset(kbuf, 0, klen);
352        xfree(kbuf);
353
354        key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
355
356        if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
357                min = max = -1;
358
359        /* calc H */                    /* XXX depends on 'kex' */
360        hash = kexgex_hash(
361            kex->client_version_string,
362            kex->server_version_string,
363            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
364            buffer_ptr(&kex->my), buffer_len(&kex->my),
365            server_host_key_blob, sbloblen,
366            min, nbits, max,
367            dh->p, dh->g,
368            dh_client_pub,
369            dh->pub_key,
370            shared_secret
371        );
372        BN_clear_free(dh_client_pub);
373
374        /* save session id := H */
375        /* XXX hashlen depends on KEX */
376        if (kex->session_id == NULL) {
377                kex->session_id_len = 20;
378                kex->session_id = xmalloc(kex->session_id_len);
379                memcpy(kex->session_id, hash, kex->session_id_len);
380        }
381
382        /* sign H */
383        /* XXX hashlen depends on KEX */
384        PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
385
386        /* destroy_sensitive_data(); */
387
388        /* send server hostkey, DH pubkey 'f' and singed H */
389        debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
390        packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
391        packet_put_string(server_host_key_blob, sbloblen);
392        packet_put_bignum2(dh->pub_key);        /* f */
393        packet_put_string(signature, slen);
394        packet_send();
395
396        xfree(signature);
397        xfree(server_host_key_blob);
398        /* have keys, free DH */
399        DH_free(dh);
400
401        kex_derive_keys(kex, hash, shared_secret);
402        BN_clear_free(shared_secret);
403
404        kex_finish(kex);
405}
406
407void
408kexgex(Kex *kex)
409{
410        if (kex->server)
411                kexgex_server(kex);
412        else
413                kexgex_client(kex);
414}
Note: See TracBrowser for help on using the repository browser.