Coverage Report

Created: 2026-09-01 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hpn-ssh/kex.c
Line
Count
Source
1
/* $OpenBSD: kex.c,v 1.193 2026/03/05 05:40:35 djm Exp $ */
2
/*
3
 * Copyright (c) 2000, 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"
27
28
#include <sys/types.h>
29
#include <errno.h>
30
#include <signal.h>
31
#include <stdarg.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
37
#ifdef WITH_OPENSSL
38
#include <openssl/crypto.h>
39
#include <openssl/dh.h>
40
#endif
41
42
#include "ssh.h"
43
#include "ssh2.h"
44
#include "atomicio.h"
45
#include "version.h"
46
#include "packet.h"
47
#include "compat.h"
48
#include "cipher.h"
49
#include "sshkey.h"
50
#include "kex.h"
51
#include "log.h"
52
#include "mac.h"
53
#include "match.h"
54
#include "misc.h"
55
#include "dispatch.h"
56
#include "myproposal.h"
57
58
#include "ssherr.h"
59
#include "sshbuf.h"
60
#include "canohost.h"
61
#include "digest.h"
62
#include "xmalloc.h"
63
64
/* prototype */
65
static int kex_choose_conf(struct ssh *, uint32_t seq);
66
static int kex_input_newkeys(int, uint32_t, struct ssh *);
67
68
static const char * const proposal_names[PROPOSAL_MAX] = {
69
  "KEX algorithms",
70
  "host key algorithms",
71
  "ciphers ctos",
72
  "ciphers stoc",
73
  "MACs ctos",
74
  "MACs stoc",
75
  "compression ctos",
76
  "compression stoc",
77
  "languages ctos",
78
  "languages stoc",
79
};
80
81
/*
82
 * Fill out a proposal array with dynamically allocated values, which may
83
 * be modified as required for compatibility reasons.
84
 * Any of the options may be NULL, in which case the default is used.
85
 * Array contents must be freed by calling kex_proposal_free_entries.
86
 */
87
void
88
kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX],
89
    const char *kexalgos, const char *ciphers, const char *macs,
90
    const char *comp, const char *hkalgs)
91
59.4k
{
92
59.4k
  const char *defpropserver[PROPOSAL_MAX] = { KEX_SERVER };
93
59.4k
  const char *defpropclient[PROPOSAL_MAX] = { KEX_CLIENT };
94
59.4k
  const char **defprop = ssh->kex->server ? defpropserver : defpropclient;
95
59.4k
  u_int i;
96
59.4k
  char *cp;
97
98
59.4k
  if (prop == NULL)
99
0
    fatal_f("proposal missing");
100
101
  /* Append EXT_INFO signalling to KexAlgorithms */
102
59.4k
  if (kexalgos == NULL)
103
0
    kexalgos = defprop[PROPOSAL_KEX_ALGS];
104
59.4k
  if ((cp = kex_names_cat(kexalgos, ssh->kex->server ?
105
29.7k
      "ext-info-s,kex-strict-s-v00@openssh.com" :
106
59.4k
      "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL)
107
0
    fatal_f("kex_names_cat");
108
109
653k
  for (i = 0; i < PROPOSAL_MAX; i++) {
110
594k
    switch(i) {
111
59.4k
    case PROPOSAL_KEX_ALGS:
112
59.4k
      prop[i] = compat_kex_proposal(ssh, cp);
113
59.4k
      break;
114
59.4k
    case PROPOSAL_ENC_ALGS_CTOS:
115
118k
    case PROPOSAL_ENC_ALGS_STOC:
116
118k
      prop[i] = xstrdup(ciphers ? ciphers : defprop[i]);
117
118k
      break;
118
59.4k
    case PROPOSAL_MAC_ALGS_CTOS:
119
118k
    case PROPOSAL_MAC_ALGS_STOC:
120
118k
      prop[i]  = xstrdup(macs ? macs : defprop[i]);
121
118k
      break;
122
59.4k
    case PROPOSAL_COMP_ALGS_CTOS:
123
118k
    case PROPOSAL_COMP_ALGS_STOC:
124
118k
      prop[i] = xstrdup(comp ? comp : defprop[i]);
125
118k
      break;
126
59.4k
    case PROPOSAL_SERVER_HOST_KEY_ALGS:
127
59.4k
      prop[i] = xstrdup(hkalgs ? hkalgs : defprop[i]);
128
59.4k
      break;
129
118k
    default:
130
118k
      prop[i] = xstrdup(defprop[i]);
131
594k
    }
132
594k
  }
133
59.4k
  free(cp);
134
59.4k
}
135
136
void
137
kex_proposal_free_entries(char *prop[PROPOSAL_MAX])
138
59.4k
{
139
59.4k
  u_int i;
140
141
653k
  for (i = 0; i < PROPOSAL_MAX; i++)
142
594k
    free(prop[i]);
143
59.4k
}
144
145
/* put algorithm proposal into buffer */
146
int
147
kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
148
77.1k
{
149
77.1k
  u_int i;
150
77.1k
  int r;
151
152
77.1k
  sshbuf_reset(b);
153
154
  /*
155
   * add a dummy cookie, the cookie will be overwritten by
156
   * kex_send_kexinit(), each time a kexinit is set
157
   */
158
1.31M
  for (i = 0; i < KEX_COOKIE_LEN; i++) {
159
1.23M
    if ((r = sshbuf_put_u8(b, 0)) != 0)
160
0
      return r;
161
1.23M
  }
162
848k
  for (i = 0; i < PROPOSAL_MAX; i++) {
163
771k
    if ((r = sshbuf_put_cstring(b, proposal[i])) != 0)
164
0
      return r;
165
771k
  }
166
77.1k
  if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */
167
77.1k
      (r = sshbuf_put_u32(b, 0)) != 0)  /* uint32 reserved */
168
0
    return r;
169
77.1k
  return 0;
170
77.1k
}
171
172
/* parse buffer and return algorithm proposal */
173
int
174
kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
175
25.9k
{
176
25.9k
  struct sshbuf *b = NULL;
177
25.9k
  u_char v;
178
25.9k
  u_int i;
179
25.9k
  char **proposal = NULL;
180
25.9k
  int r;
181
182
25.9k
  *propp = NULL;
183
25.9k
  if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL)
184
0
    return SSH_ERR_ALLOC_FAIL;
185
25.9k
  if ((b = sshbuf_fromb(raw)) == NULL) {
186
0
    r = SSH_ERR_ALLOC_FAIL;
187
0
    goto out;
188
0
  }
189
25.9k
  if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) { /* skip cookie */
190
0
    error_fr(r, "consume cookie");
191
0
    goto out;
192
0
  }
193
  /* extract kex init proposal strings */
194
282k
  for (i = 0; i < PROPOSAL_MAX; i++) {
195
257k
    if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) {
196
375
      error_fr(r, "parse proposal %u", i);
197
375
      goto out;
198
375
    }
199
256k
    debug2("%s: %s", proposal_names[i], proposal[i]);
200
256k
  }
201
  /* first kex follows / reserved */
202
25.5k
  if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */
203
25.5k
      (r = sshbuf_get_u32(b, &i)) != 0) { /* reserved */
204
0
    error_fr(r, "parse");
205
0
    goto out;
206
0
  }
207
25.5k
  if (first_kex_follows != NULL)
208
3.70k
    *first_kex_follows = v;
209
25.5k
  debug2("first_kex_follows %d ", v);
210
25.5k
  debug2("reserved %u ", i);
211
25.5k
  r = 0;
212
25.5k
  *propp = proposal;
213
25.9k
 out:
214
25.9k
  if (r != 0 && proposal != NULL)
215
375
    kex_prop_free(proposal);
216
25.9k
  sshbuf_free(b);
217
25.9k
  return r;
218
25.5k
}
219
220
void
221
kex_prop_free(char **proposal)
222
26.2k
{
223
26.2k
  u_int i;
224
225
26.2k
  if (proposal == NULL)
226
375
    return;
227
285k
  for (i = 0; i < PROPOSAL_MAX; i++)
228
259k
    free(proposal[i]);
229
25.9k
  free(proposal);
230
25.9k
}
231
232
int
233
kex_protocol_error(int type, uint32_t seq, struct ssh *ssh)
234
1.94M
{
235
1.94M
  int r;
236
237
  /* If in strict mode, any unexpected message is an error */
238
1.94M
  if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) {
239
0
    ssh_packet_disconnect(ssh, "strict KEX violation: "
240
0
        "unexpected packet type %u (seqnr %u)", type, seq);
241
0
  }
