Coverage Report

Created: 2026-10-22 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/auth.c
Line
Count
Source
1
/*
2
 * auth.c - Authentication with SSH protocols
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2003-2013 by Aris Adamantiadis <aris@0xbadc0de.be>
7
 * Copyright (c) 2008-2013 Andreas Schneider <asn@cryptomilk.org>
8
 *
9
 * The SSH Library is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or (at your
12
 * option) any later version.
13
 *
14
 * The SSH Library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17
 * License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with the SSH Library; see the file COPYING.  If not, write to
21
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22
 * MA 02111-1307, USA.
23
 */
24
25
#include "config.h"
26
27
#include <stdio.h>
28
#include <string.h>
29
30
#ifndef _WIN32
31
#include <netinet/in.h>
32
#include <arpa/inet.h>
33
#endif
34
35
#include "libssh/agent.h"
36
#include "libssh/auth.h"
37
#include "libssh/buffer.h"
38
#include "libssh/crypto.h"
39
#include "libssh/gssapi.h"
40
#include "libssh/keys.h"
41
#include "libssh/legacy.h"
42
#include "libssh/misc.h"
43
#include "libssh/packet.h"
44
#include "libssh/pki.h"
45
#include "libssh/priv.h"
46
#include "libssh/session.h"
47
#include "libssh/ssh2.h"
48
49
/**
50
 * @defgroup libssh_auth The SSH authentication functions
51
 * @ingroup libssh
52
 *
53
 * Functions to authenticate with a server.
54
 *
55
 * @{
56
 */
57
58
/**
59
 * @internal
60
 *
61
 * @brief Ask for access to the ssh-userauth service.
62
 *
63
 * @param[in] session   The SSH session handle.
64
 *
65
 * @returns SSH_OK on success, SSH_ERROR on error.
66
 * @returns SSH_AGAIN on nonblocking mode, if calling that function
67
 * again is necessary
68
 */
69
static int ssh_userauth_request_service(ssh_session session)
70
0
{
71
0
    int rc;
72
73
0
    rc = ssh_service_request(session, "ssh-userauth");
74
0
    if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
75
0
        SSH_LOG(SSH_LOG_TRACE,
76
0
                "Failed to request \"ssh-userauth\" service");
77
0
    }
78
79
0
    return rc;
80
0
}
81
82
static int ssh_auth_response_termination(void *user)
83
0
{
84
0
    ssh_session session = (ssh_session)user;
85
0
    switch (session->auth.state) {
86
0
        case SSH_AUTH_STATE_NONE:
87
0
        case SSH_AUTH_STATE_KBDINT_SENT:
88
0
        case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
89
0
        case SSH_AUTH_STATE_GSSAPI_TOKEN:
90
0
        case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
91
0
        case SSH_AUTH_STATE_GSSAPI_KEYEX_MIC_SENT:
92
0
        case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
93
0
        case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
94
0
        case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
95
0
        case SSH_AUTH_STATE_AUTH_NONE_SENT:
96
0
            return 0;
97
0
        default:
98
0
            return 1;
99
0
    }
100
0
}
101
102
static const char *ssh_auth_get_current_method(ssh_session session)
103
0
{
104
0
    const char *method = "unknown";
105
106
0
    switch (session->auth.current_method) {
107
0
    case SSH_AUTH_METHOD_NONE:
108
0
        method = "none";
109
0
        break;
110
0
    case SSH_AUTH_METHOD_PASSWORD:
111
0
        method = "password";
112
0
        break;
113
0
    case SSH_AUTH_METHOD_PUBLICKEY:
114
0
        method = "publickey";
115
0
        break;
116
0
    case SSH_AUTH_METHOD_HOSTBASED:
117
0
        method = "hostbased";
118
0
        break;
119
0
    case SSH_AUTH_METHOD_INTERACTIVE:
120
0
        method = "keyboard interactive";
121
0
        break;
122
#ifdef WITH_GSSAPI
123
    case SSH_AUTH_METHOD_GSSAPI_MIC:
124
        method = "gssapi";
125
        break;
126
    case SSH_AUTH_METHOD_GSSAPI_KEYEX:
127
        method = "gssapi-keyex";
128
        break;
129
#endif
130
0
    default:
131
0
        break;
132
0
    }
133
134
0
    return method;
135
0
}
136
137
/**
138
 * @internal
139
 * @brief Wait for a response of an authentication function.
140
 *
141
 * @param[in] session   The SSH session.
142
 *
143
 * @returns SSH_AUTH_SUCCESS Authentication success, or pubkey accepted
144
 *          SSH_AUTH_PARTIAL Authentication succeeded but another mean
145
 *                           of authentication is needed.
146
 *          SSH_AUTH_INFO    Data for keyboard-interactive
147
 *          SSH_AUTH_AGAIN   In nonblocking mode, call has to be made again
148
 *          SSH_AUTH_ERROR   Error during the process.
149
 */
150
static int ssh_userauth_get_response(ssh_session session)
151
0
{
152
0
    int rc = SSH_AUTH_ERROR;
153
154
0
    rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
155
0
        ssh_auth_response_termination, session);
156
0
    if (rc == SSH_ERROR) {
157
0
        return SSH_AUTH_ERROR;
158
0
    }
159
0
    if (!ssh_auth_response_termination(session)) {
160
0
        return SSH_AUTH_AGAIN;
161
0
    }
162
163
0
    switch(session->auth.state) {
164
0
        case SSH_AUTH_STATE_ERROR:
165
0
            rc = SSH_AUTH_ERROR;
166
0
            break;
167
0
        case SSH_AUTH_STATE_FAILED:
168
0
            rc = SSH_AUTH_DENIED;
169
0
            break;
170
0
        case SSH_AUTH_STATE_INFO:
171
0
            rc = SSH_AUTH_INFO;
172
0
            break;
173
0
        case SSH_AUTH_STATE_PARTIAL:
174
0
            rc = SSH_AUTH_PARTIAL;
175
0
            break;
176
0
        case SSH_AUTH_STATE_PK_OK:
177
0
        case SSH_AUTH_STATE_SUCCESS:
178
0
            rc = SSH_AUTH_SUCCESS;
179
0
            break;
180
0
        case SSH_AUTH_STATE_KBDINT_SENT:
181
0
        case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
182
0
        case SSH_AUTH_STATE_GSSAPI_TOKEN:
183
0
        case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
184
0
        case SSH_AUTH_STATE_GSSAPI_KEYEX_MIC_SENT:
185
0
        case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
186
0
        case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
187
0
        case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
188
0
        case SSH_AUTH_STATE_AUTH_NONE_SENT:
189
0
        case SSH_AUTH_STATE_NONE:
190
            /* not reached */
191
0
            rc = SSH_AUTH_ERROR;
192
0
            break;
193
0
    }
194
195
0
    return rc;
196
0
}
197
198
/**
199
 * @internal
200
 *
201
 * @brief Handles a SSH_USERAUTH_BANNER packet.
202
 *
203
 * This banner should be shown to user prior to authentication
204
 */
205
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner)
206
0
{
207
0
    ssh_string banner = NULL;
208
0
    (void)type;
209
0
    (void)user;
210
211
0
    banner = ssh_buffer_get_ssh_string(packet);
212
0
    if (banner == NULL) {
213
0
        SSH_LOG(SSH_LOG_TRACE,
214
0
                "Invalid SSH_USERAUTH_BANNER packet");
215
0
    } else {
216
0
        SSH_LOG(SSH_LOG_DEBUG,
217
0
                "Received SSH_USERAUTH_BANNER packet");
218
0
        if (session->banner != NULL)
219
0
            SSH_STRING_FREE(session->banner);
220
0
        session->banner = banner;
221
0
    }
222
223
0
    return SSH_PACKET_USED;
224
0
}
225
226
/**
227
 * @internal
228
 *
229
 * @brief Get the authentication method bitmask from a method name string.
230
 *
231
 * @param[in] method  The method name string. Valid values are:
232
 *                    - "password"
233
 *                    - "publickey"
234
 *                    - "keyboard-interactive"
235
 *                    - "hostbased"
236
 *                    - "gssapi-with-mic"
237
 *                    - "gssapi-keyex"
238
 *
239
 * @returns The SSH_AUTH_METHOD_* bitmask, or 0 if the name is unknown.
240
 */
241
static uint32_t ssh_auth_method_from_name(const char *method)
242
0
{
243
0
    if (strcmp(method, "password") == 0) {
244
0
        return SSH_AUTH_METHOD_PASSWORD;
245
0
    }
246
0
    if (strcmp(method, "publickey") == 0) {
247
0
        return SSH_AUTH_METHOD_PUBLICKEY;
248
0
    }
249
0
    if (strcmp(method, "keyboard-interactive") == 0) {
250
0
        return SSH_AUTH_METHOD_INTERACTIVE;
251
0
    }
252
0
    if (strcmp(method, "hostbased") == 0) {
253
0
        return SSH_AUTH_METHOD_HOSTBASED;
254
0
    }
255
#ifdef WITH_GSSAPI
256
    if (strcmp(method, "gssapi-with-mic") == 0) {
257
        return SSH_AUTH_METHOD_GSSAPI_MIC;
258
    }
259
    if (strcmp(method, "gssapi-keyex") == 0) {
260
        return SSH_AUTH_METHOD_GSSAPI_KEYEX;
261
    }
262
#endif
263
0
    return 0;
264
0
}
265
266
/**
267
 * @internal
268
 *
269
 * @brief Handles a SSH_USERAUTH_FAILURE packet.
270
 *
271
 * This handles the complete or partial authentication failure.
272
 */
273
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) {
274
0
    const char *current_method = ssh_auth_get_current_method(session);
275
0
    char *auth_methods = NULL;
276
0
    char *methods_copy = NULL;
277
0
    uint8_t partial = 0;
278
0
    int rc;
279
0
    (void) type;
280
0
    (void) user;
281
282
0
    rc = ssh_buffer_unpack(packet, "sb", &auth_methods, &partial);
283
0
    if (rc != SSH_OK) {
284
0
        ssh_set_error(session, SSH_FATAL,
285
0
                      "Invalid SSH_MSG_USERAUTH_FAILURE message");
286
0
        session->auth.state = SSH_AUTH_STATE_ERROR;
287
0
        goto end;
288
0
    }
289
290
0
    if (partial) {
291
0
        session->auth.state = SSH_AUTH_STATE_PARTIAL;
292
0
        SSH_LOG(SSH_LOG_DEBUG,
293
0
                "Partial success for '%s'. Authentication that can continue: %s",
294
0
                current_method,
295
0
                auth_methods);
296
0
    } else {
297
0
        session->auth.state = SSH_AUTH_STATE_FAILED;
298
0
        ssh_set_error(session, SSH_REQUEST_DENIED,
299
0
                      "Access denied for '%s'. Authentication that can continue: %s",
300
0
                      current_method,
301
0
                      auth_methods);
302
0
        SSH_LOG(SSH_LOG_DEBUG,
303
0
                "%s",
304
0
                ssh_get_error(session));
305
306
0
    }
307
0
    methods_copy = strdup(auth_methods);
308
0
    if (methods_copy != NULL) {
309
0
        char *saveptr = NULL;
310
0
        char *tok = strtok_r(methods_copy, ",", &saveptr);
311
312
0
        session->auth.supported_methods = 0;
313
0
        while (tok != NULL) {
314
0
            session->auth.supported_methods |=
315
0
                ssh_auth_method_from_name(tok);
316
0
            tok = strtok_r(NULL, ",", &saveptr);
317
0
        }
318
0
        SAFE_FREE(methods_copy);
319
0
    }
320
0
end:
321
0
    session->auth.current_method = SSH_AUTH_METHOD_UNKNOWN;
322
0
    SAFE_FREE(auth_methods);
323
0
    SAFE_FREE(methods_copy);
324
325
0
    return SSH_PACKET_USED;
326
0
}
327
328
/**
329
 * @internal
330
 *
331
 * @brief Handles a SSH_USERAUTH_SUCCESS packet.
332
 *
333
 * It is also used to communicate the new to the upper levels.
334
 */
335
SSH_PACKET_CALLBACK(ssh_packet_userauth_success)
336
0
{
337
0
  struct ssh_crypto_struct *crypto = NULL;
338
339
0
  (void)packet;
340
0
  (void)type;
341
0
  (void)user;
342
343
0
  SSH_LOG(SSH_LOG_DEBUG, "Authentication successful");
344
0
  SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_SUCCESS");
345
346
0
  session->auth.state = SSH_AUTH_STATE_SUCCESS;
347
0
  session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
348
0
  session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
349
350
0
  crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
351
0
  if (crypto != NULL && crypto->delayed_compress_out) {
352
0
      SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT");
353
0
      crypto->do_compress_out = 1;
354
0
  }
355
356
0
  crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
357
0
  if (crypto != NULL && crypto->delayed_compress_in) {
358
0
      SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN");
359
0
      crypto->do_compress_in = 1;
360
0
  }
361
362
    /* Reset errors by previous authentication methods. */
363
0
    ssh_reset_error(session);
364
0
    session->auth.current_method = SSH_AUTH_METHOD_UNKNOWN;
365
0
  return SSH_PACKET_USED;
366
0
}
367
368
/**
369
 * @internal
370
 *
371
 * @brief Handles a SSH_USERAUTH_PK_OK or SSH_USERAUTH_INFO_REQUEST packet.
372
 *
373
 * Since the two types of packets share the same code, additional work is done
374
 * to understand if we are in a public key or keyboard-interactive context.
375
 */
