~ubuntu-branches/ubuntu/utopic/pgadmin3/utopic-proposed

« back to all changes in this revision

Viewing changes to pgadmin/libssh2/kex.c

  • Committer: Package Import Robot
  • Author(s): Christoph Berg
  • Date: 2013-09-10 16:16:38 UTC
  • mfrom: (1.3.4)
  • Revision ID: package-import@ubuntu.com-20130910161638-wwup1q553ylww7dr
Tags: 1.18.0-1
* New upstream release.
* Don't install /usr/bin/png2c anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
 
2
 * Copyright (c) 2010, Daniel Stenberg <daniel@haxx.se>
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms,
 
6
 * with or without modification, are permitted provided
 
7
 * that the following conditions are met:
 
8
 *
 
9
 *   Redistributions of source code must retain the above
 
10
 *   copyright notice, this list of conditions and the
 
11
 *   following disclaimer.
 
12
 *
 
13
 *   Redistributions in binary form must reproduce the above
 
14
 *   copyright notice, this list of conditions and the following
 
15
 *   disclaimer in the documentation and/or other materials
 
16
 *   provided with the distribution.
 
17
 *
 
18
 *   Neither the name of the copyright holder nor the names
 
19
 *   of any other contributors may be used to endorse or
 
20
 *   promote products derived from this software without
 
21
 *   specific prior written permission.
 
22
 *
 
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 
24
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 
25
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
26
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
27
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
28
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
29
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 
30
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
31
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
32
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
33
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
34
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 
35
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 
36
 * OF SUCH DAMAGE.
 
37
 */
 
38
 
 
39
#include "libssh2_priv.h"
 
40
 
 
41
#include "transport.h"
 
42
#include "comp.h"
 
43
#include "mac.h"
 
44
 
 
45
/* TODO: Switch this to an inline and handle alloc() failures */
 
46
/* Helper macro called from kex_method_diffie_hellman_group1_sha1_key_exchange */
 
47
#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \
 
48
    {                                                                   \
 
49
        libssh2_sha1_ctx hash;                                          \
 
50
        unsigned long len = 0;                                          \
 
51
        if (!(value)) {                                                 \
 
52
            value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \
 
53
        }                                                               \
 
54
        if (value)                                                      \
 
55
            while (len < (unsigned long)reqlen) {                       \
 
56
                libssh2_sha1_init(&hash);                               \
 
57
                libssh2_sha1_update(hash, exchange_state->k_value,      \
 
58
                                    exchange_state->k_value_len);       \
 
59
                libssh2_sha1_update(hash, exchange_state->h_sig_comp,   \
 
60
                                    SHA_DIGEST_LENGTH);                 \
 
61
                if (len > 0) {                                          \
 
62
                    libssh2_sha1_update(hash, value, len);              \
 
63
                }    else {                                             \
 
64
                    libssh2_sha1_update(hash, (version), 1);            \
 
65
                    libssh2_sha1_update(hash, session->session_id,      \
 
66
                                        session->session_id_len);       \
 
67
                }                                                       \
 
68
                libssh2_sha1_final(hash, (value) + len);                \
 
69
                len += SHA_DIGEST_LENGTH;                               \
 
70
            }                                                           \
 
71
    }
 
72
 
 
73
/*
 
74
 * diffie_hellman_sha1
 
75
 *
 
76
 * Diffie Hellman Key Exchange, Group Agnostic
 
77
 */
 
78
static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
 
79
                               _libssh2_bn *g,
 
80
                               _libssh2_bn *p,
 
81
                               int group_order,
 
82
                               unsigned char packet_type_init,
 
83
                               unsigned char packet_type_reply,
 
84
                               unsigned char *midhash,
 
85
                               unsigned long midhash_len,
 
86
                               kmdhgGPsha1kex_state_t *exchange_state)
 
87
{
 
88
    int ret = 0;
 
89
    int rc;
 
90
 
 
91
    if (exchange_state->state == libssh2_NB_state_idle) {
 
92
        /* Setup initial values */
 
93
        exchange_state->e_packet = NULL;
 
94
        exchange_state->s_packet = NULL;
 
95
        exchange_state->k_value = NULL;
 
96
        exchange_state->ctx = _libssh2_bn_ctx_new();
 
97
        exchange_state->x = _libssh2_bn_init(); /* Random from client */
 
98
        exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
 
99
        exchange_state->f = _libssh2_bn_init(); /* g^(Random from server) mod p */
 
100
        exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
 
101
 
 
102
        /* Zero the whole thing out */
 
103
        memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
 
104
 
 
105
        /* Generate x and e */
 
106
        _libssh2_bn_rand(exchange_state->x, group_order, 0, -1);
 
107
        _libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
 
108
                            exchange_state->ctx);
 
109
 
 
110
        /* Send KEX init */
 
111
        /* packet_type(1) + String Length(4) + leading 0(1) */
 
112
        exchange_state->e_packet_len =
 
113
            _libssh2_bn_bytes(exchange_state->e) + 6;
 
114
        if (_libssh2_bn_bits(exchange_state->e) % 8) {
 
115
            /* Leading 00 not needed */
 
116
            exchange_state->e_packet_len--;
 
117
        }
 
118
 
 
119
        exchange_state->e_packet =
 
120
            LIBSSH2_ALLOC(session, exchange_state->e_packet_len);
 
121
        if (!exchange_state->e_packet) {
 
122
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 
123
                                 "Out of memory error");
 
124
            goto clean_exit;
 
125
        }
 
126
        exchange_state->e_packet[0] = packet_type_init;
 
127
        _libssh2_htonu32(exchange_state->e_packet + 1,
 
128
                         exchange_state->e_packet_len - 5);
 
129
        if (_libssh2_bn_bits(exchange_state->e) % 8) {
 
130
            _libssh2_bn_to_bin(exchange_state->e,
 
131
                               exchange_state->e_packet + 5);
 
132
        } else {
 
133
            exchange_state->e_packet[5] = 0;
 
134
            _libssh2_bn_to_bin(exchange_state->e,
 
135
                               exchange_state->e_packet + 6);
 
136
        }
 
137
 
 
138
        _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d",
 
139
                       (int) packet_type_init);
 
140
        exchange_state->state = libssh2_NB_state_created;
 
141
    }
 
142
 
 
143
    if (exchange_state->state == libssh2_NB_state_created) {
 
144
        rc = _libssh2_transport_send(session, exchange_state->e_packet,
 
145
                                     exchange_state->e_packet_len,
 
146
                                     NULL, 0);
 
147
        if (rc == LIBSSH2_ERROR_EAGAIN) {
 
148
            return rc;
 
149
        } else if (rc) {
 
150
            ret = _libssh2_error(session, rc,
 
151
                                 "Unable to send KEX init message");
 
152
            goto clean_exit;
 
153
        }
 
154
        exchange_state->state = libssh2_NB_state_sent;
 
155
    }
 
156
 
 
157
    if (exchange_state->state == libssh2_NB_state_sent) {
 
158
        if (session->burn_optimistic_kexinit) {
 
159
            /* The first KEX packet to come along will be the guess initially
 
160
             * sent by the server.  That guess turned out to be wrong so we
 
161
             * need to silently ignore it */
 
162
            int burn_type;
 
163
 
 
164
            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
165
                           "Waiting for badly guessed KEX packet (to be ignored)");
 
166
            burn_type =
 
167
                _libssh2_packet_burn(session, &exchange_state->burn_state);
 
168
            if (burn_type == LIBSSH2_ERROR_EAGAIN) {
 
169
                return burn_type;
 
170
            } else if (burn_type <= 0) {
 
171
                /* Failed to receive a packet */
 
172
                ret = burn_type;
 
173
                goto clean_exit;
 
174
            }
 
175
            session->burn_optimistic_kexinit = 0;
 
176
 
 
177
            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
178
                           "Burnt packet of type: %02x",
 
179
                           (unsigned int) burn_type);
 
180
        }
 
181
 
 
182
        exchange_state->state = libssh2_NB_state_sent1;
 
183
    }
 
184
 
 
185
    if (exchange_state->state == libssh2_NB_state_sent1) {
 
186
        /* Wait for KEX reply */
 
187
        rc = _libssh2_packet_require(session, packet_type_reply,
 
188
                                     &exchange_state->s_packet,
 
189
                                     &exchange_state->s_packet_len, 0, NULL,
 
190
                                     0, &exchange_state->req_state);
 
191
        if (rc == LIBSSH2_ERROR_EAGAIN) {
 
192
            return rc;
 
193
        }
 
194
        if (rc) {
 
195
            ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
 
196
                                 "Timed out waiting for KEX reply");
 
197
            goto clean_exit;
 
198
        }
 
199
 
 
200
        /* Parse KEXDH_REPLY */
 
201
        exchange_state->s = exchange_state->s_packet + 1;
 
202
 
 
203
        session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
 
204
        exchange_state->s += 4;
 
205
        session->server_hostkey =
 
206
            LIBSSH2_ALLOC(session, session->server_hostkey_len);
 
207
        if (!session->server_hostkey) {
 
208
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 
209
                                 "Unable to allocate memory for a copy "
 
210
                                 "of the host key");
 
211
            goto clean_exit;
 
212
        }
 
213
        memcpy(session->server_hostkey, exchange_state->s,
 
214
               session->server_hostkey_len);
 
215
        exchange_state->s += session->server_hostkey_len;
 
216
 
 
217
#if LIBSSH2_MD5
 
218
        {
 
219
            libssh2_md5_ctx fingerprint_ctx;
 
220
 
 
221
            if (libssh2_md5_init(&fingerprint_ctx)) {
 
222
                libssh2_md5_update(fingerprint_ctx, session->server_hostkey,
 
223
                                   session->server_hostkey_len);
 
224
                libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
 
225
                session->server_hostkey_md5_valid = TRUE;
 
226
            }
 
227
            else {
 
228
                session->server_hostkey_md5_valid = FALSE;
 
229
            }
 
230
        }
 
231
#ifdef LIBSSH2DEBUG
 
