Coverage Report

Created: 2026-07-05 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/session.c
Line
Count
Source
1
/*
2
 * session.c - non-networking functions
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2005-2013 by Aris Adamantiadis
7
 *
8
 * The SSH Library is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or (at your
11
 * option) any later version.
12
 *
13
 * The SSH Library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16
 * License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with the SSH Library; see the file COPYING.  If not, write to
20
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21
 * MA 02111-1307, USA.
22
 */
23
24
#include "config.h"
25
26
#include <string.h>
27
#include <stdlib.h>
28
29
#ifdef _WIN32
30
#include <winsock2.h>
31
#endif
32
33
#include "libssh/priv.h"
34
#include "libssh/libssh.h"
35
#include "libssh/crypto.h"
36
#include "libssh/server.h"
37
#include "libssh/socket.h"
38
#include "libssh/ssh2.h"
39
#include "libssh/agent.h"
40
#include "libssh/packet.h"
41
#include "libssh/kex.h"
42
#include "libssh/session.h"
43
#include "libssh/misc.h"
44
#include "libssh/buffer.h"
45
#include "libssh/poll.h"
46
#include "libssh/pki.h"
47
#include "libssh/gssapi.h"
48
49
0
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
50
51
/**
52
 * @defgroup libssh_session The SSH session functions
53
 * @ingroup libssh
54
 *
55
 * Functions that manage a session.
56
 *
57
 * @{
58
 */
59
60
/**
61
 * @brief Create a new ssh session.
62
 *
63
 * @returns             A new ssh_session pointer, NULL on error.
64
 */
65
ssh_session ssh_new(void)
66
0
{
67
0
    ssh_session session = NULL;
68
0
    char *id = NULL;
69
0
    int rc;
70
71
0
    session = calloc(1, sizeof (struct ssh_session_struct));
72
0
    if (session == NULL) {
73
0
        return NULL;
74
0
    }
75
76
0
    session->next_crypto = crypto_new();
77
0
    if (session->next_crypto == NULL) {
78
0
        goto err;
79
0
    }
80
81
0
    session->socket = ssh_socket_new(session);
82
0
    if (session->socket == NULL) {
83
0
        goto err;
84
0
    }
85
86
0
    session->out_buffer = ssh_buffer_new();
87
0
    if (session->out_buffer == NULL) {
88
0
        goto err;
89
0
    }
90
91
0
    session->in_buffer = ssh_buffer_new();
92
0
    if (session->in_buffer == NULL) {
93
0
        goto err;
94
0
    }
95
96
0
    session->out_queue = ssh_list_new();
97
0
    if (session->out_queue == NULL) {
98
0
        goto err;
99
0
    }
100
101
0
    session->alive = 0;
102
0
    session->auth.supported_methods = 0;
103
0
    ssh_set_blocking(session, 1);
104
0
    session->maxchannel = FIRST_CHANNEL;
105
0
    session->proxy_root = true;
106
107
0
    session->agent = ssh_agent_new(session);
108
0
    if (session->agent == NULL) {
109
0
        goto err;
110
0
    }
111
112
    /* Initialise a default PKI context */
113
0
    session->pki_context = ssh_pki_ctx_new();
114
0
    if (session->pki_context == NULL) {
115
0
        goto err;
116
0
    }
117
118
    /* OPTIONS */
119
0
    session->opts.StrictHostKeyChecking = SSH_STRICT_HOSTKEY_ASK;
120
0
    session->opts.port = 22;
121
0
    session->opts.fd = -1;
122
0
    session->opts.compressionlevel = 7;
123
0
    session->opts.nodelay = 0;
124
0
    session->opts.identities_only = false;
125
0
    session->opts.batch_mode = false;
126
0
    session->opts.control_master = SSH_CONTROL_MASTER_NO;
127
128
0
    session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH |
129
0
                          SSH_OPT_FLAG_PUBKEY_AUTH |
130
0
                          SSH_OPT_FLAG_KBDINT_AUTH |
131
0
                          SSH_OPT_FLAG_GSSAPI_AUTH;
132
0
    session->opts.pubkey_auth = SSH_PUBKEY_AUTH_ALL;
133
134
0
    session->opts.exp_flags = 0;
135
136
0
    session->opts.identity = ssh_list_new();
137
0
    if (session->opts.identity == NULL) {
138
0
        goto err;
139
0
    }
140
0
    session->opts.identity_non_exp = ssh_list_new();
141
0
    if (session->opts.identity_non_exp == NULL) {
142
0
        goto err;
143
0
    }
144
145
0
    session->opts.certificate = ssh_list_new();
146
0
    if (session->opts.certificate == NULL) {
147
0
        goto err;
148
0
    }
149
0
    session->opts.certificate_non_exp = ssh_list_new();
150
0
    if (session->opts.certificate_non_exp == NULL) {
151
0
        goto err;
152
0
    }
153
    /* the default certificates are loaded automatically from the default
154
     * identities later */
155
156
0
    session->opts.local_forward = ssh_list_new();
157
0
    if (session->opts.local_forward == NULL) {
158
0
        goto err;
159
0
    }
160
161
0
    session->opts.proxy_jumps = ssh_list_new();
162
0
    if (session->opts.proxy_jumps == NULL) {
163
0
        goto err;
164
0
    }
165
166
0
    session->opts.send_env = ssh_list_new();
167
0
    if (session->opts.send_env == NULL) {
168
0
        goto err;
169
0
    }
170
171
0
    session->opts.proxy_jumps_user_cb = ssh_list_new();
172
0
    if (session->opts.proxy_jumps_user_cb == NULL) {
173
0
        goto err;
174
0
    }
175
176
#ifdef WITH_GSSAPI
177
    session->opts.gssapi_key_exchange_algs =
178
        strdup(GSSAPI_KEY_EXCHANGE_SUPPORTED);
179
    if (session->opts.gssapi_key_exchange_algs == NULL) {
180
        goto err;
181
    }
182
#endif /* WITH_GSSAPI */
183
184
0
    id = strdup("%d/.ssh/id_ed25519");
185
0
    if (id == NULL) {
186
0
        goto err;
187
0
    }
188
189
0
    rc = ssh_list_append(session->opts.identity_non_exp, id);
190
0
    if (rc == SSH_ERROR) {
191
0
        goto err;
192
0
    }
193
194
0
#ifdef HAVE_ECC
195
0
    id = strdup("%d/.ssh/id_ecdsa");
196
0
    if (id == NULL) {
197
0
        goto err;
198
0
    }
199
0
    rc = ssh_list_append(session->opts.identity_non_exp, id);
200
0
    if (rc == SSH_ERROR) {
201
0
        goto err;
202
0
    }
203
0
#endif
204
205
0
    id = strdup("%d/.ssh/id_rsa");
206
0
    if (id == NULL) {
207
0
        goto err;
208
0
    }
209
0
    rc = ssh_list_append(session->opts.identity_non_exp, id);
210
0
    if (rc == SSH_ERROR) {
211
0
        goto err;
212
0
    }
213
214
#ifdef WITH_FIDO2
215
    /* Add security key identities */
216
    id = strdup("%d/.ssh/id_ed25519_sk");
217
    if (id == NULL) {
218
        goto err;
219
    }
220
    rc = ssh_list_append(session->opts.identity_non_exp, id);
221
    if (rc == SSH_ERROR) {
222
        goto err;
223
    }
224
225
#ifdef HAVE_ECC
226
    id = strdup("%d/.ssh/id_ecdsa_sk");
227
    if (id == NULL) {
228
        goto err;
229
    }
230
    rc = ssh_list_append(session->opts.identity_non_exp, id);
231
    if (rc == SSH_ERROR) {
232
        goto err;
233
    }
234
#endif /* HAVE_ECC */
235
#endif /* WITH_FIDO2 */
236
237
    /* Explicitly initialize states */
238
0
    session->session_state = SSH_SESSION_STATE_NONE;
239
0
    session->pending_call_state = SSH_PENDING_CALL_NONE;
240
0
    session->packet_state = PACKET_STATE_INIT;
241
0
    session->dh_handshake_state = DH_STATE_INIT;
242
0
    session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
243
244
0
    session->auth.state = SSH_AUTH_STATE_NONE;
245
0
    session->auth.service_state = SSH_AUTH_SERVICE_NONE;
246
247
0
    return session;
248
249
0
err:
250
0
    free(id);
251
0
    ssh_free(session);
252
0
    return NULL;
253
0
}
254
255
/**
256
 * @brief Deallocate a SSH session handle.
257
 *
258
 * @param[in] session   The SSH session to free.
259
 *
260
 * @see ssh_disconnect()
261
 * @see ssh_new()
262
 */