376
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok) {
377
0
    int rc;
378
379
0
    SSH_LOG(SSH_LOG_TRACE,
380
0
            "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
381
382
0
    if (session->auth.state == SSH_AUTH_STATE_KBDINT_SENT) {
383
        /* Assuming we are in keyboard-interactive context */
384
0
        SSH_LOG(SSH_LOG_TRACE,
385
0
                "keyboard-interactive context, "
386
0
                "assuming SSH_USERAUTH_INFO_REQUEST");
387
0
        rc = ssh_packet_userauth_info_request(session,type,packet,user);
388
#ifdef WITH_GSSAPI
389
    } else if (session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) {
390
        rc = ssh_packet_userauth_gssapi_response(session, type, packet, user);
391
#endif
392
0
    } else if (session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) {
393
0
        session->auth.state = SSH_AUTH_STATE_PK_OK;
394
0
        SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
395
0
        rc = SSH_PACKET_USED;
396
0
    } else {
397
0
        session->auth.state = SSH_AUTH_STATE_ERROR;
398
0
        SSH_LOG(SSH_LOG_TRACE, "SSH_USERAUTH_PK_OK received in wrong state");
399
0
        rc = SSH_PACKET_USED;
400
0
    }
401
402
0
    return rc;
403
0
}
404
405
/**
406
 * @brief Get available authentication methods from the server.
407
 *
408
 * This requires the function ssh_userauth_none() to be called before the
409
 * methods are available. The server MAY return a list of methods that may
410
 * continue.
411
 *
412
 * If the PreferredAuthentications option is set via ssh_options_set(), only
413
 * methods listed in that option will be returned, filtered by intersection
414
 * with server-advertised methods. This allows the client to restrict which
415
 * authentication methods are attempted. Method name resolution is handled
416
 * by ssh_auth_method_from_name().
417
 *
418
 * @param[in] session   The SSH session.
419
 *
420
 * @param[in] username  Deprecated, set to NULL.
421
 *
422
 * @returns             A bitfield of the following values:
423
 *                      - SSH_AUTH_METHOD_PASSWORD
424
 *                      - SSH_AUTH_METHOD_PUBLICKEY
425
 *                      - SSH_AUTH_METHOD_HOSTBASED
426
 *                      - SSH_AUTH_METHOD_INTERACTIVE
427
 *                      - SSH_AUTH_METHOD_GSSAPI_MIC
428
 *                      - SSH_AUTH_METHOD_GSSAPI_KEYEX
429
 *
430
 * @warning Other reserved flags may appear in future versions.
431
 * @see ssh_userauth_none()
432
 * @see ssh_options_set()
433
 * @see ssh_auth_method_from_name()
434
 */
435
int ssh_userauth_list(ssh_session session, const char *username)
436
0
{
437
0
    int methods = 0;
438
0
    (void) username; /* unused */
439
440
0
    if (session == NULL) {
441
0
        return 0;
442
0
    }
443
444
0
    methods = session->auth.supported_methods;
445
446
0
    if (session->opts.preferred_authentications != NULL) {
447
0
        int allowed = 0;
448
0
        char *saveptr = NULL;
449
0
        char *method = NULL;
450
0
        char *auth_copy = strdup(session->opts.preferred_authentications);
451
452
0
        if (auth_copy == NULL) {
453
0
            ssh_set_error_oom(session);
454
0
            SSH_LOG(SSH_LOG_WARNING,
455
0
                    "Failed to allocate memory for PreferredAuthentications");
456
0
            return methods;
457
0
        }
458
459
0
        method = strtok_r(auth_copy, ",", &saveptr);
460
461
0
        while (method != NULL) {
462
0
            char *end = NULL;
463
464
            /* Trim leading whitespace */
465
0
            while (*method == ' ' || *method == '\t') {
466
0
                method++;
467
0
            }
468
            /* Trim trailing whitespace */
469
0
            end = method + strlen(method) - 1;
470
0
            while (end > method && (*end == ' ' || *end == '\t')) {
471
0
                *end = '\0';
472
0
                end--;
473
0
            }
474
475
0
            allowed |= ssh_auth_method_from_name(method);
476
477
0
            method = strtok_r(NULL, ",", &saveptr);
478
0
        }
479
480
0
        free(auth_copy);
481
482
0
        if (methods != (methods & allowed)) {
483
0
            SSH_LOG(SSH_LOG_DEBUG,
484
0
                    "PreferredAuthentications filtered methods from 0x%x to 0x%x",
485
0
                    methods,
486
0
                    methods & allowed);
487
0
        }
488
489
0
        methods &= allowed;
490
0
    }
491
492
0
    return methods;
493
0
}
494
495
/**
496
 * @brief Try to authenticate through the "none" method.
497
 *
498
 * @param[in] session   The ssh session to use.
499
 *
500
 * @param[in] username    The username, this SHOULD be NULL.
501
 *
502
 * @returns SSH_AUTH_ERROR:   A serious error happened.\n
503
 *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
504
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
505
 *                            have to use another method\n
506
 *          SSH_AUTH_SUCCESS: Authentication success\n
507
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
508
 *                            later.
509
 *
510
 * @note Most server implementations do not permit changing the username during
511
 * authentication. The username should only be set with ssh_options_set() only
512
 * before you connect to the server.
513
 */
514
int ssh_userauth_none(ssh_session session, const char *username)
515
0
{
516
0
    int rc;
517
518
0
    switch (session->pending_call_state) {
519
0
        case SSH_PENDING_CALL_NONE:
520
0
            break;
521
0
        case SSH_PENDING_CALL_AUTH_NONE:
522
0
            goto pending;
523
0
        default:
524
0
            ssh_set_error(session, SSH_FATAL,
525
0
                          "Wrong state (%d) during pending SSH call",
526
0
                          session->pending_call_state);
527
0
            return SSH_AUTH_ERROR;
528
0
    }
529
530
0
    rc = ssh_userauth_request_service(session);
531
0
    if (rc == SSH_AGAIN) {
532
0
        return SSH_AUTH_AGAIN;
533
0
    } else if (rc == SSH_ERROR) {
534
0
        return SSH_AUTH_ERROR;
535
0
    }
536
537
    /* request */
538
0
    rc = ssh_buffer_pack(session->out_buffer, "bsss",
539
0
            SSH2_MSG_USERAUTH_REQUEST,
540
0
            username ? username : session->opts.username,
541
0
            "ssh-connection",
542
0
            "none"
543
0
            );
544
0
    if (rc < 0) {
545
0
        goto fail;
546
0
    }
547
548
0
    session->auth.current_method = SSH_AUTH_METHOD_NONE;
549
0
    session->auth.state = SSH_AUTH_STATE_AUTH_NONE_SENT;
550
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE;
551
0
    rc = ssh_packet_send(session);
552
0
    if (rc == SSH_ERROR) {
553
0
        return SSH_AUTH_ERROR;
554
0
    }
555
556
0
pending:
557
0
    rc = ssh_userauth_get_response(session);
558
0
    if (rc != SSH_AUTH_AGAIN) {
559
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
560
0
    }
561
562
0
    return rc;
563
0
fail:
564
0
    ssh_set_error_oom(session);
565
0
    ssh_buffer_reinit(session->out_buffer);
566
567
0
    return SSH_AUTH_ERROR;
568
0
}
569
570
/**
571
 * @internal
572
 *
573
 * @brief Adds the server's public key to the authentication request.
574
 *
575
 * This function is used internally when the hostbound public key authentication
576
 * extension is enabled. It export the server's public key and adds it to the
577
 * authentication buffer.
578
 *
579
 * @param[in]  session          The SSH session.
580
 *
581
 * @returns SSH_OK on success, SSH_ERROR if an error occurred.
582
 */
583
static int add_hostbound_pubkey(ssh_session session)
584
0
{
585
0
    int rc;
586
0
    ssh_string server_pubkey_s = NULL;
587
588
0
    if (session == NULL) {
589
0
        return SSH_ERROR;
590
0
    }
591
592
0
    if (session->current_crypto == NULL ||
593
0
        session->current_crypto->server_pubkey == NULL) {
594
0
        ssh_set_error(session,
595
0
                      SSH_FATAL,
596
0
                      "Invalid session or server public key");
597
0
        return SSH_ERROR;
598
0
    }
599
600
0
    rc = ssh_pki_export_pubkey_blob(session->current_crypto->server_pubkey,
601
0
                                    &server_pubkey_s);
602
0
    if (rc < 0) {
603
0
        goto error;
604
0
    }
605
606
0
    rc = ssh_buffer_add_ssh_string(session->out_buffer, server_pubkey_s);
607
0
    if (rc < 0) {
608
0
        goto error;
609
0
    }
610
611
0
error:
612
0
    SSH_STRING_FREE(server_pubkey_s);
613
0
    return rc;
614
0
}
615
616
static bool use_hostbound_pubkey_auth(ssh_session session)
617
0
{
618
0
    if ((session->extensions & SSH_EXT_PUBLICKEY_HOSTBOUND) == 0 ||
619
0
        session->current_crypto == NULL ||
620
0
        session->current_crypto->server_pubkey == NULL) {
621
0
        return false;
622
0
    }
623
624
0
    return session->opts.pubkey_auth == SSH_PUBKEY_AUTH_ALL ||
625
0
           session->opts.pubkey_auth == SSH_PUBKEY_AUTH_HOST_BOUND;
626
0
}
627
628
/**
629
 * @internal
630
 *
631
 * @brief Build a public key authentication request.
632
 *
633
 * This helper function creates a SSH2_MSG_USERAUTH_REQUEST message for public
634
 * key authentication and adds the server's public key if the hostbound
635
 * extension is enabled.
636
 *
637
 * @param[in] session       The SSH session.
638
 * @param[in] username      The username, may be NULL.
639
 * @param[in] auth_type     Authentication type (0 for key offer, 1 for actual
640
 * auth).
641
 * @param[in] sig_type_c    The signature algorithm name.
642
 * @param[in] pubkey_s      The public key string.
643
 *
644
 * @return  SSH_OK on success, SSH_ERROR if an error occurred.
645
 */
646
static int build_pubkey_auth_request(ssh_session session,
647
                                     const char *username,
648
                                     int has_signature,
649
                                     const char *sig_type_c,
650
                                     ssh_string pubkey_s)
651
0
{
652
0
    int rc;
653
0
    const char *auth_method = "publickey";
654
655
0
    if (use_hostbound_pubkey_auth(session)) {
656
0
        auth_method = "publickey-hostbound-v00@openssh.com";
657
0
    }
658
659
    /* request */
660
0
    rc = ssh_buffer_pack(session->out_buffer,
661
0
                         "bsssbsS",
662
0
                         SSH2_MSG_USERAUTH_REQUEST,
663
0
                         username ? username : session->opts.username,
664
0
                         "ssh-connection",
665
0
                         auth_method,
666
0
                         has_signature, /* private key? */
667
0
                         sig_type_c,    /* algo */
668
0
                         pubkey_s       /* public key */
669
0
    );
670
0
    if (rc < 0) {
671
0
        return SSH_ERROR;
672
0
    }
673
674
0
    if (use_hostbound_pubkey_auth(session)) {
675
0
        rc = add_hostbound_pubkey(session);
676
0
        if (rc < 0) {
677
0
            return SSH_ERROR;
678
0
        }
679
0
    }
680
681
0
    return SSH_OK;
682
0
}
683
684
static int check_pubkey_auth_mode(ssh_session session)
685
0
{
686
0
    if (!(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH) ||
687
0
        session->opts.pubkey_auth == SSH_PUBKEY_AUTH_NO) {
688
0
        SSH_LOG(SSH_LOG_DEBUG, "Public key authentication is disabled");
689
0
        return SSH_AUTH_DENIED;
690
0
    }
691
692
0
    return SSH_OK;
693
0
}
694
695
/**
696
 * @brief Try to authenticate with the given public key.
697
 *
698
 * To avoid unnecessary processing and user interaction, the following method
699
 * is provided for querying whether authentication using the 'pubkey' would
700
 * be possible.
701
 *
702
 * @param[in] session     The SSH session.
703
 *
704
 * @param[in] username    The username, this SHOULD be NULL.
705
 *
706
 * @param[in] pubkey      The public key to try.
707
 *
708
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
709
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
710
 *                            authentication token. Try another key or another
711
 *                            method.\n
712
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
713
 *                            have to use another method.\n
714
 *          SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
715
 *                            ssh_userauth_publickey().\n
716
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
717
 *                            later.
718
 *
719
 * @note Most server implementations do not permit changing the username during
720
 * authentication. The username should only be set with ssh_options_set() only
721
 * before you connect to the server.
722
 */
723
int ssh_userauth_try_publickey(ssh_session session,
724
                               const char *username,
725
                               const ssh_key pubkey)
726
0
{
727
0
    ssh_string pubkey_s = NULL;
728
0
    const char *sig_type_c = NULL;
729
0
    bool allowed;
730
0
    int rc;
731
732
0
    if (session == NULL) {
733
0
        return SSH_AUTH_ERROR;
734
0
    }
735
736
0
    if (pubkey == NULL || !ssh_key_is_public(pubkey)) {
737
0
        ssh_set_error(session, SSH_FATAL, "Invalid pubkey");
738
0
        return SSH_AUTH_ERROR;
739
0
    }
740
741
0
    switch (session->pending_call_state) {
742
0
    case SSH_PENDING_CALL_NONE:
743
0
        rc = check_pubkey_auth_mode(session);
744
0
        if (rc != SSH_OK) {
745
0
            return rc;
746
0
        }
747
0
        session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
748
0
        break;
749
0
    case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
750
0
        if (session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) {
751
0
            goto pending;
752
0
        }
753
0
        break;
754
0
    default:
755
0
        ssh_set_error(session,
756
0
                      SSH_FATAL,
757
0
                      "Wrong state (%d) during pending SSH call",
758
0
                      session->pending_call_state);
759
0
        return SSH_AUTH_ERROR;
760
0
    }
761
762
    /* Note, that this is intentionally before checking the signature type
763
     * compatibility to make sure the possible EXT_INFO packet is processed,
764
     * extensions recorded and the right signature type is used below
765
     */
766
0
    rc = ssh_userauth_request_service(session);
767
0
    if (rc == SSH_AGAIN) {
768
0
        return SSH_AUTH_AGAIN;
769
0
    } else if (rc == SSH_ERROR) {
770
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
771
0
        return SSH_AUTH_ERROR;
772
0
    }
773
774
    /* Check if the given public key algorithm is allowed */
775
0
    sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
776
0
    if (sig_type_c == NULL) {
777
0
        ssh_set_error(session,
778
0
                      SSH_REQUEST_DENIED,
779
0
                      "Invalid key type (unknown)");
780
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
781
0
        return SSH_AUTH_DENIED;
782
0
    }
783
0
    rc = ssh_key_algorithm_allowed(session, sig_type_c);
784
0
    if (!rc) {
785
0
        ssh_set_error(session,
786
0
                      SSH_REQUEST_DENIED,
787
0
                      "The key algorithm '%s' is not allowed to be used by"
788
0
                      " PUBLICKEY_ACCEPTED_TYPES configuration option",
789
0
                      sig_type_c);
790
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
791
0
        return SSH_AUTH_DENIED;
792
0
    }
793
0
    allowed = ssh_key_size_allowed(session, pubkey);
794
0
    if (!allowed) {
795
0
        ssh_set_error(session,
796
0
                      SSH_REQUEST_DENIED,
797
0
                      "The '%s' key type of size %d is not allowed by "
798
0
                      "RSA_MIN_SIZE",
799
0
                      sig_type_c,
800
0
                      ssh_key_size(pubkey));
801
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
802
0
        return SSH_AUTH_DENIED;
803
0
    }
804
805
    /* public key */
806
0
    rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s);
807
0
    if (rc < 0) {
808
0
        goto fail;
809
0
    }
810
811
0
    SSH_LOG(SSH_LOG_TRACE, "Trying signature type %s", sig_type_c);
812
0
    rc = build_pubkey_auth_request(session, username, 0, sig_type_c, pubkey_s);
813
0
    if (rc < 0) {
814
0
        goto fail;
815
0
    }
816
0
    SSH_STRING_FREE(pubkey_s);
817
818
0
    session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
819
0
    session->auth.state = SSH_AUTH_STATE_PUBKEY_OFFER_SENT;
820
0
    rc = ssh_packet_send(session);
821
0
    if (rc == SSH_ERROR) {
822
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
823
0
        return SSH_AUTH_ERROR;
824
0
    }
825
826
0
pending:
827
0
    rc = ssh_userauth_get_response(session);
828
0
    if (rc != SSH_AUTH_AGAIN) {
829
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
830
0
    }
831
832
0
    return rc;
833
0
fail:
834
0
    SSH_STRING_FREE(pubkey_s);
835
0
    ssh_set_error_oom(session);
836
0
    ssh_buffer_reinit(session->out_buffer);
837
0
    session->pending_call_state = SSH_PENDING_CALL_NONE;
838
839
0
    return SSH_AUTH_ERROR;
840
0
}
841
842
/**
843
 * @brief Authenticate with public/private key or certificate.
844
 *
845
 * @param[in] session     The SSH session.
846
 *
847
 * @param[in] username    The username, this SHOULD be NULL.
848
 *
849
 * @param[in] privkey     The private key for authentication.
850
 *
851
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
852
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
853
 *                            authentication token. Try another key or another
854
 *                            method.\n
855
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
856
 *                            have to use another method.\n
857
 *          SSH_AUTH_SUCCESS: The public key is accepted.\n
858
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
859
 *                            later.
860
 *
861
 * @note Most server implementations do not permit changing the username during
862
 * authentication. The username should only be set with ssh_options_set() only
863
 * before you connect to the server.
864
 */