232
        {
 
233
            char fingerprint[50], *fprint = fingerprint;
 
234
            int i;
 
235
            for(i = 0; i < 16; i++, fprint += 3) {
 
236
                snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
 
237
            }
 
238
            *(--fprint) = '\0';
 
239
            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
240
                           "Server's MD5 Fingerprint: %s", fingerprint);
 
241
        }
 
242
#endif /* LIBSSH2DEBUG */
 
243
#endif /* ! LIBSSH2_MD5 */
 
244
 
 
245
        {
 
246
            libssh2_sha1_ctx fingerprint_ctx;
 
247
 
 
248
            libssh2_sha1_init(&fingerprint_ctx);
 
249
            libssh2_sha1_update(fingerprint_ctx, session->server_hostkey,
 
250
                                session->server_hostkey_len);
 
251
            libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
 
252
        }
 
253
#ifdef LIBSSH2DEBUG
 
254
        {
 
255
            char fingerprint[64], *fprint = fingerprint;
 
256
            int i;
 
257
 
 
258
            for(i = 0; i < 20; i++, fprint += 3) {
 
259
                snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
 
260
            }
 
261
            *(--fprint) = '\0';
 
262
            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
263
                           "Server's SHA1 Fingerprint: %s", fingerprint);
 
264
        }
 
265
#endif /* LIBSSH2DEBUG */
 
266
 
 
267
        if (session->hostkey->init(session, session->server_hostkey,
 
268
                                   session->server_hostkey_len,
 
269
                                   &session->server_hostkey_abstract)) {
 
270
            ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
 
271
                                 "Unable to initialize hostkey importer");
 
272
            goto clean_exit;
 
273
        }
 
274
 
 
275
        exchange_state->f_value_len = _libssh2_ntohu32(exchange_state->s);
 
276
        exchange_state->s += 4;
 
277
        exchange_state->f_value = exchange_state->s;
 
278
        exchange_state->s += exchange_state->f_value_len;
 
279
        _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len,
 
280
                             exchange_state->f_value);
 
281
 
 
282
        exchange_state->h_sig_len = _libssh2_ntohu32(exchange_state->s);
 
283
        exchange_state->s += 4;
 
284
        exchange_state->h_sig = exchange_state->s;
 
285
 
 
286
        /* Compute the shared secret */
 
287
        _libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
 
288
                            exchange_state->x, p, exchange_state->ctx);
 
289
        exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
 
290
        if (_libssh2_bn_bits(exchange_state->k) % 8) {
 
291
            /* don't need leading 00 */
 
292
            exchange_state->k_value_len--;
 
293
        }
 
294
        exchange_state->k_value =
 
295
            LIBSSH2_ALLOC(session, exchange_state->k_value_len);
 
296
        if (!exchange_state->k_value) {
 
297
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 
298
                                 "Unable to allocate buffer for K");
 
299
            goto clean_exit;
 
300
        }
 
301
        _libssh2_htonu32(exchange_state->k_value,
 
302
                         exchange_state->k_value_len - 4);
 
303
        if (_libssh2_bn_bits(exchange_state->k) % 8) {
 
304
            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4);
 
305
        } else {
 
306
            exchange_state->k_value[4] = 0;
 
307
            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
 
308
        }
 
309
 
 
310
        libssh2_sha1_init(&exchange_state->exchange_hash);
 
311
        if (session->local.banner) {
 
312
            _libssh2_htonu32(exchange_state->h_sig_comp,
 
313
                             strlen((char *) session->local.banner) - 2);
 
314
            libssh2_sha1_update(exchange_state->exchange_hash,
 
315
                                exchange_state->h_sig_comp, 4);
 
316
            libssh2_sha1_update(exchange_state->exchange_hash,
 
317
                                (char *) session->local.banner,
 
318
                                strlen((char *) session->local.banner) - 2);
 
319
        } else {
 
320
            _libssh2_htonu32(exchange_state->h_sig_comp,
 
321
                             sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
 
322
            libssh2_sha1_update(exchange_state->exchange_hash,
 
323
                                exchange_state->h_sig_comp, 4);
 
324
            libssh2_sha1_update(exchange_state->exchange_hash,
 
325
                                LIBSSH2_SSH_DEFAULT_BANNER,
 
326
                                sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
 
327
        }
 
328
 
 
329
        _libssh2_htonu32(exchange_state->h_sig_comp,
 
330
                         strlen((char *) session->remote.banner));
 
331
        libssh2_sha1_update(exchange_state->exchange_hash,
 
332
                            exchange_state->h_sig_comp, 4);
 
333
        libssh2_sha1_update(exchange_state->exchange_hash,
 
334
                            session->remote.banner,
 
335
                            strlen((char *) session->remote.banner));
 
336
 
 
337
        _libssh2_htonu32(exchange_state->h_sig_comp,
 
338
                         session->local.kexinit_len);
 
339
        libssh2_sha1_update(exchange_state->exchange_hash,
 
340
                            exchange_state->h_sig_comp, 4);
 
341
        libssh2_sha1_update(exchange_state->exchange_hash,
 
342
                            session->local.kexinit,
 
343
                            session->local.kexinit_len);
 
344
 
 
345
        _libssh2_htonu32(exchange_state->h_sig_comp,
 
346
                         session->remote.kexinit_len);
 
347
        libssh2_sha1_update(exchange_state->exchange_hash,
 
348
                            exchange_state->h_sig_comp, 4);
 
349
        libssh2_sha1_update(exchange_state->exchange_hash,
 
350
                            session->remote.kexinit,
 
351
                            session->remote.kexinit_len);
 
352
 
 
353
        _libssh2_htonu32(exchange_state->h_sig_comp,
 
354
                         session->server_hostkey_len);
 
355
        libssh2_sha1_update(exchange_state->exchange_hash,
 
356
                            exchange_state->h_sig_comp, 4);
 
357
        libssh2_sha1_update(exchange_state->exchange_hash,
 
358
                            session->server_hostkey,
 
359
                            session->server_hostkey_len);
 
360
 
 
361
        if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
 
362
            /* diffie-hellman-group-exchange hashes additional fields */
 
363
#ifdef LIBSSH2_DH_GEX_NEW
 
364
            _libssh2_htonu32(exchange_state->h_sig_comp,
 
365
                             LIBSSH2_DH_GEX_MINGROUP);
 
366
            _libssh2_htonu32(exchange_state->h_sig_comp + 4,
 
367
                             LIBSSH2_DH_GEX_OPTGROUP);
 
368
            _libssh2_htonu32(exchange_state->h_sig_comp + 8,
 
369
                             LIBSSH2_DH_GEX_MAXGROUP);
 
370
            libssh2_sha1_update(exchange_state->exchange_hash,
 
371
                                exchange_state->h_sig_comp, 12);
 
372
#else
 
373
            _libssh2_htonu32(exchange_state->h_sig_comp,
 
374
                             LIBSSH2_DH_GEX_OPTGROUP);
 
375
            libssh2_sha1_update(exchange_state->exchange_hash,
 
376
                                exchange_state->h_sig_comp, 4);
 
377
#endif
 
378
        }
 
379
 
 
380
        if (midhash) {
 
381
            libssh2_sha1_update(exchange_state->exchange_hash, midhash,
 
382
                                midhash_len);
 
383
        }
 
384
 
 
385
        libssh2_sha1_update(exchange_state->exchange_hash,
 
386
                            exchange_state->e_packet + 1,
 
387
                            exchange_state->e_packet_len - 1);
 
388
 
 
389
        _libssh2_htonu32(exchange_state->h_sig_comp,
 
390
                         exchange_state->f_value_len);
 
391
        libssh2_sha1_update(exchange_state->exchange_hash,
 
392
                            exchange_state->h_sig_comp, 4);
 
393
        libssh2_sha1_update(exchange_state->exchange_hash,
 
394
                            exchange_state->f_value,
 
395
                            exchange_state->f_value_len);
 
396
 
 
397
        libssh2_sha1_update(exchange_state->exchange_hash,
 
398
                            exchange_state->k_value,
 
399
                            exchange_state->k_value_len);
 
400
 
 
401
        libssh2_sha1_final(exchange_state->exchange_hash,
 
402
                           exchange_state->h_sig_comp);
 
403
 
 
404
        if (session->hostkey->
 
405
            sig_verify(session, exchange_state->h_sig,
 
406
                       exchange_state->h_sig_len, exchange_state->h_sig_comp,
 
407
                       20, &session->server_hostkey_abstract)) {
 
408
            ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
 
409
                                 "Unable to verify hostkey signature");
 
410
            goto clean_exit;
 
411
        }
 
412
 
 
413
        _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message");
 
414
        exchange_state->c = SSH_MSG_NEWKEYS;
 
415
 
 
416
        exchange_state->state = libssh2_NB_state_sent2;
 
417
    }
 
418
 
 
419
    if (exchange_state->state == libssh2_NB_state_sent2) {
 
420
        rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0);
 
421
        if (rc == LIBSSH2_ERROR_EAGAIN) {
 
422
            return rc;
 
423
        } else if (rc) {
 
424
            ret = _libssh2_error(session, rc, "Unable to send NEWKEYS message");
 
425
            goto clean_exit;
 
426
        }
 
427
 
 
428
        exchange_state->state = libssh2_NB_state_sent3;
 
429
    }
 
430
 
 
431
    if (exchange_state->state == libssh2_NB_state_sent3) {
 
432
        rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS,
 
433
                                     &exchange_state->tmp,
 
434
                                     &exchange_state->tmp_len, 0, NULL, 0,
 
435
                                     &exchange_state->req_state);
 
436
        if (rc == LIBSSH2_ERROR_EAGAIN) {
 
437
            return rc;
 
438
        } else if (rc) {
 
439
            ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS");
 
440
            goto clean_exit;
 
441
        }
 
442
        /* The first key exchange has been performed,
 
443
           switch to active crypt/comp/mac mode */
 
444
        session->state |= LIBSSH2_STATE_NEWKEYS;
 
445
        _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message");
 
446
 
 
447
        /* This will actually end up being just packet_type(1)
 
448
           for this packet type anyway */
 