242
1.94M
  error_f("type %u seq %u", type, seq);
243
1.94M
  if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
244
1.94M
      (r = sshpkt_put_u32(ssh, seq)) != 0 ||
245
1.94M
      (r = sshpkt_send(ssh)) != 0)
246
0
    return r;
247
1.94M
  return 0;
248
1.94M
}
249
250
static void
251
kex_reset_dispatch(struct ssh *ssh)
252
59.4k
{
253
59.4k
  ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
254
59.4k
      SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
255
59.4k
}
256
257
void
258
kex_set_server_sig_algs(struct ssh *ssh, const char *allowed_algs)
259
0
{
260
0
  char *alg, *oalgs, *algs, *sigalgs;
261
0
  const char *sigalg;
262
263
  /*
264
   * NB. allowed algorithms may contain certificate algorithms that
265
   * map to a specific plain signature type, e.g.
266
   * rsa-sha2-512-cert-v01@openssh.com => rsa-sha2-512
267
   * We need to be careful here to match these, retain the mapping
268
   * and only add each signature algorithm once.
269
   */
270
0
  if ((sigalgs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
271
0
    fatal_f("sshkey_alg_list failed");
272
0
  oalgs = algs = xstrdup(allowed_algs);
273
0
  free(ssh->kex->server_sig_algs);
274
0
  ssh->kex->server_sig_algs = NULL;
275
0
  for ((alg = strsep(&algs, ",")); alg != NULL && *alg != '\0';
276
0
      (alg = strsep(&algs, ","))) {
277
0
    if ((sigalg = sshkey_sigalg_by_name(alg)) == NULL)
278
0
      continue;
279
0
    if (!kex_has_any_alg(sigalg, sigalgs))
280
0
      continue;
281
    /* Don't add an algorithm twice. */
282
0
    if (ssh->kex->server_sig_algs != NULL &&
283
0
        kex_has_any_alg(sigalg, ssh->kex->server_sig_algs))
284
0
      continue;
285
0
    xextendf(&ssh->kex->server_sig_algs, ",", "%s", sigalg);
286
0
  }
287
0
  free(oalgs);
288
0
  free(sigalgs);
289
0
  if (ssh->kex->server_sig_algs == NULL)
290
0
    ssh->kex->server_sig_algs = xstrdup("");
291
0
}
292
293
static int
294
kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m)
295
0
{
296
0
  int r;
297
298
0
  if (ssh->kex->server_sig_algs == NULL &&
299
0
      (ssh->kex->server_sig_algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
300
0
    return SSH_ERR_ALLOC_FAIL;
301
0
  if ((r = sshbuf_put_u32(m, 4)) != 0 ||
302
0
      (r = sshbuf_put_cstring(m, "server-sig-algs")) != 0 ||
303
0
      (r = sshbuf_put_cstring(m, ssh->kex->server_sig_algs)) != 0 ||
304
0
      (r = sshbuf_put_cstring(m,
305
0
      "publickey-hostbound@openssh.com")) != 0 ||
306
0
      (r = sshbuf_put_cstring(m, "0")) != 0 ||
307
0
      (r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 ||
308
0
      (r = sshbuf_put_cstring(m, "0")) != 0 ||
309
0
      (r = sshbuf_put_cstring(m, "agent-forward")) != 0 ||
310
0
      (r = sshbuf_put_cstring(m, "0")) != 0) {
311
0
    error_fr(r, "compose");
312
0
    return r;
313
0
  }
314
0
  return 0;
315
0
}
316
317
static int
318
kex_compose_ext_info_client(struct ssh *ssh, struct sshbuf *m)
319
0
{
320
0
  int r;
321
322
0
  if ((r = sshbuf_put_u32(m, 1)) != 0 ||
323
0
      (r = sshbuf_put_cstring(m, "ext-info-in-auth@openssh.com")) != 0 ||
324
0
      (r = sshbuf_put_cstring(m, "0")) != 0) {
325
0
    error_fr(r, "compose");
326
0
    goto out;
327
0
  }
328
  /* success */
329
0
  r = 0;
330
0
 out:
331
0
  return r;
332
0
}
333
334
static int
335
kex_maybe_send_ext_info(struct ssh *ssh)
336
0
{
337
0
  int r;
338
0
  struct sshbuf *m = NULL;
339
340
0
  if ((ssh->kex->flags & KEX_INITIAL) == 0)
341
0
    return 0;
342
0
  if (!ssh->kex->ext_info_c && !ssh->kex->ext_info_s)
343
0
    return 0;
344
345
  /* Compose EXT_INFO packet. */
346
0
  if ((m = sshbuf_new()) == NULL)
347
0
    fatal_f("sshbuf_new failed");
348
0
  if (ssh->kex->ext_info_c &&
349
0
      (r = kex_compose_ext_info_server(ssh, m)) != 0)
350
0
    goto fail;
351
0
  if (ssh->kex->ext_info_s &&
352
0
      (r = kex_compose_ext_info_client(ssh, m)) != 0)
353
0
    goto fail;
354
355
  /* Send the actual KEX_INFO packet */
356
0
  debug("Sending SSH2_MSG_EXT_INFO");
357
0
  if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
358
0
      (r = sshpkt_putb(ssh, m)) != 0 ||
359
0
      (r = sshpkt_send(ssh)) != 0) {
360
0
    error_f("send EXT_INFO");
361
0
    goto fail;
362
0
  }
363
364
0
  r = 0;
365
366
0
 fail:
367
0
  sshbuf_free(m);
368
0
  return r;
369
0
}
370
371
int
372
kex_server_update_ext_info(struct ssh *ssh)
373
0
{
374
0
  int r;
375
376
0
  if ((ssh->kex->flags & KEX_HAS_EXT_INFO_IN_AUTH) == 0)
377
0
    return 0;
378
379
0
  debug_f("Sending SSH2_MSG_EXT_INFO");
380
0
  if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
381
0
      (r = sshpkt_put_u32(ssh, 1)) != 0 ||
382
0
      (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
383
0
      (r = sshpkt_put_cstring(ssh, ssh->kex->server_sig_algs)) != 0 ||
384
0
      (r = sshpkt_send(ssh)) != 0) {
385
0
    error_f("send EXT_INFO");
386
0
    return r;
387
0
  }
388
0
  return 0;
389
0
}
390
391
int
392
kex_send_newkeys(struct ssh *ssh)
393
0
{
394
0
  int r;
395
396
0
  kex_reset_dispatch(ssh);
397
0
  if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
398
0
      (r = sshpkt_send(ssh)) != 0)
399
0
    return r;
400
0
  debug("SSH2_MSG_NEWKEYS sent");
401
0
  ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
402
0
  if ((r = kex_maybe_send_ext_info(ssh)) != 0)
403
0
    return r;
404
0
  debug("expecting SSH2_MSG_NEWKEYS");
405
0
  return 0;
406
0
}
407
408
/* Check whether an ext_info value contains the expected version string */
409
static int
410
kex_ext_info_check_ver(struct kex *kex, const char *name,
411
    const u_char *val, size_t len, const char *want_ver, u_int flag)
412
0
{
413
0
  if (memchr(val, '\0', len) != NULL) {
414
0
    error("SSH2_MSG_EXT_INFO: %s value contains nul byte", name);
415
0
    return SSH_ERR_INVALID_FORMAT;
416
0
  }
417
0
  debug_f("%s=<%s>", name, val);
418
0
  if (strcmp(val, want_ver) == 0)
419
0
    kex->flags |= flag;
420
0
  else
421
0
    debug_f("unsupported version of %s extension", name);
422
0
  return 0;
423
0
}
424
425
static int
426
kex_ext_info_client_parse(struct ssh *ssh, const char *name,
427
    const u_char *value, size_t vlen)
428
0
{
429
0
  int r;
430
431
  /* NB. some messages are only accepted in the initial EXT_INFO */
432
0
  if (strcmp(name, "server-sig-algs") == 0) {
433
    /* Ensure no \0 lurking in value */
434
0
    if (memchr(value, '\0', vlen) != NULL) {
435
0
      error_f("nul byte in %s", name);
436
0
      return SSH_ERR_INVALID_FORMAT;
437
0
    }
438
0
    debug_f("%s=<%s>", name, value);
439
0
    free(ssh->kex->server_sig_algs);
440
0
    ssh->kex->server_sig_algs = xstrdup((const char *)value);
441
0
  } else if (ssh->kex->ext_info_received == 1 &&
442
0
      strcmp(name, "publickey-hostbound@openssh.com") == 0) {
443
0
    if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
444
0
        "0", KEX_HAS_PUBKEY_HOSTBOUND)) != 0) {
445
0
      return r;
446
0
    }
447
0
  } else if (ssh->kex->ext_info_received == 1 &&
448
0
      strcmp(name, "ping@openssh.com") == 0) {
449
0
    if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
450
0
        "0", KEX_HAS_PING)) != 0) {
451
0
      return r;
452
0
    }