865
int ssh_userauth_publickey(ssh_session session,
866
                           const char *username,
867
                           const ssh_key privkey)
868
0
{
869
0
    ssh_string str = NULL;
870
0
    bool allowed;
871
0
    int rc;
872
0
    const char *sig_type_c = NULL;
873
0
    enum ssh_keytypes_e key_type;
874
0
    enum ssh_digest_e hash_type;
875
876
0
    if (session == NULL) {
877
0
        return SSH_AUTH_ERROR;
878
0
    }
879
880
0
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
881
0
        ssh_set_error(session, SSH_FATAL, "Invalid private key");
882
0
        return SSH_AUTH_ERROR;
883
0
    }
884
885
0
    switch (session->pending_call_state) {
886
0
    case SSH_PENDING_CALL_NONE:
887
0
        rc = check_pubkey_auth_mode(session);
888
0
        if (rc != SSH_OK) {
889
0
            return rc;
890
0
        }
891
0
        session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
892
0
        break;
893
0
    case SSH_PENDING_CALL_AUTH_PUBKEY:
894
0
        if (session->auth.state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT) {
895
0
            goto pending;
896
0
        }
897
0
        break;
898
0
    default:
899
0
        ssh_set_error(
900
0
            session,
901
0
            SSH_FATAL,
902
0
            "Bad call during pending SSH call in ssh_userauth_try_publickey");
903
0
        return SSH_AUTH_ERROR;
904
0
    }
905
906
    /* Note, that this is intentionally before checking the signature type
907
     * compatibility to make sure the possible EXT_INFO packet is processed,
908
     * extensions recorded and the right signature type is used below
909
     */
910
0
    rc = ssh_userauth_request_service(session);
911
0
    if (rc == SSH_AGAIN) {
912
0
        return SSH_AUTH_AGAIN;
913
0
    } else if (rc == SSH_ERROR) {
914
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
915
0
        return SSH_AUTH_ERROR;
916
0
    }
917
918
    /* Cert auth requires presenting the cert type name (*-cert@openssh.com) */
919
0
    key_type = privkey->cert != NULL ? privkey->cert_type : privkey->type;
920
921
    /* Check if the given public key algorithm is allowed */
922
0
    sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
923
0
    if (sig_type_c == NULL) {
924
0
        ssh_set_error(session,
925
0
                      SSH_REQUEST_DENIED,
926
0
                      "Invalid key type (unknown)");
927
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
928
0
        return SSH_AUTH_DENIED;
929
0
    }
930
0
    rc = ssh_key_algorithm_allowed(session, sig_type_c);
931
0
    if (!rc) {
932
0
        ssh_set_error(session,
933
0
                      SSH_REQUEST_DENIED,
934
0
                      "The key algorithm '%s' is not allowed to be used by"
935
0
                      " PUBLICKEY_ACCEPTED_TYPES configuration option",
936
0
                      sig_type_c);
937
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
938
0
        return SSH_AUTH_DENIED;
939
0
    }
940
0
    allowed = ssh_key_size_allowed(session, privkey);
941
0
    if (!allowed) {
942
0
        ssh_set_error(session,
943
0
                      SSH_REQUEST_DENIED,
944
0
                      "The '%s' key type of size %d is not allowed by "
945
0
                      "RSA_MIN_SIZE",
946
0
                      sig_type_c,
947
0
                      ssh_key_size(privkey));
948
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
949
0
        return SSH_AUTH_DENIED;
950
0
    }
951
952
    /* get public key or cert */
953
0
    rc = ssh_pki_export_pubkey_blob(privkey, &str);
954
0
    if (rc < 0) {
955
0
        goto fail;
956
0
    }
957
958
0
    SSH_LOG(SSH_LOG_TRACE, "Sending signature type %s", sig_type_c);
959
0
    rc = build_pubkey_auth_request(session, username, 1, sig_type_c, str);
960
0
    if (rc < 0) {
961
0
        goto fail;
962
0
    }
963
0
    SSH_STRING_FREE(str);
964
965
    /* Get the hash type to be used in the signature based on the key type */
966
0
    hash_type = ssh_key_type_to_hash(session, privkey->type);
967
968
    /* sign the buffer with the private key */
969
0
    str = ssh_pki_do_sign(session, session->out_buffer, privkey, hash_type);
970
0
    if (str == NULL) {
971
0
        goto fail;
972
0
    }
973
974
0
    rc = ssh_buffer_add_ssh_string(session->out_buffer, str);
975
0
    SSH_STRING_FREE(str);
976
0
    str = NULL;
977
0
    if (rc < 0) {
978
0
        goto fail;
979
0
    }
980
981
0
    session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
982
0
    session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
983
0
    rc = ssh_packet_send(session);
984
0
    if (rc == SSH_ERROR) {
985
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
986
0
        return SSH_AUTH_ERROR;
987
0
    }
988
989
0
pending:
990
0
    rc = ssh_userauth_get_response(session);
991
0
    if (rc != SSH_AUTH_AGAIN) {
992
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
993
0
    }
994
995
0
    return rc;
996
0
fail:
997
0
    SSH_STRING_FREE(str);
998
0
    ssh_set_error_oom(session);
999
0
    ssh_buffer_reinit(session->out_buffer);
1000
0
    session->pending_call_state = SSH_PENDING_CALL_NONE;
1001
1002
0
    return SSH_AUTH_ERROR;
1003
0
}
1004
1005
static int ssh_userauth_agent_publickey(ssh_session session,
1006
                                        const char *username,
1007
                                        ssh_key pubkey)
1008
0
{
1009
0
    ssh_string pubkey_s = NULL;
1010
0
    ssh_string sig_blob = NULL;
1011
0
    const char *sig_type_c = NULL;
1012
0
    bool allowed;
1013
0
    int rc;
1014
1015
0
    switch (session->pending_call_state) {
1016
0
    case SSH_PENDING_CALL_NONE:
1017
0
        if (session->auth.state != SSH_AUTH_STATE_PK_OK) {
1018
0
            rc = check_pubkey_auth_mode(session);
1019
0
            if (rc != SSH_OK) {
1020
0
                return rc;
1021
0
            }
1022
0
        }
1023
0
        session->pending_call_state = SSH_PENDING_CALL_AUTH_AGENT;
1024
0
        break;
1025
0
    case SSH_PENDING_CALL_AUTH_AGENT:
1026
0
        if (session->auth.state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT) {
1027
0
            goto pending;
1028
0
        }
1029
0
        break;
1030
0
    default:
1031
0
        ssh_set_error(session,
1032
0
                      SSH_FATAL,
1033
0
                      "Bad call during pending SSH call in %s",
1034
0
                      __func__);
1035
0
        return SSH_ERROR;
1036
0
    }
1037
1038
    /* Note, that this is intentionally before checking the signature type
1039
     * compatibility to make sure the possible EXT_INFO packet is processed,
1040
     * extensions recorded and the right signature type is used below
1041
     */
1042
0
    rc = ssh_userauth_request_service(session);
1043
0
    if (rc == SSH_AGAIN) {
1044
0
        return SSH_AUTH_AGAIN;
1045
0
    } else if (rc == SSH_ERROR) {
1046
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1047
0
        return SSH_AUTH_ERROR;
1048
0
    }
1049
1050
    /* public key */
1051
0
    rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s);
1052
0
    if (rc < 0) {
1053
0
        goto fail;
1054
0
    }
1055
1056
    /* Check if the given public key algorithm is allowed */
1057
0
    sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
1058
0
    if (sig_type_c == NULL) {
1059
0
        ssh_set_error(session,
1060
0
                      SSH_REQUEST_DENIED,
1061
0
                      "Invalid key type (unknown)");
1062
0
        SSH_STRING_FREE(pubkey_s);
1063
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1064
0
        return SSH_AUTH_DENIED;
1065
0
    }
1066
0
    rc = ssh_key_algorithm_allowed(session, sig_type_c);
1067
0
    if (!rc) {
1068
0
        ssh_set_error(session,
1069
0
                      SSH_REQUEST_DENIED,
1070
0
                      "The key algorithm '%s' is not allowed to be used by"
1071
0
                      " PUBLICKEY_ACCEPTED_TYPES configuration option",
1072
0
                      sig_type_c);
1073
0
        SSH_STRING_FREE(pubkey_s);
1074
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1075
0
        return SSH_AUTH_DENIED;
1076
0
    }
1077
0
    allowed = ssh_key_size_allowed(session, pubkey);
1078
0
    if (!allowed) {
1079
0
        ssh_set_error(session,
1080
0
                      SSH_REQUEST_DENIED,
1081
0
                      "The '%s' key type of size %d is not allowed by "
1082
0
                      "RSA_MIN_SIZE",
1083
0
                      sig_type_c,
1084
0
                      ssh_key_size(pubkey));
1085
0
        SSH_STRING_FREE(pubkey_s);
1086
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1087
0
        return SSH_AUTH_DENIED;
1088
0
    }
1089
1090
0
    rc = build_pubkey_auth_request(session, username, 1, sig_type_c, pubkey_s);
1091
0
    if (rc < 0) {
1092
0
        goto fail;
1093
0
    }
1094
0
    SSH_STRING_FREE(pubkey_s);
1095
1096
    /* sign the buffer with the private key */
1097
0
    sig_blob = ssh_pki_do_sign_agent(session, session->out_buffer, pubkey);
1098
0
    if (sig_blob == NULL) {
1099
0
        goto fail;
1100
0
    }
1101
1102
0
    rc = ssh_buffer_add_ssh_string(session->out_buffer, sig_blob);
1103
0
    SSH_STRING_FREE(sig_blob);