449
        LIBSSH2_FREE(session, exchange_state->tmp);
 
450
 
 
451
        if (!session->session_id) {
 
452
            session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
 
453
            if (!session->session_id) {
 
454
                ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 
455
                                     "Unable to allocate buffer for SHA digest");
 
456
                goto clean_exit;
 
457
            }
 
458
            memcpy(session->session_id, exchange_state->h_sig_comp,
 
459
                   SHA_DIGEST_LENGTH);
 
460
            session->session_id_len = SHA_DIGEST_LENGTH;
 
461
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated");
 
462
        }
 
463
 
 
464
        /* Cleanup any existing cipher */
 
465
        if (session->local.crypt->dtor) {
 
466
            session->local.crypt->dtor(session,
 
467
                                       &session->local.crypt_abstract);
 
468
        }
 
469
 
 
470
        /* Calculate IV/Secret/Key for each direction */
 
471
        if (session->local.crypt->init) {
 
472
            unsigned char *iv = NULL, *secret = NULL;
 
473
            int free_iv = 0, free_secret = 0;
 
474
 
 
475
            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
 
476
                                                        session->local.crypt->
 
477
                                                        iv_len, "A");
 
478
            if (!iv) {
 
479
                ret = -1;
 
480
                goto clean_exit;
 
481
            }
 
482
            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
 
483
                                                        session->local.crypt->
 
484
                                                        secret_len, "C");
 
485
            if (!secret) {
 
486
                LIBSSH2_FREE(session, iv);
 
487
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
488
                goto clean_exit;
 
489
            }
 
490
            if (session->local.crypt->
 
491
                init(session, session->local.crypt, iv, &free_iv, secret,
 
492
                     &free_secret, 1, &session->local.crypt_abstract)) {
 
493
                LIBSSH2_FREE(session, iv);
 
494
                LIBSSH2_FREE(session, secret);
 
495
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
496
                goto clean_exit;
 
497
            }
 
498
 
 
499
            if (free_iv) {
 
500
                memset(iv, 0, session->local.crypt->iv_len);
 
501
                LIBSSH2_FREE(session, iv);
 
502
            }
 
503
 
 
504
            if (free_secret) {
 
505
                memset(secret, 0, session->local.crypt->secret_len);
 
506
                LIBSSH2_FREE(session, secret);
 
507
            }
 
508
        }
 
509
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
510
                       "Client to Server IV and Key calculated");
 
511
 
 
512
        if (session->remote.crypt->dtor) {
 
513
            /* Cleanup any existing cipher */
 
514
            session->remote.crypt->dtor(session,
 
515
                                        &session->remote.crypt_abstract);
 
516
        }
 
517
 
 
518
        if (session->remote.crypt->init) {
 
519
            unsigned char *iv = NULL, *secret = NULL;
 
520
            int free_iv = 0, free_secret = 0;
 
521
 
 
522
            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
 
523
                                                        session->remote.crypt->
 
524
                                                        iv_len, "B");
 
525
            if (!iv) {
 
526
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
527
                goto clean_exit;
 
528
            }
 
529
            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
 
530
                                                        session->remote.crypt->
 
531
                                                        secret_len, "D");
 
532
            if (!secret) {
 
533
                LIBSSH2_FREE(session, iv);
 
534
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
535
                goto clean_exit;
 
536
            }
 
537
            if (session->remote.crypt->
 
538
                init(session, session->remote.crypt, iv, &free_iv, secret,
 
539
                     &free_secret, 0, &session->remote.crypt_abstract)) {
 
540
                LIBSSH2_FREE(session, iv);
 
541
                LIBSSH2_FREE(session, secret);
 
542
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
543
                goto clean_exit;
 
544
            }
 
545
 
 
546
            if (free_iv) {
 
547
                memset(iv, 0, session->remote.crypt->iv_len);
 
548
                LIBSSH2_FREE(session, iv);
 
549
            }
 
550
 
 
551
            if (free_secret) {
 
552
                memset(secret, 0, session->remote.crypt->secret_len);
 
553
                LIBSSH2_FREE(session, secret);
 
554
            }
 
555
        }
 
556
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
557
                       "Server to Client IV and Key calculated");
 
558
 
 
559
        if (session->local.mac->dtor) {
 
560
            session->local.mac->dtor(session, &session->local.mac_abstract);
 
561
        }
 
562
 
 
563
        if (session->local.mac->init) {
 
564
            unsigned char *key = NULL;
 
565
            int free_key = 0;
 
566
 
 
567
            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
 
568
                                                        session->local.mac->
 
569
                                                        key_len, "E");
 
570
            if (!key) {
 
571
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
572
                goto clean_exit;
 
573
            }
 
574
            session->local.mac->init(session, key, &free_key,
 
575
                                     &session->local.mac_abstract);
 
576
 
 
577
            if (free_key) {
 
578
                memset(key, 0, session->local.mac->key_len);
 
579
                LIBSSH2_FREE(session, key);
 
580
            }
 
581
        }
 
582
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
583
                       "Client to Server HMAC Key calculated");
 
584
 
 
585
        if (session->remote.mac->dtor) {
 
586
            session->remote.mac->dtor(session, &session->remote.mac_abstract);
 
587
        }
 
588
 
 
589
        if (session->remote.mac->init) {
 
590
            unsigned char *key = NULL;
 
591
            int free_key = 0;
 
592
 
 
593
            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
 
594
                                                        session->remote.mac->
 
595
                                                        key_len, "F");
 
596
            if (!key) {
 
597
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
598
                goto clean_exit;
 
599
            }
 
600
            session->remote.mac->init(session, key, &free_key,
 
601
                                      &session->remote.mac_abstract);
 
602
 
 
603
            if (free_key) {
 
604
                memset(key, 0, session->remote.mac->key_len);
 
605
                LIBSSH2_FREE(session, key);
 
606
            }
 
607
        }
 
608
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
609
                       "Server to Client HMAC Key calculated");
 
610
 
 
611
        /* Initialize compression for each direction */
 
612
 
 
613
        /* Cleanup any existing compression */
 
614
        if (session->local.comp && session->local.comp->dtor) {
 
615
            session->local.comp->dtor(session, 1,
 
616
                                      &session->local.comp_abstract);
 
617
        }
 
618
 
 
619
        if (session->local.comp && session->local.comp->init) {
 
620
            if (session->local.comp->init(session, 1,
 
621
                                          &session->local.comp_abstract)) {
 
622
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
623
                goto clean_exit;
 
624
            }
 
625
        }
 
626
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
627
                       "Client to Server compression initialized");
 
628
 
 
629
        if (session->remote.comp && session->remote.comp->dtor) {
 
630
            session->remote.comp->dtor(session, 0,
 
631
                                       &session->remote.comp_abstract);
 
632
        }
 
633
 
 
634
        if (session->remote.comp && session->remote.comp->init) {
 
635
            if (session->remote.comp->init(session, 0,
 
636
                                           &session->remote.comp_abstract)) {
 
637
                ret = LIBSSH2_ERROR_KEX_FAILURE;
 
638
                goto clean_exit;
 
639
            }
 
640
        }
 
641
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
642
                       "Server to Client compression initialized");
 
643
 
 
644
    }
 
645
 
 
646
  clean_exit:
 
647
    _libssh2_bn_free(exchange_state->x);
 
648
    exchange_state->x = NULL;
 
649
    _libssh2_bn_free(exchange_state->e);
 
650
    exchange_state->e = NULL;
 
651
    _libssh2_bn_free(exchange_state->f);
 
652
    exchange_state->f = NULL;
 
653
    _libssh2_bn_free(exchange_state->k);
 
654
    exchange_state->k = NULL;
 
655
    _libssh2_bn_ctx_free(exchange_state->ctx);
 
656
    exchange_state->ctx = NULL;
 
657
 
 
658
    if (exchange_state->e_packet) {
 
659
        LIBSSH2_FREE(session, exchange_state->e_packet);
 
660
        exchange_state->e_packet = NULL;
 
661
    }
 
662
 
 
663
    if (exchange_state->s_packet) {
 
664
        LIBSSH2_FREE(session, exchange_state->s_packet);
 
665
        exchange_state->s_packet = NULL;
 
666
    }
 
667
 
 
668
    if (exchange_state->k_value) {
 
669
        LIBSSH2_FREE(session, exchange_state->k_value);
 
670
        exchange_state->k_value = NULL;
 
671
    }
 
672
 
 
673
    exchange_state->state = libssh2_NB_state_idle;
 
674
 
 
675
    return ret;
 
676
}
 
677
 
 
678
 
 
679
 
 
680
/* kex_method_diffie_hellman_group1_sha1_key_exchange
 
681
 * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1
 
682
 */
 
683
static int
 
684
kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session,
 
685
                                                   key_exchange_state_low_t
 
686
                                                   * key_state)
 
687
{
 
688
    static const unsigned char p_value[128] = {
 
689
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 
690
        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 
691
        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 
692
        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 
693
        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 
694
        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 
695
        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 
696
        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 
697
        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 
698
        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 
699
        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 
700
        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 
701
        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 
702
        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 
703
        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
 
704
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 
705
    };
 
706
 
 
707
    int ret;
 
708
 
 
709
    if (key_state->state == libssh2_NB_state_idle) {
 
710
        /* g == 2 */
 
711
        key_state->p = _libssh2_bn_init();      /* SSH2 defined value (p_value) */
 
712
        key_state->g = _libssh2_bn_init();      /* SSH2 defined value (2) */
 
713
 
 
714
        /* Initialize P and G */
 
715
        _libssh2_bn_set_word(key_state->g, 2);
 
716
        _libssh2_bn_from_bin(key_state->p, 128, p_value);
 
717
 
 
718
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
719
                       "Initiating Diffie-Hellman Group1 Key Exchange");
 
720
 
 
721
        key_state->state = libssh2_NB_state_created;
 
722
    }
 
723
    ret = diffie_hellman_sha1(session, key_state->g, key_state->p, 128,
 
724
                              SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY,
 
725
                              NULL, 0, &key_state->exchange_state);
 