263
void ssh_free(ssh_session session)
264
0
{
265
0
  int i;
266
0
  struct ssh_iterator *it = NULL;
267
0
  struct ssh_buffer_struct *b = NULL;
268
269
0
  if (session == NULL) {
270
0
    return;
271
0
  }
272
273
  /*
274
   * Delete all channels
275
   *
276
   * This needs the first thing we clean up cause if there is still an open
277
   * channel we call ssh_channel_close() first. So we need a working socket
278
   * and poll context for it.
279
   */
280
0
  for (it = ssh_list_get_iterator(session->channels);
281
0
       it != NULL;
282
0
       it = ssh_list_get_iterator(session->channels)) {
283
0
      ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));
284
0
      ssh_list_remove(session->channels, it);
285
0
  }
286
0
  ssh_list_free(session->channels);
287
0
  session->channels = NULL;
288
289
0
#ifdef WITH_PCAP
290
0
  if (session->pcap_ctx) {
291
0
      ssh_pcap_context_free(session->pcap_ctx);
292
0
      session->pcap_ctx = NULL;
293
0
  }
294
0
#endif
295
296
0
  ssh_socket_free(session->socket);
297
0
  session->socket = NULL;
298
299
0
  if (session->default_poll_ctx) {
300
0
      ssh_poll_ctx_free(session->default_poll_ctx);
301
0
  }
302
303
0
  SSH_BUFFER_FREE(session->in_buffer);
304
0
  SSH_BUFFER_FREE(session->out_buffer);
305
0
  session->in_buffer = session->out_buffer = NULL;
306
307
0
  if (session->in_hashbuf != NULL) {
308
0
      SSH_BUFFER_FREE(session->in_hashbuf);
309
0
  }
310
0
  if (session->out_hashbuf != NULL) {
311
0
      SSH_BUFFER_FREE(session->out_hashbuf);
312
0
  }
313
314
0
  crypto_free(session->current_crypto);
315
0
  crypto_free(session->next_crypto);
316
317
0
  ssh_agent_free(session->agent);
318
319
0
  SSH_PKI_CTX_FREE(session->pki_context);
320
321
0
  ssh_key_free(session->srv.rsa_key);
322
0
  session->srv.rsa_key = NULL;
323
0
  ssh_key_free(session->srv.ecdsa_key);
324
0
  session->srv.ecdsa_key = NULL;
325
0
  ssh_key_free(session->srv.ed25519_key);
326
0
  session->srv.ed25519_key = NULL;
327
328
0
  if (session->ssh_message_list) {
329
0
      ssh_message msg;
330
331
0
      for (msg = ssh_list_pop_head(ssh_message, session->ssh_message_list);
332
0
           msg != NULL;
333
0
           msg = ssh_list_pop_head(ssh_message, session->ssh_message_list)) {
334
0
          ssh_message_free(msg);
335
0
      }
336
0
      ssh_list_free(session->ssh_message_list);
337
0
  }
338
339
0
  if (session->kbdint != NULL) {
340
0
    ssh_kbdint_free(session->kbdint);
341
0
  }
342
343
0
  if (session->packet_callbacks) {
344
0
    ssh_list_free(session->packet_callbacks);
345
0
  }
346
347
#ifdef WITH_GSSAPI
348
    ssh_gssapi_free(session);
349
    SAFE_FREE(session->opts.gssapi_key_exchange_algs);
350
#endif
351
352
  /* options */
353
0
  if (session->opts.identity) {
354
0
      char *id = NULL;
355
356
0
      for (id = ssh_list_pop_head(char *, session->opts.identity);
357
0
           id != NULL;
358
0
           id = ssh_list_pop_head(char *, session->opts.identity)) {
359
0
          SAFE_FREE(id);
360
0
      }
361
0
      ssh_list_free(session->opts.identity);
362
0
  }
363
364
0
  if (session->opts.identity_non_exp) {
365
0
      char *id = NULL;
366
367
0
      for (id = ssh_list_pop_head(char *, session->opts.identity_non_exp);
368
0
           id != NULL;
369
0
           id = ssh_list_pop_head(char *, session->opts.identity_non_exp)) {
370
0
          SAFE_FREE(id);
371
0
      }
372
0
      ssh_list_free(session->opts.identity_non_exp);
373
0
  }
374
375
0
    if (session->opts.certificate) {
376
0
        char *cert = NULL;
377
378
0
        for (cert = ssh_list_pop_head(char *, session->opts.certificate);
379
0
             cert != NULL;
380
0
             cert = ssh_list_pop_head(char *, session->opts.certificate)) {
381
0
            SAFE_FREE(cert);
382
0
        }
383
0
        ssh_list_free(session->opts.certificate);
384
0
    }
385
386
0
    if (session->opts.certificate_non_exp) {
387
0
        char *cert = NULL;
388
389
0
        for (cert = ssh_list_pop_head(char *, session->opts.certificate_non_exp);
390
0
             cert != NULL;
391
0
             cert = ssh_list_pop_head(char *, session->opts.certificate_non_exp)) {
392
0
            SAFE_FREE(cert);
393
0
        }
394
0
        ssh_list_free(session->opts.certificate_non_exp);
395
0
    }