453
0
  } else if (ssh->kex->ext_info_received == 1 &&
454
0
      strcmp(name, "agent-forward") == 0) {
455
0
    if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
456
0
        "0", KEX_HAS_NEWAGENT)) != 0) {
457
0
      return r;
458
0
    }
459
0
  } else
460
0
    debug_f("%s (unrecognised)", name);
461
462
0
  return 0;
463
0
}
464
465
static int
466
kex_ext_info_server_parse(struct ssh *ssh, const char *name,
467
    const u_char *value, size_t vlen)
468
0
{
469
0
  int r;
470
471
0
  if (strcmp(name, "ext-info-in-auth@openssh.com") == 0) {
472
0
    if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
473
0
        "0", KEX_HAS_EXT_INFO_IN_AUTH)) != 0) {
474
0
      return r;
475
0
    }
476
0
  } else
477
0
    debug_f("%s (unrecognised)", name);
478
0
  return 0;
479
0
}
480
481
int
482
kex_input_ext_info(int type, uint32_t seq, struct ssh *ssh)
483
0
{
484
0
  struct kex *kex = ssh->kex;
485
0
  const int max_ext_info = kex->server ? 1 : 2;
486
0
  uint32_t i, ninfo;
487
0
  char *name;
488
0
  u_char *val;
489
0
  size_t vlen;
490
0
  int r;
491
492
0
  debug("SSH2_MSG_EXT_INFO received");
493
0
  if (++kex->ext_info_received > max_ext_info) {
494
0
    error("too many SSH2_MSG_EXT_INFO messages sent by peer");
495
0
    return dispatch_protocol_error(type, seq, ssh);
496
0
  }
497
0
  ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
498
0
  if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
499
0
    return r;
500
0
  if (ninfo >= 1024) {
501
0
    error("SSH2_MSG_EXT_INFO with too many entries, expected "
502
0
        "<=1024, received %u", ninfo);
503
0
    return dispatch_protocol_error(type, seq, ssh);
504
0
  }
505
0
  for (i = 0; i < ninfo; i++) {
506
0
    if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
507
0
      return r;
508
0
    if ((r = sshpkt_get_string(ssh, &val, &vlen)) != 0) {
509
0
      free(name);
510
0
      return r;
511
0
    }
512
0
    debug3_f("extension %s", name);
513
0
    if (kex->server) {
514
0
      if ((r = kex_ext_info_server_parse(ssh, name,
515
0
          val, vlen)) != 0)
516
0
        return r;
517
0
    } else {
518
0
      if ((r = kex_ext_info_client_parse(ssh, name,
519
0
          val, vlen)) != 0)
520
0
        return r;
521
0
    }
522
0
    free(name);
523
0
    free(val);
524
0
  }
525
0
  return sshpkt_get_end(ssh);
526
0
}
527
528
static int
529
kex_input_newkeys(int type, uint32_t seq, struct ssh *ssh)
530
0
{
531
0
  struct kex *kex = ssh->kex;
532
0
  int r, initial = (kex->flags & KEX_INITIAL) != 0;
533
0
  char *cp, **prop;
534
535
0
  debug("SSH2_MSG_NEWKEYS received");
536
0
  if (kex->ext_info_c && initial)
537
0
    ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_input_ext_info);
538
0
  ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
539
0
  ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
540
0
  if ((r = sshpkt_get_end(ssh)) != 0)
541
0
    return r;
542
0
  if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0)
543
0
    return r;
544
0
  if (initial) {
545
    /* Remove initial KEX signalling from proposal for rekeying */
546
0
    if ((r = kex_buf2prop(kex->my, NULL, &prop)) != 0)
547
0
      return r;
548
0
    if ((cp = match_filter_denylist(prop[PROPOSAL_KEX_ALGS],
549
0
        kex->server ?
550
0
        "ext-info-s,kex-strict-s-v00@openssh.com" :
551
0
        "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL) {
552
0
      error_f("match_filter_denylist failed");
553
0
      goto fail;
554
0
    }
555
0
    free(prop[PROPOSAL_KEX_ALGS]);
556
0
    prop[PROPOSAL_KEX_ALGS] = cp;
557
0
    if ((r = kex_prop2buf(ssh->kex->my, prop)) != 0) {
558
0
      error_f("kex_prop2buf failed");
559
0
 fail:
560
0
      kex_proposal_free_entries(prop);
561
0
      free(prop);
562
0
      return SSH_ERR_INTERNAL_ERROR;
563
0
    }
564
0
    kex_proposal_free_entries(prop);
565
0
    free(prop);
566
0
  }
567
0
  kex->done = 1;
568
0
  kex->flags &= ~KEX_INITIAL;
569
0
  sshbuf_reset(kex->peer);
570
0
  kex->flags &= ~KEX_INIT_SENT;
571
0
  return 0;
572
0
}
573
574
int
575
kex_send_kexinit(struct ssh *ssh)
576
17.7k
{
577
17.7k
  u_char *cookie;
578
17.7k
  struct kex *kex = ssh->kex;
579
17.7k
  int r;
580
581
17.7k
  if (kex == NULL) {
582
0
    error_f("no kex");
583
0
    return SSH_ERR_INTERNAL_ERROR;
584
0
  }
585
17.7k
  if (kex->flags & KEX_INIT_SENT)
586
0
    return 0;
587
17.7k
  kex->done = 0;
588
589
  /* generate a random cookie */
590
17.7k
  if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) {
591
0
    error_f("bad kex length: %zu < %d",
592
0
        sshbuf_len(kex->my), KEX_COOKIE_LEN);
593
0
    return SSH_ERR_INVALID_FORMAT;
594
0
  }
595
17.7k
  if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) {
596
0
    error_f("buffer error");
597
0
    return SSH_ERR_INTERNAL_ERROR;
598
0
  }
599
17.7k
  arc4random_buf(cookie, KEX_COOKIE_LEN);
600
601
17.7k
  if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
602
17.7k
      (r = sshpkt_putb(ssh, kex->my)) != 0 ||
603
17.7k
      (r = sshpkt_send(ssh)) != 0) {
604
0
    error_fr(r, "compose reply");
605
0
    return r;
606
0
  }
607
17.7k
  debug("SSH2_MSG_KEXINIT sent");
608
17.7k
  kex->flags |= KEX_INIT_SENT;
609
17.7k
  return 0;
610
17.7k
}
611
612
int
613
kex_input_kexinit(int type, uint32_t seq, struct ssh *ssh)
614
8.19k
{
615
8.19k
  struct kex *kex = ssh->kex;
616
8.19k
  const u_char *ptr;
617
8.19k
  u_int i;
618
8.19k
  size_t dlen;
619
8.19k
  int r;
620
621
8.19k
  debug("SSH2_MSG_KEXINIT received");
622
8.19k
  if (kex == NULL) {
623
0
    error_f("no kex");
624
0
    return SSH_ERR_INTERNAL_ERROR;
625
0
  }
626
8.19k
  free(kex->name);
627
8.19k
  kex->name = NULL;
628
8.19k
  ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error);
629
8.19k
  ptr = sshpkt_ptr(ssh, &dlen);
630
8.19k
  if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
631
0
    return r;
632
633
  /* discard packet */
634
134k
  for (i = 0; i < KEX_COOKIE_LEN; i++) {
635
126k
    if ((r = sshpkt_get_u8(ssh, NULL)) != 0) {
636
465
      error_fr(r, "discard cookie");
637
465
      return r;
638
465
    }
639
126k
  }