726
    if (ret == LIBSSH2_ERROR_EAGAIN) {
 
727
        return ret;
 
728
    }
 
729
 
 
730
    _libssh2_bn_free(key_state->p);
 
731
    key_state->p = NULL;
 
732
    _libssh2_bn_free(key_state->g);
 
733
    key_state->g = NULL;
 
734
    key_state->state = libssh2_NB_state_idle;
 
735
 
 
736
    return ret;
 
737
}
 
738
 
 
739
 
 
740
 
 
741
/* kex_method_diffie_hellman_group14_sha1_key_exchange
 
742
 * Diffie-Hellman Group14 Key Exchange using SHA1
 
743
 */
 
744
static int
 
745
kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session,
 
746
                                                    key_exchange_state_low_t
 
747
                                                    * key_state)
 
748
{
 
749
    static const unsigned char p_value[256] = {
 
750
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 
751
        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 
752
        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 
753
        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 
754
        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 
755
        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 
756
        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 
757
        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 
758
        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 
759
        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 
760
        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 
761
        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 
762
        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 
763
        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 
764
        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
 
765
        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
 
766
        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
 
767
        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
 
768
        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
 
769
        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
 
770
        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
 
771
        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
 
772
        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
 
773
        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
 
774
        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
 
775
        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
 
776
        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
 
777
        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
 
778
        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
 
779
        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
 
780
        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
 
781
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 
782
    };
 
783
    int ret;
 
784
 
 
785
    if (key_state->state == libssh2_NB_state_idle) {
 
786
        key_state->p = _libssh2_bn_init();      /* SSH2 defined value (p_value) */
 
787
        key_state->g = _libssh2_bn_init();      /* SSH2 defined value (2) */
 
788
 
 
789
        /* g == 2 */
 
790
        /* Initialize P and G */
 
791
        _libssh2_bn_set_word(key_state->g, 2);
 
792
        _libssh2_bn_from_bin(key_state->p, 256, p_value);
 
793
 
 
794
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
795
                       "Initiating Diffie-Hellman Group14 Key Exchange");
 
796
 
 
797
        key_state->state = libssh2_NB_state_created;
 
798
    }
 
799
    ret = diffie_hellman_sha1(session, key_state->g, key_state->p,
 
800
                              256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY,
 
801
                              NULL, 0, &key_state->exchange_state);
 
802
    if (ret == LIBSSH2_ERROR_EAGAIN) {
 
803
        return ret;
 
804
    }
 
805
 
 
806
    key_state->state = libssh2_NB_state_idle;
 
807
    _libssh2_bn_free(key_state->p);
 
808
    key_state->p = NULL;
 
809
    _libssh2_bn_free(key_state->g);
 
810
    key_state->g = NULL;
 
811
 
 
812
    return ret;
 
813
}
 
814
 
 
815
 
 
816
 
 
817
/* kex_method_diffie_hellman_group_exchange_sha1_key_exchange
 
818
 * Diffie-Hellman Group Exchange Key Exchange using SHA1
 
819
 * Negotiates random(ish) group for secret derivation
 
820
 */
 
821
static int
 
822
kex_method_diffie_hellman_group_exchange_sha1_key_exchange
 
823
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
 
824
{
 
825
    unsigned long p_len, g_len;
 
826
    int ret = 0;
 
827
    int rc;
 
828
 
 
829
    if (key_state->state == libssh2_NB_state_idle) {
 
830
        key_state->p = _libssh2_bn_init();
 
831
        key_state->g = _libssh2_bn_init();
 
832
        /* Ask for a P and G pair */
 
833
#ifdef LIBSSH2_DH_GEX_NEW
 
834
        key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST;
 
835
        _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP);
 
836
        _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP);
 
837
        _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP);
 
838
        key_state->request_len = 13;
 
839
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
840
                       "Initiating Diffie-Hellman Group-Exchange (New Method)");
 
841
#else
 
842
        key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
 
843
        _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP);
 
844
        key_state->request_len = 5;
 
845
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
 
846
                       "Initiating Diffie-Hellman Group-Exchange (Old Method)");
 
847
#endif
 
848
 
 
849
        key_state->state = libssh2_NB_state_created;
 
850
    }
 
851
 
 
852
    if (key_state->state == libssh2_NB_state_created) {
 
853
        rc = _libssh2_transport_send(session, key_state->request,
 
854
                                     key_state->request_len, NULL, 0);
 
855
        if (rc == LIBSSH2_ERROR_EAGAIN) {
 
856
            return rc;
 
857
        } else if (rc) {
 
858
            ret = _libssh2_error(session, rc,
 
859
                                 "Unable to send Group Exchange Request");
 
860
            goto dh_gex_clean_exit;
 
861
        }
 
862
 
 
863
        key_state->state = libssh2_NB_state_sent;
 
864
    }
 
865
 
 
866
    if (key_state->state == libssh2_NB_state_sent) {
 
867
        rc = _libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP,
 
868
                                     &key_state->data, &key_state->data_len,
 
869
                                     0, NULL, 0, &key_state->req_state);
 
870
        if (rc == LIBSSH2_ERROR_EAGAIN) {
 
871
            return rc;
 
872
        } else if (rc) {
 
873
            ret = _libssh2_error(session, rc,
 
874
                                 "Timeout waiting for GEX_GROUP reply");
 
875
            goto dh_gex_clean_exit;
 
876
        }
 
877
 
 
878
        key_state->state = libssh2_NB_state_sent1;
 
879
    }
 
880
 
 
881
    if (key_state->state == libssh2_NB_state_sent1) {
 
882
        unsigned char *s = key_state->data + 1;
 
883
        p_len = _libssh2_ntohu32(s);
 
884
        s += 4;
 
885
        _libssh2_bn_from_bin(key_state->p, p_len, s);
 
886
        s += p_len;
 
887
 
 
888
        g_len = _libssh2_ntohu32(s);
 
889
        s += 4;
 
890
        _libssh2_bn_from_bin(key_state->g, g_len, s);
 
891
 
 
892
        ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len,
 
893
                                  SSH_MSG_KEX_DH_GEX_INIT,
 
894
                                  SSH_MSG_KEX_DH_GEX_REPLY,
 
895
                                  key_state->data + 1,
 
896
                                  key_state->data_len - 1,
 
897
                                  &key_state->exchange_state);
 
898
        if (ret == LIBSSH2_ERROR_EAGAIN) {
 
899
            return ret;
 
900
        }
 
901
 
 
902
        LIBSSH2_FREE(session, key_state->data);
 
903
    }
 
904
 
 
905
  dh_gex_clean_exit:
 
906
    key_state->state = libssh2_NB_state_idle;
 
907
    _libssh2_bn_free(key_state->g);
 
908
    key_state->g = NULL;
 
909
    _libssh2_bn_free(key_state->p);
 
910
    key_state->p = NULL;
 
911
 
 
912
    return ret;
 
913
}
 
914
 
 
915
 
 
916
 
 
917
#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY     0x0001
 
918
#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY    0x0002
 
919
 
 
920
static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group1_sha1 = {
 
921
    "diffie-hellman-group1-sha1",
 
922
    kex_method_diffie_hellman_group1_sha1_key_exchange,
 
923
    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
 
924
};
 
925
 
 
926
static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha1 = {
 
927
    "diffie-hellman-group14-sha1",
 
928
    kex_method_diffie_hellman_group14_sha1_key_exchange,
 
929
    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
 
930
};
 
931
 
 
932
static const LIBSSH2_KEX_METHOD
 
933
kex_method_diffie_helman_group_exchange_sha1 = {
 
934
    "diffie-hellman-group-exchange-sha1",
 
935
    kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
 
936
    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
 
937
};
 
938
 
 
939
static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
 
940
    &kex_method_diffie_helman_group14_sha1,
 
941
    &kex_method_diffie_helman_group_exchange_sha1,
 
942
    &kex_method_diffie_helman_group1_sha1,
 
943
    NULL
 
944
};
 
945
 
 
946
typedef struct _LIBSSH2_COMMON_METHOD
 
947
{
 
948
    const char *name;
 
949
} LIBSSH2_COMMON_METHOD;
 
950
 
 
951
/* kex_method_strlen
 
952
 * Calculate the length of a particular method list's resulting string
 
953
 * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 (because the last coma isn't used)
 
954
 * Another sign of bad coding practices gone mad.  Pretend you don't see this.
 
955
 */
 
956
static size_t
 
957
kex_method_strlen(LIBSSH2_COMMON_METHOD ** method)
 
958
{
 
959
    size_t len = 0;
 
960
 
 
961
    if (!method || !*method) {
 
962
        return 0;
 
963
    }
 
964
 
 
965
    while (*method && (*method)->name) {
 
966
        len += strlen((*method)->name) + 1;
 
967
        method++;
 
968
    }
 
969
 
 
970
    return len - 1;
 
971
}
 
972
 
 
973
 
 
974
 
 
975
/* kex_method_list
 
976
 * Generate formatted preference list in buf
 
977
 */
 
978
static size_t
 
979
kex_method_list(unsigned char *buf, size_t list_strlen,
 
980
                LIBSSH2_COMMON_METHOD ** method)
 
981
{
 
982
    _libssh2_htonu32(buf, list_strlen);
 
983
    buf += 4;
 
984
 
 
985
    if (!method || !*method) {
 
986
        return 4;
 
987
    }
 
988
 
 
989
    while (*method && (*method)->name) {
 
990
        int mlen = strlen((*method)->name);
 
991
        memcpy(buf, (*method)->name, mlen);
 
992
        buf += mlen;
 
993
        *(buf++) = ',';
 
994
        method++;
 
995
    }
 
996
 
 
997
    return list_strlen + 4;
 
998
}
 
999
 
 
1000
 
 
1001
 
 
1002
#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar)           \
 