396
397
0
    ssh_proxyjumps_free(session->opts.proxy_jumps);
398
0
    SSH_LIST_FREE(session->opts.proxy_jumps);
399
0
    SSH_LIST_FREE(session->opts.proxy_jumps_user_cb);
400
0
    SAFE_FREE(session->opts.proxy_jumps_str);
401
402
0
    if (session->opts.send_env) {
403
0
        char *pattern = NULL;
404
405
0
        for (pattern = ssh_list_pop_head(char *, session->opts.send_env);
406
0
             pattern != NULL;
407
0
             pattern = ssh_list_pop_head(char *, session->opts.send_env)) {
408
0
            SAFE_FREE(pattern);
409
0
        }
410
0
        ssh_list_free(session->opts.send_env);
411
0
    }
412
413
0
    while ((b = ssh_list_pop_head(struct ssh_buffer_struct *,
414
0
                                  session->out_queue)) != NULL) {
415
0
        SSH_BUFFER_FREE(b);
416
0
    }
417
0
    ssh_list_free(session->out_queue);
418
419
0
  ssh_agent_state_free(session->agent_state);
420
0
  session->agent_state = NULL;
421
422
0
  SAFE_FREE(session->auth.auto_state);
423
0
  SAFE_FREE(session->serverbanner);
424
0
  SAFE_FREE(session->clientbanner);
425
0
  SAFE_FREE(session->banner);
426
0
  SAFE_FREE(session->disconnect_message);
427
0
  SAFE_FREE(session->peer_discon_msg);
428
429
0
  SAFE_FREE(session->opts.agent_socket);
430
0
  SAFE_FREE(session->opts.bindaddr);
431
0
  SAFE_FREE(session->opts.username);
432
0
  SAFE_FREE(session->opts.host);
433
0
  SAFE_FREE(session->opts.originalhost);
434
0
  SAFE_FREE(session->opts.config_hostname);
435
0
  SAFE_FREE(session->opts.tag);
436
0
  SAFE_FREE(session->opts.homedir);
437
0
  SAFE_FREE(session->opts.sshdir);
438
0
  SAFE_FREE(session->opts.knownhosts);
439
0
  SAFE_FREE(session->opts.global_knownhosts);
440
0
  SAFE_FREE(session->opts.ProxyCommand);
441
0
  SAFE_FREE(session->opts.gss_server_identity);
442
0
  SAFE_FREE(session->opts.gss_client_identity);
443
0
  SAFE_FREE(session->opts.pubkey_accepted_types);
444
0
  SAFE_FREE(session->opts.control_path);
445
0
  SAFE_FREE(session->opts.preferred_authentications);
446
447
0
  if (session->opts.local_forward) {
448
0
      char *entry = NULL;
449
450
0
      for (entry = ssh_list_pop_head(char *, session->opts.local_forward);
451
0
           entry != NULL;
452
0
           entry = ssh_list_pop_head(char *, session->opts.local_forward)) {
453
0
          SAFE_FREE(entry);
454
0
      }
455
0
      ssh_list_free(session->opts.local_forward);
456
0
  }
457
458
0
  for (i = 0; i < SSH_KEX_METHODS; i++) {
459
0
      if (session->opts.wanted_methods[i]) {
460
0
          SAFE_FREE(session->opts.wanted_methods[i]);
461
0
      }
462
0
  }
463
464
0
  SAFE_FREE(session->server_opts.custombanner);
465
0
  SAFE_FREE(session->server_opts.moduli_file);
466
467
0
  _ssh_remove_legacy_log_cb();
468
469
  /* burn connection, it could contain sensitive data */
470
0
  ssh_burn(session, sizeof(struct ssh_session_struct));
471
0
  SAFE_FREE(session);
472
0
}
473
474
/**
475
 * @brief get the client banner
476
 *
477
 * @param[in] session   The SSH session
478
 *
479
 * @return Returns the client banner string or NULL.
480
 */
481
0
const char* ssh_get_clientbanner(ssh_session session) {
482
0
    if (session == NULL) {
483
0
        return NULL;
484
0
    }
485
486
0
    return session->clientbanner;
487
0
}
488
489
/**
490
 * @brief get the server banner
491
 *
492
 * @param[in] session   The SSH session
493
 *
494
 * @return Returns the server banner string or NULL.
495
 */
496
0
const char* ssh_get_serverbanner(ssh_session session) {
497
0
    if (!session) {
498
0
        return NULL;
499
0
    }
500
0
    return session->serverbanner;
501
0
}
502
503
/**
504
 * @brief get the name of the current key exchange algorithm.
505
 *
506
 * @param[in] session   The SSH session
507
 *
508
 * @return Returns the key exchange algorithm string or NULL.
509
 */
510
0
const char* ssh_get_kex_algo(ssh_session session) {
511
0
    if ((session == NULL) ||
512
0
        (session->current_crypto == NULL)) {
513
0
        return NULL;
514
0
    }
515
516
0
    switch (session->current_crypto->kex_type) {
517
0
    case SSH_KEX_DH_GROUP1_SHA1:
518
0
        return "diffie-hellman-group1-sha1";
519
0
    case SSH_KEX_DH_GROUP14_SHA1:
520
0
        return "diffie-hellman-group14-sha1";
521
0
    case SSH_KEX_DH_GROUP14_SHA256:
522
0
        return "diffie-hellman-group14-sha256";
523
0
    case SSH_GSS_KEX_DH_GROUP14_SHA256:
524
0
        return "gss-group14-sha256-";
525
0
    case SSH_KEX_DH_GROUP16_SHA512:
526
0
        return "diffie-hellman-group16-sha512";
527
0
    case SSH_GSS_KEX_DH_GROUP16_SHA512:
528
0
        return "gss-group16-sha512-";
529
0
    case SSH_KEX_DH_GROUP18_SHA512:
530
0
        return "diffie-hellman-group18-sha512";
531
0
    case SSH_KEX_ECDH_SHA2_NISTP256:
532
0
        return "ecdh-sha2-nistp256";
533
0
    case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
534
0
        return "gss-nistp256-sha256-";
535
0
    case SSH_KEX_ECDH_SHA2_NISTP384:
536
0
        return "ecdh-sha2-nistp384";
537
0
    case SSH_KEX_ECDH_SHA2_NISTP521:
538
0
        return "ecdh-sha2-nistp521";
539
0
    case SSH_KEX_CURVE25519_SHA256:
540
0
        return "curve25519-sha256";
541
0
    case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
542
0
        return "curve25519-sha256@libssh.org";
543
0
    case SSH_GSS_KEX_CURVE25519_SHA256:
544
0
        return "gss-curve25519-sha256-";
545
0
    case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
546
0
        return "sntrup761x25519-sha512@openssh.com";
547
0
    case SSH_KEX_SNTRUP761X25519_SHA512:
548
0
        return "sntrup761x25519-sha512";
549
0
    case SSH_KEX_MLKEM768X25519_SHA256:
550
0
        return "mlkem768x25519-sha256";
551
0
    case SSH_KEX_MLKEM768NISTP256_SHA256:
552
0
        return "mlkem768nistp256-sha256";
553
#ifdef HAVE_MLKEM1024
554
    case SSH_KEX_MLKEM1024NISTP384_SHA384:
555
        return "mlkem1024nistp384-sha384";
556
#endif /* HAVE_MLKEM1024 */
557
0
#ifdef WITH_GEX
558
0
    case SSH_KEX_DH_GEX_SHA1:
559
0
        return "diffie-hellman-group-exchange-sha1";
560
0
    case SSH_KEX_DH_GEX_SHA256:
561
0
        return "diffie-hellman-group-exchange-sha256";
562
0
#endif /* WITH_GEX */
563
0
    }
564
0
    return NULL;
565
0
}
566
567
/**
568
 * @brief Check if current session keys were exchanged using
569
 *        a GSSAPI key exchange method.
570
 *
571
 * @param[in] session The SSH session.
572
 *
573
 * @return True if GSSAPI key exchange took place, false otherwise
574
 *         (other or no key exchange took place).
575
 */