640
59.5k
  for (i = 0; i < PROPOSAL_MAX; i++) {
641
54.7k
    if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
642
2.89k
      error_fr(r, "discard proposal");
643
2.89k
      return r;
644
2.89k
    }
645
54.7k
  }
646
  /*
647
   * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
648
   * KEX method has the server move first, but a server might be using
649
   * a custom method or one that we otherwise don't support. We should
650
   * be prepared to remember first_kex_follows here so we can eat a
651
   * packet later.
652
   * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
653
   * for cases where the server *doesn't* go first. I guess we should
654
   * ignore it when it is set for these cases, which is what we do now.
655
   */
656
4.83k
  if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */
657
4.78k
      (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */
658
4.71k
      (r = sshpkt_get_end(ssh)) != 0)
659
750
      return r;
660
661
4.08k
  if (!(kex->flags & KEX_INIT_SENT))
662
0
    if ((r = kex_send_kexinit(ssh)) != 0)
663
0
      return r;
664
4.08k
  if ((r = kex_choose_conf(ssh, seq)) != 0)
665
4.08k
    return r;
666
667
0
  if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
668
0
    return (kex->kex[kex->kex_type])(ssh);
669
670
0
  error_f("unknown kex type %u", kex->kex_type);
671
0
  return SSH_ERR_INTERNAL_ERROR;
672
0
}
673
674
struct kex *
675
kex_new(void)
676
59.4k
{
677
59.4k
  struct kex *kex;
678
679
59.4k
  if ((kex = calloc(1, sizeof(*kex))) == NULL ||
680
59.4k
      (kex->peer = sshbuf_new()) == NULL ||
681
59.4k
      (kex->my = sshbuf_new()) == NULL ||
682
59.4k
      (kex->client_version = sshbuf_new()) == NULL ||
683
59.4k
      (kex->server_version = sshbuf_new()) == NULL ||
684
59.4k
      (kex->session_id = sshbuf_new()) == NULL) {
685
0
    kex_free(kex);
686
0
    return NULL;
687
0
  }
688
59.4k
  return kex;
689
59.4k
}
690
691
void
692
kex_free_newkeys(struct newkeys *newkeys)
693
237k
{
694
237k
  if (newkeys == NULL)
695
237k
    return;
696
93
  if (newkeys->enc.key) {
697
0
    explicit_bzero(newkeys->enc.key, newkeys->enc.key_len);
698
0
    free(newkeys->enc.key);
699
0
    newkeys->enc.key = NULL;
700
0
  }
701
93
  if (newkeys->enc.iv) {
702
0
    explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
703
0
    free(newkeys->enc.iv);
704
0
    newkeys->enc.iv = NULL;
705
0
  }
706
93
  free(newkeys->enc.name);
707
93
  explicit_bzero(&newkeys->enc, sizeof(newkeys->enc));
708
93
  free(newkeys->comp.name);
709
93
  explicit_bzero(&newkeys->comp, sizeof(newkeys->comp));
710
93
  mac_clear(&newkeys->mac);
711
93
  if (newkeys->mac.key) {
712
0
    explicit_bzero(newkeys->mac.key, newkeys->mac.key_len);
713
0
    free(newkeys->mac.key);
714
0
    newkeys->mac.key = NULL;
715
0
  }
716
93
  free(newkeys->mac.name);
717
93
  explicit_bzero(&newkeys->mac, sizeof(newkeys->mac));
718
93
  freezero(newkeys, sizeof(*newkeys));
719
93
}
720
721
void
722
kex_free(struct kex *kex)
723
59.4k
{
724
59.4k
  u_int mode;
725
726
59.4k
  if (kex == NULL)
727
0
    return;
728
729
59.4k
#ifdef WITH_OPENSSL
730
59.4k
  DH_free(kex->dh);
731
59.4k
#ifdef OPENSSL_HAS_ECC
732
59.4k
  EC_KEY_free(kex->ec_client_key);
733
59.4k
#endif /* OPENSSL_HAS_ECC */
734
59.4k
#endif /* WITH_OPENSSL */
735
178k
  for (mode = 0; mode < MODE_MAX; mode++) {
736
118k
    kex_free_newkeys(kex->newkeys[mode]);
737
118k
    kex->newkeys[mode] = NULL;
738
118k
  }
739
59.4k
  sshbuf_free(kex->peer);
740
59.4k
  sshbuf_free(kex->my);
741
59.4k
  sshbuf_free(kex->client_version);
742
59.4k
  sshbuf_free(kex->server_version);
743
59.4k
  sshbuf_free(kex->client_pub);
744
59.4k
  sshbuf_free(kex->session_id);
745
59.4k
  sshbuf_free(kex->initial_sig);
746
59.4k
  sshkey_free(kex->initial_hostkey);
747
59.4k
  free(kex->failed_choice);
748
59.4k
  free(kex->hostkey_alg);
749
59.4k
  free(kex->name);
750
59.4k
  free(kex->server_sig_algs);
751
59.4k
  free(kex);
752
59.4k
}
753
754
/*
755
 * This function seeks through a comma-separated list and checks for instances
756
 * of the multithreaded CC20 cipher. If found, it then ensures that the serial
757
 * CC20 cipher is also in the list, adding it if necessary.
758
 */