1003
    ((prefvar) ? strlen(prefvar) :                              \
 
1004
     kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
 
1005
 
 
1006
#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar)  \
 
1007
    if (prefvar) {                                                      \
 
1008
        _libssh2_htonu32((buf), (prefvarlen));                          \
 
1009
        buf += 4;                                                       \
 
1010
        memcpy((buf), (prefvar), (prefvarlen));                         \
 
1011
        buf += (prefvarlen);                                            \
 
1012
    } else {                                                            \
 
1013
        buf += kex_method_list((buf), (prefvarlen),                     \
 
1014
                               (LIBSSH2_COMMON_METHOD**)(defaultvar));  \
 
1015
    }
 
1016
 
 
1017
/* kexinit
 
1018
 * Send SSH_MSG_KEXINIT packet
 
1019
 */
 
1020
static int kexinit(LIBSSH2_SESSION * session)
 
1021
{
 
1022
    /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) +
 
1023
       reserved(4) + length longs(40) */
 
1024
    size_t data_len = 62;
 
1025
    size_t kex_len, hostkey_len = 0;
 
1026
    size_t crypt_cs_len, crypt_sc_len;
 
1027
    size_t comp_cs_len, comp_sc_len;
 
1028
    size_t mac_cs_len, mac_sc_len;
 
1029
    size_t lang_cs_len, lang_sc_len;
 
1030
    unsigned char *data, *s;
 
1031
    int rc;
 
1032
 
 
1033
    if (session->kexinit_state == libssh2_NB_state_idle) {
 
1034
        kex_len =
 
1035
            LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
 
1036
        hostkey_len =
 
1037
            LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs,
 
1038
                                     libssh2_hostkey_methods());
 
1039
        crypt_cs_len =
 
1040
            LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs,
 
1041
                                     libssh2_crypt_methods());
 
1042
        crypt_sc_len =
 
1043
            LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs,
 
1044
                                     libssh2_crypt_methods());
 
1045
        mac_cs_len =
 
1046
            LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs,
 
1047
                                     _libssh2_mac_methods());
 
1048
        mac_sc_len =
 
1049
            LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs,
 
1050
                                     _libssh2_mac_methods());
 
1051
        comp_cs_len =
 
1052
            LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
 
1053
                                     _libssh2_comp_methods(session));
 
1054
        comp_sc_len =
 
1055
            LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
 
1056
                                     _libssh2_comp_methods(session));
 
1057
        lang_cs_len =
 
1058
            LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
 
1059
        lang_sc_len =
 
1060
            LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
 
1061
 
 
1062
        data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len +
 
1063
            comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len +
 
1064
            lang_cs_len + lang_sc_len;
 
1065
 
 
1066
        s = data = LIBSSH2_ALLOC(session, data_len);
 
1067
        if (!data) {
 
1068
            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 
1069
                                  "Unable to allocate memory");
 
1070
        }
 
1071
 
 
1072
        *(s++) = SSH_MSG_KEXINIT;
 
1073
 
 
1074
        _libssh2_random(s, 16);
 
1075
        s += 16;
 
1076
 
 
1077
        /* Ennumerating through these lists twice is probably (certainly?)
 
1078
           inefficient from a CPU standpoint, but it saves multiple
 
1079
           malloc/realloc calls */
 
1080
        LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs,
 
1081
                                 libssh2_kex_methods);
 
1082
        LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs,
 
1083
                                 libssh2_hostkey_methods());
 
1084
        LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs,
 
1085
                                 libssh2_crypt_methods());
 
1086
        LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs,
 
1087
                                 libssh2_crypt_methods());
 
1088
        LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs,
 
1089
                                 _libssh2_mac_methods());
 
1090
        LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs,
 
1091
                                 _libssh2_mac_methods());
 
1092
        LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs,
 
1093
                                 _libssh2_comp_methods(session));
 
1094
        LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs,
 
1095
                                 _libssh2_comp_methods(session));
 
1096
        LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs,
 
1097
                                 NULL);
 
1098
        LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs,
 
1099
                                 NULL);
 
1100
 
 
1101
        /* No optimistic KEX packet follows */
 
1102
        /* Deal with optimistic packets
 
1103
         * session->flags |= KEXINIT_OPTIMISTIC
 
1104
         * session->flags |= KEXINIT_METHODSMATCH
 
1105
         */
 
1106
        *(s++) = 0;
 
1107
 
 
1108
        /* Reserved == 0 */
 
1109
        _libssh2_htonu32(s, 0);
 
1110
 
 
1111
#ifdef LIBSSH2DEBUG
 
1112
        {
 
1113
            /* Funnily enough, they'll all "appear" to be '\0' terminated */
 
1114
            unsigned char *p = data + 21;       /* type(1) + cookie(16) + len(4) */
 
1115
 
 
1116
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent KEX: %s", p);
 
1117
            p += kex_len + 4;
 
1118
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent HOSTKEY: %s", p);
 
1119
            p += hostkey_len + 4;
 
1120
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_CS: %s", p);
 
1121
            p += crypt_cs_len + 4;
 
1122
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_SC: %s", p);
 
1123
            p += crypt_sc_len + 4;
 
1124
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_CS: %s", p);
 
1125
            p += mac_cs_len + 4;
 
1126
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_SC: %s", p);
 
1127
            p += mac_sc_len + 4;
 
1128
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_CS: %s", p);
 
1129
            p += comp_cs_len + 4;
 
1130
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_SC: %s", p);
 
1131
            p += comp_sc_len + 4;
 
1132
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_CS: %s", p);
 
1133
            p += lang_cs_len + 4;
 
1134
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_SC: %s", p);
 
1135
            p += lang_sc_len + 4;
 
1136
        }
 
1137
#endif /* LIBSSH2DEBUG */
 
1138
 
 
1139
        session->kexinit_state = libssh2_NB_state_created;
 
1140
    } else {
 
1141
        data = session->kexinit_data;
 
1142
        data_len = session->kexinit_data_len;
 
1143
        /* zap the variables to ensure there is NOT a double free later */
 
1144
        session->kexinit_data = NULL;
 
1145
        session->kexinit_data_len = 0;
 
1146
    }
 
1147
 
 
1148
    rc = _libssh2_transport_send(session, data, data_len, NULL, 0);
 
1149
    if (rc == LIBSSH2_ERROR_EAGAIN) {
 
1150
        session->kexinit_data = data;
 
1151
        session->kexinit_data_len = data_len;
 
1152
        return rc;
 
1153
    }
 
1154
    else if (rc) {
 
1155
        LIBSSH2_FREE(session, data);
 
1156
        session->kexinit_state = libssh2_NB_state_idle;
 
1157
        return _libssh2_error(session, rc,
 
1158
                              "Unable to send KEXINIT packet to remote host");
 
1159
 
 
1160
    }
 
1161
 
 
1162
    if (session->local.kexinit) {
 
1163
        LIBSSH2_FREE(session, session->local.kexinit);
 
1164
    }
 
1165
 
 
1166
    session->local.kexinit = data;
 
1167
    session->local.kexinit_len = data_len;
 
1168
 
 
1169
    session->kexinit_state = libssh2_NB_state_idle;
 
1170
 
 
1171
    return 0;
 
1172
}
 
1173
 
 
1174
/* kex_agree_instr
 
1175
 * Kex specific variant of strstr()
 
1176
 * Needle must be preceed by BOL or ',', and followed by ',' or EOL
 
1177
 */
 
1178
static unsigned char *
 
1179
kex_agree_instr(unsigned char *haystack, unsigned long haystack_len,
 
1180
                const unsigned char *needle, unsigned long needle_len)
 
1181
{
 
1182
    unsigned char *s;
 
1183
 
 
1184
    /* Haystack too short to bother trying */
 
1185
    if (haystack_len < needle_len) {
 
1186
        return NULL;
 
1187
    }
 
1188
 
 
1189
    /* Needle at start of haystack */
 
1190
    if ((strncmp((char *) haystack, (char *) needle, needle_len) == 0) &&
 
1191
        (needle_len == haystack_len || haystack[needle_len] == ',')) {
 
1192
        return haystack;
 
1193
    }
 
1194
 
 
1195
    s = haystack;
 
1196
    /* Search until we run out of comas or we run out of haystack,
 
1197
       whichever comes first */
 
1198
    while ((s = (unsigned char *) strchr((char *) s, ','))
 
1199
           && ((haystack_len - (s - haystack)) > needle_len)) {
 
1200
        s++;
 
1201
        /* Needle at X position */
 
1202
        if ((strncmp((char *) s, (char *) needle, needle_len) == 0) &&
 
1203
            (((s - haystack) + needle_len) == haystack_len
 
1204
             || s[needle_len] == ',')) {
 
1205
            return s;
 
1206
        }
 
1207
    }
 
1208
 
 
1209
    return NULL;
 
1210
}
 
1211
 
 
1212
 
 
1213
 
 
1214
/* kex_get_method_by_name
 
1215
 */
 
1216
static const LIBSSH2_COMMON_METHOD *
 
1217
kex_get_method_by_name(const char *name, size_t name_len,
 
1218
                       const LIBSSH2_COMMON_METHOD ** methodlist)
 
1219
{
 
1220
    while (*methodlist) {
 
1221
        if ((strlen((*methodlist)->name) == name_len) &&
 
1222
            (strncmp((*methodlist)->name, name, name_len) == 0)) {
 
1223
            return *methodlist;
 
1224
        }
 
1225
        methodlist++;
 
1226
    }
 
1227
    return NULL;
 
1228
}
 
1229
 
 
1230
 
 
1231
 
 
1232
/* kex_agree_hostkey
 
1233
 * Agree on a Hostkey which works with this kex
 
1234
 */
 
1235
static int kex_agree_hostkey(LIBSSH2_SESSION * session,
 
1236
                             unsigned long kex_flags,
 
1237
                             unsigned char *hostkey, unsigned long hostkey_len)
 