576
bool ssh_session_kex_is_gss(ssh_session session)
577
0
{
578
0
    if (session == NULL || session->current_crypto == NULL) {
579
0
        return false;
580
0
    }
581
0
    return ssh_kex_is_gss(session->current_crypto);
582
0
}
583
/**
584
 * @brief get the name of the input cipher for the given session.
585
 *
586
 * @param[in] session The SSH session.
587
 *
588
 * @return Returns cipher name or NULL.
589
 */
590
0
const char* ssh_get_cipher_in(ssh_session session) {
591
0
    if ((session != NULL) &&
592
0
        (session->current_crypto != NULL) &&
593
0
        (session->current_crypto->in_cipher != NULL)) {
594
0
        return session->current_crypto->in_cipher->name;
595
0
    }
596
0
    return NULL;
597
0
}
598
599
/**
600
 * @brief get the name of the output cipher for the given session.
601
 *
602
 * @param[in] session The SSH session.
603
 *
604
 * @return Returns cipher name or NULL.
605
 */
606
0
const char* ssh_get_cipher_out(ssh_session session) {
607
0
    if ((session != NULL) &&
608
0
        (session->current_crypto != NULL) &&
609
0
        (session->current_crypto->out_cipher != NULL)) {
610
0
        return session->current_crypto->out_cipher->name;
611
0
    }
612
0
    return NULL;
613
0
}
614
615
/**
616
 * @brief get the name of the input HMAC algorithm for the given session.
617
 *
618
 * @param[in] session The SSH session.
619
 *
620
 * @return Returns HMAC algorithm name or NULL if unknown.
621
 */
622
0
const char* ssh_get_hmac_in(ssh_session session) {
623
0
    if ((session != NULL) &&
624
0
        (session->current_crypto != NULL)) {
625
0
        return ssh_hmac_type_to_string(session->current_crypto->in_hmac, session->current_crypto->in_hmac_etm);
626
0
    }
627
0
    return NULL;
628
0
}
629
630
/**
631
 * @brief get the name of the output HMAC algorithm for the given session.
632
 *
633
 * @param[in] session The SSH session.
634
 *
635
 * @return Returns HMAC algorithm name or NULL if unknown.
636
 */
637
0
const char* ssh_get_hmac_out(ssh_session session) {
638
0
    if ((session != NULL) &&
639
0
        (session->current_crypto != NULL)) {
640
0
        return ssh_hmac_type_to_string(session->current_crypto->out_hmac, session->current_crypto->out_hmac_etm);
641
0
    }
642
0
    return NULL;
643
0
}
644
645
/**
646
 * @internal
647
 * @brief Close the connection socket if it is a socket created by us.
648
 * Does not close the sockets provided by the user through options API.
649
 */
650
void
651
ssh_session_socket_close(ssh_session session)
652
0
{
653
0
    if (session->opts.fd == SSH_INVALID_SOCKET) {
654
0
        ssh_socket_close(session->socket);
655
0
    }
656
0
    session->alive = 0;
657
0
    session->session_state = SSH_SESSION_STATE_ERROR;
658
0
}
659
660
/**
661
 * @brief Disconnect impolitely from a remote host by closing the socket.
662
 *
663
 * Suitable if you forked and want to destroy this session.
664
 *
665
 * @param[in]  session  The SSH session to disconnect.
666
 */
667
void
668
ssh_silent_disconnect(ssh_session session)
669
0
{
670
0
    if (session == NULL) {
671
0
        return;
672
0
    }
673
674
0
    ssh_session_socket_close(session);
675
0
    ssh_disconnect(session);
676
0
}
677
678
/**
679
 * @brief Set the session in blocking/nonblocking mode.
680
 *
681
 * @param[in]  session  The ssh session to change.
682
 *
683
 * @param[in]  blocking Zero for nonblocking mode.
684
 */
685
void ssh_set_blocking(ssh_session session, int blocking)
686
0
{
687
0
    if (session == NULL) {
688
0
        return;
689
0
    }
690
0
    session->flags &= ~SSH_SESSION_FLAG_BLOCKING;
691
0
    session->flags |= blocking ? SSH_SESSION_FLAG_BLOCKING : 0;
692
0
}
693
694
/**
695
 * @brief Return the blocking mode of libssh
696
 * @param[in] session The SSH session
697
 * @returns 0 if the session is nonblocking,
698
 * @returns 1 if the functions may block.
699
 */
700
int ssh_is_blocking(ssh_session session)
701
0
{
702
0
    return (session->flags & SSH_SESSION_FLAG_BLOCKING) ? 1 : 0;
703
0
}
704
705
/* Waits until the output socket is empty */
706
0
static int ssh_flush_termination(void *c){
707
0
  ssh_session session = c;
708
0
  if (ssh_socket_buffered_write_bytes(session->socket) == 0 ||
709
0
      session->session_state == SSH_SESSION_STATE_ERROR)
710
0
    return 1;
711
0
  else
712
0
    return 0;
713
0
}
714
715
/**
716
 * @brief Blocking flush of the outgoing buffer
717
 * @param[in] session The SSH session
718
 * @param[in] timeout Set an upper limit on the time for which this function
719
 *                    will block, in milliseconds. Specifying -1
720
 *                    means an infinite timeout. This parameter is passed to
721
 *                    the poll() function.
722
 * @returns           `SSH_OK` on success, `SSH_AGAIN` if timeout occurred,
723
 *                    `SSH_ERROR` otherwise.
724
 */