759
char *
760
patch_list(char * orig)
761
118k
{
762
118k
  char * adj = xstrdup(orig);
763
118k
  char * match;
764
118k
  u_int next;
765
766
118k
  const char * ccpstr = "chacha20-poly1305@openssh.com";
767
118k
  const char * ccpmtstr = "chacha20-poly1305-mt@hpnssh.org";
768
769
118k
  match = match_list(ccpmtstr, orig, &next);
770
118k
  if (match != NULL) { /* CC20-MT found in the list */
771
0
    free(match);
772
0
    match = match_list(ccpstr, orig, NULL);
773
0
    if (match == NULL) { /* CC20-Serial NOT found in the list */
774
0
      adj = xreallocarray(adj,
775
0
          strlen(adj) /* original string length */
776
0
          + 1 /* for the original null-terminator */
777
0
          + strlen(ccpstr) /* make room for ccpstr */
778
0
          + 1 /* make room for the comma delimiter */
779
0
          , sizeof(char));
780
      /*
781
       * adj[next] points to the character after the CC20-MT
782
       * string. adj[next] might be ',' or '\0' at this point.
783
       */
784
0
      adj[next] = ',';
785
      /* adj + next + 1 is the character after that comma */
786
0
      memcpy(adj + next + 1, ccpstr, strlen(ccpstr));
787
      /* rewrite the rest of the original list */
788
0
      memcpy(adj + next + 1 + strlen(ccpstr), orig + next,
789
0
          strlen(orig + next) + 1);
790
0
    } else { /* CC20-Serial found in the list, nothing to do */
791
0
      free(match);
792
0
    }
793
0
  }
794
795
118k
  return adj;
796
118k
}
797
798
int
799
kex_ready(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
800
59.4k
{
801
59.4k
  int r = 0;
802
803
59.4k
#ifdef WITH_OPENSSL
804
59.4k
  char * orig_ctos = proposal[PROPOSAL_ENC_ALGS_CTOS];
805
59.4k
  char * orig_stoc = proposal[PROPOSAL_ENC_ALGS_STOC];
806
59.4k
  proposal[PROPOSAL_ENC_ALGS_CTOS] =
807
59.4k
      patch_list(proposal[PROPOSAL_ENC_ALGS_CTOS]);
808
59.4k
  proposal[PROPOSAL_ENC_ALGS_STOC] =
809
59.4k
      patch_list(proposal[PROPOSAL_ENC_ALGS_STOC]);
810
811
  /*
812
   * TODO: Likely memory leak here. The original contents of
813
   * proposal[PROPOSAL_ENC_ALGS_CTOS] are no longer accessible or
814
   * freeable.
815
   */
816
59.4k
#endif
817
818
59.4k
  if ((r = kex_prop2buf(ssh->kex->my, proposal)) != 0)
819
0
    goto restoreProposal;
820
59.4k
  ssh->kex->flags = KEX_INITIAL;
821
59.4k
  kex_reset_dispatch(ssh);
822
59.4k
  ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
823
59.4k
 restoreProposal:
824
59.4k
#ifdef WITH_OPENSSL
825
59.4k
  free(proposal[PROPOSAL_ENC_ALGS_CTOS]);
826
59.4k
  free(proposal[PROPOSAL_ENC_ALGS_STOC]);
827
59.4k
  proposal[PROPOSAL_ENC_ALGS_CTOS] = orig_ctos;
828
59.4k
  proposal[PROPOSAL_ENC_ALGS_STOC] = orig_stoc;
829
59.4k
#endif
830
59.4k
  return r;
831
59.4k
}
832
833
int
834
kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
835
0
{
836
0
  int r;
837
838
0
  if ((r = kex_ready(ssh, proposal)) != 0)
839
0
    return r;
840
0
  if ((r = kex_send_kexinit(ssh)) != 0) {   /* we start */
841
0
    kex_free(ssh->kex);
842
0
    ssh->kex = NULL;
843
0
    return r;
844
0
  }
845
0
  return 0;
846
0
}
847
848
/*
849
 * Request key re-exchange, returns 0 on success or a ssherr.h error
850
 * code otherwise. Must not be called if KEX is incomplete or in-progress.
851
 */
852
int
853
kex_start_rekex(struct ssh *ssh)
854
0
{
855
0
  if (ssh->kex == NULL) {
856
0
    error_f("no kex");
857
0
    return SSH_ERR_INTERNAL_ERROR;
858
0
  }
859
0
  if (ssh->kex->done == 0) {
860
0
    error_f("requested twice");
861
0
    return SSH_ERR_INTERNAL_ERROR;
862
0
  }
863
0
  ssh->kex->done = 0;
864
0
  return kex_send_kexinit(ssh);
865
0
}
866
867
static int
868
choose_enc(struct sshenc *enc, char *client, char *server)
869
93
{
870
93
  char *name = match_list(client, server, NULL);
871
872
93
  if (name == NULL)
873
18
    return SSH_ERR_NO_CIPHER_ALG_MATCH;
874
75
  if ((enc->cipher = cipher_by_name(name)) == NULL) {
875
0
    error_f("unsupported cipher %s", name);
876
0
    free(name);
877
0
    return SSH_ERR_INTERNAL_ERROR;
878
0
  }
879
75
  enc->name = name;
880
75
  enc->enabled = 0;
881
75
  enc->iv = NULL;
882
75
  enc->iv_len = cipher_ivlen(enc->cipher);
883
75
  enc->key = NULL;
884
75
  enc->key_len = cipher_keylen(enc->cipher);
885
75
  enc->block_size = cipher_blocksize(enc->cipher);
886
75
  return 0;
887
75
}
888
889
static int
890
choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
891
75
{
892
75
  char *name = match_list(client, server, NULL);
893
894
75
  if (name == NULL)
895
31
    return SSH_ERR_NO_MAC_ALG_MATCH;
896
44
  if (mac_setup(mac, name) < 0) {
897
0
    error_f("unsupported MAC %s", name);
898
0
    free(name);
899
0
    return SSH_ERR_INTERNAL_ERROR;
900
0
  }
901
44
  mac->name = name;
902
44
  mac->key = NULL;
903
44
  mac->enabled = 0;
904
44
  return 0;
905
44
}
906
907
static int
908
choose_comp(struct sshcomp *comp, char *client, char *server)
909
44
{
910
44
  char *name = match_list(client, server, NULL);
911
912
44
  if (name == NULL)
913
44
    return SSH_ERR_NO_COMPRESS_ALG_MATCH;
914
0
#ifdef WITH_ZLIB
915
0
  if (strcmp(name, "zlib@openssh.com") == 0) {
916
0
    comp->type = COMP_DELAYED;
917
0
  } else
918
0
#endif  /* WITH_ZLIB */
919
0
  if (strcmp(name, "none") == 0) {
920
0
    comp->type = COMP_NONE;
921
0
  } else {
922
0
    error_f("unsupported compression scheme %s", name);
923
0
    free(name);
924
0
    return SSH_ERR_INTERNAL_ERROR;
925
0
  }
926
0
  comp->name = name;
927
0
  return 0;
928
0
}
929
930
static int
931
choose_kex(struct kex *k, char *client, char *server)
932
3.70k
{
933
3.70k
  k->name = match_list(client, server, NULL);
934
935
3.70k
  debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
936
3.70k
  if (k->name == NULL)
937
3.18k
    return SSH_ERR_NO_KEX_ALG_MATCH;
938
516
  if (!kex_name_valid(k->name)) {
939
135
    error_f("unsupported KEX method %s", k->name);
940
135
    return SSH_ERR_INTERNAL_ERROR;
941
135
  }
942
381
  k->kex_type = kex_type_from_name(k->name);
943
381
  k->hash_alg = kex_hash_from_name(k->name);
944
381
  k->ec_nid = kex_nid_from_name(k->name);
945
381
  return 0;
946
516
}
947
948
static int
949
choose_hostkeyalg(struct kex *k, char *client, char *server)
950
381
{
951
381
  free(k->hostkey_alg);
952
381
  k->hostkey_alg = match_list(client, server, NULL);
953
954
381
  debug("kex: host key algorithm: %s",
955
381
      k->hostkey_alg ? k->hostkey_alg : "(no match)");
956
381
  if (k->hostkey_alg == NULL)
957
288
    return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
958
93
  k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
959
93
  if (k->hostkey_type == KEY_UNSPEC) {
960
0
    error_f("unsupported hostkey algorithm %s", k->hostkey_alg);
961
0
    return SSH_ERR_INTERNAL_ERROR;
962
0
  }
963
93
  k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
964
93
  return 0;
965
93
}
966
967
static int
968
proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
969
0
{
970
0
  static int check[] = {
971
0
    PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
972
0
  };
973
0
  int *idx;
974
0
  char *p;
975
976
0
  for (idx = &check[0]; *idx != -1; idx++) {
977
0
    if ((p = strchr(my[*idx], ',')) != NULL)
978
0
      *p = '\0';
979
0
    if ((p = strchr(peer[*idx], ',')) != NULL)
980
0
      *p = '\0';
981
0
    if (strcmp(my[*idx], peer[*idx]) != 0) {
982
0
      debug2("proposal mismatch: my %s peer %s",
983
0
          my[*idx], peer[*idx]);
984
0
      return (0);
985
0
    }
986
0
  }
987
0
  debug2("proposals match");
988
0
  return (1);
989
0
}
990
991
static int
992
kexalgs_contains(char **peer, const char *ext)
993
7.41k
{
994
7.41k
  return kex_has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);
995
7.41k
}
996
997
static int
998
kex_choose_conf(struct ssh *ssh, uint32_t seq)
999
4.08k
{
1000
4.08k
  struct kex *kex = ssh->kex;
1001
4.08k
  struct newkeys *newkeys;
1002
4.08k
  char **my = NULL, **peer = NULL;
1003
4.08k
  char **cprop, **sprop;
1004
4.08k
  int nenc, nmac, ncomp;
1005
4.08k
  u_int mode, ctos, need, dh_need, authlen;
1006
4.08k
  int r, first_kex_follows;
1007
4.08k
  int auth_flag = 0;
1008
4.08k
  int log_flag = 0;
1009
1010
4.08k
  auth_flag = packet_authentication_state(ssh);
1011
4.08k
  debug("AUTH STATE IS %d", auth_flag);
1012
1013
4.08k
  debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
1014
4.08k
  if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
1015
0
    goto out;
1016
4.08k
  debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
1017
4.08k
  if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
1018
375
    goto out;
1019
1020
3.70k
  if (kex->server) {
1021
1.75k
    cprop=peer;
1022
1.75k
    sprop=my;
1023
1.95k
  } else {
1024
1.95k
    cprop=my;
1025
1.95k
    sprop=peer;
1026
1.95k
  }
1027
1028
  /* Check whether peer supports ext_info/kex_strict */
1029
3.70k
  if ((kex->flags & KEX_INITIAL) != 0) {
1030
3.70k
    if (kex->server) {
1031
1.75k
      kex->ext_info_c = kexalgs_contains(peer, "ext-info-c");
1032
1.75k
      kex->kex_strict = kexalgs_contains(peer,
1033
1.75k
          "kex-strict-c-v00@openssh.com");
1034
1.95k
    } else {
1035
1.95k
      kex->ext_info_s = kexalgs_contains(peer, "ext-info-s");
1036
1.95k
      kex->kex_strict = kexalgs_contains(peer,
1037
1.95k
          "kex-strict-s-v00@openssh.com");
1038
1.95k
    }
1039
3.70k
    if (kex->kex_strict) {
1040
15
      debug3_f("will use strict KEX ordering");
1041
15
      if (seq != 0)
1042
0
        ssh_packet_disconnect(ssh,
1043
0
            "strict KEX violation: "
1044
0
            "KEXINIT was not the first packet");
1045
15
    }
1046
3.70k
  }
1047
1048
  /* Check whether client supports rsa-sha2 algorithms */
1049
3.70k
  if (kex->server && (kex->flags & KEX_INITIAL)) {
1050
1.75k
    if (kex_has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],
1051
1.75k
        "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com"))