1238
{
 
1239
    const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
 
1240
    unsigned char *s;
 
1241
 
 
1242
    if (session->hostkey_prefs) {
 
1243
        s = (unsigned char *) session->hostkey_prefs;
 
1244
 
 
1245
        while (s && *s) {
 
1246
            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
 
1247
            size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
 
1248
            if (kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
 
1249
                const LIBSSH2_HOSTKEY_METHOD *method =
 
1250
                    (const LIBSSH2_HOSTKEY_METHOD *)
 
1251
                    kex_get_method_by_name((char *) s, method_len,
 
1252
                                           (const LIBSSH2_COMMON_METHOD **)
 
1253
                                           hostkeyp);
 
1254
 
 
1255
                if (!method) {
 
1256
                    /* Invalid method -- Should never be reached */
 
1257
                    return -1;
 
1258
                }
 
1259
 
 
1260
                /* So far so good, but does it suit our purposes? (Encrypting
 
1261
                   vs Signing) */
 
1262
                if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) ==
 
1263
                     0) || (method->encrypt)) {
 
1264
                    /* Either this hostkey can do encryption or this kex just
 
1265
                       doesn't require it */
 
1266
                    if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY)
 
1267
                         == 0) || (method->sig_verify)) {
 
1268
                        /* Either this hostkey can do signing or this kex just
 
1269
                           doesn't require it */
 
1270
                        session->hostkey = method;
 
1271
                        return 0;
 
1272
                    }
 
1273
                }
 
1274
            }
 
1275
 
 
1276
            s = p ? p + 1 : NULL;
 
1277
        }
 
1278
        return -1;
 
1279
    }
 
1280
 
 
1281
    while (hostkeyp && (*hostkeyp) && (*hostkeyp)->name) {
 
1282
        s = kex_agree_instr(hostkey, hostkey_len,
 
1283
                            (unsigned char *) (*hostkeyp)->name,
 
1284
                            strlen((*hostkeyp)->name));
 
1285
        if (s) {
 
1286
            /* So far so good, but does it suit our purposes? (Encrypting vs
 
1287
               Signing) */
 
1288
            if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
 
1289
                ((*hostkeyp)->encrypt)) {
 
1290
                /* Either this hostkey can do encryption or this kex just
 
1291
                   doesn't require it */
 
1292
                if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) ==
 
1293
                     0) || ((*hostkeyp)->sig_verify)) {
 
1294
                    /* Either this hostkey can do signing or this kex just
 
1295
                       doesn't require it */
 
1296
                    session->hostkey = *hostkeyp;
 
1297
                    return 0;
 
1298
                }
 
1299
            }
 
1300
        }
 
1301
        hostkeyp++;
 
1302
    }
 
1303
 
 
1304
    return -1;
 
1305
}
 
1306
 
 
1307
 
 
1308
 
 
1309
/* kex_agree_kex_hostkey
 
1310
 * Agree on a Key Exchange method and a hostkey encoding type
 
1311
 */
 
1312
static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
 
1313
                                 unsigned long kex_len, unsigned char *hostkey,
 
1314
                                 unsigned long hostkey_len)
 
1315
{
 
1316
    const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
 
1317
    unsigned char *s;
 
1318
 
 
1319
    if (session->kex_prefs) {
 
1320
        s = (unsigned char *) session->kex_prefs;
 
1321
 
 
1322
        while (s && *s) {
 
1323
            unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
 
1324
            size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
 
1325
            if ((q = kex_agree_instr(kex, kex_len, s, method_len))) {
 
1326
                const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
 
1327
                    kex_get_method_by_name((char *) s, method_len,
 
1328
                                           (const LIBSSH2_COMMON_METHOD **)
 
1329
                                           kexp);
 
1330
 
 
1331
                if (!method) {
 
1332
                    /* Invalid method -- Should never be reached */
 
1333
                    return -1;
 
1334
                }
 
1335
 
 
1336
                /* We've agreed on a key exchange method,
 
1337
                 * Can we agree on a hostkey that works with this kex?
 
1338
                 */
 
1339
                if (kex_agree_hostkey(session, method->flags, hostkey,
 
1340
                                      hostkey_len) == 0) {
 
1341
                    session->kex = method;
 
1342
                    if (session->burn_optimistic_kexinit && (kex == q)) {
 
1343
                        /* Server sent an optimistic packet,
 
1344
                         * and client agrees with preference
 
1345
                         * cancel burning the first KEX_INIT packet that comes in */
 
1346
                        session->burn_optimistic_kexinit = 0;
 
1347
                    }
 
1348
                    return 0;
 
1349
                }
 
1350
            }
 
1351
 
 
1352
            s = p ? p + 1 : NULL;
 
1353
        }
 
1354
        return -1;
 
1355
    }
 
1356
 
 
1357
    while (*kexp && (*kexp)->name) {
 
1358
        s = kex_agree_instr(kex, kex_len,
 
1359
                            (unsigned char *) (*kexp)->name,
 
1360
                            strlen((*kexp)->name));
 
1361
        if (s) {
 
1362
            /* We've agreed on a key exchange method,
 
1363
             * Can we agree on a hostkey that works with this kex?
 
1364
             */
 
1365
            if (kex_agree_hostkey(session, (*kexp)->flags, hostkey,
 
1366
                                  hostkey_len) == 0) {
 
1367
                session->kex = *kexp;
 
1368
                if (session->burn_optimistic_kexinit && (kex == s)) {
 
1369
                    /* Server sent an optimistic packet,
 
1370
                     * and client agrees with preference
 
1371
                     * cancel burning the first KEX_INIT packet that comes in */
 
1372
                    session->burn_optimistic_kexinit = 0;
 
1373
                }
 
1374
                return 0;
 
1375
            }
 
1376
        }
 
1377
        kexp++;
 
1378
    }
 
1379
    return -1;
 
1380
}
 
1381
 
 
1382
 
 
1383
 
 
1384
/* kex_agree_crypt
 
1385
 * Agree on a cipher algo
 
1386
 */
 
1387
static int kex_agree_crypt(LIBSSH2_SESSION * session,
 
1388
                           libssh2_endpoint_data *endpoint,
 
1389
                           unsigned char *crypt,
 
1390
                           unsigned long crypt_len)
 
1391
{
 
1392
    const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
 
1393
    unsigned char *s;
 
1394
 
 
1395
    (void) session;
 
1396
 
 
1397
    if (endpoint->crypt_prefs) {
 
1398
        s = (unsigned char *) endpoint->crypt_prefs;
 
1399
 
 
1400
        while (s && *s) {
 
1401
            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
 
1402
            size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
 
1403
 
 
1404
            if (kex_agree_instr(crypt, crypt_len, s, method_len)) {
 
1405
                const LIBSSH2_CRYPT_METHOD *method =
 
1406
                    (const LIBSSH2_CRYPT_METHOD *)
 
1407
                    kex_get_method_by_name((char *) s, method_len,
 
1408
                                           (const LIBSSH2_COMMON_METHOD **)
 
1409
                                           cryptp);
 
1410
 
 
1411
                if (!method) {
 
1412
                    /* Invalid method -- Should never be reached */
 
1413
                    return -1;
 
1414
                }
 
1415
 
 
1416
                endpoint->crypt = method;
 
1417
                return 0;
 
1418
            }
 
1419
 
 
1420
            s = p ? p + 1 : NULL;
 
1421
        }
 
1422
        return -1;
 
1423
    }
 
1424
 
 
1425
    while (*cryptp && (*cryptp)->name) {
 
1426
        s = kex_agree_instr(crypt, crypt_len,
 
1427
                            (unsigned char *) (*cryptp)->name,
 
1428
                            strlen((*cryptp)->name));
 
1429
        if (s) {
 
1430
            endpoint->crypt = *cryptp;
 
1431
            return 0;
 
1432
        }
 
1433
        cryptp++;
 
1434
    }
 
1435
 
 
1436
    return -1;
 
1437
}
 
1438
 
 
1439
 
 
1440
 
 
1441
/* kex_agree_mac
 
1442
 * Agree on a message authentication hash
 
1443
 */
 
1444
static int kex_agree_mac(LIBSSH2_SESSION * session,
 
1445
                         libssh2_endpoint_data * endpoint, unsigned char *mac,
 
1446
                         unsigned long mac_len)
 
1447
{
 
1448
    const LIBSSH2_MAC_METHOD **macp = _libssh2_mac_methods();
 
1449
    unsigned char *s;
 
1450
    (void) session;
 
1451
 
 
1452
    if (endpoint->mac_prefs) {
 
1453
        s = (unsigned char *) endpoint->mac_prefs;
 
1454
 
 
1455
        while (s && *s) {
 
1456
            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
 
1457
            size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
 
1458
 
 
1459
            if (kex_agree_instr(mac, mac_len, s, method_len)) {
 
1460
                const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
 
1461
                    kex_get_method_by_name((char *) s, method_len,
 
1462
                                           (const LIBSSH2_COMMON_METHOD **)
 
1463
                                           macp);
 
1464
 
 
1465
                if (!method) {
 
1466
                    /* Invalid method -- Should never be reached */
 
1467
                    return -1;
 
1468
                }
 
1469
 
 
1470
                endpoint->mac = method;
 
1471
                return 0;
 
1472
            }
 
1473
 
 
1474
            s = p ? p + 1 : NULL;
 
1475
        }
 
1476
        return -1;
 
1477
    }
 
1478
 
 
1479
    while (*macp && (*macp)->name) {
 
1480
        s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name,
 
1481
                            strlen((*macp)->name));
 
1482
        if (s) {
 
1483
            endpoint->mac = *macp;
 
1484
            return 0;
 
1485
        }
 
1486
        macp++;
 
1487
    }
 
1488
 
 
1489
    return -1;
 
1490
}
 
1491
 
 
1492
 
 
1493
 
 
1494
/* kex_agree_comp
 
1495
 * Agree on a compression scheme
 
1496
 */
 
1497
static int kex_agree_comp(LIBSSH2_SESSION *session,
 
1498
                          libssh2_endpoint_data *endpoint, unsigned char *comp,
 
1499
                          unsigned long comp_len)
 
1500
{
 
1501
    const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session);
 
1502
    unsigned char *s;
 
1503
    (void) session;
 