725
0
int ssh_blocking_flush(ssh_session session, int timeout){
726
0
    int rc;
727
0
    if (session == NULL) {
728
0
        return SSH_ERROR;
729
0
    }
730
731
0
    rc = ssh_handle_packets_termination(session, timeout,
732
0
            ssh_flush_termination, session);
733
0
    if (rc == SSH_ERROR) {
734
0
        return rc;
735
0
    }
736
0
    if (!ssh_flush_termination(session)) {
737
0
        rc = SSH_AGAIN;
738
0
    }
739
740
0
    return rc;
741
0
}
742
743
/**
744
 * @brief Check if we are connected.
745
 *
746
 * @param[in]  session  The session to check if it is connected.
747
 *
748
 * @return              1 if we are connected, 0 if not.
749
 */
750
0
int ssh_is_connected(ssh_session session) {
751
0
    if (session == NULL) {
752
0
        return 0;
753
0
    }
754
755
0
    return session->alive;
756
0
}
757
758
/**
759
 * @brief Get the fd of a connection.
760
 *
761
 * In case you'd need the file descriptor of the connection to the server/client.
762
 *
763
 * @param[in] session   The ssh session to use.
764
 *
765
 * @return              The file descriptor of the connection, or -1 if it is
766
 *                      not connected
767
 */
768
0
socket_t ssh_get_fd(ssh_session session) {
769
0
  if (session == NULL) {
770
0
    return -1;
771
0
  }
772
773
0
  return ssh_socket_get_fd(session->socket);
774
0
}
775
776
/**
777
 * @brief Tell the session it has data to read on the file descriptor without
778
 * blocking.
779
 *
780
 * @param[in] session   The ssh session to use.
781
 */
782
0
void ssh_set_fd_toread(ssh_session session) {
783
0
  if (session == NULL) {
784
0
    return;
785
0
  }
786
787
0
  ssh_socket_set_read_wontblock(session->socket);
788
0
}
789
790
/**
791
 * @brief Tell the session it may write to the file descriptor without blocking.
792
 *
793
 * @param[in] session   The ssh session to use.
794
 */
795
0
void ssh_set_fd_towrite(ssh_session session) {
796
0
  if (session == NULL) {
797
0
    return;
798
0
  }
799
800
0
  ssh_socket_set_write_wontblock(session->socket);
801
0
}
802
803
/**
804
 * @brief Tell the session it has an exception to catch on the file descriptor.
805
 *
806
 * @param[in] session   The ssh session to use.
807
 */
808
0
void ssh_set_fd_except(ssh_session session) {
809
0
  if (session == NULL) {
810
0
    return;
811
0
  }
812
813
0
  ssh_socket_set_except(session->socket);
814
0
}
815
816
/**
817
 * @internal
818
 *
819
 * @brief Poll the current session for an event and call the appropriate
820
 * callbacks. This function will not loop until the @p timeout is expired.
821
 *
822
 * This will block until one event happens.
823
 *
824
 * @param[in] session   The session handle to use.
825
 *
826
 * @param[in] timeout   Set an upper limit on the time for which this function
827
 *                      will block, in milliseconds. Specifying
828
 *                      `SSH_TIMEOUT_INFINITE`
829
 *                      (-1) means an infinite timeout.
830
 *                      Specifying `SSH_TIMEOUT_USER` means to use the timeout
831
 *                      specified in options. 0 means poll will return
832
 *                      immediately.
833
 *                      This parameter is passed to the poll() function.
834
 *
835
 * @return              `SSH_OK` on success, `SSH_ERROR` otherwise.
836
 */
837
int ssh_handle_packets(ssh_session session, int timeout)
838
0
{
839
0
    ssh_poll_handle spoll = NULL;
840
0
    ssh_poll_ctx ctx = NULL;
841
0
    int tm = timeout;
842
0
    int rc;
843
844
0
    if (session == NULL || session->socket == NULL) {
845
0
        return SSH_ERROR;
846
0
    }
847
848
0
    spoll = ssh_socket_get_poll_handle(session->socket);
849
0
    if (spoll == NULL) {
850
0
        ssh_set_error_oom(session);
851
0
        return SSH_ERROR;
852
0
    }
853
0
    ssh_poll_add_events(spoll, POLLIN);
854
0
    ctx = ssh_poll_get_ctx(spoll);
855
856
0
    if (ctx == NULL) {
857
0
        ctx = ssh_poll_get_default_ctx(session);
858
0
        if (ctx == NULL) {
859
0
            ssh_set_error_oom(session);
860
0
            return SSH_ERROR;
861
0
        }
862
0
        rc = ssh_poll_ctx_add(ctx, spoll);
863
0
        if (rc != SSH_OK) {
864
0
            return SSH_ERROR;
865
0
        }
866
0
    }
867
868
0
    if (timeout == SSH_TIMEOUT_USER) {
869
0
        if (ssh_is_blocking(session)) {
870
0
            tm = ssh_make_milliseconds(session->opts.timeout,
871
0
                                       session->opts.timeout_usec);
872
0
        } else {
873
0
            tm = 0;
874
0
        }
875
0
    }
876
0
    rc = ssh_poll_ctx_dopoll(ctx, tm);
877
0
    if (rc == SSH_ERROR) {
878
0
        session->session_state = SSH_SESSION_STATE_ERROR;
879
0
    }
880
881
0
    return rc;
882
0
}
883
884
/**
885
 * @internal
886
 *
887
 * @brief Poll the current session for an event and call the appropriate
888
 * callbacks.
889
 *
890
 * This will block until termination function returns true, or @p timeout
891
 * expired.
892
 *
893
 * @param[in] session   The session handle to use.
894
 *
895
 * @param[in] timeout   Set an upper limit on the time for which this function
896
 *                      will block, in milliseconds. Specifying
897
 *                      `SSH_TIMEOUT_INFINITE` (-1) means an infinite timeout.
898
 *                      Specifying SSH_TIMEOUT_USER means using the timeout
899
 *                      specified in options. 0 means poll will return
900
 *                      immediately.
901
 *                      SSH_TIMEOUT_DEFAULT uses the session timeout if set or
902
 *                      uses blocking parameters of the session.
903
 *                      This parameter is passed to the poll() function.
904
 *
905
 * @param[in] fct       Termination function to be used to determine if it is
906
 *                      possible to stop polling.
907
 * @param[in] user      User parameter to be passed to fct termination function.
908
 * @returns             `SSH_OK` on success, `SSH_AGAIN` if timeout occurred,
909
 *                      `SSH_ERROR` otherwise.
910
 */
911
int ssh_handle_packets_termination(ssh_session session,
912
                                   int timeout,
913
                                   ssh_termination_function fct,
914
                                   void *user)