1052
15
      kex->flags |= KEX_RSA_SHA2_256_SUPPORTED;
1053
1.75k
    if (kex_has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],
1054
1.75k
        "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com"))
1055
0
      kex->flags |= KEX_RSA_SHA2_512_SUPPORTED;
1056
1.75k
  }
1057
1058
  /* Algorithm Negotiation */
1059
3.70k
  if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
1060
3.70k
      sprop[PROPOSAL_KEX_ALGS])) != 0) {
1061
3.32k
    kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
1062
3.32k
    peer[PROPOSAL_KEX_ALGS] = NULL;
1063
3.32k
    goto out;
1064
3.32k
  }
1065
381
  if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
1066
381
      sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
1067
288
    kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
1068
288
    peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
1069
288
    goto out;
1070
288
  }
1071
93
  for (mode = 0; mode < MODE_MAX; mode++) {
1072
93
    if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
1073
0
      r = SSH_ERR_ALLOC_FAIL;
1074
0
      goto out;
1075
0
    }
1076
93
    kex->newkeys[mode] = newkeys;
1077
93
    ctos = (!kex->server && mode == MODE_OUT) ||
1078
93
        (kex->server && mode == MODE_IN);
1079
93
    nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
1080
93
    nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
1081
93
    ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
1082
93
    if ((r = choose_enc(&newkeys->enc, cprop[nenc],
1083
93
        sprop[nenc])) != 0) {
1084
18
      kex->failed_choice = peer[nenc];
1085
18
      peer[nenc] = NULL;
1086
18
      goto out;
1087
18
    }
1088
75
#ifdef WITH_OPENSSL
1089
75
    if ((strcmp(newkeys->enc.name, "chacha20-poly1305@openssh.com")
1090
75
        == 0) && (match_list("chacha20-poly1305-mt@hpnssh.org",
1091
0
        my[nenc], NULL) != NULL)) {
1092
      /*
1093
       * if we're using the serial CC20 cipher while the
1094
       * multithreaded implementation is an option...
1095
       */
1096
0
      free(newkeys->enc.name);
1097
0
      newkeys->enc.cipher = cipher_by_name(
1098
0
          "chacha20-poly1305-mt@hpnssh.org");
1099
0
      if (newkeys->enc.cipher == NULL) {
1100
0
        error_f("%s cipher not found.",
1101
0
            "chacha20-poly1305-mt@hpnssh.org");
1102
0
        r = SSH_ERR_INTERNAL_ERROR;
1103
0
        kex->failed_choice = peer[nenc];
1104
0
        peer[nenc] = NULL;
1105
0
        goto out;
1106
0
      } else {
1107
0
        newkeys->enc.name = xstrdup(
1108
0
            "chacha20-poly1305-mt@hpnssh.org");
1109
0
      }
1110
      /* we promote to the multithreaded implementation */
1111
0
    }
1112
75
#endif
1113
75
    authlen = cipher_authlen(newkeys->enc.cipher);
1114
    /* ignore mac for authenticated encryption */
1115
75
    if (authlen == 0 &&
1116
75
        (r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
1117
75
        sprop[nmac])) != 0) {
1118
31
      kex->failed_choice = peer[nmac];
1119
31
      peer[nmac] = NULL;
1120
31
      goto out;
1121
31
    }
1122
44
    if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
1123
44
        sprop[ncomp])) != 0) {
1124
44
      kex->failed_choice = peer[ncomp];
1125
44
      peer[ncomp] = NULL;
1126
44
      goto out;
1127
44
    }
1128
0
    debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name);
1129
0
    debug("REQUESTED MAC.NAME is '%s'", newkeys->mac.name);
1130
0
    if (strcmp(newkeys->enc.name, "none") == 0) {
1131
0
      if (auth_flag == 1) {
1132
0
        debug("None requested post authentication.");
1133
0
        ssh->none = 1;
1134
0
      }
1135
0
      else
1136
0
        fatal("Pre-authentication none cipher requests are not allowed.");
1137
1138
0
      if (newkeys->mac.name != NULL && strcmp(newkeys->mac.name, "none") == 0) {
1139
0
        debug("Requesting: NONEMAC. Authflag is %d", auth_flag);
1140
0
        ssh->none_mac = 1;
1141
0
      }
1142
0
    }
1143
1144
0
    debug("kex: %s cipher: %s MAC: %s compression: %s",
1145
0
        ctos ? "client->server" : "server->client",
1146
0
        newkeys->enc.name,
1147
0
        authlen == 0 ? newkeys->mac.name : "<implicit>",
1148
0
        newkeys->comp.name);
1149
    /*
1150
     * client starts with ctos = 0 && log flag = 0 and no log.
1151
     * 2nd client pass ctos = 1 and flag = 1 so no log.
1152
     * server starts with ctos = 1 && log_flag = 0 so log.
1153
     * 2nd sever pass ctos = 1 && log flag = 1 so no log.
1154
     * -cjr
1155
     */
1156
0
    if (ctos && !log_flag) {
1157
0
      logit("SSH: Server;Ltype: Kex;Remote: %s-%d;Enc: %s;MAC: %s;Comp: %s",
1158
0
          ssh_remote_ipaddr(ssh),
1159
0
          ssh_remote_port(ssh),
1160
0
          newkeys->enc.name,
1161
0
          authlen == 0 ? newkeys->mac.name : "<implicit>",
1162
0
          newkeys->comp.name);
1163
0
    }
1164
0
    log_flag = 1;
1165
0
  }
1166
0
  need = dh_need = 0;
1167
0
  for (mode = 0; mode < MODE_MAX; mode++) {
1168
0
    newkeys = kex->newkeys[mode];
1169
0
    need = MAXIMUM(need, newkeys->enc.key_len);
1170
0
    need = MAXIMUM(need, newkeys->enc.block_size);
1171
0
    need = MAXIMUM(need, newkeys->enc.iv_len);
1172
0
    need = MAXIMUM(need, newkeys->mac.key_len);
1173
0
    dh_need = MAXIMUM(dh_need, cipher_seclen(newkeys->enc.cipher));
1174
0
    dh_need = MAXIMUM(dh_need, newkeys->enc.block_size);
1175
0
    dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len);
1176
0
    dh_need = MAXIMUM(dh_need, newkeys->mac.key_len);
1177
0
  }
1178
  /* XXX need runden? */
1179
0
  kex->we_need = need;
1180
0
  kex->dh_need = dh_need;
1181
1182
  /* ignore the next message if the proposals do not match */
1183
0
  if (first_kex_follows && !proposals_match(my, peer))
1184
0
    ssh->dispatch_skip_packets = 1;
1185
0
  r = 0;
1186
4.08k
 out:
1187
4.08k
  kex_prop_free(my);
1188
4.08k
  kex_prop_free(peer);
1189
4.08k
  return r;
1190
0
}
1191
1192
static int
1193
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
1194
    const struct sshbuf *shared_secret, u_char **keyp)
1195
0
{
1196
0
  struct kex *kex = ssh->kex;
1197
0
  struct ssh_digest_ctx *hashctx = NULL;
1198
0
  char c = id;
1199
0
  u_int have;
1200
0
  size_t mdsz;
1201
0
  u_char *digest;
1202
0
  int r;
1203
1204
0
  if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
1205
0
    return SSH_ERR_INVALID_ARGUMENT;
1206
0
  if ((digest = calloc(1, ROUNDUP(need, mdsz))) == NULL) {
1207
0
    r = SSH_ERR_ALLOC_FAIL;
1208
0
    goto out;
1209
0
  }
1210
1211
  /* K1 = HASH(K || H || "A" || session_id) */
1212
0
  if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
1213
0
      ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
1214
0
      ssh_digest_update(hashctx, hash, hashlen) != 0 ||
1215
0
      ssh_digest_update(hashctx, &c, 1) != 0 ||
1216
0
      ssh_digest_update_buffer(hashctx, kex->session_id) != 0 ||
1217
0
      ssh_digest_final(hashctx, digest, mdsz) != 0) {
1218
0
    r = SSH_ERR_LIBCRYPTO_ERROR;
1219
0
    error_f("KEX hash failed");
1220
0
    goto out;
1221
0
  }