1504
 
 
1505
    if (endpoint->comp_prefs) {
 
1506
        s = (unsigned char *) endpoint->comp_prefs;
 
1507
 
 
1508
        while (s && *s) {
 
1509
            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
 
1510
            size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
 
1511
 
 
1512
            if (kex_agree_instr(comp, comp_len, s, method_len)) {
 
1513
                const LIBSSH2_COMP_METHOD *method =
 
1514
                    (const LIBSSH2_COMP_METHOD *)
 
1515
                    kex_get_method_by_name((char *) s, method_len,
 
1516
                                           (const LIBSSH2_COMMON_METHOD **)
 
1517
                                           compp);
 
1518
 
 
1519
                if (!method) {
 
1520
                    /* Invalid method -- Should never be reached */
 
1521
                    return -1;
 
1522
                }
 
1523
 
 
1524
                endpoint->comp = method;
 
1525
                return 0;
 
1526
            }
 
1527
 
 
1528
            s = p ? p + 1 : NULL;
 
1529
        }
 
1530
        return -1;
 
1531
    }
 
1532
 
 
1533
    while (*compp && (*compp)->name) {
 
1534
        s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name,
 
1535
                            strlen((*compp)->name));
 
1536
        if (s) {
 
1537
            endpoint->comp = *compp;
 
1538
            return 0;
 
1539
        }
 
1540
        compp++;
 
1541
    }
 
1542
 
 
1543
    return -1;
 
1544
}
 
1545
 
 
1546
 
 
1547
 
 
1548
/* TODO: When in server mode we need to turn this logic on its head
 
1549
 * The Client gets to make the final call on "agreed methods"
 
1550
 */
 
1551
 
 
1552
/* kex_agree_methods
 
1553
 * Decide which specific method to use of the methods offered by each party
 
1554
 */
 
1555
static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
 
1556
                             unsigned data_len)
 
1557
{
 
1558
    unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc,
 
1559
        *mac_cs, *mac_sc;
 
1560
    size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len;
 
1561
    size_t comp_sc_len, mac_cs_len, mac_sc_len;
 
1562
    unsigned char *s = data;
 
1563
 
 
1564
    /* Skip packet_type, we know it already */
 
1565
    s++;
 
1566
 
 
1567
    /* Skip cookie, don't worry, it's preserved in the kexinit field */
 
1568
    s += 16;
 
1569
 
 
1570
    /* Locate each string */
 
1571
    kex_len = _libssh2_ntohu32(s);
 
1572
    kex = s + 4;
 
1573
    s += 4 + kex_len;
 
1574
    hostkey_len = _libssh2_ntohu32(s);
 
1575
    hostkey = s + 4;
 
1576
    s += 4 + hostkey_len;
 
1577
    crypt_cs_len = _libssh2_ntohu32(s);
 
1578
    crypt_cs = s + 4;
 
1579
    s += 4 + crypt_cs_len;
 
1580
    crypt_sc_len = _libssh2_ntohu32(s);
 
1581
    crypt_sc = s + 4;
 
1582
    s += 4 + crypt_sc_len;
 
1583
    mac_cs_len = _libssh2_ntohu32(s);
 
1584
    mac_cs = s + 4;
 
1585
    s += 4 + mac_cs_len;
 
1586
    mac_sc_len = _libssh2_ntohu32(s);
 
1587
    mac_sc = s + 4;
 
1588
    s += 4 + mac_sc_len;
 
1589
    comp_cs_len = _libssh2_ntohu32(s);
 
1590
    comp_cs = s + 4;
 
1591
    s += 4 + comp_cs_len;
 
1592
    comp_sc_len = _libssh2_ntohu32(s);
 
1593
    comp_sc = s + 4;
 
1594
#if 0
 
1595
    s += 4 + comp_sc_len;
 
1596
    lang_cs_len = _libssh2_ntohu32(s);
 
1597
    lang_cs = s + 4;
 
1598
    s += 4 + lang_cs_len;
 
1599
    lang_sc_len = _libssh2_ntohu32(s);
 
1600
    lang_sc = s + 4;
 
1601
    s += 4 + lang_sc_len;
 
1602
#endif
 
1603
    /* If the server sent an optimistic packet, assume that it guessed wrong.
 
1604
     * If the guess is determined to be right (by kex_agree_kex_hostkey)
 
1605
     * This flag will be reset to zero so that it's not ignored */
 
1606
    session->burn_optimistic_kexinit = *(s++);
 
1607
    /* Next uint32 in packet is all zeros (reserved) */
 
1608
 
 
1609
    if (data_len < (unsigned) (s - data))
 
1610
        return -1;              /* short packet */
 
1611
 
 
1612
    if (kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) {
 
1613
        return -1;
 
1614
    }
 
1615
 
 
1616
    if (kex_agree_crypt(session, &session->local, crypt_cs, crypt_cs_len)
 
1617
        || kex_agree_crypt(session, &session->remote, crypt_sc, crypt_sc_len)) {
 
1618
        return -1;
 
1619
    }
 
1620
 
 
1621
    if (kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) ||
 
1622
        kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) {
 
1623
        return -1;
 
1624
    }
 
1625
 
 
1626
    if (kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) ||
 
1627
        kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) {
 
1628
        return -1;
 
1629
    }
 
1630
 
 
1631
#if 0
 
1632
    if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len)
 
1633
        || libssh2_kex_agree_lang(session, &session->remote, lang_sc,
 
1634
                                  lang_sc_len)) {
 
1635
        return -1;
 
1636
    }
 
1637
#endif
 
1638
 
 
1639
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on KEX method: %s",
 
1640
                   session->kex->name);
 
1641
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on HOSTKEY method: %s",
 
1642
                   session->hostkey->name);
 
1643
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_CS method: %s",
 
1644
                   session->local.crypt->name);
 
1645
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_SC method: %s",
 
1646
                   session->remote.crypt->name);
 
1647
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_CS method: %s",
 
1648
                   session->local.mac->name);
 
1649
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_SC method: %s",
 
1650
                   session->remote.mac->name);
 
1651
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_CS method: %s",
 
1652
                   session->local.comp->name);
 
1653
    _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_SC method: %s",
 
1654
                   session->remote.comp->name);
 
1655
 
 
1656
    return 0;
 
1657
}
 
1658
 
 
1659
 
 
1660
 
 
1661
/* _libssh2_kex_exchange
 
1662
 * Exchange keys
 
1663
 * Returns 0 on success, non-zero on failure
 
1664
 *
 
1665
 * Returns some errors without _libssh2_error()
 
1666
 */
 
1667
int
 
1668
_libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
 
1669
                     key_exchange_state_t * key_state)
 
1670
{
 
1671
    int rc = 0;
 
1672
    int retcode;
 
1673
 
 
1674
    session->state |= LIBSSH2_STATE_KEX_ACTIVE;
 
1675
 
 
1676
    if (key_state->state == libssh2_NB_state_idle) {
 
1677
        /* Prevent loop in packet_add() */
 
1678
        session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
 
1679
 
 
1680
        if (reexchange) {
 
1681
            session->kex = NULL;
 
1682
 
 
1683
            if (session->hostkey && session->hostkey->dtor) {
 
1684
                session->hostkey->dtor(session,
 
1685
                                       &session->server_hostkey_abstract);
 
1686
            }
 
1687
            session->hostkey = NULL;
 
1688
        }
 
1689
 
 
1690
        key_state->state = libssh2_NB_state_created;
 
1691
    }
 
1692
 
 
1693
    if (!session->kex || !session->hostkey) {
 
1694
        if (key_state->state == libssh2_NB_state_created) {
 
1695
            /* Preserve in case of failure */
 
1696
            key_state->oldlocal = session->local.kexinit;
 
1697
            key_state->oldlocal_len = session->local.kexinit_len;
 
1698
 
 
1699
            session->local.kexinit = NULL;
 
1700
 
 
1701
            key_state->state = libssh2_NB_state_sent;
 
1702
        }
 
1703
 
 
1704
        if (key_state->state == libssh2_NB_state_sent) {
 
1705
            retcode = kexinit(session);
 
1706
            if (retcode == LIBSSH2_ERROR_EAGAIN) {
 
1707
                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
 
1708
                return retcode;
 
1709
            } else if (retcode) {
 
1710
                session->local.kexinit = key_state->oldlocal;
 
1711
                session->local.kexinit_len = key_state->oldlocal_len;
 
1712
                key_state->state = libssh2_NB_state_idle;
 
1713
                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
 
1714
                session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
 
1715
                return -1;
 
1716
            }
 
1717
 
 
1718
            key_state->state = libssh2_NB_state_sent1;
 
1719
        }
 
1720
 
 
1721
        if (key_state->state == libssh2_NB_state_sent1) {
 
1722
            retcode =
 
1723
                _libssh2_packet_require(session, SSH_MSG_KEXINIT,
 
1724
                                        &key_state->data,
 
1725
                                        &key_state->data_len, 0, NULL, 0,
 
1726
                                        &key_state->req_state);
 
1727
            if (retcode == LIBSSH2_ERROR_EAGAIN) {
 
1728
                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
 
1729
                return retcode;
 
1730
            }
 
1731
            else if (retcode) {
 
1732
                if (session->local.kexinit) {
 
1733
                    LIBSSH2_FREE(session, session->local.kexinit);
 
1734
                }
 
1735
                session->local.kexinit = key_state->oldlocal;
 
1736
                session->local.kexinit_len = key_state->oldlocal_len;
 
1737
                key_state->state = libssh2_NB_state_idle;
 
1738
                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
 
1739
                session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
 
1740
                return -1;
 
1741
            }
 
1742
 
 
1743
            if (session->remote.kexinit) {
 
1744
                LIBSSH2_FREE(session, session->remote.kexinit);
 
1745
            }
 
1746
            session->remote.kexinit = key_state->data;
 
1747
            session->remote.kexinit_len = key_state->data_len;
 
1748
 
 
1749
            if (kex_agree_methods(session, key_state->data,
 
1750
                                  key_state->data_len))
 
1751
                rc = LIBSSH2_ERROR_KEX_FAILURE;
 
1752
 
 
1753
            key_state->state = libssh2_NB_state_sent2;
 
1754
        }
 
1755
    } else {
 
1756
        key_state->state = libssh2_NB_state_sent2;
 
1757
    }
 
1758
 
 
1759
    if (rc == 0) {
 
1760
        if (key_state->state == libssh2_NB_state_sent2) {
 
1761
            retcode = session->kex->exchange_keys(session,
 
1762
                                                  &key_state->key_state_low);
 
1763
            if (retcode == LIBSSH2_ERROR_EAGAIN) {
 
1764
                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
 
1765
                return retcode;
 
1766
            } else if (retcode) {
 
1767
                rc = _libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE,
 
1768
                                    "Unrecoverable error exchanging keys");
 
1769
            }
 
1770
        }
 
1771
    }
 