915
0
{
916
0
    struct ssh_timestamp ts;
917
0
    int timeout_ms = SSH_TIMEOUT_INFINITE;
918
0
    int tm;
919
0
    int ret = SSH_OK;
920
921
    /* If a timeout has been provided, use it */
922
0
    if (timeout >= 0) {
923
0
        timeout_ms = timeout;
924
0
    } else {
925
0
        if (ssh_is_blocking(session)) {
926
0
            if (timeout == SSH_TIMEOUT_USER || timeout == SSH_TIMEOUT_DEFAULT) {
927
0
                if (session->opts.timeout > 0 ||
928
0
                    session->opts.timeout_usec > 0) {
929
0
                    timeout_ms =
930
0
                        ssh_make_milliseconds(session->opts.timeout,
931
0
                                              session->opts.timeout_usec);
932
0
                }
933
0
            }
934
0
        } else {
935
0
            timeout_ms = SSH_TIMEOUT_NONBLOCKING;
936
0
        }
937
0
    }
938
939
    /* avoid unnecessary syscall for the SSH_TIMEOUT_NONBLOCKING case */
940
0
    if (timeout_ms != SSH_TIMEOUT_NONBLOCKING) {
941
0
        ssh_timestamp_init(&ts);
942
0
    }
943
944
0
    tm = timeout_ms;
945
0
    while(!fct(user)) {
946
0
        ret = ssh_handle_packets(session, tm);
947
0
        if (ret == SSH_ERROR) {
948
0
            break;
949
0
        }
950
0
        if (ssh_timeout_elapsed(&ts, timeout_ms)) {
951
0
            ret = fct(user) ? SSH_OK : SSH_AGAIN;
952
0
            break;
953
0
        }
954
955
0
        tm = ssh_timeout_update(&ts, timeout_ms);
956
0
    }
957
958
0
    return ret;
959
0
}
960
961
/**
962
 * @brief Get session status
963
 *
964
 * @param session       The ssh session to use.
965
 *
966
 * @returns A bitmask including `SSH_CLOSED`, `SSH_READ_PENDING`,
967
 *          `SSH_WRITE_PENDING` or `SSH_CLOSED_ERROR` which
968
 *          respectively means the session is closed, has data to
969
 *          read on the connection socket and session was closed
970
 *          due to an error.
971
 */
972
0
int ssh_get_status(ssh_session session) {
973
0
  int socketstate;
974
0
  int r = 0;
975
976
0
  if (session == NULL) {
977
0
    return 0;
978
0
  }
979
980
0
  socketstate = ssh_socket_get_status(session->socket);
981
982
0
  if (session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
983
0
    r |= SSH_CLOSED;
984
0
  }
985
0
  if (socketstate & SSH_READ_PENDING) {
986
0
    r |= SSH_READ_PENDING;
987
0
  }
988
0
  if (socketstate & SSH_WRITE_PENDING) {
989
0
      r |= SSH_WRITE_PENDING;
990
0
  }
991
0
  if ((session->session_state == SSH_SESSION_STATE_DISCONNECTED &&
992
0
       (socketstate & SSH_CLOSED_ERROR)) ||
993
0
      session->session_state == SSH_SESSION_STATE_ERROR) {
994
0
    r |= SSH_CLOSED_ERROR;
995
0
  }
996
997
0
  return r;
998
0
}
999
1000
/**
1001
 * @brief Get poll flags for an external mainloop
1002
 *
1003
 * @param session       The ssh session to use.
1004
 *
1005
 * @returns A bitmask including `SSH_READ_PENDING` or `SSH_WRITE_PENDING`.
1006
 *          For `SSH_READ_PENDING`, your invocation of poll() should include
1007
 *          POLLIN.  For `SSH_WRITE_PENDING`, your invocation of poll() should
1008
 *          include POLLOUT.
1009
 */
1010
int ssh_get_poll_flags(ssh_session session)
1011
0
{
1012
0
  if (session == NULL) {
1013
0
    return 0;
1014
0
  }
1015
1016
0
  return ssh_socket_get_poll_flags (session->socket);
1017
0
}
1018
1019
/**
1020
 * @brief Get the disconnect message from the server.
1021
 *
1022
 * @param[in] session   The ssh session to use.
1023
 *
1024
 * @return              The message sent by the server along with the
1025
 *                      disconnect, or NULL in which case the reason of the
1026
 *                      disconnect may be found with ssh_get_error.
1027
 *
1028
 * @see ssh_get_error()
1029
 */
1030
0
const char *ssh_get_disconnect_message(ssh_session session) {
1031
0
  if (session == NULL) {
1032
0
    return NULL;
1033
0
  }
1034
1035
0
  if (session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
1036
0
    ssh_set_error(session, SSH_REQUEST_DENIED,
1037
0
        "Connection not closed yet");
1038
0
  } else if(!session->peer_discon_msg) {
1039
0
    ssh_set_error(session, SSH_FATAL,
1040
0
        "Connection correctly closed but no disconnect message");
1041
0
  } else {
1042
0
    return session->peer_discon_msg;
1043
0
  }
1044
1045
0
  return NULL;
1046
0
}
1047
1048
/**
1049
 * @brief Get the protocol version of the session.
1050
 *
1051
 * @param session       The ssh session to use.
1052
 *
1053
 * @return The SSH version as integer, < 0 on error.
1054
 */
1055
0
int ssh_get_version(ssh_session session) {
1056
0
    if (session == NULL) {
1057
0
        return -1;
1058
0
    }
1059
1060
0
    return 2;
1061
0
}
1062
1063
/**
1064
 * @internal
1065
 * @brief Callback to be called when the socket received an exception code.
1066
 * @param code        The exception code from the socket layer.
1067
 * @param errno_code  The errno value associated with the exception.
1068
 * @param user        Pointer to the SSH session.
1069
 */