1222
0
  ssh_digest_free(hashctx);
1223
0
  hashctx = NULL;
1224
1225
  /*
1226
   * expand key:
1227
   * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
1228
   * Key = K1 || K2 || ... || Kn
1229
   */
1230
0
  for (have = mdsz; need > have; have += mdsz) {
1231
0
    if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
1232
0
        ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
1233
0
        ssh_digest_update(hashctx, hash, hashlen) != 0 ||
1234
0
        ssh_digest_update(hashctx, digest, have) != 0 ||
1235
0
        ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
1236
0
      error_f("KDF failed");
1237
0
      r = SSH_ERR_LIBCRYPTO_ERROR;
1238
0
      goto out;
1239
0
    }
1240
0
    ssh_digest_free(hashctx);
1241
0
    hashctx = NULL;
1242
0
  }
1243
#ifdef DEBUG_KEX
1244
  fprintf(stderr, "key '%c'== ", c);
1245
  dump_digest("key", digest, need);
1246
#endif
1247
0
  *keyp = digest;
1248
0
  digest = NULL;
1249
0
  r = 0;
1250
0
 out:
1251
0
  free(digest);
1252
0
  ssh_digest_free(hashctx);
1253
0
  return r;
1254
0
}
1255
1256
0
#define NKEYS 6
1257
int
1258
kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
1259
    const struct sshbuf *shared_secret)
1260
0
{
1261
0
  struct kex *kex = ssh->kex;
1262
0
  u_char *keys[NKEYS];
1263
0
  u_int i, j, mode, ctos;
1264
0
  int r;
1265
1266
  /* save initial hash as session id */
1267
0
  if ((kex->flags & KEX_INITIAL) != 0) {
1268
0
    if (sshbuf_len(kex->session_id) != 0) {
1269
0
      error_f("already have session ID at kex");
1270
0
      return SSH_ERR_INTERNAL_ERROR;
1271
0
    }
1272
0
    if ((r = sshbuf_put(kex->session_id, hash, hashlen)) != 0)
1273
0
      return r;
1274
0
  } else if (sshbuf_len(kex->session_id) == 0) {
1275
0
    error_f("no session ID in rekex");
1276
0
    return SSH_ERR_INTERNAL_ERROR;
1277
0
  }
1278
0
  for (i = 0; i < NKEYS; i++) {
1279
0
    if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
1280
0
        shared_secret, &keys[i])) != 0) {
1281
0
      for (j = 0; j < i; j++)
1282
0
        free(keys[j]);
1283
0
      return r;
1284
0
    }
1285
0
  }
1286
0
  for (mode = 0; mode < MODE_MAX; mode++) {
1287
0
    ctos = (!kex->server && mode == MODE_OUT) ||
1288
0
        (kex->server && mode == MODE_IN);
1289
0
    kex->newkeys[mode]->enc.iv  = keys[ctos ? 0 : 1];
1290
0
    kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
1291
0
    kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
1292
0
  }
1293
0
  return 0;
1294
0
}
1295
1296
int
1297
kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp)
1298
0
{
1299
0
  struct kex *kex = ssh->kex;
1300
1301
0
  *pubp = NULL;
1302
0
  *prvp = NULL;
1303
0
  if (kex->load_host_public_key == NULL ||
1304
0
      kex->load_host_private_key == NULL) {
1305
0
    error_f("missing hostkey loader");
1306
0
    return SSH_ERR_INVALID_ARGUMENT;
1307
0
  }
1308
0
  *pubp = kex->load_host_public_key(kex->hostkey_type,
1309
0
      kex->hostkey_nid, ssh);
1310
0
  *prvp = kex->load_host_private_key(kex->hostkey_type,
1311
0
      kex->hostkey_nid, ssh);
1312
0
  if (*pubp == NULL)
1313
0
    return SSH_ERR_NO_HOSTKEY_LOADED;
1314
0
  return 0;
1315
0
}
1316
1317
int
1318
kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key)
1319
0
{
1320
0
  struct kex *kex = ssh->kex;
1321
1322
0
  if (kex->verify_host_key == NULL) {
1323
0
    error_f("missing hostkey verifier");
1324
0
    return SSH_ERR_INVALID_ARGUMENT;
1325
0
  }
1326
0
  if (server_host_key->type != kex->hostkey_type ||
1327
0
      (kex->hostkey_type == KEY_ECDSA &&
1328
0
      server_host_key->ecdsa_nid != kex->hostkey_nid))
1329
0
    return SSH_ERR_KEY_TYPE_MISMATCH;
1330
0
  if (kex->verify_host_key(server_host_key, ssh) == -1)
1331
0
    return  SSH_ERR_SIGNATURE_INVALID;
1332
0
  return 0;
1333
0
}
1334
1335
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
1336
void
1337
dump_digest(const char *msg, const u_char *digest, int len)
1338
{
1339
  fprintf(stderr, "%s\n", msg);
1340
  sshbuf_dump_data(digest, len, stderr);
1341
}
1342
#endif
1343
1344
/*
1345
 * Send a plaintext error message to the peer, suffixed by \r\n.
1346
 * Only used during banner exchange, and there only for the server.
1347
 */
1348
static void
1349
send_error(struct ssh *ssh, char *msg)
1350
0
{
1351
0
  char *crnl = "\r\n";
1352
1353
0
  if (!ssh->kex->server)
1354
0
    return;
1355
1356
0
  if (atomicio(vwrite, ssh_packet_get_connection_out(ssh),
1357
0
      msg, strlen(msg)) != strlen(msg) ||
1358
0
      atomicio(vwrite, ssh_packet_get_connection_out(ssh),
1359
0
      crnl, strlen(crnl)) != strlen(crnl))
1360
0
    error_f("write: %.100s", strerror(errno));
1361
0
}
1362
1363
/*
1364
 * Sends our identification string and waits for the peer's. Will block for
1365
 * up to timeout_ms (or indefinitely if timeout_ms <= 0).
1366
 * Returns on 0 success or a ssherr.h code on failure.
1367
 */
1368
int
1369
kex_exchange_identification(struct ssh *ssh, int timeout_ms,
1370
    const char *version_addendum)
1371
0
{
1372
0
  int remote_major, remote_minor, mismatch, oerrno = 0;
1373
0
  size_t len, n;
1374
0
  int r, expect_nl;
1375
0
  u_char c;
1376
0
  struct sshbuf *our_version = ssh->kex->server ?
1377
0
      ssh->kex->server_version : ssh->kex->client_version;
1378
0
  struct sshbuf *peer_version = ssh->kex->server ?
1379
0
      ssh->kex->client_version : ssh->kex->server_version;
1380
0
  char *our_version_string = NULL, *peer_version_string = NULL;
1381
0
  char *cp, *remote_version = NULL;
1382
1383
  /* Prepare and send our banner */
1384
0
  sshbuf_reset(our_version);
1385
0
  if (version_addendum != NULL && *version_addendum == '\0')
1386
0
    version_addendum = NULL;
1387
0
  if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%s%s%s\r\n",
1388
0
      PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE,
1389
0
      version_addendum == NULL ? "" : " ",
1390
0
      version_addendum == NULL ? "" : version_addendum)) != 0) {
1391
0
    oerrno = errno;
1392
0
    error_fr(r, "sshbuf_putf");
1393
0
    goto out;
1394
0
  }
1395
1396
0
  if (atomicio(vwrite, ssh_packet_get_connection_out(ssh),
1397
0
      sshbuf_mutable_ptr(our_version),
1398
0
      sshbuf_len(our_version)) != sshbuf_len(our_version)) {
1399
0
    oerrno = errno;
1400
0
    debug_f("write: %.100s", strerror(errno));
1401
0
    r = SSH_ERR_SYSTEM_ERROR;
1402
0
    goto out;
1403
0
  }