1104
0
    if (rc < 0) {
1105
0
        goto fail;
1106
0
    }
1107
1108
0
    session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
1109
0
    session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
1110
0
    rc = ssh_packet_send(session);
1111
0
    if (rc == SSH_ERROR) {
1112
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1113
0
        return SSH_AUTH_ERROR;
1114
0
    }
1115
1116
0
pending:
1117
0
    rc = ssh_userauth_get_response(session);
1118
0
    if (rc != SSH_AUTH_AGAIN) {
1119
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1120
0
    }
1121
1122
0
    return rc;
1123
0
fail:
1124
0
    ssh_set_error_oom(session);
1125
0
    ssh_buffer_reinit(session->out_buffer);
1126
0
    SSH_STRING_FREE(pubkey_s);
1127
0
    SSH_STRING_FREE(sig_blob);
1128
0
    session->pending_call_state = SSH_PENDING_CALL_NONE;
1129
1130
0
    return SSH_AUTH_ERROR;
1131
0
}
1132
1133
enum ssh_agent_state_e {
1134
    SSH_AGENT_STATE_NONE = 0,
1135
    SSH_AGENT_STATE_PUBKEY,
1136
    SSH_AGENT_STATE_CERT,
1137
    SSH_AGENT_STATE_AUTH
1138
};
1139
1140
struct ssh_agent_state_struct {
1141
    enum ssh_agent_state_e state;
1142
    ssh_key pubkey;
1143
    char *comment;
1144
};
1145
1146
/* Internal function */
1147
void ssh_agent_state_free(void *data)
1148
0
{
1149
0
    struct ssh_agent_state_struct *state = data;
1150
1151
0
    if (state) {
1152
0
        SSH_STRING_FREE_CHAR(state->comment);
1153
0
        ssh_key_free(state->pubkey);
1154
0
        free(state);
1155
0
    }
1156
0
}
1157
1158
/**
1159
 * @brief Try to do public key authentication with ssh agent.
1160
 *
1161
 * @param[in]  session  The ssh session to use.
1162
 *
1163
 * @param[in]  username The username, this SHOULD be NULL.
1164
 *
1165
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
1166
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
1167
 *                            authentication token. Try another key or another
1168
 *                            method.\n
1169
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1170
 *                            have to use another method.\n
1171
 *          SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
1172
 *                            ssh_userauth_publickey().\n
1173
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1174
 *                            later.
1175
 *
1176
 * @note Most server implementations do not permit changing the username during
1177
 * authentication. The username should only be set with ssh_options_set() only
1178
 * before you connect to the server.
1179
 */
1180
int ssh_userauth_agent(ssh_session session, const char *username)
1181
0
{
1182
0
    int rc = SSH_AUTH_ERROR;
1183
0
    struct ssh_agent_state_struct *state = NULL;
1184
0
    ssh_key *configKeys = NULL;
1185
0
    ssh_key *configCerts = NULL;
1186
0
    size_t configKeysCount = 0;
1187
0
    size_t configCertsCount = 0;
1188
0
    size_t i;
1189
1190
0
    if (session == NULL) {
1191
0
        return SSH_AUTH_ERROR;
1192
0
    }
1193
1194
0
    if (session->agent_state == NULL &&
1195
0
        !(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
1196
0
        SSH_LOG(SSH_LOG_DEBUG, "Public key authentication is disabled");
1197
0
        return SSH_AUTH_DENIED;
1198
0
    }
1199
1200
0
    if (!ssh_agent_is_running(session)) {
1201
0
        return SSH_AUTH_DENIED;
1202
0
    }
1203
1204
0
    if (!session->agent_state) {
1205
0
        session->agent_state = calloc(1, sizeof(struct ssh_agent_state_struct));
1206
0
        if (!session->agent_state) {
1207
0
            ssh_set_error_oom(session);
1208
0
            return SSH_AUTH_ERROR;
1209
0
        }
1210
0
        session->agent_state->state = SSH_AGENT_STATE_NONE;
1211
0
    }
1212
1213
0
    state = session->agent_state;
1214
0
    if (state->pubkey == NULL) {
1215
0
        state->pubkey = ssh_agent_get_first_ident(session, &state->comment);
1216
0
    }
1217
1218
0
    if (state->pubkey == NULL) {
1219
0
        return SSH_AUTH_DENIED;
1220
0
    }
1221
1222
0
    if (session->opts.identities_only) {
1223
        /*
1224
         * Read keys mentioned in the config, so we can check if key from agent
1225
         * is in there.
1226
         */
1227
0
        size_t identityLen = ssh_list_count(session->opts.identity);
1228
0
        size_t certsLen = ssh_list_count(session->opts.certificate);
1229
0
        struct ssh_iterator *it = ssh_list_get_iterator(session->opts.identity);
1230
1231
0
        configKeys = malloc(identityLen * sizeof(ssh_key));
1232
0
        configCerts = malloc((certsLen + identityLen) * sizeof(ssh_key));
1233
0
        if (configKeys == NULL || configCerts == NULL) {
1234
0
            free(configKeys);
1235
0
            free(configCerts);
1236
0
            ssh_set_error_oom(session);
1237
0
            return SSH_AUTH_ERROR;
1238
0
        }
1239
1240
0
        while (it != NULL && configKeysCount < identityLen) {
1241
0
            const char *privkeyFile = ssh_iterator_value(const char *, it);
1242
0
            size_t certPathLen;
1243
0
            char *certFile = NULL;
1244
0
            ssh_key pubkey = NULL;
1245
0
            ssh_key cert = NULL;
1246
1247
            /*
1248
             * Read the private key file listed in the config, but we're only
1249
             * interested in the public key. Don't try to decrypt private key.
1250
             */
1251
0
            rc = ssh_pki_import_pubkey_file(privkeyFile, &pubkey);
1252
0
            if (rc == SSH_OK) {
1253
0
                configKeys[configKeysCount++] = pubkey;
1254
0
            } else {
1255
0
                char *pubkeyFile = NULL;
1256
0
                size_t pubkeyPathLen = strlen(privkeyFile) + sizeof(".pub");
1257
1258
0
                SSH_KEY_FREE(pubkey);
1259
1260
                /*
1261
                * If we couldn't get the public key from the private key file,
1262
                * try a .pub file instead.
1263
                */
1264
0
                pubkeyFile = malloc(pubkeyPathLen);
1265
0
                if (!pubkeyFile) {
1266
0
                    ssh_set_error_oom(session);
1267
0
                    rc = SSH_AUTH_ERROR;
1268
0
                    goto done;
1269
0
                }
1270
0
                snprintf(pubkeyFile, pubkeyPathLen, "%s.pub", privkeyFile);
1271
0
                rc = ssh_pki_import_pubkey_file(pubkeyFile, &pubkey);
1272
0
                free(pubkeyFile);
1273
0
                if (rc == SSH_OK) {
1274
0
                    configKeys[configKeysCount++] = pubkey;
1275
0
                } else if (pubkey) {
1276
0
                    SSH_KEY_FREE(pubkey);
1277
0
                }
1278
0
            }
1279
            /* Now try to see if there is a certificate with default name
1280
             * do not merge it yet with the key as we need to try first the
1281
             * non-certified key */
1282
0
            certPathLen = strlen(privkeyFile) + sizeof("-cert.pub");
1283
0
            certFile = malloc(certPathLen);
1284
0
            if (!certFile) {
1285
0
                ssh_set_error_oom(session);
1286
0
                rc = SSH_AUTH_ERROR;
1287
0
                goto done;
1288
0
            }
1289
0
            snprintf(certFile, certPathLen, "%s-cert.pub", privkeyFile);
1290
0
            rc = ssh_pki_import_cert_file(certFile, &cert);
1291
0
            free(certFile);
1292
0
            if (rc == SSH_OK) {
1293
0
                configCerts[configCertsCount++] = cert;
1294
0
            } else if (cert) {
1295
0
                SSH_KEY_FREE(cert);
1296
0
            }
1297
1298
0
            it = it->next;
1299
0
        }
1300
        /* And now load separately-listed certificates. */
1301
0
        it = ssh_list_get_iterator(session->opts.certificate);
1302
0
        while (it != NULL && configCertsCount < certsLen + identityLen) {
1303
0
            const char *certFile = ssh_iterator_value(const char *, it);
1304
0
            ssh_key cert = NULL;
1305
1306
0
            rc = ssh_pki_import_cert_file(certFile, &cert);
1307
0
            if (rc == SSH_OK) {
1308
0
                configCerts[configCertsCount++] = cert;
1309
0
            } else if (cert) {
1310
0
                SSH_KEY_FREE(cert);
1311
0
            }
1312
1313
0
            it = it->next;
1314
0
        }
1315
0
    }
1316
1317
0
    while (state->pubkey != NULL) {
1318
0
        if (state->state == SSH_AGENT_STATE_NONE) {
1319
0
            SSH_LOG(SSH_LOG_DEBUG,
1320
0
                    "Trying identity %s",
1321
0
                    state->comment);
1322
0
            if (session->opts.identities_only) {
1323
                /* Check if this key is one of the keys listed in the config */
1324
0
                bool found_key = false;
1325
0
                for (i = 0; i < configKeysCount; i++) {
1326
0
                    int cmp = ssh_key_cmp(state->pubkey,
1327
0
                                          configKeys[i],
1328
0
                                          SSH_KEY_CMP_PUBLIC);
1329
0
                    if (cmp == 0) {
1330
0
                        found_key = true;
1331
0
                        break;
1332
0
                    }
1333
0
                }
1334
                /* or in separate certificates */
1335
0
                for (i = 0; i < configCertsCount; i++) {
1336
0
                    int cmp = ssh_key_cmp(state->pubkey,
1337
0
                                          configCerts[i],
1338
0
                                          SSH_KEY_CMP_PUBLIC);
1339
0
                    if (cmp == 0) {
1340
0
                        found_key = true;
1341
0
                        break;
1342
0
                    }
1343
0
                }
1344
1345
0
                if (!found_key) {
1346
0
                    SSH_LOG(SSH_LOG_DEBUG,
1347
0
                            "Identities only is enabled and identity %s was "
1348
0
                            "not listed in config, skipping",
1349
0
                            state->comment);
1350
0
                    SSH_STRING_FREE_CHAR(state->comment);
1351
0
                    state->comment = NULL;
1352
0
                    SSH_KEY_FREE(state->pubkey);
1353
0
                    state->pubkey = ssh_agent_get_next_ident(
1354
0
                        session, &state->comment);
1355
1356
0
                    if (state->pubkey == NULL) {
1357
0
                        rc = SSH_AUTH_DENIED;
1358
0
                    }
1359
0
                    continue;
1360
0
                }
1361
0
            }
1362
0
        }
1363
0
        if (state->state == SSH_AGENT_STATE_NONE ||
1364
0
            state->state == SSH_AGENT_STATE_PUBKEY ||
1365
0
            state->state == SSH_AGENT_STATE_CERT) {
1366
0
            rc = ssh_userauth_try_publickey(session, username, state->pubkey);
1367
0
            if (rc == SSH_AUTH_ERROR) {
1368
0
                ssh_agent_state_free(state);
1369
0
                session->agent_state = NULL;
1370
0
                goto done;
1371
0
            } else if (rc == SSH_AUTH_AGAIN) {
1372
0
                state->state = (state->state == SSH_AGENT_STATE_NONE ?
1373
0
                                SSH_AGENT_STATE_PUBKEY : state->state);
1374
0
                goto done;
1375
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1376
0
                SSH_LOG(SSH_LOG_DEBUG,
1377
0
                        "Public key of %s refused by server",
1378
0
                        state->comment);
1379
0
                if (state->state == SSH_AGENT_STATE_PUBKEY) {
1380
0
                    for (i = 0; i < configCertsCount; i++) {
1381
0
                        int cmp = ssh_key_cmp(state->pubkey,
1382
0
                                              configCerts[i],
1383
0
                                              SSH_KEY_CMP_PUBLIC);
1384
0
                        if (cmp == 0) {
1385
0
                            SSH_LOG(SSH_LOG_DEBUG,
1386
0
                                    "Retry with matching certificate");
1387
0
                            SSH_KEY_FREE(state->pubkey);
1388
0
                            state->pubkey = ssh_key_dup(configCerts[i]);
1389
0
                            state->state = SSH_AGENT_STATE_CERT;
1390
0
                            continue;
1391
0
                        }
1392
0
                    }
1393
0
                }
1394
0
                SSH_STRING_FREE_CHAR(state->comment);
1395
0
                state->comment = NULL;
1396
0
                SSH_KEY_FREE(state->pubkey);
1397
0
                state->pubkey = ssh_agent_get_next_ident(session,
1398
0
                                                         &state->comment);
1399
0
                state->state = SSH_AGENT_STATE_NONE;
1400
0
                continue;
1401
0
            }
1402
1403
0
            SSH_LOG(SSH_LOG_DEBUG,
1404
0
                    "Public key of %s accepted by server",
1405
0
                    state->comment);
1406
0
            state->state = SSH_AGENT_STATE_AUTH;
1407
0
        }
1408
0
        if (state->state == SSH_AGENT_STATE_AUTH) {
1409
0
            rc = ssh_userauth_agent_publickey(session, username, state->pubkey);
1410
0
            if (rc == SSH_AUTH_AGAIN) {
1411
0
                goto done;
1412
0
            }
1413
0
            SSH_STRING_FREE_CHAR(state->comment);
1414
0
            state->comment = NULL;
1415
0
            if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_PARTIAL) {
1416
0
                ssh_agent_state_free(session->agent_state);
1417
0
                session->agent_state = NULL;
1418
0
                goto done;
1419
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1420
0
                SSH_LOG(SSH_LOG_DEBUG,
1421
0
                        "Server accepted public key but refused the signature");
1422
0
                SSH_KEY_FREE(state->pubkey);
1423
0
                state->pubkey = ssh_agent_get_next_ident(session,
1424
0
                                                         &state->comment);
1425
0
                state->state = SSH_AGENT_STATE_NONE;
1426
0
                continue;
1427
0
            }
1428
0
            ssh_agent_state_free (session->agent_state);
1429
0
            session->agent_state = NULL;
1430
0
            rc = SSH_AUTH_SUCCESS;
1431
0
            goto done;
1432
0
        }
1433
0
    }
1434
1435
0
    ssh_agent_state_free (session->agent_state);
1436
0
    session->agent_state = NULL;
1437
0
done:
1438
0
    for (i = 0; i < configKeysCount; i++) {
1439
0
        ssh_key_free(configKeys[i]);
1440
0
    }
1441
0
    free(configKeys);
1442
0
    for (i = 0; i < configCertsCount; i++) {
1443
0
        ssh_key_free(configCerts[i]);
1444
0
    }
1445
0
    free(configCerts);
1446
0
    return rc;
1447
0
}
1448
1449
enum ssh_auth_auto_state_e {
1450
    SSH_AUTH_AUTO_STATE_NONE = 0,
1451
    SSH_AUTH_AUTO_STATE_PUBKEY,
1452
    SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
1453
    SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE,
1454
    SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION_INIT,
1455
    SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION,
1456
    SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
1457
};
1458
1459
struct ssh_auth_auto_state_struct {
1460
    enum ssh_auth_auto_state_e state;
1461
    struct ssh_iterator *it;
1462
    ssh_key privkey;
1463
    ssh_key pubkey;
1464
    ssh_key cert;
1465
    struct ssh_iterator *cert_it;
1466
};
1467
1468
/**
1469
 * @brief Get the identity that is currently being processed by
1470
 * ssh_userauth_publickey_auto()
1471
 *
1472
 * This is meant to be used by a callback that happens as part of the
1473
 * execution of ssh_userauth_publickey_auto().  The auth_function
1474
 * callback might want to know which key a passphrase is needed for,
1475
 * for example.
1476
 *
1477
 * @param[in]  session     The SSH session.
1478
 *
1479
 * @param[out] value       The value to get into. As a char**, space will be
1480
 *                         allocated by the function for the value, it is
1481
 *                         your responsibility to free the memory using
1482
 *                         ssh_string_free_char().
1483
 *
1484
 * @return  SSH_OK on success, SSH_ERROR on error.
1485
 */