1070
0
void ssh_socket_exception_callback(int code, int errno_code, void *user){
1071
0
    ssh_session session = (ssh_session)user;
1072
1073
0
    SSH_LOG(SSH_LOG_RARE,
1074
0
            "Socket exception callback: %d (%d)",
1075
0
            code,
1076
0
            errno_code);
1077
0
    session->session_state = SSH_SESSION_STATE_ERROR;
1078
0
    if (errno_code == 0 && code == SSH_SOCKET_EXCEPTION_EOF) {
1079
0
        ssh_set_error(session, SSH_FATAL, "Socket error: disconnected");
1080
#ifdef _WIN32
1081
    } else if (errno_code == WSAENETDOWN) {
1082
        ssh_set_error(session, SSH_FATAL, "Socket error: network down");
1083
    } else if (errno_code == WSAENETUNREACH) {
1084
        ssh_set_error(session, SSH_FATAL, "Socket error: network unreachable");
1085
    } else if (errno_code == WSAENETRESET) {
1086
        ssh_set_error(session, SSH_FATAL, "Socket error: network reset");
1087
    } else if (errno_code == WSAECONNABORTED) {
1088
        ssh_set_error(session, SSH_FATAL, "Socket error: connection aborted");
1089
    } else if (errno_code == WSAECONNRESET) {
1090
        ssh_set_error(session,
1091
                      SSH_FATAL,
1092
                      "Socket error: connection reset by peer");
1093
    } else if (errno_code == WSAETIMEDOUT) {
1094
        ssh_set_error(session, SSH_FATAL, "Socket error: connection timed out");
1095
    } else if (errno_code == WSAECONNREFUSED) {
1096
        ssh_set_error(session, SSH_FATAL, "Socket error: connection refused");
1097
    } else if (errno_code == WSAEHOSTUNREACH) {
1098
        ssh_set_error(session, SSH_FATAL, "Socket error: host unreachable");
1099
#endif
1100
0
    } else {
1101
0
        char err_msg[SSH_ERRNO_MSG_MAX] = {0};
1102
0
        ssh_set_error(session,
1103
0
                      SSH_FATAL,
1104
0
                      "Socket error: %s",
1105
0
                      ssh_strerror(errno_code, err_msg, SSH_ERRNO_MSG_MAX));
1106
0
    }
1107
1108
0
    session->ssh_connection_callback(session);
1109
0
}
1110
1111
/**
1112
 * @brief Send a message that should be ignored
1113
 *
1114
 * @param[in] session   The SSH session
1115
 * @param[in] data      Data to be sent
1116
 *
1117
 * @return              `SSH_OK` on success, `SSH_ERROR` otherwise.
1118
 */
1119
0
int ssh_send_ignore (ssh_session session, const char *data) {
1120
0
    const int type = SSH2_MSG_IGNORE;
1121
0
    int rc;
1122
1123
0
    if (ssh_socket_is_open(session->socket)) {
1124
0
        rc = ssh_buffer_pack(session->out_buffer,
1125
0
                             "bs",
1126
0
                             type,
1127
0
                             data);
1128
0
        if (rc != SSH_OK){
1129
0
            ssh_set_error_oom(session);
1130
0
            goto error;
1131
0
        }
1132
0
        ssh_packet_send(session);
1133
0
        ssh_handle_packets(session, 0);
1134
0
    }
1135
1136
0
    return SSH_OK;
1137
1138
0
error:
1139
0
    ssh_buffer_reinit(session->out_buffer);
1140
0
    return SSH_ERROR;
1141
0
}
1142
1143
/**
1144
 * @brief Send a debug message
1145
 *
1146
 * @param[in] session          The SSH session
1147
 * @param[in] message          Data to be sent
1148
 * @param[in] always_display   Message SHOULD be displayed by the server. It
1149
 *                             SHOULD NOT be displayed unless debugging
1150
 *                             information has been explicitly requested.
1151
 *
1152
 * @return                     `SSH_OK` on success, `SSH_ERROR` otherwise.
1153
 */
1154
0
int ssh_send_debug (ssh_session session, const char *message, int always_display) {
1155
0
    int rc;
1156
1157
0
    if (ssh_socket_is_open(session->socket)) {
1158
0
        rc = ssh_buffer_pack(session->out_buffer,
1159
0
                             "bbsd",
1160
0
                             SSH2_MSG_DEBUG,
1161
0
                             always_display != 0 ? 1 : 0,
1162
0
                             message,
1163
0
                             0); /* empty language tag */
1164
0
        if (rc != SSH_OK) {
1165
0
            ssh_set_error_oom(session);
1166
0
            goto error;
1167
0
        }
1168
0
        ssh_packet_send(session);
1169
0
        ssh_handle_packets(session, 0);
1170
0
    }
1171
1172
0
    return SSH_OK;
1173
1174
0
error:
1175
0
    ssh_buffer_reinit(session->out_buffer);
1176
0
    return SSH_ERROR;
1177
0
}
1178
1179
 /**
1180
 * @brief Set the session data counters.
1181
 *
1182
 * This function sets the counter structures to be used to calculate data
1183
 * which comes in and goes out through the session at different levels.
1184
 *
1185
 * @code
1186
 * struct ssh_counter_struct scounter = {
1187
 *     .in_bytes = 0,
1188
 *     .out_bytes = 0,
1189
 *     .in_packets = 0,
1190
 *     .out_packets = 0
1191
 * };
1192
 *
1193
 * struct ssh_counter_struct rcounter = {
1194
 *     .in_bytes = 0,
1195
 *     .out_bytes = 0,
1196
 *     .in_packets = 0,
1197
 *     .out_packets = 0
1198
 * };
1199
 *
1200
 * ssh_set_counters(session, &scounter, &rcounter);
1201
 * @endcode
1202
 *
1203
 * @param[in] session   The SSH session.
1204
 *
1205
 * @param[in] scounter  Counter for byte data handled by the session sockets.
1206
 *
1207
 * @param[in] rcounter  Counter for byte and packet data handled by the session,
1208
 *                      prior compression and SSH overhead.
1209
 */
1210
void ssh_set_counters(ssh_session session, ssh_counter scounter,
1211
0
                              ssh_counter rcounter) {
1212
0
    if (session != NULL) {
1213
0
        session->socket_counter = scounter;
1214
0
        session->raw_counter = rcounter;
1215
0
    }
1216
0
}
1217
1218
/**
1219
 * @deprecated Use ssh_get_publickey_hash()
1220
 */
1221
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash)
1222
0
{
1223
0
    ssh_key pubkey = NULL;
1224
0
    ssh_string pubkey_blob = NULL;
1225
0
    MD5CTX ctx = NULL;
1226
0
    unsigned char *h = NULL;
1227
0
    int rc;
1228
1229
0
    if (session == NULL || hash == NULL) {
1230
0
        return SSH_ERROR;
1231
0
    }
1232
1233
    /* In FIPS mode, we cannot use MD5 */
1234
0
    if (ssh_fips_mode()) {
1235
0
        ssh_set_error(session,
1236
0
                      SSH_FATAL,
1237
0
                      "In FIPS mode MD5 is not allowed."
1238
0
                      "Try ssh_get_publickey_hash() with"
1239
0
                      "SSH_PUBLICKEY_HASH_SHA256");
1240
0
        return SSH_ERROR;
1241
0
    }
1242
1243
0
    *hash = NULL;
1244
0
    if (session->current_crypto == NULL ||
1245
0
        session->current_crypto->server_pubkey == NULL) {
1246
0
        ssh_set_error(session, SSH_FATAL, "No current cryptographic context");
1247
0
        return SSH_ERROR;
1248
0
    }
1249
1250
0
    rc = ssh_get_server_publickey(session, &pubkey);
1251
0
    if (rc != SSH_OK) {
1252
0
        return SSH_ERROR;
1253
0
    }
1254
1255
0
    rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
1256
0
    ssh_key_free(pubkey);
1257
0
    if (rc != SSH_OK) {
1258
0
        return SSH_ERROR;
1259
0
    }
1260
1261
0
    h = calloc(MD5_DIGEST_LEN, sizeof(unsigned char));
1262
0
    if (h == NULL) {
1263
0
        SSH_STRING_FREE(pubkey_blob);
1264
0
        return SSH_ERROR;
1265
0
    }
1266
1267
0
    ctx = md5_init();
1268
0
    if (ctx == NULL) {
1269
0
        SSH_STRING_FREE(pubkey_blob);
1270
0
        SAFE_FREE(h);
1271
0
        return SSH_ERROR;
1272
0
    }
1273
1274
0
    rc = md5_update(ctx,
1275
0
                    ssh_string_data(pubkey_blob),
1276
0
                    ssh_string_len(pubkey_blob));
1277
0
    if (rc != SSH_OK) {
1278
0
        SSH_STRING_FREE(pubkey_blob);
1279
0
        md5_ctx_free(ctx);
1280
0
        SAFE_FREE(h);
1281
0
        return rc;
1282
0
    }
1283
0
    SSH_STRING_FREE(pubkey_blob);
1284
0
    rc = md5_final(h, ctx);
1285
0
    if (rc != SSH_OK) {
1286
0
        SAFE_FREE(h);
1287
0
        return rc;
1288
0
    }
1289
1290
0
    *hash = h;
1291
1292
0
    return MD5_DIGEST_LEN;
1293
0
}
1294
1295
/**
1296
 * @brief Deallocate the hash obtained by ssh_get_pubkey_hash.
1297
 *
1298
 * This is required under Microsoft platform as this library might use a
1299
 * different C library than your software, hence a different heap.
1300
 *
1301
 * @param[in] hash      The buffer to deallocate.
1302
 *
1303
 * @see ssh_get_pubkey_hash()
1304
 */