1772
 
 
1773
    /* Done with kexinit buffers */
 
1774
    if (session->local.kexinit) {
 
1775
        LIBSSH2_FREE(session, session->local.kexinit);
 
1776
        session->local.kexinit = NULL;
 
1777
    }
 
1778
    if (session->remote.kexinit) {
 
1779
        LIBSSH2_FREE(session, session->remote.kexinit);
 
1780
        session->remote.kexinit = NULL;
 
1781
    }
 
1782
 
 
1783
    session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
 
1784
    session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
 
1785
 
 
1786
    key_state->state = libssh2_NB_state_idle;
 
1787
 
 
1788
    return rc;
 
1789
}
 
1790
 
 
1791
 
 
1792
 
 
1793
/* libssh2_session_method_pref
 
1794
 * Set preferred method
 
1795
 */
 
1796
LIBSSH2_API int
 
1797
libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
 
1798
                            const char *prefs)
 
1799
{
 
1800
    char **prefvar, *s, *newprefs;
 
1801
    int prefs_len = strlen(prefs);
 
1802
    const LIBSSH2_COMMON_METHOD **mlist;
 
1803
 
 
1804
    switch (method_type) {
 
1805
    case LIBSSH2_METHOD_KEX:
 
1806
        prefvar = &session->kex_prefs;
 
1807
        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
 
1808
        break;
 
1809
 
 
1810
    case LIBSSH2_METHOD_HOSTKEY:
 
1811
        prefvar = &session->hostkey_prefs;
 
1812
        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
 
1813
        break;
 
1814
 
 
1815
    case LIBSSH2_METHOD_CRYPT_CS:
 
1816
        prefvar = &session->local.crypt_prefs;
 
1817
        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
 
1818
        break;
 
1819
 
 
1820
    case LIBSSH2_METHOD_CRYPT_SC:
 
1821
        prefvar = &session->remote.crypt_prefs;
 
1822
        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
 
1823
        break;
 
1824
 
 
1825
    case LIBSSH2_METHOD_MAC_CS:
 
1826
        prefvar = &session->local.mac_prefs;
 
1827
        mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods();
 
1828
        break;
 
1829
 
 
1830
    case LIBSSH2_METHOD_MAC_SC:
 
1831
        prefvar = &session->remote.mac_prefs;
 
1832
        mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods();
 
1833
        break;
 
1834
 
 
1835
    case LIBSSH2_METHOD_COMP_CS:
 
1836
        prefvar = &session->local.comp_prefs;
 
1837
        mlist = (const LIBSSH2_COMMON_METHOD **)
 
1838
            _libssh2_comp_methods(session);
 
1839
        break;
 
1840
 
 
1841
    case LIBSSH2_METHOD_COMP_SC:
 
1842
        prefvar = &session->remote.comp_prefs;
 
1843
        mlist = (const LIBSSH2_COMMON_METHOD **)
 
1844
            _libssh2_comp_methods(session);
 
1845
        break;
 
1846
 
 
1847
    case LIBSSH2_METHOD_LANG_CS:
 
1848
        prefvar = &session->local.lang_prefs;
 
1849
        mlist = NULL;
 
1850
        break;
 
1851
 
 
1852
    case LIBSSH2_METHOD_LANG_SC:
 
1853
        prefvar = &session->remote.lang_prefs;
 
1854
        mlist = NULL;
 
1855
        break;
 
1856
 
 
1857
    default:
 
1858
        return _libssh2_error(session, LIBSSH2_ERROR_INVAL,
 
1859
                              "Invalid parameter specified for method_type");
 
1860
    }
 
1861
 
 
1862
    s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
 
1863
    if (!newprefs) {
 
1864
        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 
1865
                              "Error allocated space for method preferences");
 
1866
    }
 
1867
    memcpy(s, prefs, prefs_len + 1);
 
1868
 
 
1869
    while (s && *s) {
 
1870
        char *p = strchr(s, ',');
 
1871
        int method_len = p ? (p - s) : (int) strlen(s);
 
1872
 
 
1873
        if (!kex_get_method_by_name(s, method_len, mlist)) {
 
1874
            /* Strip out unsupported method */
 
1875
            if (p) {
 
1876
                memcpy(s, p + 1, strlen(s) - method_len);
 
1877
            } else {
 
1878
                if (s > newprefs) {
 
1879
                    *(--s) = '\0';
 
1880
                } else {
 
1881
                    *s = '\0';
 
1882
                }
 
1883
            }
 
1884
        }
 
1885
 
 
1886
        s = p ? (p + 1) : NULL;
 
1887
    }
 
1888
 
 
1889
    if (strlen(newprefs) == 0) {
 
1890
        LIBSSH2_FREE(session, newprefs);
 
1891
        return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
 
1892
                              "The requested method(s) are not currently "
 
1893
                              "supported");
 
1894
    }
 
1895
 
 
1896
    if (*prefvar) {
 
1897
        LIBSSH2_FREE(session, *prefvar);
 
1898
    }
 
1899
    *prefvar = newprefs;
 
1900
 
 
1901
    return 0;
 
1902
}
 
1903
 
 
1904
/*
 
1905
 * libssh2_session_supported_algs()
 
1906
 * returns a number of returned algorithms (a positive number) on success,
 
1907
 * a negative number on failure
 
1908
 */
 
1909
 
 
1910
LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session,
 
1911
                                               int method_type,
 
1912
                                               const char*** algs)
 
1913
{
 
1914
    unsigned int i;
 
1915
    unsigned int j;
 
1916
    unsigned int ialg;
 
1917
    const LIBSSH2_COMMON_METHOD **mlist;
 
1918
 
 
1919
    /* to prevent coredumps due to dereferencing of NULL */
 
1920
    if (NULL == algs)
 
1921
        return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
 
1922
                              "algs must not be NULL");
 
1923
 
 
1924
    switch (method_type) {
 
1925
    case LIBSSH2_METHOD_KEX:
 
1926
        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
 
1927
        break;
 
1928
 
 
1929
    case LIBSSH2_METHOD_HOSTKEY:
 
1930
        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
 
1931
        break;
 
1932
 
 
1933
    case LIBSSH2_METHOD_CRYPT_CS:
 
1934
    case LIBSSH2_METHOD_CRYPT_SC:
 
1935
        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
 
1936
        break;
 
1937
 
 
1938
    case LIBSSH2_METHOD_MAC_CS:
 
1939
    case LIBSSH2_METHOD_MAC_SC:
 
1940
        mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods();
 
1941
        break;
 
1942
 
 
1943
    case LIBSSH2_METHOD_COMP_CS:
 
1944
    case LIBSSH2_METHOD_COMP_SC:
 
1945
        mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods(session);
 
1946
        break;
 
1947
 
 
1948
    default:
 
1949
        return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
 
1950
                              "Unknown method type");
 
1951
    }  /* switch */
 
1952
 
 
1953
    /* weird situation */
 
1954
    if (NULL==mlist)
 
1955
        return _libssh2_error(session, LIBSSH2_ERROR_INVAL,
 
1956
                              "No algorithm found");
 
1957
 
 
1958
    /*
 
1959
      mlist is looped through twice. The first time to find the number od
 
1960
      supported algorithms (needed to allocate the proper size of array) and
 
1961
      the second time to actually copy the pointers.  Typically this function
 
1962
      will not be called often (typically at the beginning of a session) and
 
1963
      the number of algorithms (i.e. niumber of iterations in one loop) will
 
1964
      not be high (typically it will not exceed 20) for quite a long time.
 
1965
 
 
1966
      So double looping really shouldn't be an issue and it is definitely a
 
1967
      better solution than reallocation several times.
 
1968
    */
 
1969
 
 
1970
    /* count the number of supported algorithms */
 
1971
    for ( i=0, ialg=0; NULL!=mlist[i]; i++) {
 
1972
        /* do not count fields with NULL name */
 
1973
        if (mlist[i]->name)
 
1974
            ialg++;
 
1975
    }
 
1976
 
 
1977
    /* weird situation, no algorithm found */
 
1978
    if (0==ialg)
 
1979
        return _libssh2_error(session, LIBSSH2_ERROR_INVAL,
 
1980
                              "No algorithm found");
 
1981
 
 
1982
    /* allocate buffer */
 
1983
    *algs = (const char**) LIBSSH2_ALLOC(session, ialg*sizeof(const char*));
 
1984
    if ( NULL==*algs ) {
 
1985
        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 
1986
                              "Memory allocation failed");
 
1987
    }
 
1988
    /* Past this point *algs must be deallocated in case of an error!! */
 
1989
 
 
1990
    /* copy non-NULL pointers only */
 
1991
    for ( i=0, j=0; NULL!=mlist[i] && j<ialg; i++ ) {
 
1992
        if ( NULL==mlist[i]->name ){
 
1993
            /* maybe a weird situation but if it occurs, do not include NULL
 
1994
               pointers */
 
1995
            continue;
 
1996
        }
 
1997
 
 
1998
        /* note that [] has higher priority than * (dereferencing) */
 
1999
        (*algs)[j++] = mlist[i]->name;
 
2000
    }
 
2001
 
 
2002
    /* correct number of pointers copied? (test the code above) */
 
2003
    if ( j!=ialg ) {
 
2004
        /* deallocate buffer */
 
2005
        LIBSSH2_FREE(session, (void *)*algs);
 
2006
        *algs = NULL;
 
2007
 
 
2008
        return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
 
2009
                              "Internal error");
 
2010
    }
 
2011
 
 
2012
    return ialg;
 
2013
}