1486
int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
1487
                                                     char** value)
1488
0
{
1489
0
    const char *id = NULL;
1490
1491
0
    if (session == NULL) {
1492
0
        return SSH_ERROR;
1493
0
    }
1494
1495
0
    if (value == NULL) {
1496
0
        ssh_set_error_invalid(session);
1497
0
        return SSH_ERROR;
1498
0
    }
1499
1500
0
    if (session->auth.auto_state != NULL &&
1501
0
        session->auth.auto_state->it != NULL) {
1502
0
        id = ssh_iterator_value(char *, session->auth.auto_state->it);
1503
0
    }
1504
1505
0
    if (id == NULL) {
1506
0
        return SSH_ERROR;
1507
0
    }
1508
1509
0
    *value = strdup(id);
1510
0
    if (*value == NULL) {
1511
0
        ssh_set_error_oom(session);
1512
0
        return SSH_ERROR;
1513
0
    }
1514
1515
0
    return SSH_OK;
1516
0
}
1517
1518
/**
1519
 * @brief Tries to automatically authenticate with public key and "none"
1520
 *
1521
 * It may fail, for instance it doesn't ask for a password and uses a default
1522
 * asker for passphrases (in case the private key is encrypted).
1523
 *
1524
 * @param[in]  session     The SSH session.
1525
 *
1526
 * @param[in]  username    The username, this SHOULD be NULL.
1527
 *
1528
 * @param[in]  passphrase  Use this passphrase to unlock the privatekey. Use NULL
1529
 *                         if you don't want to use a passphrase or the user
1530
 *                         should be asked.
1531
 *
1532
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
1533
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
1534
 *                            authentication token. Try another key or another
1535
 *                            method.\n
1536
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1537
 *                            have to use another method.\n
1538
 *          SSH_AUTH_SUCCESS: Authentication success\n
1539
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1540
 *                            later.
1541
 *
1542
 * @note Most server implementations do not permit changing the username during
1543
 * authentication. The username should only be set with ssh_options_set() only
1544
 * before you connect to the server.
1545
 *
1546
 * The OpenSSH iterates over the identities and first try the plain public key
1547
 * and then the certificate if it is in place.
1548
 */
1549
int ssh_userauth_publickey_auto(ssh_session session,
1550
                                const char *username,
1551
                                const char *passphrase)
1552
0
{
1553
0
    ssh_auth_callback auth_fn = NULL;
1554
0
    void *auth_data = NULL;
1555
0
    struct ssh_auth_auto_state_struct *state = NULL;
1556
0
    int rc;
1557
1558
0
    if (session == NULL) {
1559
0
        return SSH_AUTH_ERROR;
1560
0
    }
1561
1562
0
    SSH_LOG(SSH_LOG_DEBUG,
1563
0
            "Starting authentication as a user %s",
1564
0
            username ? username : session->opts.username);
1565
1566
0
    if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
1567
0
        session->auth.supported_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
1568
0
        return SSH_AUTH_DENIED;
1569
0
    }
1570
0
    if (session->common.callbacks) {
1571
0
        auth_fn = session->common.callbacks->auth_function;
1572
0
        auth_data = session->common.callbacks->userdata;
1573
0
    }
1574
0
    if (!session->auth.auto_state) {
1575
0
        session->auth.auto_state =
1576
0
                calloc(1, sizeof(struct ssh_auth_auto_state_struct));
1577
0
        if (!session->auth.auto_state) {
1578
0
            ssh_set_error_oom(session);
1579
0
            return SSH_AUTH_ERROR;
1580
0
        }
1581
1582
        /* Set state explicitly */
1583
0
        session->auth.auto_state->state = SSH_AUTH_AUTO_STATE_NONE;
1584
0
    }
1585
0
    state = session->auth.auto_state;
1586
0
    if (state->state == SSH_AUTH_AUTO_STATE_NONE) {
1587
        /* Try authentication with ssh-agent first */
1588
0
        rc = ssh_userauth_agent(session, username);
1589
0
        if (rc == SSH_AUTH_SUCCESS ||
1590
0
            rc == SSH_AUTH_PARTIAL ||
1591
0
            rc == SSH_AUTH_AGAIN) {
1592
0
            return rc;
1593
0
        }
1594
0
        state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1595
0
    }
1596
0
    if (state->it == NULL) {
1597
0
        state->it = ssh_list_get_iterator(session->opts.identity);
1598
0
    }
1599
1600
0
    while (state->it != NULL) {
1601
0
        const char *privkey_file = ssh_iterator_value(const char *, state->it);
1602
0
        char pubkey_file[PATH_MAX] = {0};
1603
1604
0
        if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
1605
0
            SSH_LOG(SSH_LOG_DEBUG,
1606
0
                    "Trying to authenticate with %s",
1607
0
                    privkey_file);
1608
0
            state->cert = NULL;
1609
0
            state->privkey = NULL;
1610
0
            state->pubkey = NULL;
1611
1612
#ifdef WITH_PKCS11_URI
1613
            if (ssh_pki_is_uri(privkey_file)) {
1614
                char *pub_uri_from_priv = NULL;
1615
                SSH_LOG(SSH_LOG_INFO,
1616
                        "Authenticating with PKCS #11 URI.");
1617
                pub_uri_from_priv = ssh_pki_export_pub_uri_from_priv_uri(privkey_file);
1618
                if (pub_uri_from_priv == NULL) {
1619
                    return SSH_ERROR;
1620
                } else {
1621
                    snprintf(pubkey_file,
1622
                             sizeof(pubkey_file),
1623
                             "%s",
1624
                             pub_uri_from_priv);
1625
                    SAFE_FREE(pub_uri_from_priv);
1626
                }
1627
            } else
1628
#endif /* WITH_PKCS11_URI */
1629
0
            {
1630
0
                snprintf(pubkey_file,
1631
0
                         sizeof(pubkey_file),
1632
0
                         "%s.pub",
1633
0
                         privkey_file);
1634
0
            }
1635
1636
0
            rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
1637
0
            if (rc == SSH_ERROR) {
1638
0
                ssh_set_error(session,
1639
0
                              SSH_FATAL,
1640
0
                              "Failed to import public key: %s",
1641
0
                              pubkey_file);
1642
0
                SAFE_FREE(session->auth.auto_state);
1643
0
                return SSH_AUTH_ERROR;
1644
0
            } else if (rc == SSH_EOF) {
1645
                /* Read the private key and save the public key to file */
1646
0
                rc = ssh_pki_import_privkey_file(privkey_file,
1647
0
                                                 passphrase,
1648
0
                                                 auth_fn,
1649
0
                                                 auth_data,
1650
0
                                                 &state->privkey);
1651
0
                if (rc == SSH_ERROR) {
1652
0
                    ssh_set_error(session,
1653
0
                                  SSH_FATAL,
1654
0
                                  "Failed to read private key: %s",
1655
0
                                  privkey_file);
1656
0
                    state->it = state->it->next;
1657
0
                    continue;
1658
0
                } else if (rc == SSH_EOF) {
1659
                    /* If the file doesn't exist, continue */
1660
0
                    SSH_LOG(SSH_LOG_DEBUG,
1661
0
                            "Private key %s doesn't exist.",
1662
0
                            privkey_file);
1663
0
                    state->it = state->it->next;
1664
0
                    continue;
1665
0
                }
1666
1667
0
                rc = ssh_pki_export_privkey_to_pubkey(state->privkey,
1668
0
                                                      &state->pubkey);
1669
0
                if (rc == SSH_ERROR) {
1670
0
                    SSH_KEY_FREE(state->privkey);
1671
0
                    SAFE_FREE(session->auth.auto_state);
1672
0
                    return SSH_AUTH_ERROR;
1673
0
                }
1674
1675
0
                rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file);
1676
0
                if (rc == SSH_ERROR) {
1677
0
                    SSH_LOG(SSH_LOG_TRACE,
1678
0
                            "Could not write public key to file: %s",
1679
0
                            pubkey_file);
1680
0
                }
1681
0
            }
1682
0
            state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
1683
0
        }
1684
0
        if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED ||
1685
0
            state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE ||
1686
0
            state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION_INIT ||
1687
0
            state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
1688
0
            ssh_key k = state->pubkey;
1689
0
            if (state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
1690
0
                k = state->cert;
1691
0
            }
1692
0
            rc = ssh_userauth_try_publickey(session, username, k);
1693
0
            if (rc == SSH_AUTH_ERROR) {
1694
0
                SSH_LOG(SSH_LOG_TRACE,
1695
0
                        "Public key authentication error for %s",
1696
0
                        privkey_file);
1697
0
                SSH_KEY_FREE(state->cert);
1698
0
                SSH_KEY_FREE(state->privkey);
1699
0
                SSH_KEY_FREE(state->pubkey);
1700
0
                SAFE_FREE(session->auth.auto_state);
1701
0
                return rc;
1702
0
            } else if (rc == SSH_AUTH_AGAIN) {
1703
0
                return rc;
1704
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1705
0
                int r; /* do not reuse `rc` as it is used to return from here */
1706
0
                SSH_KEY_FREE(state->cert);
1707
0
                SSH_LOG(SSH_LOG_DEBUG,
1708
0
                        "Public key for %s%s refused by server",
1709
0
                        privkey_file,
1710
0
                        (state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED
1711
0
                            ? " (with certificate)" : ""));
1712
                /* Try certificate file by appending -cert.pub (if present) */
1713
0
                if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
1714
0
                    char cert_file[PATH_MAX] = {0};
1715
0
                    ssh_key cert = NULL;
1716
1717
0
                    snprintf(cert_file,
1718
0
                             sizeof(cert_file),
1719
0
                             "%s-cert.pub",
1720
0
                             privkey_file);
1721
0
                    SSH_LOG(SSH_LOG_TRACE,
1722
0
                            "Trying to load the certificate %s (default path)",
1723
0
                            cert_file);
1724
0
                    r = ssh_pki_import_cert_file(cert_file, &cert);
1725
0
                    if (r == SSH_OK) {
1726
                        /* TODO check the pubkey and certs match */
1727
0
                        SSH_LOG(SSH_LOG_TRACE,
1728
0
                                "Certificate loaded %s. Retry the authentication.",
1729
0
                                cert_file);
1730
0
                        state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE;
1731
0
                        SSH_KEY_FREE(state->cert);
1732
0
                        state->cert = cert;
1733
                        /* try to authenticate with this certificate */
1734
0
                        continue;
1735
0
                    }
1736
                    /* if the file does not exists, try configuration options */
1737
0
                    state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION_INIT;
1738
0
                }
1739
                /* Try certificate files loaded through options */
1740
0
                if (state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION_INIT) {
1741
0
                    state->cert_it = ssh_list_get_iterator(session->opts.certificate);
1742
0
                    state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
1743
0
                }
