Coverage Report

Created: 2025-11-09 06:46

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