1305
void ssh_clean_pubkey_hash(unsigned char **hash)
1306
0
{
1307
0
    SAFE_FREE(*hash);
1308
0
}
1309
1310
/**
1311
 * @brief Get the server public key from a session.
1312
 *
1313
 * @param[in]  session  The session to get the key from.
1314
 *
1315
 * @param[out] key      A pointer to store the allocated key. You need to free
1316
 *                      the key using ssh_key_free().
1317
 *
1318
 * @return              `SSH_OK` on success, `SSH_ERROR` on error.
1319
 *
1320
 * @see ssh_key_free()
1321
 */
1322
int ssh_get_server_publickey(ssh_session session, ssh_key *key)
1323
0
{
1324
0
    ssh_key pubkey = NULL;
1325
1326
0
    if (session == NULL ||
1327
0
        session->current_crypto == NULL ||
1328
0
        session->current_crypto->server_pubkey == NULL) {
1329
0
        return SSH_ERROR;
1330
0
    }
1331
1332
0
    pubkey = ssh_key_dup(session->current_crypto->server_pubkey);
1333
0
    if (pubkey == NULL) {
1334
0
        return SSH_ERROR;
1335
0
    }
1336
1337
0
    *key = pubkey;
1338
0
    return SSH_OK;
1339
0
}
1340
1341
/**
1342
 * @deprecated Use ssh_get_server_publickey()
1343
 */
1344
int ssh_get_publickey(ssh_session session, ssh_key *key)
1345
0
{
1346
0
    return ssh_get_server_publickey(session, key);
1347
0
}
1348
1349
/**
1350
 * @brief Allocates a buffer with the hash of the public key.
1351
 *
1352
 * This function allows you to get a @p hash of the public @p key. You can then
1353
 * print this hash in a human-readable form to the user so that he is able to
1354
 * verify it. Use ssh_get_hexa() or ssh_print_hash() to display it.
1355
 *
1356
 * @param[in]  key      The public key to create the hash for.
1357
 *
1358
 * @param[in]  type     The type of the hash you want.
1359
 *
1360
 * @param[out]  hash    A pointer to store the allocated buffer. It can be
1361
 *                      freed using ssh_clean_pubkey_hash().
1362
 *
1363
 * @param[in]  hlen     The length of the hash.
1364
 *
1365
 * @return SSH_OK on success, SSH_ERROR if an error occurred.
1366
 *
1367
 * @warning It is very important that you verify at some moment that the hash
1368
 *          matches a known server. If you don't do it, cryptography won't help
1369
 *          you at making things secure.
1370
 *          OpenSSH uses SHA256 to print public key digests.
1371
 *
1372
 * @see ssh_session_update_known_hosts()
1373
 * @see ssh_get_hexa()
1374
 * @see ssh_print_hash()
1375
 * @see ssh_clean_pubkey_hash()
1376
 */
1377
int ssh_get_publickey_hash(const ssh_key key,
1378
                           enum ssh_publickey_hash_type type,
1379
                           unsigned char **hash,
1380
                           size_t *hlen)
1381
0
{
1382
0
    ssh_string blob = NULL;
1383
0
    unsigned char *h = NULL;
1384
0
    int (*digest)(const unsigned char *, size_t, unsigned char *) = NULL;
1385
0
    int rc, ret = SSH_ERROR;
1386
1387
0
    rc = ssh_pki_export_pubkey_blob(key, &blob);
1388
0
    if (rc < 0) {
1389
0
        goto out;
1390
0
    }
1391
1392
0
    switch (type) {
1393
0
    case SSH_PUBLICKEY_HASH_SHA1:
1394
0
        digest = sha1;
1395
0
        *hlen = SHA_DIGEST_LEN;
1396
0
        break;
1397
0
    case SSH_PUBLICKEY_HASH_SHA256:
1398
0
        digest = sha256;
1399
0
        *hlen = SHA256_DIGEST_LEN;
1400
0
        break;
1401
0
    case SSH_PUBLICKEY_HASH_MD5:
1402
0
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER < 0x30000000L
1403
        /* In FIPS mode without OpenSSL providers, we cannot use MD5 */
1404
0
        if (ssh_fips_mode()) {
1405
0
            SSH_LOG(SSH_LOG_TRACE,
1406
0
                    "In FIPS mode MD5 is not allowed."
1407
0
                    "Try using SSH_PUBLICKEY_HASH_SHA256");
1408
0
            goto out;
1409
0
        }
1410
0
#endif
1411
0
        digest = md5;
1412
0
        *hlen = MD5_DIGEST_LEN;
1413
0
        break;
1414
0
    default:
1415
0
        goto out;
1416
0
    }
1417
1418
0
    h = calloc(1, *hlen);
1419
0
    if (h == NULL) {
1420
0
        goto out;
1421
0
    }
1422
1423
0
    rc = digest(ssh_string_data(blob), ssh_string_len(blob), h);
1424
0
    if (rc != SSH_OK) {
1425
0
        free(h);
1426
0
        goto out;
1427
0
    }
1428
1429
0
    *hash = h;
1430
0
    ret = SSH_OK;
1431
1432
0
out:
1433
    SSH_STRING_FREE(blob);
1434
0
    return ret;
1435
0
}
1436
1437
/** @} */