1744
0
                if (state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
1745
0
                    SSH_KEY_FREE(state->cert);
1746
0
                    while (state->cert_it != NULL) {
1747
0
                        const char *cert_file = ssh_iterator_value(const char *, state->cert_it);
1748
0
                        ssh_key cert = NULL;
1749
1750
0
                        SSH_LOG(SSH_LOG_TRACE,
1751
0
                                "Trying to load the certificate %s (options)",
1752
0
                                cert_file);
1753
0
                        r = ssh_pki_import_cert_file(cert_file, &cert);
1754
0
                        if (r == SSH_OK) {
1755
0
                            int cmp = ssh_key_cmp(cert,
1756
0
                                                  state->pubkey,
1757
0
                                                  SSH_KEY_CMP_PUBLIC);
1758
0
                            if (cmp != 0) {
1759
0
                                state->cert_it = state->cert_it->next;
1760
0
                                SSH_KEY_FREE(cert);
1761
0
                                continue; /* with next cert */
1762
0
                            }
1763
0
                            SSH_LOG(SSH_LOG_TRACE,
1764
0
                                    "Found matching certificate %s in options. Retry the authentication.",
1765
0
                                    cert_file);
1766
0
                            state->cert = cert;
1767
0
                            cert = NULL;
1768
0
                            state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
1769
0
                            state->cert_it = state->cert_it->next;
1770
                            /* try to authenticate with this identity */
1771
0
                            break; /* try this cert */
1772
0
                        }
1773
                        /* continue with next identity */
1774
0
                        state->cert_it = state->cert_it->next;
1775
0
                    }
1776
0
                    if (state->cert != NULL) {
1777
0
                        continue; /* retry with the certificate */
1778
0
                    }
1779
0
                }
1780
0
                SSH_KEY_FREE(state->cert);
1781
0
                SSH_KEY_FREE(state->privkey);
1782
0
                SSH_KEY_FREE(state->pubkey);
1783
0
                state->it = state->it->next;
1784
0
                state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1785
0
                continue;
1786
0
            }
1787
0
            state->state = SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED;
1788
0
        }
1789
0
        if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED) {
1790
            /* Public key has been accepted by the server */
1791
0
            if (state->privkey == NULL) {
1792
0
                rc = ssh_pki_import_privkey_file(privkey_file,
1793
0
                                                 passphrase,
1794
0
                                                 auth_fn,
1795
0
                                                 auth_data,
1796
0
                                                 &state->privkey);
1797
0
                if (rc == SSH_ERROR) {
1798
0
                    SSH_KEY_FREE(state->cert);
1799
0
                    SSH_KEY_FREE(state->pubkey);
1800
0
                    ssh_set_error(session,
1801
0
                                  SSH_FATAL,
1802
0
                                  "Failed to read private key: %s",
1803
0
                                  privkey_file);
1804
0
                    state->it = state->it->next;
1805
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1806
0
                    continue;
1807
0
                } else if (rc == SSH_EOF) {
1808
                    /* If the file doesn't exist, continue */
1809
0
                    SSH_KEY_FREE(state->cert);
1810
0
                    SSH_KEY_FREE(state->pubkey);
1811
0
                    SSH_LOG(SSH_LOG_DEBUG,
1812
0
                            "Private key %s doesn't exist.",
1813
0
                            privkey_file);
1814
0
                    state->it = state->it->next;
1815
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1816
0
                    continue;
1817
0
                }
1818
0
            }
1819
0
            if (state->cert != NULL && !is_cert_type(state->privkey->cert_type)) {
1820
0
                rc = ssh_pki_copy_cert_to_privkey(state->cert, state->privkey);
1821
0
                if (rc != SSH_OK) {
1822
0
                    SSH_KEY_FREE(state->cert);
1823
0
                    SSH_KEY_FREE(state->privkey);
1824
0
                    SSH_KEY_FREE(state->pubkey);
1825
0
                    ssh_set_error(session,
1826
0
                                  SSH_FATAL,
1827
0
                                  "Failed to copy cert to private key");
1828
0
                    state->it = state->it->next;
1829
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1830
0
                    continue;
1831
0
                }
1832
0
            }
1833
1834
0
            rc = ssh_userauth_publickey(session, username, state->privkey);
1835
0
            if (rc != SSH_AUTH_AGAIN && rc != SSH_AUTH_DENIED) {
1836
0
                bool cert_used = (state->cert != NULL);
1837
0
                SSH_KEY_FREE(state->cert);
1838
0
                SSH_KEY_FREE(state->privkey);
1839
0
                SSH_KEY_FREE(state->pubkey);
1840
0
                SAFE_FREE(session->auth.auto_state);
1841
0
                if (rc == SSH_AUTH_SUCCESS) {
1842
0
                    SSH_LOG(SSH_LOG_DEBUG,
1843
0
                            "Successfully authenticated using %s%s",
1844
0
                            privkey_file,
1845
0
                            (cert_used ? " and certificate" : ""));
1846
0
                }
1847
0
                return rc;
1848
0
            }
1849
0
            if (rc == SSH_AUTH_AGAIN) {
1850
0
                return rc;
1851
0
            }
1852
1853
0
            SSH_KEY_FREE(state->cert);
1854
0
            SSH_KEY_FREE(state->privkey);
1855
0
            SSH_KEY_FREE(state->pubkey);
1856
1857
0
            SSH_LOG(SSH_LOG_DEBUG,
1858
0
                    "The server accepted the public key but refused the signature");
1859
0
            state->it = state->it->next;
1860
0
            state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1861
            /* continue */
1862
0
        }
1863
0
    }
1864
0
    SSH_LOG(SSH_LOG_WARN,
1865
0
            "Access denied: Tried every public key, none matched");
1866
0
    SAFE_FREE(session->auth.auto_state);
1867
0
    return SSH_AUTH_DENIED;
1868
0
}
1869
1870
/**
1871
 * @brief Try to authenticate by password.
1872
 *
1873
 * This authentication method is normally disabled on SSHv2 server. You should
1874
 * use keyboard-interactive mode.
1875
 *
1876
 * The 'password' value MUST be encoded UTF-8.  It is up to the server how to
1877
 * interpret the password and validate it against the password database.
1878
 * However, if you read the password in some other encoding, you MUST convert
1879
 * the password to UTF-8.
1880
 *
1881
 * @param[in] session   The ssh session to use.
1882
 *
1883
 * @param[in] username  The username, this SHOULD be NULL.
1884
 *
1885
 * @param[in] password  The password to authenticate in UTF-8.
1886
 *
1887
 * @returns SSH_AUTH_ERROR:   A serious error happened.\n
1888
 *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
1889
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1890
 *                            have to use another method\n
1891
 *          SSH_AUTH_SUCCESS: Authentication success\n
1892
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1893
 *                            later.
1894
 *
1895
 * @note Most server implementations do not permit changing the username during
1896
 * authentication. The username should only be set with ssh_options_set() only
1897
 * before you connect to the server.
1898
 *
1899
 * @see ssh_userauth_none()
1900
 * @see ssh_userauth_kbdint()
1901
 */
1902
int ssh_userauth_password(ssh_session session,
1903
                          const char *username,
1904
                          const char *password)
1905
0
{
1906
0
    int rc;
1907
1908
0
    if (session == NULL) {
1909
0
        return SSH_AUTH_ERROR;
1910
0
    }
1911
1912
0
    if (session->pending_call_state == SSH_PENDING_CALL_NONE &&
1913
0
        !(session->opts.flags & SSH_OPT_FLAG_PASSWORD_AUTH)) {
1914
0
        SSH_LOG(SSH_LOG_DEBUG, "Password authentication is disabled");
1915
0
        return SSH_AUTH_DENIED;
1916
0
    }
1917
1918
0
    switch (session->pending_call_state) {
1919
0
        case SSH_PENDING_CALL_NONE:
1920
0
            break;
1921
0
        case SSH_PENDING_CALL_AUTH_PASSWORD:
1922
0
            goto pending;
1923
0
        default:
1924
0
            ssh_set_error(session,
1925
0
                          SSH_FATAL,
1926
0
                          "Wrong state (%d) during pending SSH call",
1927
0
                          session->pending_call_state);
1928
0
            return SSH_ERROR;
1929
0
    }
1930
1931
0
    rc = ssh_userauth_request_service(session);
1932
0
    if (rc == SSH_AGAIN) {
1933
0
        return SSH_AUTH_AGAIN;
1934
0
    } else if (rc == SSH_ERROR) {
1935
0
        return SSH_AUTH_ERROR;
1936
0
    }
1937
1938
    /* request */
1939
0
    rc = ssh_buffer_pack(session->out_buffer, "bsssbs",
1940
0
            SSH2_MSG_USERAUTH_REQUEST,
1941
0
            username ? username : session->opts.username,
1942
0
            "ssh-connection",
1943
0
            "password",
1944
0
            0, /* false */
1945
0
            password
1946
0
    );
1947
0
    if (rc < 0) {
1948
0
        goto fail;
1949
0
    }
1950
1951
    /* Set the buffer as secure to be explicitly zeroed when freed */
1952
0
    ssh_buffer_set_secure(session->out_buffer);
1953
1954
0
    session->auth.current_method = SSH_AUTH_METHOD_PASSWORD;
1955
0
    session->auth.state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
1956
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
1957
0
    rc = ssh_packet_send(session);
1958
0
    if (rc == SSH_ERROR) {
1959
0
        return SSH_AUTH_ERROR;
1960
0
    }
1961
1962
0
pending:
1963
0
    rc = ssh_userauth_get_response(session);
1964
0
    if (rc != SSH_AUTH_AGAIN) {
1965
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1966
0
    }
1967
1968
0
    return rc;
1969
0
fail:
1970
0
    ssh_set_error_oom(session);
1971
0
    ssh_buffer_reinit(session->out_buffer);
1972
0
    session->pending_call_state = SSH_PENDING_CALL_NONE;
1973
1974
0
    return SSH_AUTH_ERROR;
1975
0
}
1976
1977
/* LEGACY */
1978
int ssh_userauth_agent_pubkey(ssh_session session,
1979
                              const char *username,
1980
                              ssh_public_key publickey)
1981
0
{
1982
0
    ssh_key key = NULL;
1983
0
    int rc;
1984
1985
0
    if (session == NULL) {
1986
0
        return SSH_AUTH_ERROR;
1987
0
    }
1988
1989
0
    if (session->pending_call_state == SSH_PENDING_CALL_NONE &&
1990
0
        !(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
1991
0
        SSH_LOG(SSH_LOG_DEBUG, "Public key authentication is disabled");
1992
0
        return SSH_AUTH_DENIED;
1993
0
    }
1994
1995
0
    key = ssh_key_new();
1996
0
    if (key == NULL) {
1997
0
        return SSH_AUTH_ERROR;
1998
0
    }
1999
2000
0
    key->type = publickey->type;
2001
0
    key->type_c = ssh_key_type_to_char(key->type);
2002
0
    key->flags = SSH_KEY_FLAG_PUBLIC;
2003
#if defined(HAVE_LIBMBEDCRYPTO)
2004
    key->pk = publickey->rsa_pub;
2005
#elif defined(HAVE_LIBCRYPTO)
2006
    key->key = publickey->key_pub;
2007
#else
2008
    key->rsa = publickey->rsa_pub;
2009
#endif /* HAVE_LIBCRYPTO */
2010
2011
0
    rc = ssh_userauth_agent_publickey(session, username, key);
2012
2013
#if defined(HAVE_LIBMBEDCRYPTO)
2014
    key->pk = NULL;
2015
#elif defined(HAVE_LIBCRYPTO)
2016
0
    key->key = NULL;
2017
#else
2018
    key->rsa = NULL;
2019
#endif /* HAVE_LIBCRYPTO */
2020
0
    ssh_key_free(key);
2021
2022
0
    return rc;
2023
0
}
2024
2025
/**
2026
 * @internal
2027
 *
2028
 * @brief  Allocates memory for keyboard interactive auth structure.
2029
 *
2030
 * @return A newly allocated ssh_kbdint structure `kbd` on success, NULL on failure.
2031
 *         The caller is responsible for freeing allocated memory.
2032
 */
2033
ssh_kbdint ssh_kbdint_new(void)
2034
0
{
2035
0
    ssh_kbdint kbd;
2036
2037
0
    kbd = calloc(1, sizeof(struct ssh_kbdint_struct));
2038
0
    if (kbd == NULL) {
2039
0
        return NULL;
2040
0
    }
2041
2042
0
    return kbd;
2043
0
}
2044
2045
/**
2046
 * @brief Deallocate memory for keyboard interactive auth structure.
2047
 *
2048
 * @param[in] kbd   The keyboard interactive structure to free.
2049
 */
2050
void ssh_kbdint_free(ssh_kbdint kbd)
2051
0
{
2052
0
    size_t i, n;
2053
2054
0
    if (kbd == NULL) {
2055
0
        return;
2056
0
    }
2057
2058
0
    SAFE_FREE(kbd->name);
2059
0
    SAFE_FREE(kbd->instruction);
2060
0
    SAFE_FREE(kbd->echo);
2061
2062
0
    n = kbd->nprompts;
2063
0
    if (kbd->prompts) {
2064
0
        for (i = 0; i < n; i++) {
2065
0
            if (kbd->prompts[i] != NULL) {
2066
0
                ssh_burn(kbd->prompts[i], strlen(kbd->prompts[i]));
2067
0
            }
2068
0
            SAFE_FREE(kbd->prompts[i]);
2069
0
        }
2070
0
        SAFE_FREE(kbd->prompts);
2071
0
    }
2072
2073
0
    n = kbd->nanswers;
2074
0
    if (kbd->answers) {
2075
0
        for (i = 0; i < n; i++) {
2076
0
            if (kbd->answers[i] != NULL) {
2077
0
                ssh_burn(kbd->answers[i], strlen(kbd->answers[i]));
2078
0
            }
2079
0
            SAFE_FREE(kbd->answers[i]);
2080
0
        }
2081
0
        SAFE_FREE(kbd->answers);
2082
0
    }
2083
2084
0
    SAFE_FREE(kbd);
2085
0
}
2086
2087
/**
2088
 * @brief Clean a keyboard interactive auth structure.
2089
 *
2090
 * Clears structure's fields and resets nanswers and nprompts to 0, allowing
2091
 * reuse.
2092
 *
2093
 * @param[in] kbd The keyboard interactive struct to clean
2094
 */
2095
void ssh_kbdint_clean(ssh_kbdint kbd)
2096
0
{
2097
0
    size_t i, n;
2098
2099
0
    if (kbd == NULL) {
2100
0
        return;
2101
0
    }
2102
2103
0
    SAFE_FREE(kbd->name);
2104
0
    SAFE_FREE(kbd->instruction);
2105
0
    SAFE_FREE(kbd->echo);
2106
2107
0
    n = kbd->nprompts;
2108
0
    if (kbd->prompts) {
2109
0
        for (i = 0; i < n; i++) {
2110
0
            ssh_burn(kbd->prompts[i], strlen(kbd->prompts[i]));
2111
0
            SAFE_FREE(kbd->prompts[i]);
2112
0
        }
2113
0
        SAFE_FREE(kbd->prompts);
2114
0
    }
2115
2116
0
    n = kbd->nanswers;
2117
2118
0
    if (kbd->answers) {
2119
0
        for (i = 0; i < n; i++) {
2120
0
            ssh_burn(kbd->answers[i], strlen(kbd->answers[i]));
2121
0
            SAFE_FREE(kbd->answers[i]);
2122
0
        }
2123
0
        SAFE_FREE(kbd->answers);
2124
0
    }
2125
2126
0
    kbd->nprompts = 0;
2127
0
    kbd->nanswers = 0;
2128
0
}
2129
2130
/*
2131
 * This function sends the first packet as explained in RFC 3066 section 3.1.
2132
 */
2133
static int ssh_userauth_kbdint_init(ssh_session session,
2134
                                    const char *username,
2135
                                    const char *submethods)
2136
0
{
2137
0
    int rc;
2138
2139
0
    if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT) {
2140
0
        goto pending;
2141
0
    }
2142
0
    if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
2143
0
        ssh_set_error_invalid(session);
2144
0
        return SSH_ERROR;
2145
0
    }