1404
0
  if ((r = sshbuf_consume_end(our_version, 2)) != 0) { /* trim \r\n */
1405
0
    oerrno = errno;
1406
0
    error_fr(r, "sshbuf_consume_end");
1407
0
    goto out;
1408
0
  }
1409
0
  our_version_string = sshbuf_dup_string(our_version);
1410
0
  if (our_version_string == NULL) {
1411
0
    error_f("sshbuf_dup_string failed");
1412
0
    r = SSH_ERR_ALLOC_FAIL;
1413
0
    goto out;
1414
0
  }
1415
0
  debug("Local version string %.100s", our_version_string);
1416
1417
  /* Read other side's version identification. */
1418
0
  for (n = 0; ; n++) {
1419
0
    if (n >= SSH_MAX_PRE_BANNER_LINES) {
1420
0
      send_error(ssh, "No SSH identification string "
1421
0
          "received.");
1422
0
      error_f("No SSH version received in first %u lines "
1423
0
          "from server", SSH_MAX_PRE_BANNER_LINES);
1424
0
      r = SSH_ERR_INVALID_FORMAT;
1425
0
      goto out;
1426
0
    }
1427
0
    sshbuf_reset(peer_version);
1428
0
    expect_nl = 0;
1429
0
    for (;;) {
1430
0
      if (timeout_ms > 0) {
1431
0
        r = waitrfd(ssh_packet_get_connection_in(ssh),
1432
0
            &timeout_ms, NULL);
1433
0
        if (r == -1 && errno == ETIMEDOUT) {
1434
0
          send_error(ssh, "Timed out waiting "
1435
0
              "for SSH identification string.");
1436
0
          error("Connection timed out during "
1437
0
              "banner exchange");
1438
0
          r = SSH_ERR_CONN_TIMEOUT;
1439
0
          goto out;
1440
0
        } else if (r == -1) {
1441
0
          oerrno = errno;
1442
0
          error_f("%s", strerror(errno));
1443
0
          r = SSH_ERR_SYSTEM_ERROR;
1444
0
          goto out;
1445
0
        }
1446
0
      }
1447
1448
0
      len = atomicio(read, ssh_packet_get_connection_in(ssh),
1449
0
          &c, 1);
1450
0
      if (len != 1 && errno == EPIPE) {
1451
0
        verbose_f("Connection closed by remote host");
1452
0
        r = SSH_ERR_CONN_CLOSED;
1453
0
        goto out;
1454
0
      } else if (len != 1) {
1455
0
        oerrno = errno;
1456
0
        error_f("read: %.100s", strerror(errno));
1457
0
        r = SSH_ERR_SYSTEM_ERROR;
1458
0
        goto out;
1459
0
      }
1460
0
      if (c == '\r') {
1461
0
        expect_nl = 1;
1462
0
        continue;
1463
0
      }
1464
0
      if (c == '\n')
1465
0
        break;
1466
0
      if (c == '\0' || expect_nl) {
1467
0
        verbose_f("banner line contains invalid "
1468
0
            "characters");
1469
0
        goto invalid;
1470
0
      }
1471
0
      if ((r = sshbuf_put_u8(peer_version, c)) != 0) {
1472
0
        oerrno = errno;
1473
0
        error_fr(r, "sshbuf_put");
1474
0
        goto out;
1475
0
      }
1476
0
      if (sshbuf_len(peer_version) > SSH_MAX_BANNER_LEN) {
1477
0
        verbose_f("banner line too long");
1478
0
        goto invalid;
1479
0
      }
1480
0
    }
1481
    /* Is this an actual protocol banner? */
1482
0
    if (sshbuf_len(peer_version) > 4 &&
1483
0
        memcmp(sshbuf_ptr(peer_version), "SSH-", 4) == 0)
1484
0
      break;
1485
    /* If not, then just log the line and continue */
1486
0
    if ((cp = sshbuf_dup_string(peer_version)) == NULL) {
1487
0
      error_f("sshbuf_dup_string failed");
1488
0
      r = SSH_ERR_ALLOC_FAIL;
1489
0
      goto out;
1490
0
    }
1491
    /* Do not accept lines before the SSH ident from a client */
1492
0
    if (ssh->kex->server) {
1493
0
      verbose_f("client sent invalid protocol identifier "
1494
0
          "\"%.256s\"", cp);
1495
0
      free(cp);
1496
0
      goto invalid;
1497
0
    }
1498
0
    debug_f("banner line %zu: %s", n, cp);
1499
0
    free(cp);
1500
0
  }
1501
0
  peer_version_string = sshbuf_dup_string(peer_version);
1502
0
  if (peer_version_string == NULL)
1503
0
    fatal_f("sshbuf_dup_string failed");
1504
  /* XXX must be same size for sscanf */
1505
0
  if ((remote_version = calloc(1, sshbuf_len(peer_version))) == NULL) {
1506
0
    error_f("calloc failed");
1507
0
    r = SSH_ERR_ALLOC_FAIL;
1508
0
    goto out;
1509
0
  }
1510
1511
  /*
1512
   * Check that the versions match.  In future this might accept
1513
   * several versions and set appropriate flags to handle them.
1514
   */
1515
0
  if (sscanf(peer_version_string, "SSH-%d.%d-%[^\n]\n",
1516
0
      &remote_major, &remote_minor, remote_version) != 3) {
1517
0
    error("Bad remote protocol version identification: '%.100s'",
1518
0
        peer_version_string);
1519
0
 invalid:
1520
0
    send_error(ssh, "Invalid SSH identification string.");
1521
0
    r = SSH_ERR_INVALID_FORMAT;
1522
0
    goto out;
1523
0
  }
1524
1525
  /* report the version information to syslog if this is the server */
1526
0
        if (timeout_ms == -1) { /* only the server uses this value */
1527
0
    logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s",
1528
0
          ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1529
0
          remote_major, remote_minor, remote_version);
1530
0
  }
1531
1532
0
  debug("Remote protocol version %d.%d, remote software version %.100s",
1533
0
      remote_major, remote_minor, remote_version);
1534
0
  compat_banner(ssh, remote_version);
1535
0
  if (ssh->compat & SSH_HPNSSH)
1536
0
    debug("HPN to HPN Connection.");
1537
0
  else
1538
0
    debug("Non-HPN to HPN Connection.");
1539
1540
0
  if(ssh->compat & SSH_RESTRICT_WINDOW)
1541
0
    debug ("Window size restricted.");
1542
1543
0
  mismatch = 0;
1544
0
  switch (remote_major) {
1545
0
  case 2:
1546
0
    break;
1547
0
  case 1:
1548
0
    if (remote_minor != 99)
1549
0
      mismatch = 1;
1550
0
    break;
1551
0
  default:
1552
0
    mismatch = 1;
1553
0
    break;
1554
0
  }
1555
0
  if (mismatch) {
1556
0
    error("Protocol major versions differ: %d vs. %d",
1557
0
        PROTOCOL_MAJOR_2, remote_major);
1558
0
    send_error(ssh, "Protocol major versions differ.");
1559
0
    r = SSH_ERR_NO_PROTOCOL_VERSION;
1560
0
    goto out;
1561
0
  }
1562
1563
0
  if (ssh->kex->server && (ssh->compat & SSH_BUG_PROBE) != 0) {
1564
0
    logit("probed from %s port %d with %s.  Don't panic.",
1565
0
        ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1566
0
        peer_version_string);
1567
0
    r = SSH_ERR_CONN_CLOSED; /* XXX */
1568
0
    goto out;
1569
0
  }
1570
0
  if (ssh->kex->server && (ssh->compat & SSH_BUG_SCANNER) != 0) {
1571
0
    logit("scanned from %s port %d with %s.  Don't panic.",
1572
0
        ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1573
0
        peer_version_string);
1574
0
    r = SSH_ERR_CONN_CLOSED; /* XXX */
1575
0
    goto out;
1576
0
  }
1577
  /* success */
1578
0
  r = 0;
1579
0
 out:
1580
0
  free(our_version_string);
1581
0
  free(peer_version_string);
1582
0
  free(remote_version);
1583
0
  if (r == SSH_ERR_SYSTEM_ERROR)
1584
0
    errno = oerrno;
1585
0
  return r;
1586
0
}