2146
2147
0
    rc = ssh_userauth_request_service(session);
2148
0
    if (rc == SSH_AGAIN) {
2149
0
        return SSH_AUTH_AGAIN;
2150
0
    }
2151
0
    if (rc != SSH_OK) {
2152
0
        return SSH_AUTH_ERROR;
2153
0
    }
2154
2155
    /* request */
2156
0
    rc = ssh_buffer_pack(session->out_buffer, "bsssss",
2157
0
            SSH2_MSG_USERAUTH_REQUEST,
2158
0
            username ? username : session->opts.username,
2159
0
            "ssh-connection",
2160
0
            "keyboard-interactive",
2161
0
            "", /* lang (ignore it) */
2162
0
            submethods ? submethods : ""
2163
0
    );
2164
0
    if (rc < 0) {
2165
0
        goto fail;
2166
0
    }
2167
2168
2169
0
    session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
2170
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_INIT;
2171
2172
0
    SSH_LOG(SSH_LOG_DEBUG,
2173
0
            "Sending keyboard-interactive init request");
2174
2175
0
    rc = ssh_packet_send(session);
2176
0
    if (rc == SSH_ERROR) {
2177
0
        return SSH_AUTH_ERROR;
2178
0
    }
2179
0
pending:
2180
0
    rc = ssh_userauth_get_response(session);
2181
0
    if (rc != SSH_AUTH_AGAIN)
2182
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2183
0
    return rc;
2184
0
fail:
2185
0
    ssh_set_error_oom(session);
2186
0
    ssh_buffer_reinit(session->out_buffer);
2187
2188
0
    return SSH_AUTH_ERROR;
2189
0
}
2190
2191
/**
2192
 * @internal
2193
 *
2194
 * @brief Send the current challenge response and wait for a reply from the
2195
 *        server.
2196
 *
2197
 * @returns SSH_AUTH_INFO if more info is needed
2198
 * @returns SSH_AUTH_SUCCESS
2199
 * @returns SSH_AUTH_FAILURE
2200
 * @returns SSH_AUTH_PARTIAL
2201
 */
2202
static int ssh_userauth_kbdint_send(ssh_session session)
2203
0
{
2204
0
    uint32_t i;
2205
0
    int rc;
2206
0
    if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND)
2207
0
        goto pending;
2208
0
    if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
2209
0
        ssh_set_error_invalid(session);
2210
0
        return SSH_ERROR;
2211
0
    }
2212
0
    rc = ssh_buffer_pack(session->out_buffer, "bd",
2213
0
            SSH2_MSG_USERAUTH_INFO_RESPONSE,
2214
0
            session->kbdint->nprompts);
2215
0
    if (rc < 0) {
2216
0
        goto fail;
2217
0
    }
2218
2219
0
    for (i = 0; i < session->kbdint->nprompts; i++) {
2220
0
        rc = ssh_buffer_pack(session->out_buffer, "s",
2221
0
                session->kbdint->answers && session->kbdint->answers[i] ?
2222
0
                        session->kbdint->answers[i]:"");
2223
0
        if (rc < 0) {
2224
0
            goto fail;
2225
0
        }
2226
0
    }
2227
2228
0
    session->auth.current_method = SSH_AUTH_METHOD_INTERACTIVE;
2229
0
    session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
2230
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_SEND;
2231
0
    ssh_kbdint_free(session->kbdint);
2232
0
    session->kbdint = NULL;
2233
2234
0
    SSH_LOG(SSH_LOG_DEBUG,
2235
0
            "Sending keyboard-interactive response packet");
2236
2237
0
    rc = ssh_packet_send(session);
2238
0
    if (rc == SSH_ERROR) {
2239
0
        return SSH_AUTH_ERROR;
2240
0
    }
2241
0
pending:
2242
0
    rc = ssh_userauth_get_response(session);
2243
0
    if (rc != SSH_AUTH_AGAIN)
2244
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2245
0
    return rc;
2246
0
fail:
2247
0
    ssh_set_error_oom(session);
2248
0
    ssh_buffer_reinit(session->out_buffer);
2249
2250
0
    return SSH_AUTH_ERROR;
2251
0
}
2252
2253
/**
2254
 * @internal
2255
 * @brief handles a SSH_USERAUTH_INFO_REQUEST packet, as used in
2256
 *        keyboard-interactive authentication, and changes the
2257
 *        authentication state.
2258
 */
2259
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) {
2260
0
    ssh_string tmp = NULL;
2261
0
    uint32_t nprompts;
2262
0
    uint32_t i;
2263
0
    int rc;
2264
0
    (void)user;
2265
0
    (void)type;
2266
2267
2268
0
    if (session->kbdint == NULL) {
2269
0
        session->kbdint = ssh_kbdint_new();
2270
0
        if (session->kbdint == NULL) {
2271
0
            ssh_set_error_oom(session);
2272
0
            return SSH_PACKET_USED;
2273
0
        }
2274
0
    } else {
2275
0
        ssh_kbdint_clean(session->kbdint);
2276
0
    }
2277
2278
0
    rc = ssh_buffer_unpack(packet, "ssSd",
2279
0
            &session->kbdint->name, /* name of the "asking" window shown to client */
2280
0
            &session->kbdint->instruction,
2281
0
            &tmp, /* to ignore */
2282
0
            &nprompts
2283
0
            );
2284
2285
    /* We don't care about tmp */
2286
0
    SSH_STRING_FREE(tmp);
2287
2288
0
    if (rc != SSH_OK) {
2289
0
        ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
2290
0
        ssh_kbdint_free(session->kbdint);
2291
0
        session->kbdint = NULL;
2292
0
        return SSH_PACKET_USED;
2293
0
    }
2294
2295
0
    SSH_LOG(SSH_LOG_DEBUG,
2296
0
            "%" PRIu32 " keyboard-interactive prompts", nprompts);
2297
0
    if (nprompts > KBDINT_MAX_PROMPT) {
2298
0
        ssh_set_error(session, SSH_FATAL,
2299
0
                "Too much prompts requested by the server: %" PRIu32 " (0x%.4" PRIx32 ")",
2300
0
                nprompts, nprompts);
2301
0
        ssh_kbdint_free(session->kbdint);
2302
0
        session->kbdint = NULL;
2303
2304
0
        return SSH_PACKET_USED;
2305
0
    }
2306
2307
0
    session->kbdint->nprompts = nprompts;
2308
0
    session->kbdint->nanswers = nprompts;
2309
0
    session->kbdint->prompts = calloc(nprompts, sizeof(char *));
2310
0
    if (session->kbdint->prompts == NULL) {
2311
0
        session->kbdint->nprompts = 0;
2312
0
        ssh_set_error_oom(session);
2313
0
        ssh_kbdint_free(session->kbdint);
2314
0
        session->kbdint = NULL;
2315
2316
0
        return SSH_PACKET_USED;
2317
0
    }
2318
2319
0
    session->kbdint->echo = calloc(nprompts, sizeof(unsigned char));
2320
0
    if (session->kbdint->echo == NULL) {
2321
0
        session->kbdint->nprompts = 0;
2322
0
        ssh_set_error_oom(session);
2323
0
        ssh_kbdint_free(session->kbdint);
2324
0
        session->kbdint = NULL;
2325
2326
0
        return SSH_PACKET_USED;
2327
0
    }
2328
2329
0
    for (i = 0; i < nprompts; i++) {
2330
0
        rc = ssh_buffer_unpack(packet, "sb",
2331
0
                &session->kbdint->prompts[i],
2332
0
                &session->kbdint->echo[i]);
2333
0
        if (rc == SSH_ERROR) {
2334
0
            ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
2335
0
            ssh_kbdint_free(session->kbdint);
2336
0
            session->kbdint = NULL;
2337
2338
0
            return SSH_PACKET_USED;
2339
0
        }
2340
0
    }
2341
0
    session->auth.state=SSH_AUTH_STATE_INFO;
2342
2343
0
    return SSH_PACKET_USED;
2344
0
}
2345
2346
/**
2347
 * @brief Try to authenticate through the "keyboard-interactive" method.
2348
 *
2349
 * @param[in]  session  The ssh session to use.
2350
 *
2351
 * @param[in]  user     The username to authenticate. You can specify NULL if
2352
 *                      ssh_option_set_username() has been used. You cannot try
2353
 *                      two different logins in a row.
2354
 *
2355
 * @param[in]  submethods Undocumented. Set it to NULL.
2356
 *
2357
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
2358
 *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
2359
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
2360
 *                            have to use another method\n
2361
 *          SSH_AUTH_SUCCESS: Authentication success\n
2362
 *          SSH_AUTH_INFO:    The server asked some questions. Use
2363
 *                            ssh_userauth_kbdint_getnprompts() and such.\n
2364
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
2365
 *                            later.
2366
 *
2367
 * @see ssh_userauth_kbdint_getnprompts()
2368
 * @see ssh_userauth_kbdint_getname()
2369
 * @see ssh_userauth_kbdint_getinstruction()
2370
 * @see ssh_userauth_kbdint_getprompt()
2371
 * @see ssh_userauth_kbdint_setanswer()
2372
 */
2373
int ssh_userauth_kbdint(ssh_session session, const char *user,
2374
                        const char *submethods)
2375
0
{
2376
0
    int rc = SSH_AUTH_ERROR;
2377
2378
0
    if (session == NULL) {
2379
0
        return SSH_AUTH_ERROR;
2380
0
    }
2381
2382
0
    if (session->pending_call_state == SSH_PENDING_CALL_NONE &&
2383
0
        session->kbdint == NULL &&
2384
0
        !(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH)) {
2385
0
        SSH_LOG(SSH_LOG_DEBUG,
2386
0
                "Keyboard-interactive authentication is disabled");
2387
0
        return SSH_AUTH_DENIED;
2388
0
    }
2389
2390
0
    if ((session->pending_call_state == SSH_PENDING_CALL_NONE && session->kbdint == NULL) ||
2391
0
            session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT)
2392
0
        rc = ssh_userauth_kbdint_init(session, user, submethods);
2393
0
    else if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND ||
2394
0
            session->kbdint != NULL) {
2395
        /*
2396
         * If we are at this point, it is because session->kbdint exists.
2397
         * It means the user has set some information there we need to send
2398
         * the server and then we need to ack the status (new questions or ok
2399
         * pass in).
2400
         * It is possible that session->kbdint is NULL while we're waiting for
2401
         * a reply, hence the test for the pending call.
2402
         */
2403
0
        rc = ssh_userauth_kbdint_send(session);
2404
0
    } else {
2405
        /* We are here because session->kbdint == NULL & state != NONE.
2406
         * This should not happen
2407
         */
2408
0
        rc = SSH_AUTH_ERROR;
2409
0
        ssh_set_error(session, SSH_FATAL, "Invalid state in %s", __func__);
2410
0
    }
2411
0
    return rc;
2412
0
}
2413
2414
/**
2415
 * @brief Get the number of prompts (questions) the server has given.
2416
 *
2417
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2418
 * code, this function can be used to retrieve information about the keyboard
2419
 * interactive authentication questions sent by the remote host.
2420
 *
2421
 * @param[in]  session  The ssh session to use.
2422
 *
2423
 * @returns             The number of prompts.
2424
 */
2425
int ssh_userauth_kbdint_getnprompts(ssh_session session)
2426
0
{
2427
0
    if (session == NULL) {
2428
0
        return SSH_ERROR;
2429
0
    }
2430
0
    if (session->kbdint == NULL) {
2431
0
        ssh_set_error_invalid(session);
2432
0
        return SSH_ERROR;
2433
0
    }
2434
0
    return session->kbdint->nprompts;
2435
0
}
2436
2437
/**
2438
 * @brief Get the "name" of the message block.
2439
 *
2440
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2441
 * code, this function can be used to retrieve information about the keyboard
2442
 * interactive authentication questions sent by the remote host.
2443
 *
2444
 * @param[in]  session  The ssh session to use.
2445
 *
2446
 * @returns             The name of the message block. Do not free it.
2447
 */
2448
const char *ssh_userauth_kbdint_getname(ssh_session session)
2449
0
{
2450
0
    if (session == NULL) {
2451
0
        return NULL;
2452
0
    }
2453
0
    if (session->kbdint == NULL) {
2454
0
        ssh_set_error_invalid(session);
2455
0
        return NULL;
2456
0
    }
2457
0
    return session->kbdint->name;
2458
0
}
2459
2460
/**
2461
 * @brief Get the "instruction" of the message block.
2462
 *
2463
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2464
 * code, this function can be used to retrieve information about the keyboard
2465
 * interactive authentication questions sent by the remote host.
2466
 *
2467
 * @param[in]  session  The ssh session to use.
2468
 *
2469
 * @returns             The instruction of the message block.
2470
 */
2471
2472
const char *ssh_userauth_kbdint_getinstruction(ssh_session session)
2473
0
{
2474
0
    if (session == NULL)
2475
0
        return NULL;
2476
0
    if (session->kbdint == NULL) {
2477
0
        ssh_set_error_invalid(session);
2478
0
        return NULL;
2479
0
    }
2480
0
    return session->kbdint->instruction;
2481
0
}
2482
2483
/**
2484
 * @brief Get a prompt from a message block.
2485
 *
2486
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2487
 * code, this function can be used to retrieve information about the keyboard
2488
 * interactive authentication questions sent by the remote host.
2489
 *
2490
 * @param[in]  session  The ssh session to use.
2491
 *
2492
 * @param[in]  i        The index number of the i'th prompt.
2493
 *
2494
 * @param[out] echo     This is an optional variable. You can obtain a
2495
 *                      boolean if the user input should be echoed or
2496
 *                      hidden. For passwords it is usually hidden.
2497
 *
2498
 * @returns             A pointer to the prompt. Do not free it.
2499
 *
2500
 * @code
2501
 *   const char prompt;
2502
 *   char echo;
2503
 *
2504
 *   prompt = ssh_userauth_kbdint_getprompt(session, 0, &echo);
2505
 *   if (echo) ...
2506
 * @endcode
2507
 */
2508
const char *
2509
ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i, char *echo)
2510
0
{
2511
0
    if (session == NULL)
2512
0
        return NULL;
2513
0
    if (session->kbdint == NULL) {
2514
0
        ssh_set_error_invalid(session);
2515
0
        return NULL;
2516
0
    }
2517
0
    if (i >= session->kbdint->nprompts) {
2518
0
        ssh_set_error_invalid(session);
2519
0
        return NULL;
2520
0
    }
2521
2522
0
    if (echo) {
2523
0
        *echo = (char)session->kbdint->echo[i];
2524
0
    }
2525
2526
0
    return session->kbdint->prompts[i];
2527
0
}
2528
2529
#ifdef WITH_SERVER
2530
/**
2531
 * @brief Get the number of answers the client has given.
2532
 *
2533
 * @param[in]  session  The ssh session to use.
2534
 *
2535
 * @returns             The number of answers.
2536
 */
2537
int ssh_userauth_kbdint_getnanswers(ssh_session session)
2538
0
{
2539
0
    if (session == NULL || session->kbdint == NULL) {
2540
0
        return SSH_ERROR;
2541
0
    }
2542
0
    return session->kbdint->nanswers;
2543
0
}
2544
2545
/**
2546
 * @brief Get the answer to a question from a message block.
2547
 *
2548
 * @param[in]  session  The ssh session to use.
2549
 *
2550
 * @param[in]  i index  The number of the ith answer.
2551
 *
2552
 * @return              The answer string, or NULL if the answer is not
2553
 *                      available. Do not free the string.
2554
 */
2555
const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i)
2556
0
{
2557
0
    if (session == NULL || session->kbdint == NULL
2558
0
            || session->kbdint->answers == NULL) {
2559
0
        return NULL;
2560
0
    }
2561
0
    if (i >= session->kbdint->nanswers) {
2562
0
        return NULL;
2563
0
    }
2564
2565
0
    return session->kbdint->answers[i];
2566
0
}
2567
#endif
2568
2569
/**
2570
 * @brief Set the answer for a question from a message block.
2571
 *
2572
 * If you have called ssh_userauth_kbdint() and got SSH_AUTH_INFO, this
2573
 * function returns the questions from the server.
2574
 *
2575
 * @param[in]  session  The ssh session to use.
2576
 *
2577
 * @param[in]  i index  The number of the ith prompt.
2578
 *
2579
 * @param[in]  answer   The answer to give to the server. The answer MUST be
2580
 *                      encoded UTF-8. It is up to the server how to interpret
2581
 *                      the value and validate it. However, if you read the
2582
 *                      answer in some other encoding, you MUST convert it to
2583
 *                      UTF-8.
2584
 *
2585
 * @return              0 on success, < 0 on error.
2586
 */
2587
int
2588
ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
2589
                              const char *answer)
2590
0
{
2591
0
    if (session == NULL) {
2592
0
        return -1;
2593
0
    }
2594
0
    if (answer == NULL || session->kbdint == NULL ||
2595
0
            i >= session->kbdint->nprompts) {
2596
0
        ssh_set_error_invalid(session);
2597
0
        return -1;
2598
0
    }
2599
2600
0
    if (session->kbdint->answers == NULL) {
2601
0
        session->kbdint->answers = calloc(session->kbdint->nprompts, sizeof(char *));
2602
0
        if (session->kbdint->answers == NULL) {
2603
0
            ssh_set_error_oom(session);
2604
0
            return -1;
2605
0
        }
2606
0
    }
2607
2608
0
    if (session->kbdint->answers[i]) {
2609
0
        ssh_burn(session->kbdint->answers[i],
2610
0
                 strlen(session->kbdint->answers[i]));
2611
0
        SAFE_FREE(session->kbdint->answers[i]);
2612
0
    }
2613
2614
0
    session->kbdint->answers[i] = strdup(answer);
2615
0
    if (session->kbdint->answers[i] == NULL) {
2616
0
        ssh_set_error_oom(session);
2617
0
        return -1;
2618
0
    }
2619
2620
0
    return 0;
2621
0
}
2622
2623
/**
2624
 * @brief Try to authenticate through the "gssapi-with-mic" method.
2625
 *
2626
 * @param[in]  session  The ssh session to use.
2627
 *
2628
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
2629
 *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
2630
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
2631
 *                            have to use another method\n
2632
 *          SSH_AUTH_SUCCESS: Authentication success\n
2633
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
2634
 *                            later.
2635
 */
2636
int ssh_userauth_gssapi(ssh_session session)
2637
0
{
2638
0
    int rc = SSH_AUTH_DENIED;
2639
2640
0
    if (session == NULL) {
2641
0
        return SSH_AUTH_ERROR;
2642
0
    }
2643
2644
0
    if (session->pending_call_state == SSH_PENDING_CALL_NONE &&
2645
0
        !(session->opts.flags & SSH_OPT_FLAG_GSSAPI_AUTH)) {
2646
0
        SSH_LOG(SSH_LOG_DEBUG, "GSSAPI authentication is disabled");
2647
0
        return SSH_AUTH_DENIED;
2648
0
    }
2649
2650
#ifdef WITH_GSSAPI
2651
    switch(session->pending_call_state) {
2652
    case SSH_PENDING_CALL_NONE:
2653
        break;
2654
    case SSH_PENDING_CALL_AUTH_GSSAPI_MIC:
2655
        goto pending;
2656
    default:
2657
        ssh_set_error(session,
2658
                SSH_FATAL,
2659
                "Wrong state (%d) during pending SSH call",
2660
                session->pending_call_state);
2661
        return SSH_ERROR;
2662
    }
2663
2664
    rc = ssh_userauth_request_service(session);
2665
    if (rc == SSH_AGAIN) {
2666
        return SSH_AUTH_AGAIN;
2667
    } else if (rc == SSH_ERROR) {
2668
        return SSH_AUTH_ERROR;
2669
    }
2670
    SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-with-mic");
2671
2672
    session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_MIC;
2673
    session->auth.state = SSH_AUTH_STATE_NONE;
2674
    session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_MIC;
2675
    rc = ssh_gssapi_auth_mic(session);
2676
2677
    if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_DENIED) {
2678
        session->auth.state = SSH_AUTH_STATE_NONE;
2679
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2680
        return rc;
2681
    }
2682
2683
pending:
2684
    rc = ssh_userauth_get_response(session);
2685
    if (rc != SSH_AUTH_AGAIN) {
2686
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2687
    }
2688
#else
2689
0
    (void) session; /* unused */
2690
0
#endif
2691
0
    return rc;
2692
0
}
2693
2694
/**
2695
 * @brief Try to authenticate through the "gssapi-keyex" method.
2696
 *
2697
 * @param[in] session The ssh session to use.
2698
 *
2699
 * @returns
2700
 *   - `SSH_AUTH_ERROR`:   A serious error happened.
2701
 *   - `SSH_AUTH_DENIED`:  Authentication failed : use another method.
2702
 *   - `SSH_AUTH_PARTIAL`: You've been partially authenticated, you still
2703
 *                         have to use another method.
2704
 *   - `SSH_AUTH_SUCCESS`: Authentication success.
2705
 *   - `SSH_AUTH_AGAIN`:   In nonblocking mode, you've got to call this again
2706
 *                         later.
2707
 */
2708
int ssh_userauth_gssapi_keyex(ssh_session session)
2709
0
{
2710
0
    int rc = SSH_AUTH_DENIED;
2711
#ifdef WITH_GSSAPI
2712
    OM_uint32 min_stat;
2713
    gss_buffer_desc mic_token_buf = GSS_C_EMPTY_BUFFER;
2714
2715
    switch (session->pending_call_state) {
2716
    case SSH_PENDING_CALL_NONE:
2717
        break;
2718
    case SSH_PENDING_CALL_AUTH_GSSAPI_KEYEX:
2719
        goto pending;
2720
    default:
2721
        ssh_set_error(session,
2722
                      SSH_FATAL,
2723
                      "Wrong state (%d) during pending SSH call",
2724
                      session->pending_call_state);
2725
        return SSH_ERROR;
2726
    }
2727
2728
    /* Check if GSSAPI Key exchange was performed */
2729
    if (!ssh_session_kex_is_gss(session)) {
2730
        ssh_set_error(session,
2731
                      SSH_FATAL,
2732
                      "Attempt to authenticate with gssapi-keyex without "
2733
                      "doing GSSAPI Key exchange.");
2734
        return SSH_ERROR;
2735
    }
2736
2737
    if (session->gssapi == NULL) {
2738
        ssh_set_error(session, SSH_FATAL, "GSSAPI context not initialized");
2739
        return SSH_ERROR;
2740
    }
2741
2742
    rc = ssh_userauth_request_service(session);
2743
    if (rc == SSH_AGAIN) {
2744
        return SSH_AUTH_AGAIN;
2745
    } else if (rc == SSH_ERROR) {
2746
        return SSH_AUTH_ERROR;
2747
    }
2748
    SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-keyex");
2749
2750
    session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_KEYEX;
2751
    session->auth.state = SSH_AUTH_STATE_NONE;
2752
    session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_KEYEX;
2753
2754
    SAFE_FREE(session->gssapi->user);
2755
    session->gssapi->user = strdup(session->opts.username);
2756
    if (session->gssapi->user == NULL) {
2757
        ssh_set_error_oom(session);
2758
        return SSH_ERROR;
2759
    }
2760
    rc = ssh_gssapi_auth_keyex_mic(session, &mic_token_buf);
2761
    if (rc != SSH_OK) {
2762
        session->auth.state = SSH_AUTH_STATE_NONE;
2763
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2764
        return rc;
2765
    }
2766
2767
    rc = ssh_buffer_pack(session->out_buffer,
2768
                         "bsssdP",
2769
                         SSH2_MSG_USERAUTH_REQUEST,
2770
                         session->opts.username,
2771
                         "ssh-connection",
2772
                         "gssapi-keyex",
2773
                         mic_token_buf.length,
2774
                         (size_t)mic_token_buf.length,
2775
                         mic_token_buf.value);
2776
    if (rc != SSH_OK) {
2777
        ssh_set_error_oom(session);
2778
        session->auth.state = SSH_AUTH_STATE_NONE;
2779
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2780
        gss_release_buffer(&min_stat, &mic_token_buf);
2781
        return rc;
2782
    }
2783
2784
    gss_release_buffer(&min_stat, &mic_token_buf);
2785
2786
    session->auth.state = SSH_AUTH_STATE_GSSAPI_KEYEX_MIC_SENT;
2787
2788
    ssh_packet_send(session);
2789
2790
pending:
2791
    rc = ssh_userauth_get_response(session);
2792
    if (rc != SSH_AUTH_AGAIN) {
2793
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2794
    }
2795
#else
2796
0
    (void)session; /* unused */
2797
0
#endif
2798
0
    return rc;
2799
0
}
2800
2801
/** @} */