Coverage Report

Created: 2026-03-20 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/pki.c
Line
Count
Source
1
/*
2
 * pki.c
3
 * This file is part of the SSH Library
4
 *
5
 * Copyright (c) 2010 by Aris Adamantiadis
6
 * Copyright (c) 2011-2013 Andreas Schneider <asn@cryptomilk.org>
7
 * Copyright (c) 2019      Sahana Prasad     <sahana@redhat.com>
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
/**
26
 * @defgroup libssh_pki The SSH Public Key Infrastructure
27
 * @ingroup libssh
28
 *
29
 * Functions for the creation, importation and manipulation of public and
30
 * private keys in the context of the SSH protocol
31
 *
32
 * @{
33
 */
34
35
#include "config.h"
36
#include "libssh/wrapper.h"
37
38
#include <errno.h>
39
#include <ctype.h>
40
#include <stdint.h>
41
#include <stdio.h>
42
#include <fcntl.h>
43
#include <sys/stat.h>
44
#include <sys/types.h>
45
46
#include "libssh/agent.h"
47
#include "libssh/buffer.h"
48
#include "libssh/keys.h"
49
#include "libssh/libssh.h"
50
#include "libssh/misc.h"
51
#include "libssh/pki.h"
52
#include "libssh/pki_context.h"
53
#include "libssh/pki_priv.h"
54
#include "libssh/pki_sk.h"
55
#include "libssh/priv.h"
56
#include "libssh/session.h"
57
#include "libssh/sk_common.h" /* For SK_NOT_SUPPORTED_MSG */
58
59
#ifndef MAX_LINE_SIZE
60
#define MAX_LINE_SIZE 4096
61
#endif /* NOT MAX_LINE_SIZE */
62
63
#define PKCS11_URI "pkcs11:"
64
65
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey)
66
0
{
67
0
    char *start = NULL;
68
69
0
    start = strstr(privkey, RSA_HEADER_BEGIN);
70
0
    if (start != NULL) {
71
0
        return SSH_KEYTYPE_RSA;
72
0
    }
73
74
0
    start = strstr(privkey, ECDSA_HEADER_BEGIN);
75
0
    if (start != 0) {
76
        /* We don't know what the curve is at this point, so we don't actually
77
         * know the type. We figure out the actual curve and fix things up in
78
         * pki_private_key_from_base64 */
79
0
        return SSH_KEYTYPE_ECDSA_P256;
80
0
    }
81
82
0
    return SSH_KEYTYPE_UNKNOWN;
83
0
}
84
85
/**
86
 * @brief returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
87
 *
88
 * @param[in] key the ssh_key whose ECDSA name to get
89
 *
90
 * @returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
91
 *
92
 * @returns "unknown" if the ECDSA key name is not known
93
 */
94
const char *ssh_pki_key_ecdsa_name(const ssh_key key)
95
0
{
96
0
    if (key == NULL) {
97
0
        return NULL;
98
0
    }
99
100
0
#ifdef HAVE_ECC /* FIXME Better ECC check needed */
101
0
    return pki_key_ecdsa_nid_to_name(key->ecdsa_nid);
102
#else
103
    return NULL;
104
#endif /* HAVE_ECC */
105
0
}
106
107
/**
108
 * @brief creates a new empty SSH key
109
 *
110
 * @returns an empty ssh_key handle, or NULL on error.
111
 */
112
ssh_key ssh_key_new (void)
113
37
{
114
37
    ssh_key ptr = malloc (sizeof (struct ssh_key_struct));
115
37
    if (ptr == NULL) {
116
0
        return NULL;
117
0
    }
118
37
    ZERO_STRUCTP(ptr);
119
37
    return ptr;
120
37
}
121
122
/**
123
 * @internal
124
 *
125
 * @brief Initialize a new SSH key by duplicating common fields from an existing
126
 * key.
127
 *
128
 * This function creates a new SSH key and copies the common fields from the
129
 * source key, including the key type, type string, flags, and security key
130
 * fields if applicable. This is a helper function used by key duplication
131
 * routines.
132
 *
133
 * @param[in] key     The source ssh_key to copy common fields from.
134
 * @param[in] demote  Whether to demote the new key to public only. If non-zero,
135
 *                    only the public fields will be copied and the flags will
136
 *                    be set accordingly.
137
 *
138
 * @return            A new ssh_key with common fields initialized, or NULL on
139
 * error.
140
 *
141
 * @note The caller is responsible for freeing the returned key with
142
 * ssh_key_free().
143
 */
144
ssh_key pki_key_dup_common_init(const ssh_key key, int demote)
145
0
{
146
0
    ssh_key new = NULL;
147
148
0
    if (key == NULL) {
149
0
        return NULL;
150
0
    }
151
152
0
    new = ssh_key_new();
153
0
    if (new == NULL) {
154
0
        return NULL;
155
0
    }
156
157
0
    new->type = key->type;
158
0
    new->type_c = key->type_c;
159
0
    if (demote) {
160
0
        new->flags = SSH_KEY_FLAG_PUBLIC;
161
0
    } else {
162
0
        new->flags = key->flags;
163
0
    }
164
165
    /* Copy security key fields if present */
166
0
    if (is_sk_key_type(key->type)) {
167
0
        new->sk_application = ssh_string_copy(key->sk_application);
168
0
        if (new->sk_application == NULL) {
169
0
            goto fail;
170
0
        }
171
172
0
        if (key->sk_user_id != NULL) {
173
0
            new->sk_user_id = ssh_string_copy(key->sk_user_id);
174
0
            if (new->sk_user_id == NULL) {
175
0
                goto fail;
176
0
            }
177
0
        }
178
179
0
        if (!demote) {
180
0
            new->sk_flags = key->sk_flags;
181
182
0
            new->sk_key_handle = ssh_string_copy(key->sk_key_handle);
183
0
            if (new->sk_key_handle == NULL) {
184
0
                goto fail;
185
0
            }
186
187
0
            new->sk_reserved = ssh_string_copy(key->sk_reserved);
188
0
            if (new->sk_reserved == NULL) {
189
0
                goto fail;
190
0
            }
191
0
        }
192
0
    }
193
194
0
    return new;
195
196
0
fail:
197
0
    SSH_KEY_FREE(new);
198
0
    return NULL;
199
0
}
200
201
/**
202
 * @brief duplicates the key
203
 *
204
 * @param key An ssh_key to duplicate
205
 *
206
 * @return A duplicated ssh_key key
207
 */
208
ssh_key ssh_key_dup(const ssh_key key)
209
0
{
210
0
    if (key == NULL) {
211
0
        return NULL;
212
0
    }
213
214
0
    return pki_key_dup(key, 0);
215
0
}
216
217
/**
218
 * @brief clean up the key and deallocate all existing keys
219
 * @param[in] key ssh_key to clean
220
 */
221
void ssh_key_clean (ssh_key key)
222
37
{
223
37
    if (key == NULL)
224
0
        return;
225
226
37
    pki_key_clean(key);
227
228
#ifndef HAVE_LIBCRYPTO
229
    if (key->ed25519_privkey != NULL) {
230
        ssh_burn(key->ed25519_privkey, sizeof(ed25519_privkey));
231
        SAFE_FREE(key->ed25519_privkey);
232
    }
233
    SAFE_FREE(key->ed25519_pubkey);
234
#endif /* HAVE_LIBCRYPTO */
235
37
    if (key->cert != NULL) {
236
0
        SSH_BUFFER_FREE(key->cert);
237
0
    }
238
37
    if (is_sk_key_type(key->type)) {
239
1
        ssh_string_burn(key->sk_application);
240
1
        ssh_string_free(key->sk_application);
241
1
        ssh_string_burn(key->sk_key_handle);
242
1
        ssh_string_free(key->sk_key_handle);
243
1
        ssh_string_burn(key->sk_reserved);
244
1
        ssh_string_free(key->sk_reserved);
245
1
        ssh_string_burn(key->sk_user_id);
246
1
        ssh_string_free(key->sk_user_id);
247
1
        key->sk_flags = 0;
248
1
    }
249
37
    key->cert_type = SSH_KEYTYPE_UNKNOWN;
250
37
    key->flags = SSH_KEY_FLAG_EMPTY;
251
37
    key->type = SSH_KEYTYPE_UNKNOWN;
252
37
    key->ecdsa_nid = 0;
253
37
    key->type_c = NULL;
254
37
}
255
256
/**
257
 * @brief deallocate a SSH key
258
 * @param[in] key ssh_key handle to free
259
 */
260
void ssh_key_free (ssh_key key)
261
2.21k
{
262
2.21k
    if (key) {
263
37
        ssh_key_clean(key);
264
37
        SAFE_FREE(key);
265
37
    }
266
2.21k
}
267
268
/**
269
 * @brief returns the type of a ssh key
270
 * @param[in] key the ssh_key handle
271
 * @returns one of SSH_KEYTYPE_RSA,
272
 *          SSH_KEYTYPE_ECDSA_P256, SSH_KEYTYPE_ECDSA_P384,
273
 *          SSH_KEYTYPE_ECDSA_P521, SSH_KEYTYPE_ED25519,
274
 *          SSH_KEYTYPE_RSA_CERT01, SSH_KEYTYPE_ECDSA_P256_CERT01,
275
 *          SSH_KEYTYPE_ECDSA_P384_CERT01, SSH_KEYTYPE_ECDSA_P521_CERT01, or
276
 *          SSH_KEYTYPE_ED25519_CERT01.
277
 * @returns SSH_KEYTYPE_UNKNOWN if the type is unknown
278
 */
279
enum ssh_keytypes_e ssh_key_type(const ssh_key key)
280
0
{
281
0
    if (key == NULL) {
282
0
        return SSH_KEYTYPE_UNKNOWN;
283
0
    }
284
0
    return key->type;
285
0
}
286
287
/**
288
 * @brief Get security key (FIDO2) flags for a security key backed ssh_key.
289
 *
290
 * The returned value contains a bitmask of SSH_SK_* flags (e.g.
291
 * SSH_SK_USER_PRESENCE_REQD, SSH_SK_USER_VERIFICATION_REQD, etc.).
292
 * If NULL is passed, then 0 is returned.
293
 *
294
 * @param[in] key  The ssh_key handle.
295
 *
296
 * @return Bitmask of security key flags, or 0 if not applicable.
297
 */
298
uint32_t ssh_key_get_sk_flags(const ssh_key key)
299
0
{
300
0
    if (key == NULL) {
301
0
        return 0;
302
0
    }
303
0
    return key->sk_flags;
304
0
}
305
306
/**
307
 * @brief Get the application (RP ID) associated with a security key.
308
 *
309
 * This function returns a freshly allocated ssh_string containing a copy of the
310
 * application (RP ID). The caller owns the returned ssh_string and must free it
311
 * with SSH_STRING_FREE() when no longer needed.
312
 *
313
 * Returns NULL if the key is NULL, not a security key type or if the field is
314
 * not set.
315
 *
316
 * @param[in] key  The ssh_key handle.
317
 *
318
 * @return ssh_string copy of the application (RP ID) or NULL if not available.
319
 */
320
ssh_string ssh_key_get_sk_application(const ssh_key key)
321
0
{
322
0
    if (key == NULL || key->sk_application == NULL) {
323
0
        return NULL;
324
0
    }
325
326
0
    return ssh_string_copy(key->sk_application);
327
0
}
328
329
/**
330
 * @brief Get a copy of the user ID associated with a resident security key
331
 * credential.
332
 *
333
 * For resident (discoverable) credentials, authenticators may provide a user
334
 * id which can be arbitrary binary data to allow for storing multiple keys for
335
 * the same Relying Party. This function returns a freshly allocated ssh_string
336
 * containing a copy of that user id. The caller owns the returned ssh_string
337
 * and must free it with SSH_STRING_FREE() when no longer needed.
338
 *
339
 * @note This function will only return useful information if the ssh_key
340
 * passed represents a resident key loaded using the ssh_sk_resident_keys_load()
341
 * function.
342
 *
343
 * @param[in] key  The ssh_key handle.
344
 *
345
 * @return ssh_string copy of user id or NULL if not available.
346
 */
347
ssh_string ssh_key_get_sk_user_id(const ssh_key key)
348
0
{
349
0
    if (key == NULL) {
350
0
        return NULL;
351
0
    }
352
0
    return ssh_string_copy(key->sk_user_id);
353
0
}
354
355
/**
356
 * @brief Convert a signature type to a string.
357
 *
358
 * @param[in]  type     The algorithm type to convert.
359
 *
360
 * @param[in] hash_type The hash type to convert
361
 *
362
 * @return              A string for the keytype or NULL if unknown.
363
 */
364
const char *
365
ssh_key_signature_to_char(enum ssh_keytypes_e type,
366
                          enum ssh_digest_e hash_type)
367
0
{
368
0
    switch (type) {
369
0
    case SSH_KEYTYPE_RSA:
370
0
        switch (hash_type) {
371
0
        case SSH_DIGEST_SHA256:
372
0
            return "rsa-sha2-256";
373
0
        case SSH_DIGEST_SHA512:
374
0
            return "rsa-sha2-512";
375
0
        case SSH_DIGEST_SHA1:
376
0
        case SSH_DIGEST_AUTO:
377
0
            return "ssh-rsa";
378
0
        default:
379
0
            return NULL;
380
0
        }
381
0
        break;
382
0
    case SSH_KEYTYPE_RSA_CERT01:
383
0
        switch (hash_type) {
384
0
        case SSH_DIGEST_SHA256:
385
0
            return "rsa-sha2-256-cert-v01@openssh.com";
386
0
        case SSH_DIGEST_SHA512:
387
0
            return "rsa-sha2-512-cert-v01@openssh.com";
388
0
        case SSH_DIGEST_SHA1:
389
0
        case SSH_DIGEST_AUTO:
390
0
            return "ssh-rsa-cert-v01@openssh.com";
391
0
        default:
392
0
            return NULL;
393
0
        }
394
0
        break;
395
0
    default:
396
0
        return ssh_key_type_to_char(type);
397
0
    }
398
399
    /* We should never reach this */
400
0
    return NULL;
401
0
}
402
403
/**
404
 * @brief Convert a key type to a string.
405
 *
406
 * @param[in]  type     The type to convert.
407
 *
408
 * @return              A string for the keytype or NULL if unknown.
409
 */
410
39
const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
411
39
  switch (type) {
412
35
    case SSH_KEYTYPE_RSA:
413
35
      return "ssh-rsa";
414
0
    case SSH_KEYTYPE_ECDSA:
415
0
      return "ssh-ecdsa"; /* deprecated. invalid value */
416
1
    case SSH_KEYTYPE_ECDSA_P256:
417
1
      return "ecdsa-sha2-nistp256";
418
0
    case SSH_KEYTYPE_ECDSA_P384:
419
0
      return "ecdsa-sha2-nistp384";
420
0
    case SSH_KEYTYPE_ECDSA_P521:
421
0
      return "ecdsa-sha2-nistp521";
422
0
    case SSH_KEYTYPE_ED25519:
423
0
      return "ssh-ed25519";
424
0
    case SSH_KEYTYPE_RSA_CERT01:
425
0
      return "ssh-rsa-cert-v01@openssh.com";
426
1
    case SSH_KEYTYPE_ECDSA_P256_CERT01:
427
1
      return "ecdsa-sha2-nistp256-cert-v01@openssh.com";
428
0
    case SSH_KEYTYPE_ECDSA_P384_CERT01:
429
0
      return "ecdsa-sha2-nistp384-cert-v01@openssh.com";
430
0
    case SSH_KEYTYPE_ECDSA_P521_CERT01:
431
0
      return "ecdsa-sha2-nistp521-cert-v01@openssh.com";
432
0
    case SSH_KEYTYPE_ED25519_CERT01:
433
0
      return "ssh-ed25519-cert-v01@openssh.com";
434
1
    case SSH_KEYTYPE_SK_ECDSA:
435
1
      return "sk-ecdsa-sha2-nistp256@openssh.com";
436
0
    case SSH_KEYTYPE_SK_ED25519:
437
0
      return "sk-ssh-ed25519@openssh.com";
438
1
    case SSH_KEYTYPE_SK_ECDSA_CERT01:
439
1
      return "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com";
440
0
    case SSH_KEYTYPE_SK_ED25519_CERT01:
441
0
      return "sk-ssh-ed25519-cert-v01@openssh.com";
442
0
    case SSH_KEYTYPE_DSS:   /* deprecated */
443
0
    case SSH_KEYTYPE_RSA1:
444
0
    case SSH_KEYTYPE_DSS_CERT01:    /* deprecated */
445
0
    case SSH_KEYTYPE_UNKNOWN:
446
0
      return NULL;
447
39
  }
448
449
  /* We should never reach this */
450
0
  return NULL;
451
39
}
452
453
enum ssh_digest_e ssh_key_hash_from_name(const char *name)
454
1
{
455
1
    if (name == NULL) {
456
        /* TODO we should rather fail */
457
0
        return SSH_DIGEST_AUTO;
458
0
    }
459
460
1
    if (strcmp(name, "ssh-rsa") == 0) {
461
0
        return SSH_DIGEST_SHA1;
462
1
    } else if (strcmp(name, "rsa-sha2-256") == 0) {
463
0
        return SSH_DIGEST_SHA256;
464
1
    } else if (strcmp(name, "rsa-sha2-512") == 0) {
465
0
        return SSH_DIGEST_SHA512;
466
1
    } else if (strcmp(name, "ecdsa-sha2-nistp256") == 0) {
467
0
        return SSH_DIGEST_SHA256;
468
1
    } else if (strcmp(name, "ecdsa-sha2-nistp384") == 0) {
469
0
        return SSH_DIGEST_SHA384;
470
1
    } else if (strcmp(name, "ecdsa-sha2-nistp521") == 0) {
471
0
        return SSH_DIGEST_SHA512;
472
1
    } else if (strcmp(name, "ssh-ed25519") == 0) {
473
0
        return SSH_DIGEST_AUTO;
474
1
    } else if (strcmp(name, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) {
475
0
        return SSH_DIGEST_SHA256;
476
1
    } else if (strcmp(name, "sk-ssh-ed25519@openssh.com") == 0) {
477
0
        return SSH_DIGEST_AUTO;
478
0
    }
479
480
1
    SSH_LOG(SSH_LOG_TRACE, "Unknown signature name %s", name);
481
482
    /* TODO we should rather fail */
483
1
    return SSH_DIGEST_AUTO;
484
1
}
485
486
/**
487
 * @brief Checks the given key against the configured allowed
488
 * public key algorithm types
489
 *
490
 * @param[in] session The SSH session
491
 * @param[in] type    The key algorithm to check
492
 * @returns           1 if the key algorithm is allowed, 0 otherwise
493
 */
494
int ssh_key_algorithm_allowed(ssh_session session, const char *type)
495
0
{
496
0
    const char *allowed_list = NULL;
497
498
0
    if (session->client) {
499
0
        allowed_list = session->opts.pubkey_accepted_types;
500
0
        if (allowed_list == NULL) {
501
0
            if (ssh_fips_mode()) {
502
0
                allowed_list = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
503
0
            } else {
504
0
                allowed_list = ssh_kex_get_default_methods(SSH_HOSTKEYS);
505
0
            }
506
0
        }
507
0
    }
508
0
#ifdef WITH_SERVER
509
0
    else if (session->server) {
510
0
        allowed_list = session->opts.wanted_methods[SSH_HOSTKEYS];
511
0
        if (allowed_list == NULL) {
512
0
            SSH_LOG(SSH_LOG_TRACE, "Session invalid: no host key available");
513
0
            return 0;
514
0
        }
515
0
    }
516
0
#endif /* WITH_SERVER */
517
0
    else {
518
0
        SSH_LOG(SSH_LOG_TRACE, "Session invalid: not set as client nor server");
519
0
        return 0;
520
0
    }
521
522
0
    SSH_LOG(SSH_LOG_DEBUG, "Checking %s with list <%s>", type, allowed_list);
523
0
    return match_group(allowed_list, type);
524
0
}
525
526
bool ssh_key_size_allowed_rsa(int min_size, ssh_key key)
527
0
{
528
0
    int key_size = ssh_key_size(key);
529
530
0
    if (min_size < RSA_MIN_KEY_SIZE) {
531
0
        if (ssh_fips_mode()) {
532
0
            min_size = RSA_MIN_FIPS_KEY_SIZE;
533
0
        } else {
534
0
            min_size = RSA_MIN_KEY_SIZE;
535
0
        }
536
0
    }
537
0
    return (key_size >= min_size);
538
0
}
539
540
/**
541
 * @brief Check the given key is acceptable in regards to the key size policy
542
 * specified by the configuration
543
 *
544
 * @param[in] session The SSH session
545
 * @param[in] key     The SSH key
546
 * @returns           true if the key is allowed, false otherwise
547
 */
548
bool ssh_key_size_allowed(ssh_session session, ssh_key key)
549
0
{
550
0
    int min_size = 0;
551
552
0
    switch (ssh_key_type(key)) {
553
0
    case SSH_KEYTYPE_RSA:
554
0
    case SSH_KEYTYPE_RSA_CERT01:
555
0
        min_size = session->opts.rsa_min_size;
556
0
        return ssh_key_size_allowed_rsa(min_size, key);
557
0
    default:
558
0
        return true;
559
0
    }
560
0
}
561
562
/**
563
 * @brief Helper function to convert a key type to a hash type.
564
 *
565
 * @param[in]  type     The type to convert.
566
 *
567
 * @return              A hash type to be used.
568
 *
569
 * @warning This helper function is available for use without session (for
570
 *          example for signing commits) and might cause interoperability issues
571
 *          when used within session! It is recommended to use
572
 *          ssh_key_type_to_hash() instead of this helper directly when a
573
 *          session is available.
574
 *
575
 * @note    In order to follow current security best practises for RSA, defaults
576
 *          to SHA-2 with SHA-512 digest (RFC8332) instead of the default for
577
 *          the SSH protocol (SHA1 with RSA ; RFC 4253).
578
 *
579
 * @see     ssh_key_type_to_hash()
580
 */
581
static enum ssh_digest_e key_type_to_hash(enum ssh_keytypes_e type)
582
0
{
583
0
    switch (type) {
584
0
    case SSH_KEYTYPE_RSA_CERT01:
585
0
    case SSH_KEYTYPE_RSA:
586
0
        return SSH_DIGEST_SHA512;
587
0
    case SSH_KEYTYPE_ECDSA_P256_CERT01:
588
0
    case SSH_KEYTYPE_ECDSA_P256:
589
0
    case SSH_KEYTYPE_SK_ECDSA:
590
0
        return SSH_DIGEST_SHA256;
591
0
    case SSH_KEYTYPE_ECDSA_P384_CERT01:
592
0
    case SSH_KEYTYPE_ECDSA_P384:
593
0
        return SSH_DIGEST_SHA384;
594
0
    case SSH_KEYTYPE_ECDSA_P521_CERT01:
595
0
    case SSH_KEYTYPE_ECDSA_P521:
596
0
        return SSH_DIGEST_SHA512;
597
0
    case SSH_KEYTYPE_ED25519_CERT01:
598
0
    case SSH_KEYTYPE_ED25519:
599
0
    case SSH_KEYTYPE_SK_ED25519:
600
0
        return SSH_DIGEST_AUTO;
601
0
    case SSH_KEYTYPE_RSA1:
602
0
    case SSH_KEYTYPE_DSS:        /* deprecated */
603
0
    case SSH_KEYTYPE_DSS_CERT01: /* deprecated */
604
0
    case SSH_KEYTYPE_ECDSA:
605
0
    case SSH_KEYTYPE_UNKNOWN:
606
0
    default:
607
0
        SSH_LOG(SSH_LOG_WARN,
608
0
                "Digest algorithm to be used with key type %u "
609
0
                "is not defined",
610
0
                type);
611
0
    }
612
613
    /* We should never reach this */
614
0
    return SSH_DIGEST_AUTO;
615
0
}
616
617
/**
618
 * @brief Convert a key type to a hash type. This is usually unambiguous
619
 * for all the key types, unless the SHA2 extension (RFC 8332) is
620
 * negotiated during key exchange.
621
 *
622
 * @param[in]  session  SSH Session.
623
 *
624
 * @param[in]  type     The type to convert.
625
 *
626
 * @return              A hash type to be used.
627
 */
628
enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
629
                                       enum ssh_keytypes_e type)
630
0
{
631
0
    switch (type) {
632
0
    case SSH_KEYTYPE_RSA_CERT01:
633
        /* If we are talking to an old OpenSSH version which does not support
634
         * SHA2 in certificates */
635
0
        if ((session->openssh > 0) &&
636
0
            (session->openssh < SSH_VERSION_INT(7, 2, 0)))
637
0
        {
638
0
            SSH_LOG(SSH_LOG_DEBUG,
639
0
                    "We are talking to an old OpenSSH (%x); "
640
0
                    "returning SSH_DIGEST_SHA1",
641
0
                    session->openssh);
642
643
0
            return SSH_DIGEST_SHA1;
644
0
        }
645
0
        FALL_THROUGH;
646
0
    case SSH_KEYTYPE_RSA:
647
0
        if (ssh_key_algorithm_allowed(session, "rsa-sha2-512") &&
648
0
            (session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
649
0
            return SSH_DIGEST_SHA512;
650
0
        }
651
652
0
        if (ssh_key_algorithm_allowed(session, "rsa-sha2-256") &&
653
0
            (session->extensions & SSH_EXT_SIG_RSA_SHA256)) {
654
0
            return SSH_DIGEST_SHA256;
655
0
        }
656
657
        /* Default algorithm for RSA is SHA1 */
658
0
        return SSH_DIGEST_SHA1;
659
660
0
    default:
661
0
        return key_type_to_hash(type);
662
0
    }
663
664
    /* We should never reach this */
665
0
    return SSH_DIGEST_AUTO;
666
0
}
667
668
/**
669
 * @brief Gets signature algorithm name to be used with the given
670
 *        key type.
671
 *
672
 * @param[in]  session  SSH session.
673
 * @param[in]  type     The algorithm type to convert.
674
 *
675
 * @return              A string for the keytype or NULL if unknown.
676
 */
677
const char *
678
ssh_key_get_signature_algorithm(ssh_session session,
679
                                enum ssh_keytypes_e type)
680
0
{
681
0
    enum ssh_digest_e hash_type;
682
683
0
    if (type == SSH_KEYTYPE_RSA_CERT01) {
684
        /* If we are talking to an old OpenSSH version which does not support
685
         * rsa-sha2-{256,512}-cert-v01@openssh.com */
686
0
        if ((session->openssh > 0) &&
687
0
            (session->openssh < SSH_VERSION_INT(7, 8, 0)))
688
0
        {
689
0
            SSH_LOG(SSH_LOG_DEBUG,
690
0
                    "We are talking to an old OpenSSH (%x); "
691
0
                    "using old cert format",
692
0
                    session->openssh);
693
694
0
            return "ssh-rsa-cert-v01@openssh.com";
695
0
        }
696
0
    }
697
698
0
    hash_type = ssh_key_type_to_hash(session, type);
699
700
0
    return ssh_key_signature_to_char(type, hash_type);
701
0
}
702
703
/**
704
 * @brief Convert a ssh key algorithm name to a ssh key algorithm type.
705
 *
706
 * @param[in] name      The name to convert.
707
 *
708
 * @return              The enum ssh key algorithm type.
709
 */
710
1
enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name) {
711
1
    if (name == NULL) {
712
0
        return SSH_KEYTYPE_UNKNOWN;
713
0
    }
714
715
1
    if ((strcmp(name, "rsa-sha2-256") == 0) ||
716
1
        (strcmp(name, "rsa-sha2-512") == 0)) {
717
0
        return SSH_KEYTYPE_RSA;
718
0
    }
719
720
    /* Otherwise the key type matches the signature type */
721
1
    return ssh_key_type_from_name(name);
722
1
}
723
724
/**
725
 * @brief Convert a ssh key name to a ssh key type.
726
 *
727
 * @param[in] name      The name to convert.
728
 *
729
 * @return              The enum ssh key type.
730
 */
731
enum ssh_keytypes_e ssh_key_type_from_name(const char *name)
732
92
{
733
92
    if (name == NULL) {
734
0
        return SSH_KEYTYPE_UNKNOWN;
735
0
    }
736
737
92
    if (strcmp(name, "rsa") == 0) {
738
0
        return SSH_KEYTYPE_RSA;
739
92
    } else if (strcmp(name, "ssh-rsa") == 0) {
740
35
        return SSH_KEYTYPE_RSA;
741
57
    } else if (strcmp(name, "ssh-ecdsa") == 0
742
57
            || strcmp(name, "ecdsa") == 0
743
56
            || strcmp(name, "ecdsa-sha2-nistp256") == 0) {
744
1
        return SSH_KEYTYPE_ECDSA_P256;
745
56
    } else if (strcmp(name, "ecdsa-sha2-nistp384") == 0) {
746
0
        return SSH_KEYTYPE_ECDSA_P384;
747
56
    } else if (strcmp(name, "ecdsa-sha2-nistp521") == 0) {
748
0
        return SSH_KEYTYPE_ECDSA_P521;
749
56
    } else if (strcmp(name, "ssh-ed25519") == 0){
750
0
        return SSH_KEYTYPE_ED25519;
751
56
    } else if (strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) {
752
0
        return SSH_KEYTYPE_RSA_CERT01;
753
56
    } else if (strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0) {
754
1
        return SSH_KEYTYPE_ECDSA_P256_CERT01;
755
55
    } else if (strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0) {
756
0
        return SSH_KEYTYPE_ECDSA_P384_CERT01;
757
55
    } else if (strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
758
0
        return SSH_KEYTYPE_ECDSA_P521_CERT01;
759
55
    } else if (strcmp(name, "ssh-ed25519-cert-v01@openssh.com") == 0) {
760
0
        return SSH_KEYTYPE_ED25519_CERT01;
761
55
    } else if(strcmp(name, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) {
762
0
        return SSH_KEYTYPE_SK_ECDSA;
763
55
    } else if(strcmp(name, "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0) {
764
1
        return SSH_KEYTYPE_SK_ECDSA_CERT01;
765
54
    } else if(strcmp(name, "sk-ssh-ed25519@openssh.com") == 0) {
766
0
        return SSH_KEYTYPE_SK_ED25519;
767
54
    } else if(strcmp(name, "sk-ssh-ed25519-cert-v01@openssh.com") == 0) {
768
0
        return SSH_KEYTYPE_SK_ED25519_CERT01;
769
0
    }
770
771
54
    return SSH_KEYTYPE_UNKNOWN;
772
92
}
773
774
/**
775
 * @brief Get the public key type corresponding to a certificate type.
776
 *
777
 * @param[in] type   The certificate or public key type.
778
 *
779
 * @return           The matching public key type.
780
 */
781
enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type)
782
1
{
783
1
    switch (type) {
784
0
        case SSH_KEYTYPE_RSA_CERT01:
785
0
            return SSH_KEYTYPE_RSA;
786
0
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
787
0
            return SSH_KEYTYPE_ECDSA_P256;
788
0
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
789
0
            return SSH_KEYTYPE_ECDSA_P384;
790
0
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
791
0
            return SSH_KEYTYPE_ECDSA_P521;
792
0
        case SSH_KEYTYPE_ED25519_CERT01:
793
0
            return SSH_KEYTYPE_ED25519;
794
0
        case SSH_KEYTYPE_SK_ECDSA_CERT01:
795
0
            return SSH_KEYTYPE_SK_ECDSA;
796
0
        case SSH_KEYTYPE_SK_ED25519_CERT01:
797
0
            return SSH_KEYTYPE_SK_ED25519;
798
1
        default:
799
1
            return type;
800
1
    }
801
1
}
802
803
/**
804
 * @brief Check if the key has/is a public key.
805
 *
806
 * @param[in] k         The key to check.
807
 *
808
 * @return              1 if it is a public key, 0 if not.
809
 */
810
int ssh_key_is_public(const ssh_key k)
811
0
{
812
0
    if (k == NULL) {
813
0
        return 0;
814
0
    }
815
816
0
    return (k->flags & SSH_KEY_FLAG_PUBLIC) == SSH_KEY_FLAG_PUBLIC;
817
0
}
818
819
/**
820
 * @brief Check if the key is a private key.
821
 *
822
 * @param[in] k         The key to check.
823
 *
824
 * @return              1 if it is a private key, 0 if not.
825
 */
826
0
int ssh_key_is_private(const ssh_key k) {
827
0
    if (k == NULL) {
828
0
        return 0;
829
0
    }
830
831
0
    return (k->flags & SSH_KEY_FLAG_PRIVATE) == SSH_KEY_FLAG_PRIVATE;
832
0
}
833
834
/**
835
 * @brief Compare keys if they are equal.
836
 *
837
 * Note that comparing private keys is almost never needed. The private key
838
 * is cryptographically bound to the public key and comparing public keys should
839
 * always be preferred.
840
 *
841
 * @param[in] k1        The first key to compare.
842
 *
843
 * @param[in] k2        The second key to compare.
844
 *
845
 * @param[in] what      What part or type of the key do you want to compare.
846
 *
847
 * @return              0 if equal, 1 if not.
848
 */
849
int ssh_key_cmp(const ssh_key k1,
850
                const ssh_key k2,
851
                enum ssh_keycmp_e what)
852
0
{
853
0
    if (k1 == NULL || k2 == NULL) {
854
0
        return 1;
855
0
    }
856
857
0
    if (ssh_key_type_plain(k1->type) != ssh_key_type_plain(k2->type)) {
858
0
        SSH_LOG(SSH_LOG_DEBUG, "key types don't match!");
859
0
        return 1;
860
0
    }
861
862
0
    if (what == SSH_KEY_CMP_PRIVATE) {
863
0
        if (!ssh_key_is_private(k1) ||
864
0
            !ssh_key_is_private(k2)) {
865
0
            return 1;
866
0
        }
867
0
    }
868
869
0
    if (is_sk_key_type(k1->type)) {
870
0
        if (ssh_string_cmp(k1->sk_application, k2->sk_application) != 0) {
871
0
            return 1;
872
0
        }
873
874
0
        if (ssh_string_cmp(k1->sk_user_id, k2->sk_user_id) != 0) {
875
0
            return 1;
876
0
        }
877
878
0
        if (what == SSH_KEY_CMP_PRIVATE) {
879
0
            if (k1->sk_flags != k2->sk_flags) {
880
0
                return 1;
881
0
            }
882
883
0
            if (ssh_string_cmp(k1->sk_key_handle, k2->sk_key_handle) != 0) {
884
0
                return 1;
885
0
            }
886
887
0
            if (ssh_string_cmp(k1->sk_reserved, k2->sk_reserved) != 0) {
888
0
                return 1;
889
0
            }
890
0
        }
891
0
    }
892
893
0
    if (what == SSH_KEY_CMP_CERTIFICATE) {
894
0
        if (!is_cert_type(k1->type) ||
895
0
            !is_cert_type(k2->type)) {
896
0
            return 1;
897
0
        }
898
0
        if (k1->cert == NULL || k2->cert == NULL) {
899
0
            return 1;
900
0
        }
901
0
        if (ssh_buffer_get_len(k1->cert) != ssh_buffer_get_len(k2->cert)) {
902
0
            return 1;
903
0
        }
904
0
        return memcmp(ssh_buffer_get(k1->cert),
905
0
                      ssh_buffer_get(k2->cert),
906
0
                      ssh_buffer_get_len(k1->cert));
907
0
    }
908
909
#ifndef HAVE_LIBCRYPTO
910
    if (ssh_key_type_plain(k1->type) == SSH_KEYTYPE_ED25519) {
911
        return pki_ed25519_key_cmp(k1, k2, what);
912
    } else if (ssh_key_type_plain(k1->type) == SSH_KEYTYPE_SK_ED25519) {
913
        return pki_ed25519_key_cmp(k1, k2, SSH_KEY_CMP_PUBLIC);
914
    }
915
#endif
916
917
0
    return pki_key_compare(k1, k2, what);
918
0
}
919
920
ssh_signature ssh_signature_new(void)
921
0
{
922
0
    struct ssh_signature_struct *sig = NULL;
923
924
0
    sig = calloc(1, sizeof(struct ssh_signature_struct));
925
0
    if (sig == NULL) {
926
0
        return NULL;
927
0
    }
928
929
0
    return sig;
930
0
}
931
932
void ssh_signature_free(ssh_signature sig)
933
1
{
934
1
    if (sig == NULL) {
935
1
        return;
936
1
    }
937
938
0
    switch(sig->type) {
939
0
        case SSH_KEYTYPE_RSA:
940
#ifdef HAVE_LIBGCRYPT
941
            gcry_sexp_release(sig->rsa_sig);
942
#elif defined HAVE_LIBMBEDCRYPTO
943
            SAFE_FREE(sig->rsa_sig);
944
#endif /* HAVE_LIBGCRYPT */
945
0
            break;
946
0
        case SSH_KEYTYPE_ECDSA_P256:
947
0
        case SSH_KEYTYPE_ECDSA_P384:
948
0
        case SSH_KEYTYPE_ECDSA_P521:
949
0
        case SSH_KEYTYPE_SK_ECDSA:
950
#ifdef HAVE_GCRYPT_ECC
951
            gcry_sexp_release(sig->ecdsa_sig);
952
#elif defined HAVE_LIBMBEDCRYPTO
953
            bignum_safe_free(sig->ecdsa_sig.r);
954
            bignum_safe_free(sig->ecdsa_sig.s);
955
#endif /* HAVE_GCRYPT_ECC */
956
0
            break;
957
0
        case SSH_KEYTYPE_ED25519:
958
0
        case SSH_KEYTYPE_SK_ED25519:
959
#ifndef HAVE_LIBCRYPTO
960
            /* When using OpenSSL, the signature is stored in sig->raw_sig */
961
            SAFE_FREE(sig->ed25519_sig);
962
#endif /* HAVE_LIBCRYPTO */
963
0
            break;
964
0
        case SSH_KEYTYPE_DSS:   /* deprecated */
965
0
        case SSH_KEYTYPE_DSS_CERT01:    /* deprecated */
966
0
        case SSH_KEYTYPE_RSA_CERT01:
967
0
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
968
0
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
969
0
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
970
0
        case SSH_KEYTYPE_ED25519_CERT01:
971
0
        case SSH_KEYTYPE_SK_ECDSA_CERT01:
972
0
        case SSH_KEYTYPE_SK_ED25519_CERT01:
973
0
        case SSH_KEYTYPE_RSA1:
974
0
        case SSH_KEYTYPE_ECDSA:
975
0
        case SSH_KEYTYPE_UNKNOWN:
976
0
            break;
977
0
    }
978
979
    /* Explicitly zero the signature content before free */
980
0
    ssh_string_burn(sig->raw_sig);
981
0
    SSH_STRING_FREE(sig->raw_sig);
982
0
    SAFE_FREE(sig);
983
0
}
984
985
/**
986
 * @brief import a base64 formatted key from a memory c-string
987
 *
988
 * @param[in]  b64_key  The c-string holding the base64 encoded key
989
 *
990
 * @param[in]  passphrase The passphrase to decrypt the key, or NULL
991
 *
992
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
993
 *
994
 * @param[in]  auth_data Private data passed to the auth function.
995
 *
996
 * @param[out] pkey     A pointer where the allocated key can be stored. You
997
 *                      need to free the memory using ssh_key_free()
998
 *
999
 * @return  SSH_ERROR in case of error, SSH_OK otherwise.
1000
 *
1001
 * @see ssh_key_free()
1002
 */
1003
int ssh_pki_import_privkey_base64(const char *b64_key,
1004
                                  const char *passphrase,
1005
                                  ssh_auth_callback auth_fn,
1006
                                  void *auth_data,
1007
                                  ssh_key *pkey)
1008
0
{
1009
0
    ssh_key key = NULL;
1010
0
    char *openssh_header = NULL;
1011
1012
0
    if (b64_key == NULL || pkey == NULL) {
1013
0
        return SSH_ERROR;
1014
0
    }
1015
1016
0
    if (b64_key == NULL || !*b64_key) {
1017
0
        return SSH_ERROR;
1018
0
    }
1019
1020
0
    SSH_LOG(SSH_LOG_DEBUG,
1021
0
            "Trying to decode privkey passphrase=%s",
1022
0
            passphrase ? "true" : "false");
1023
1024
    /* Test for OpenSSH key format first */
1025
0
    openssh_header = strstr(b64_key, OPENSSH_HEADER_BEGIN);
1026
0
    if (openssh_header != NULL) {
1027
0
        key = ssh_pki_openssh_privkey_import(openssh_header,
1028
0
                                             passphrase,
1029
0
                                             auth_fn,
1030
0
                                             auth_data);
1031
0
    } else {
1032
        /* fallback on PEM decoder */
1033
0
        key = pki_private_key_from_base64(b64_key,
1034
0
                                          passphrase,
1035
0
                                          auth_fn,
1036
0
                                          auth_data);
1037
0
    }
1038
0
    if (key == NULL) {
1039
0
        return SSH_ERROR;
1040
0
    }
1041
1042
0
    *pkey = key;
1043
1044
0
    return SSH_OK;
1045
0
}
1046
1047
1048
 /**
1049
 * @brief Convert a private key to a base64 encoded key in given format
1050
 *
1051
 * @param[in]  privkey  The private key to export.
1052
 *
1053
 * @param[in]  passphrase The passphrase to use to encrypt the key with or
1054
 *             NULL. An empty string means no passphrase.
1055
 *
1056
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
1057
 *
1058
 * @param[in]  auth_data Private data passed to the auth function.
1059
 *
1060
 * @param[out] b64_key  A pointer to store the allocated base64 encoded key. You
1061
 *                      need to free the buffer using ssh_string_from_char().
1062
 *
1063
 * @param[in]  format   The file format (OpenSSH, PEM, or default)
1064
 *
1065
 * @return     SSH_OK on success, SSH_ERROR on error.
1066
 *
1067
 * @see ssh_string_free_char()
1068
 */
1069
int
1070
ssh_pki_export_privkey_base64_format(const ssh_key privkey,
1071
                                     const char *passphrase,
1072
                                     ssh_auth_callback auth_fn,
1073
                                     void *auth_data,
1074
                                     char **b64_key,
1075
                                     enum ssh_file_format_e format)
1076
0
{
1077
0
    ssh_string blob = NULL;
1078
0
    char *b64 = NULL;
1079
1080
0
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
1081
0
        return SSH_ERROR;
1082
0
    }
1083
1084
    /*
1085
     * For historic reasons, the Ed25519 keys are exported in OpenSSH file
1086
     * format by default also when built with OpenSSL.
1087
     *
1088
     * The FIDO2/U2F security keys are an extension to the SSH protocol
1089
     * proposed by OpenSSH, and do not have any representation in PEM format.
1090
     * So, they are always exported in the OpenSSH file format.
1091
     */
1092
0
#ifdef HAVE_LIBCRYPTO
1093
0
    if (format == SSH_FILE_FORMAT_DEFAULT &&
1094
0
        privkey->type != SSH_KEYTYPE_ED25519 &&
1095
0
        !is_sk_key_type(privkey->type)) {
1096
0
        format = SSH_FILE_FORMAT_PEM;
1097
0
    }
1098
0
#endif /* HAVE_LIBCRYPTO */
1099
1100
0
    switch (format) {
1101
0
    case SSH_FILE_FORMAT_PEM:
1102
0
        blob = pki_private_key_to_pem(privkey,
1103
0
                                      passphrase,
1104
0
                                      auth_fn,
1105
0
                                      auth_data);
1106
0
        break;
1107
0
    case SSH_FILE_FORMAT_DEFAULT:
1108
        /* default except (OpenSSL && !ED25519) handled above */
1109
0
    case SSH_FILE_FORMAT_OPENSSH:
1110
0
        blob = ssh_pki_openssh_privkey_export(privkey,
1111
0
                                              passphrase,
1112
0
                                              auth_fn,
1113
0
                                              auth_data);
1114
0
        break;
1115
0
    }
1116
0
    if (blob == NULL) {
1117
0
        return SSH_ERROR;
1118
0
    }
1119
1120
0
    b64 = strndup(ssh_string_data(blob), ssh_string_len(blob));
1121
0
    SSH_STRING_FREE(blob);
1122
0
    if (b64 == NULL) {
1123
0
        return SSH_ERROR;
1124
0
    }
1125
1126
0
    *b64_key = b64;
1127
1128
0
    return SSH_OK;
1129
0
}
1130
1131
 /**
1132
 * @brief Convert a private key to a pem base64 encoded key, or OpenSSH format for
1133
 *        keytype ssh-ed25519
1134
 *
1135
 * @param[in]  privkey  The private key to export.
1136
 *
1137
 * @param[in]  passphrase The passphrase to use to encrypt the key with or
1138
 *             NULL. An empty string means no passphrase.
1139
 *
1140
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
1141
 *
1142
 * @param[in]  auth_data Private data passed to the auth function.
1143
 *
1144
 * @param[out] b64_key  A pointer to store the allocated base64 encoded key. You
1145
 *                      need to free the buffer using ssh_string_from_char().
1146
 *
1147
 * @return     SSH_OK on success, SSH_ERROR on error.
1148
 *
1149
 * @see ssh_string_free_char()
1150
 */
1151
int ssh_pki_export_privkey_base64(const ssh_key privkey,
1152
                                  const char *passphrase,
1153
                                  ssh_auth_callback auth_fn,
1154
                                  void *auth_data,
1155
                                  char **b64_key)
1156
0
{
1157
0
    return ssh_pki_export_privkey_base64_format(privkey,
1158
0
                                                passphrase,
1159
0
                                                auth_fn,
1160
0
                                                auth_data,
1161
0
                                                b64_key,
1162
0
                                                SSH_FILE_FORMAT_DEFAULT);
1163
0
}
1164
1165
1166
1167
/**
1168
 * @brief Import a private key from a file or a PKCS #11 device.
1169
 *
1170
 * @param[in]  filename The filename of the private key or the
1171
 *                      PKCS #11 URI corresponding to the private key.
1172
 *
1173
 * @param[in]  passphrase The passphrase to decrypt the private key. Set to NULL
1174
 *                        if none is needed or it is unknown.
1175
 *
1176
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
1177
 *
1178
 * @param[in]  auth_data Private data passed to the auth function.
1179
 *
1180
 * @param[out] pkey     A pointer to store the allocated ssh_key. You need to
1181
 *                      free the key using ssh_key_free().
1182
 *
1183
 * @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
1184
 *          denied, SSH_ERROR otherwise.
1185
 *
1186
 * @see ssh_key_free()
1187
 **/
1188
int ssh_pki_import_privkey_file(const char *filename,
1189
                                const char *passphrase,
1190
                                ssh_auth_callback auth_fn,
1191
                                void *auth_data,
1192
0
                                ssh_key *pkey) {
1193
0
    struct stat sb;
1194
0
    char *key_buf = NULL;
1195
0
    FILE *file = NULL;
1196
0
    off_t size;
1197
0
    int rc;
1198
0
    char err_msg[SSH_ERRNO_MSG_MAX] = {0};
1199
1200
0
    if (pkey == NULL || filename == NULL || *filename == '\0') {
1201
0
        return SSH_ERROR;
1202
0
    }
1203
1204
#ifdef WITH_PKCS11_URI
1205
    if (ssh_pki_is_uri(filename)) {
1206
        rc = pki_uri_import(filename, pkey, SSH_KEY_PRIVATE);
1207
        return rc;
1208
    }
1209
#endif /* WITH_PKCS11_URI */
1210
1211
0
    file = fopen(filename, "rb");
1212
0
    if (file == NULL) {
1213
0
        SSH_LOG(SSH_LOG_TRACE,
1214
0
                "Error opening %s: %s",
1215
0
                filename,
1216
0
                ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
1217
0
        return SSH_EOF;
1218
0
    }
1219
1220
0
    rc = fstat(fileno(file), &sb);
1221
0
    if (rc < 0) {
1222
0
        fclose(file);
1223
0
        SSH_LOG(SSH_LOG_TRACE,
1224
0
                "Error getting stat of %s: %s",
1225
0
                filename,
1226
0
                ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
1227
0
        switch (errno) {
1228
0
            case ENOENT:
1229
0
            case EACCES:
1230
0
                return SSH_EOF;
1231
0
        }
1232
1233
0
        return SSH_ERROR;
1234
0
    }
1235
1236
0
    if (sb.st_size > MAX_PRIVKEY_SIZE) {
1237
0
        SSH_LOG(SSH_LOG_TRACE,
1238
0
                "Private key is bigger than 4M.");
1239
0
        fclose(file);
1240
0
        return SSH_ERROR;
1241
0
    }
1242
1243
0
    key_buf = malloc(sb.st_size + 1);
1244
0
    if (key_buf == NULL) {
1245
0
        fclose(file);
1246
0
        SSH_LOG(SSH_LOG_TRACE, "Out of memory!");
1247
0
        return SSH_ERROR;
1248
0
    }
1249
1250
0
    size = fread(key_buf, 1, sb.st_size, file);
1251
0
    fclose(file);
1252
1253
0
    if (size != sb.st_size) {
1254
0
        SAFE_FREE(key_buf);
1255
0
        SSH_LOG(SSH_LOG_TRACE,
1256
0
                "Error reading %s: %s",
1257
0
                filename,
1258
0
                ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
1259
0
        return SSH_ERROR;
1260
0
    }
1261
0
    key_buf[size] = 0;
1262
1263
0
    rc = ssh_pki_import_privkey_base64(key_buf,
1264
0
                                       passphrase,
1265
0
                                       auth_fn,
1266
0
                                       auth_data,
1267
0
                                       pkey);
1268
1269
0
    SAFE_FREE(key_buf);
1270
0
    return rc;
1271
0
}
1272
1273
/**
1274
 * @brief Export a private key to a file in format specified in the argument
1275
 *
1276
 * @param[in]  privkey  The private key to export.
1277
 *
1278
 * @param[in]  passphrase The passphrase to use to encrypt the key with or
1279
 *             NULL. An empty string means no passphrase.
1280
 *
1281
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
1282
 *
1283
 * @param[in]  auth_data Private data passed to the auth function.
1284
 *
1285
 * @param[in]  filename  The path where to store the pem file.
1286
 *
1287
 * @param[in]  format    The file format (OpenSSH, PEM, or default)
1288
 *
1289
 * @return     SSH_OK on success, SSH_ERROR on error.
1290
 */
1291
1292
int
1293
ssh_pki_export_privkey_file_format(const ssh_key privkey,
1294
                                   const char *passphrase,
1295
                                   ssh_auth_callback auth_fn,
1296
                                   void *auth_data,
1297
                                   const char *filename,
1298
                                   enum ssh_file_format_e format)
1299
0
{
1300
0
    ssh_string blob = NULL;
1301
0
    FILE *fp = NULL;
1302
0
    int rc;
1303
1304
0
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
1305
0
        return SSH_ERROR;
1306
0
    }
1307
1308
0
    fp = fopen(filename, "wb");
1309
0
    if (fp == NULL) {
1310
0
        char err_msg[SSH_ERRNO_MSG_MAX] = {0};
1311
0
        SSH_LOG(SSH_LOG_FUNCTIONS, "Error opening %s: %s",
1312
0
                filename, ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
1313
0
        return SSH_EOF;
1314
0
    }
1315
1316
    /*
1317
     * For historic reasons, the Ed25519 keys are exported in OpenSSH file
1318
     * format by default also when built with OpenSSL.
1319
     *
1320
     * The FIDO2/U2F security keys are an extension to the SSH protocol
1321
     * proposed by OpenSSH, and do not have any representation in PEM format.
1322
     * So, they are always exported in the OpenSSH file format.
1323
     */
1324
0
#ifdef HAVE_LIBCRYPTO
1325
0
    if (format == SSH_FILE_FORMAT_DEFAULT &&
1326
0
        privkey->type != SSH_KEYTYPE_ED25519 &&
1327
0
        !is_sk_key_type(privkey->type)) {
1328
1329
0
        format = SSH_FILE_FORMAT_PEM;
1330
0
    }
1331
0
#endif /* HAVE_LIBCRYPTO */
1332
1333
0
    switch (format) {
1334
0
    case SSH_FILE_FORMAT_PEM:
1335
0
        blob = pki_private_key_to_pem(privkey,
1336
0
                                      passphrase,
1337
0
                                      auth_fn,
1338
0
                                      auth_data);
1339
0
        break;
1340
0
    case SSH_FILE_FORMAT_DEFAULT:
1341
        /* default except (OpenSSL && !ED25519) handled above */
1342
0
    case SSH_FILE_FORMAT_OPENSSH:
1343
0
        blob = ssh_pki_openssh_privkey_export(privkey,
1344
0
                                              passphrase,
1345
0
                                              auth_fn,
1346
0
                                              auth_data);
1347
0
        break;
1348
0
    }
1349
0
    if (blob == NULL) {
1350
0
        fclose(fp);
1351
0
        return -1;
1352
0
    }
1353
1354
0
    rc = fwrite(ssh_string_data(blob), ssh_string_len(blob), 1, fp);
1355
0
    SSH_STRING_FREE(blob);
1356
0
    if (rc != 1 || ferror(fp)) {
1357
0
        fclose(fp);
1358
0
        unlink(filename);
1359
0
        return SSH_ERROR;
1360
0
    }
1361
0
    fclose(fp);
1362
1363
0
    return SSH_OK;
1364
0
}
1365
1366
/**
1367
 * @brief Export a private key to a pem file on disk, or OpenSSH format for
1368
 *        keytype ssh-ed25519
1369
 *
1370
 * @param[in]  privkey  The private key to export.
1371
 *
1372
 * @param[in]  passphrase The passphrase to use to encrypt the key with or
1373
 *             NULL. An empty string means no passphrase.
1374
 *
1375
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
1376
 *
1377
 * @param[in]  auth_data Private data passed to the auth function.
1378
 *
1379
 * @param[in]  filename  The path where to store the pem file.
1380
 *
1381
 * @return     SSH_OK on success, SSH_ERROR on error.
1382
 */
1383
int
1384
ssh_pki_export_privkey_file(const ssh_key privkey,
1385
                            const char *passphrase,
1386
                            ssh_auth_callback auth_fn,
1387
                            void *auth_data,
1388
                            const char *filename)
1389
0
{
1390
0
    return ssh_pki_export_privkey_file_format(privkey,
1391
0
                                              passphrase,
1392
0
                                              auth_fn,
1393
0
                                              auth_data,
1394
0
                                              filename,
1395
0
                                              SSH_FILE_FORMAT_DEFAULT);
1396
0
}
1397
1398
/* temporary function to migrate seamlessly to ssh_key */
1399
ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key)
1400
0
{
1401
0
    ssh_public_key pub = NULL;
1402
0
    ssh_key tmp = NULL;
1403
1404
0
    if (key == NULL) {
1405
0
        return NULL;
1406
0
    }
1407
1408
0
    tmp = ssh_key_dup(key);
1409
0
    if (tmp == NULL) {
1410
0
        return NULL;
1411
0
    }
1412
1413
0
    pub = calloc(1, sizeof(struct ssh_public_key_struct));
1414
0
    if (pub == NULL) {
1415
0
        ssh_key_free(tmp);
1416
0
        return NULL;
1417
0
    }
1418
1419
0
    pub->type = tmp->type;
1420
0
    pub->type_c = tmp->type_c;
1421
1422
#if defined(HAVE_LIBMBEDCRYPTO)
1423
    pub->rsa_pub = tmp->pk;
1424
    tmp->pk = NULL;
1425
#elif defined(HAVE_LIBCRYPTO)
1426
    pub->key_pub = tmp->key;
1427
0
    tmp->key = NULL;
1428
#else
1429
    pub->rsa_pub = tmp->rsa;
1430
    tmp->rsa = NULL;
1431
#endif /* HAVE_LIBCRYPTO */
1432
1433
0
    ssh_key_free(tmp);
1434
1435
0
    return pub;
1436
0
}
1437
1438
ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key)
1439
0
{
1440
0
    ssh_private_key privkey = NULL;
1441
1442
0
    privkey = calloc(1, sizeof(struct ssh_private_key_struct));
1443
0
    if (privkey == NULL) {
1444
0
        ssh_key_free(key);
1445
0
        return NULL;
1446
0
    }
1447
1448
0
    privkey->type = key->type;
1449
#if defined(HAVE_LIBMBEDCRYPTO)
1450
    privkey->rsa_priv = key->pk;
1451
#elif defined(HAVE_LIBCRYPTO)
1452
    privkey->key_priv = key->key;
1453
#else
1454
    privkey->rsa_priv = key->rsa;
1455
#endif /* HAVE_LIBCRYPTO */
1456
1457
0
    return privkey;
1458
0
}
1459
1460
int pki_import_privkey_buffer(enum ssh_keytypes_e type,
1461
                              ssh_buffer buffer,
1462
                              ssh_key *pkey)
1463
0
{
1464
0
    ssh_key key = NULL;
1465
0
    int rc;
1466
1467
0
    key = ssh_key_new();
1468
0
    if (key == NULL) {
1469
0
        return SSH_ERROR;
1470
0
    }
1471
1472
0
    key->type = type;
1473
0
    key->type_c = ssh_key_type_to_char(type);
1474
0
    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
1475
1476
0
    switch (type) {
1477
0
    case SSH_KEYTYPE_RSA: {
1478
0
        ssh_string n = NULL;
1479
0
        ssh_string e = NULL;
1480
0
        ssh_string d = NULL;
1481
0
        ssh_string iqmp = NULL;
1482
0
        ssh_string p = NULL;
1483
0
        ssh_string q = NULL;
1484
1485
0
        rc = ssh_buffer_unpack(buffer, "SSSSSS", &n, &e, &d, &iqmp, &p, &q);
1486
0
        if (rc != SSH_OK) {
1487
0
            SSH_LOG(SSH_LOG_TRACE, "Unpack error");
1488
0
            goto fail;
1489
0
        }
1490
1491
0
        rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
1492
#ifdef DEBUG_CRYPTO
1493
        ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
1494
        ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
1495
        ssh_log_hexdump("d", ssh_string_data(d), ssh_string_len(d));
1496
        ssh_log_hexdump("iqmp", ssh_string_data(iqmp), ssh_string_len(iqmp));
1497
        ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
1498
        ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
1499
#endif /* DEBUG_CRYPTO */
1500
0
        ssh_string_burn(n);
1501
0
        SSH_STRING_FREE(n);
1502
0
        ssh_string_burn(e);
1503
0
        SSH_STRING_FREE(e);
1504
0
        ssh_string_burn(d);
1505
0
        SSH_STRING_FREE(d);
1506
0
        ssh_string_burn(iqmp);
1507
0
        SSH_STRING_FREE(iqmp);
1508
0
        ssh_string_burn(p);
1509
0
        SSH_STRING_FREE(p);
1510
0
        ssh_string_burn(q);
1511
0
        SSH_STRING_FREE(q);
1512
0
        if (rc == SSH_ERROR) {
1513
0
            SSH_LOG(SSH_LOG_TRACE, "Failed to build RSA private key");
1514
0
            goto fail;
1515
0
        }
1516
0
        break;
1517
0
    }
1518
0
#ifdef HAVE_ECC
1519
0
    case SSH_KEYTYPE_ECDSA_P256:
1520
0
    case SSH_KEYTYPE_ECDSA_P384:
1521
0
    case SSH_KEYTYPE_ECDSA_P521: {
1522
0
        ssh_string e = NULL;
1523
0
        ssh_string exp = NULL;
1524
0
        ssh_string i = NULL;
1525
0
        int nid;
1526
1527
0
        rc = ssh_buffer_unpack(buffer, "SSS", &i, &e, &exp);
1528
0
        if (rc != SSH_OK) {
1529
0
            SSH_LOG(SSH_LOG_TRACE, "Unpack error");
1530
0
            goto fail;
1531
0
        }
1532
1533
0
        nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
1534
0
        SSH_STRING_FREE(i);
1535
0
        if (nid == -1) {
1536
0
            ssh_string_burn(e);
1537
0
            SSH_STRING_FREE(e);
1538
0
            ssh_string_burn(exp);
1539
0
            SSH_STRING_FREE(exp);
1540
0
            goto fail;
1541
0
        }
1542
1543
0
        rc = pki_privkey_build_ecdsa(key, nid, e, exp);
1544
0
        ssh_string_burn(e);
1545
0
        SSH_STRING_FREE(e);
1546
0
        ssh_string_burn(exp);
1547
0
        SSH_STRING_FREE(exp);
1548
0
        if (rc < 0) {
1549
0
            SSH_LOG(SSH_LOG_TRACE, "Failed to build ECDSA private key");
1550
0
            goto fail;
1551
0
        }
1552
0
        break;
1553
0
    }
1554
0
    case SSH_KEYTYPE_SK_ECDSA: {
1555
0
        ssh_string type_str = NULL;
1556
0
        ssh_string pubkey = NULL;
1557
0
        int nid;
1558
1559
0
        rc = ssh_buffer_unpack(buffer, "SS", &type_str, &pubkey);
1560
0
        if (rc != SSH_OK) {
1561
0
            goto fail;
1562
0
        }
1563
1564
0
        rc = pki_buffer_unpack_sk_priv_data(buffer, key);
1565
0
        if (rc != SSH_OK) {
1566
0
            SSH_STRING_FREE(type_str);
1567
0
            SSH_STRING_FREE(pubkey);
1568
0
            goto fail;
1569
0
        }
1570
1571
0
        nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(type_str));
1572
0
        SSH_STRING_FREE(type_str);
1573
1574
0
        if (nid == -1) {
1575
0
            SSH_STRING_FREE(pubkey);
1576
0
            goto fail;
1577
0
        }
1578
1579
0
        rc = pki_pubkey_build_ecdsa(key, nid, pubkey);
1580
0
        SSH_STRING_FREE(pubkey);
1581
0
        if (rc != SSH_OK) {
1582
0
            goto fail;
1583
0
        }
1584
0
        break;
1585
0
    }
1586
0
#endif /* HAVE_ECC */
1587
0
    case SSH_KEYTYPE_ED25519: {
1588
0
        ssh_string pubkey = NULL, privkey = NULL;
1589
1590
0
        if (ssh_fips_mode()) {
1591
0
            SSH_LOG(SSH_LOG_TRACE, "Ed25519 keys not supported in FIPS mode");
1592
0
            goto fail;
1593
0
        }
1594
1595
0
        rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey);
1596
0
        if (rc != SSH_OK) {
1597
0
            SSH_LOG(SSH_LOG_TRACE, "Unpack error");
1598
0
            goto fail;
1599
0
        }
1600
1601
0
        rc = pki_privkey_build_ed25519(key, pubkey, privkey);
1602
0
        ssh_string_burn(privkey);
1603
0
        SSH_STRING_FREE(privkey);
1604
0
        SSH_STRING_FREE(pubkey);
1605
0
        if (rc != SSH_OK) {
1606
0
            SSH_LOG(SSH_LOG_TRACE, "Failed to build ed25519 key");
1607
0
            goto fail;
1608
0
        }
1609
0
        break;
1610
0
    }
1611
0
    case SSH_KEYTYPE_SK_ED25519: {
1612
0
        ssh_string pubkey = NULL;
1613
1614
0
        if (ssh_fips_mode()) {
1615
0
            SSH_LOG(SSH_LOG_TRACE, "Ed25519 keys not supported in FIPS mode");
1616
0
            goto fail;
1617
0
        }
1618
1619
0
        rc = ssh_buffer_unpack(buffer, "S", &pubkey);
1620
0
        if (rc != SSH_OK) {
1621
0
            goto fail;
1622
0
        }
1623
1624
0
        rc = pki_buffer_unpack_sk_priv_data(buffer, key);
1625
0
        if (rc != SSH_OK) {
1626
0
            SSH_STRING_FREE(pubkey);
1627
0
            goto fail;
1628
0
        }
1629
1630
0
        rc = pki_pubkey_build_ed25519(key, pubkey);
1631
0
        SSH_STRING_FREE(pubkey);
1632
0
        if (rc != SSH_OK) {
1633
0
            goto fail;
1634
0
        }
1635
0
        break;
1636
0
    }
1637
0
    case SSH_KEYTYPE_RSA_CERT01:
1638
0
    case SSH_KEYTYPE_ECDSA_P256_CERT01:
1639
0
    case SSH_KEYTYPE_ECDSA_P384_CERT01:
1640
0
    case SSH_KEYTYPE_ECDSA_P521_CERT01:
1641
0
    case SSH_KEYTYPE_ED25519_CERT01:
1642
0
    case SSH_KEYTYPE_SK_ECDSA_CERT01:
1643
0
    case SSH_KEYTYPE_SK_ED25519_CERT01:
1644
0
    case SSH_KEYTYPE_RSA1:
1645
0
    case SSH_KEYTYPE_UNKNOWN:
1646
0
    default:
1647
0
        SSH_LOG(SSH_LOG_TRACE, "Unknown private key type (%d)", type);
1648
0
        goto fail;
1649
0
    }
1650
1651
0
    *pkey = key;
1652
0
    return SSH_OK;
1653
0
fail:
1654
0
    ssh_key_free(key);
1655
1656
0
    return SSH_ERROR;
1657
0
}
1658
1659
static int pki_import_pubkey_buffer(ssh_buffer buffer,
1660
                                    enum ssh_keytypes_e type,
1661
                                    ssh_key *pkey)
1662
37
{
1663
37
    ssh_key key = NULL;
1664
37
    int rc;
1665
1666
37
    key = ssh_key_new();
1667
37
    if (key == NULL) {
1668
0
        return SSH_ERROR;
1669
0
    }
1670
1671
37
    key->type = type;
1672
37
    key->type_c = ssh_key_type_to_char(type);
1673
37
    key->flags = SSH_KEY_FLAG_PUBLIC;
1674
1675
37
    switch (type) {
1676
35
        case SSH_KEYTYPE_RSA:
1677
35
            {
1678
35
                ssh_string e = NULL;
1679
35
                ssh_string n = NULL;
1680
1681
35
                rc = ssh_buffer_unpack(buffer, "SS", &e, &n);
1682
35
                if (rc != SSH_OK) {
1683
1
                    SSH_LOG(SSH_LOG_TRACE, "Unpack error");
1684
1
                    goto fail;
1685
1
                }
1686
1687
34
                rc = pki_pubkey_build_rsa(key, e, n);
1688
#ifdef DEBUG_CRYPTO
1689
                ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
1690
                ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
1691
#endif /* DEBUG_CRYPTO */
1692
34
                ssh_string_burn(e);
1693
34
                SSH_STRING_FREE(e);
1694
34
                ssh_string_burn(n);
1695
34
                SSH_STRING_FREE(n);
1696
34
                if (rc == SSH_ERROR) {
1697
0
                    SSH_LOG(SSH_LOG_TRACE, "Failed to build RSA public key");
1698
0
                    goto fail;
1699
0
                }
1700
34
            }
1701
34
            break;
1702
34
#ifdef HAVE_ECC
1703
34
        case SSH_KEYTYPE_ECDSA: /* deprecated */
1704
1
        case SSH_KEYTYPE_ECDSA_P256:
1705
1
        case SSH_KEYTYPE_ECDSA_P384:
1706
1
        case SSH_KEYTYPE_ECDSA_P521:
1707
2
        case SSH_KEYTYPE_SK_ECDSA:
1708
2
            {
1709
2
                ssh_string e = NULL;
1710
2
                ssh_string i = NULL;
1711
2
                int nid;
1712
1713
2
                rc = ssh_buffer_unpack(buffer, "SS", &i, &e);
1714
2
                if (rc != SSH_OK) {
1715
2
                    SSH_LOG(SSH_LOG_TRACE, "Unpack error");
1716
2
                    goto fail;
1717
2
                }
1718
1719
0
                nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
1720
0
                SSH_STRING_FREE(i);
1721
0
                if (nid == -1) {
1722
0
                    ssh_string_burn(e);
1723
0
                    SSH_STRING_FREE(e);
1724
0
                    goto fail;
1725
0
                }
1726
1727
0
                rc = pki_pubkey_build_ecdsa(key, nid, e);
1728
0
                ssh_string_burn(e);
1729
0
                SSH_STRING_FREE(e);
1730
0
                if (rc < 0) {
1731
0
                    SSH_LOG(SSH_LOG_TRACE, "Failed to build ECDSA public key");
1732
0
                    goto fail;
1733
0
                }
1734
1735
                /* Unpack SK specific parameters */
1736
0
                if (type == SSH_KEYTYPE_SK_ECDSA) {
1737
0
                    ssh_string application = ssh_buffer_get_ssh_string(buffer);
1738
0
                    if (application == NULL) {
1739
0
                        SSH_LOG(SSH_LOG_TRACE, "SK Unpack error");
1740
0
                        goto fail;
1741
0
                    }
1742
0
                    key->sk_application = application;
1743
0
                    key->type_c = ssh_key_type_to_char(key->type);
1744
0
                }
1745
0
            }
1746
0
            break;
1747
0
#endif /* HAVE_ECC */
1748
0
        case SSH_KEYTYPE_ED25519:
1749
0
        case SSH_KEYTYPE_SK_ED25519:
1750
0
        {
1751
0
            ssh_string pubkey = ssh_buffer_get_ssh_string(buffer);
1752
1753
0
            if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
1754
0
                SSH_LOG(SSH_LOG_TRACE, "Invalid public key length");
1755
0
                ssh_string_burn(pubkey);
1756
0
                SSH_STRING_FREE(pubkey);
1757
0
                goto fail;
1758
0
            }
1759
1760
0
            rc = pki_pubkey_build_ed25519(key, pubkey);
1761
0
            ssh_string_burn(pubkey);
1762
0
            SSH_STRING_FREE(pubkey);
1763
0
            if (rc < 0) {
1764
0
                SSH_LOG(SSH_LOG_TRACE, "Failed to build ED25519 public key");
1765
0
                goto fail;
1766
0
            }
1767
1768
0
            if (type == SSH_KEYTYPE_SK_ED25519) {
1769
0
                ssh_string application = ssh_buffer_get_ssh_string(buffer);
1770
0
                if (application == NULL) {
1771
0
                    SSH_LOG(SSH_LOG_TRACE, "SK Unpack error");
1772
0
                    goto fail;
1773
0
                }
1774
0
                key->sk_application = application;
1775
0
            }
1776
0
        }
1777
0
        break;
1778
0
        case SSH_KEYTYPE_RSA_CERT01:
1779
0
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
1780
0
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
1781
0
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
1782
0
        case SSH_KEYTYPE_SK_ECDSA_CERT01:
1783
0
        case SSH_KEYTYPE_ED25519_CERT01:
1784
0
        case SSH_KEYTYPE_SK_ED25519_CERT01:
1785
0
        case SSH_KEYTYPE_RSA1:
1786
0
        case SSH_KEYTYPE_UNKNOWN:
1787
0
        default:
1788
0
            SSH_LOG(SSH_LOG_TRACE, "Unknown public key type %d", type);
1789
0
            goto fail;
1790
37
    }
1791
1792
34
    *pkey = key;
1793
34
    return SSH_OK;
1794
3
fail:
1795
3
    ssh_key_free(key);
1796
1797
3
    return SSH_ERROR;
1798
37
}
1799
1800
static int pki_import_cert_buffer(ssh_buffer buffer,
1801
                                  enum ssh_keytypes_e type,
1802
                                  ssh_key *pkey)
1803
2
{
1804
2
    ssh_buffer cert = NULL;
1805
2
    ssh_string tmp_s = NULL;
1806
2
    const char *type_c = NULL;
1807
2
    ssh_key key = NULL;
1808
2
    int rc;
1809
1810
    /*
1811
     * The cert blob starts with the key type as an ssh_string, but this
1812
     * string has been read out of the buffer to identify the key type.
1813
     * Simply add it again as first element before copying the rest.
1814
     */
1815
2
    cert = ssh_buffer_new();
1816
2
    if (cert == NULL) {
1817
0
        goto fail;
1818
0
    }
1819
2
    type_c = ssh_key_type_to_char(type);
1820
2
    tmp_s = ssh_string_from_char(type_c);
1821
2
    if (tmp_s == NULL) {
1822
0
        goto fail;
1823
0
    }
1824
2
    rc = ssh_buffer_add_ssh_string(cert, tmp_s);
1825
2
    SSH_STRING_FREE(tmp_s);
1826
2
    if (rc != 0) {
1827
0
        goto fail;
1828
0
    }
1829
2
    rc = ssh_buffer_add_buffer(cert, buffer);
1830
2
    if (rc != 0) {
1831
0
        goto fail;
1832
0
    }
1833
1834
    /*
1835
     * After the key type, comes an ssh_string nonce. Just after this comes the
1836
     * cert public key, which can be parsed out of the buffer.
1837
     */
1838
2
    tmp_s = ssh_buffer_get_ssh_string(buffer);
1839
2
    if (tmp_s == NULL) {
1840
1
        goto fail;
1841
1
    }
1842
1
    SSH_STRING_FREE(tmp_s);
1843
1844
1
    switch (type) {
1845
0
        case SSH_KEYTYPE_RSA_CERT01:
1846
0
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_RSA, &key);
1847
0
            break;
1848
0
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
1849
0
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ECDSA_P256, &key);
1850
0
            break;
1851
0
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
1852
0
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ECDSA_P384, &key);
1853
0
            break;
1854
0
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
1855
0
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ECDSA_P521, &key);
1856
0
            break;
1857
0
        case SSH_KEYTYPE_ED25519_CERT01:
1858
0
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ED25519, &key);
1859
0
            break;
1860
1
        case SSH_KEYTYPE_SK_ECDSA_CERT01:
1861
1
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_SK_ECDSA, &key);
1862
1
            break;
1863
0
        case SSH_KEYTYPE_SK_ED25519_CERT01:
1864
0
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_SK_ED25519, &key);
1865
0
            break;
1866
0
        default:
1867
0
            key = ssh_key_new();
1868
1
    }
1869
1
    if (rc != 0 || key == NULL) {
1870
1
        goto fail;
1871
1
    }
1872
1873
0
    key->type = type;
1874
0
    key->type_c = type_c;
1875
0
    key->cert = cert;
1876
1877
0
    *pkey = key;
1878
0
    return SSH_OK;
1879
1880
2
fail:
1881
2
    ssh_key_free(key);
1882
2
    SSH_BUFFER_FREE(cert);
1883
2
    return SSH_ERROR;
1884
1
}
1885
1886
/**
1887
 * @brief Import a base64 formatted public key from a memory c-string.
1888
 *
1889
 * Note that the public key is just the base64 part (without the key
1890
 * type prefix and comment suffix you can find in the OpenSSH public
1891
 * key file or known_hosts file).
1892
 *
1893
 * @param[in]  b64_key  The base64 key to import.
1894
 * @param[in]  type     The type of the key to import.
1895
 * @param[out] pkey     A pointer where the allocated key can be stored. You
1896
 *                      need to free the memory using ssh_key_free().
1897
 *
1898
 * @return              `SSH_OK` on success, `SSH_ERROR` on error.
1899
 *
1900
 * @see ssh_key_free()
1901
 */
1902
int ssh_pki_import_pubkey_base64(const char *b64_key,
1903
                                 enum ssh_keytypes_e type,
1904
                                 ssh_key *pkey)
1905
0
{
1906
0
    ssh_buffer buffer = NULL;
1907
0
    ssh_string type_s = NULL;
1908
0
    int rc;
1909
1910
0
    if (b64_key == NULL || pkey == NULL) {
1911
0
        return SSH_ERROR;
1912
0
    }
1913
1914
0
    buffer = base64_to_bin(b64_key);
1915
0
    if (buffer == NULL) {
1916
0
        return SSH_ERROR;
1917
0
    }
1918
1919
0
    type_s = ssh_buffer_get_ssh_string(buffer);
1920
0
    if (type_s == NULL) {
1921
0
        SSH_BUFFER_FREE(buffer);
1922
0
        return SSH_ERROR;
1923
0
    }
1924
0
    SSH_STRING_FREE(type_s);
1925
1926
0
    if (is_cert_type(type)) {
1927
0
        rc = pki_import_cert_buffer(buffer, type, pkey);
1928
0
    } else {
1929
0
        rc = pki_import_pubkey_buffer(buffer, type, pkey);
1930
0
    }
1931
0
    SSH_BUFFER_FREE(buffer);
1932
1933
0
    return rc;
1934
0
}
1935
1936
/**
1937
 * @internal
1938
 *
1939
 * @brief Import a public key from a ssh string.
1940
 *
1941
 * @param[in]  key_blob The key blob to import as specified in RFC 4253 section
1942
 *                      6.6 "Public Key Algorithms".
1943
 *
1944
 * @param[out] pkey     A pointer where the allocated key can be stored. You
1945
 *                      need to free the memory using ssh_key_free().
1946
 *
1947
 * @return              SSH_OK on success, SSH_ERROR on error.
1948
 *
1949
 * @see ssh_key_free()
1950
 */
1951
int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
1952
                               ssh_key *pkey)
1953
92
{
1954
92
    ssh_buffer buffer = NULL;
1955
92
    ssh_string type_s = NULL;
1956
92
    enum ssh_keytypes_e type;
1957
92
    int rc;
1958
1959
92
    if (key_blob == NULL || pkey == NULL) {
1960
0
        return SSH_ERROR;
1961
0
    }
1962
1963
92
    buffer = ssh_buffer_new();
1964
92
    if (buffer == NULL) {
1965
0
        SSH_LOG(SSH_LOG_TRACE, "Out of memory!");
1966
0
        return SSH_ERROR;
1967
0
    }
1968
1969
92
    rc = ssh_buffer_add_data(buffer,
1970
92
                             ssh_string_data(key_blob),
1971
92
                             (uint32_t)ssh_string_len(key_blob));
1972
92
    if (rc < 0) {
1973
0
        SSH_LOG(SSH_LOG_TRACE, "Out of memory!");
1974
0
        goto fail;
1975
0
    }
1976
1977
92
    type_s = ssh_buffer_get_ssh_string(buffer);
1978
92
    if (type_s == NULL) {
1979
1
        SSH_LOG(SSH_LOG_TRACE, "Out of memory!");
1980
1
        goto fail;
1981
1
    }
1982
1983
91
    type = ssh_key_type_from_name(ssh_string_get_char(type_s));
1984
91
    if (type == SSH_KEYTYPE_UNKNOWN) {
1985
53
        SSH_LOG(SSH_LOG_TRACE, "Unknown key type found!");
1986
53
        goto fail;
1987
53
    }
1988
38
    SSH_STRING_FREE(type_s);
1989
1990
38
    if (is_cert_type(type)) {
1991
2
        rc = pki_import_cert_buffer(buffer, type, pkey);
1992
36
    } else {
1993
36
        rc = pki_import_pubkey_buffer(buffer, type, pkey);
1994
36
    }
1995
1996
38
    SSH_BUFFER_FREE(buffer);
1997
1998
38
    return rc;
1999
54
fail:
2000
54
    SSH_BUFFER_FREE(buffer);
2001
54
    SSH_STRING_FREE(type_s);
2002
2003
54
    return SSH_ERROR;
2004
91
}
2005
2006
#ifdef WITH_PKCS11_URI
2007
/**
2008
 *@brief Detect if the pathname in cmp is a PKCS #11 URI.
2009
 *
2010
 * @param[in] cmp The path to the public/private key
2011
 *                     or a private/public PKCS #11 URI.
2012
 *
2013
 * @returns true if filename is a URI starting with "pkcs11:"
2014
 *          false otherwise.
2015
 */
2016
bool ssh_pki_is_uri(const char *cmp)
2017
{
2018
    int rc;
2019
2020
    rc = strncmp(cmp, PKCS11_URI, strlen(PKCS11_URI));
2021
    if (rc == 0) {
2022
        return true;
2023
    }
2024
2025
    return false;
2026
}
2027
2028
/**
2029
 *@brief export a Public PKCS #11 URI from a Private PKCS #11 URI
2030
 *       by replacing "type=private" to "type=public".
2031
 *       TODO: Improve the parser
2032
 *
2033
 * @param[in] priv_uri Private PKCS #11 URI.
2034
 *
2035
 * @returns pointer to the public PKCS #11 URI. You need to free
2036
 *          the memory using ssh_string_free_char().
2037
 *
2038
 * @see ssh_string_free_char().
2039
 */
2040
char *ssh_pki_export_pub_uri_from_priv_uri(const char *priv_uri)
2041
{
2042
    char *pub_uri_temp = NULL;
2043
2044
    pub_uri_temp = ssh_strreplace(priv_uri,
2045
                                  "type=private",
2046
                                  "type=public");
2047
2048
    return pub_uri_temp;
2049
}
2050
#endif /* WITH_PKCS11_URI */
2051
2052
/**
2053
 * @brief Import a public key from a file or a PKCS #11 device.
2054
 *
2055
 * @param[in]  filename The filename of the public key or the
2056
 *                      PKCS #11 URI corresponding to the public key.
2057
 *
2058
 * @param[out] pkey     A pointer to store the allocated public key. You need to
2059
 *                      free the memory using ssh_key_free().
2060
 *
2061
 * @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
2062
 *          denied, SSH_ERROR otherwise.
2063
 *
2064
 * @see ssh_key_free()
2065
 */
2066
int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
2067
0
{
2068
0
    enum ssh_keytypes_e type;
2069
0
    struct stat sb;
2070
0
    char *key_buf = NULL, *p = NULL;
2071
0
    size_t buflen, i;
2072
0
    const char *q = NULL;
2073
0
    FILE *file = NULL;
2074
0
    off_t size;
2075
0
    int rc, cmp;
2076
0
    char err_msg[SSH_ERRNO_MSG_MAX] = {0};
2077
0
    ssh_key priv_key = NULL;
2078
2079
0
    if (pkey == NULL || filename == NULL || *filename == '\0') {
2080
0
        return SSH_ERROR;
2081
0
    }
2082
2083
#ifdef WITH_PKCS11_URI
2084
    if (ssh_pki_is_uri(filename)) {
2085
        rc = pki_uri_import(filename, pkey, SSH_KEY_PUBLIC);
2086
        return rc;
2087
    }
2088
#endif /* WITH_PKCS11_URI */
2089
2090
0
    file = fopen(filename, "rb");
2091
0
    if (file == NULL) {
2092
0
        SSH_LOG(SSH_LOG_TRACE, "Error opening %s: %s",
2093
0
                    filename, ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
2094
0
        return SSH_EOF;
2095
0
    }
2096
2097
0
    rc = fstat(fileno(file), &sb);
2098
0
    if (rc < 0) {
2099
0
        fclose(file);
2100
0
        SSH_LOG(SSH_LOG_TRACE, "Error gettint stat of %s: %s",
2101
0
                    filename, ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
2102
0
        switch (errno) {
2103
0
            case ENOENT:
2104
0
            case EACCES:
2105
0
                return SSH_EOF;
2106
0
        }
2107
0
        return SSH_ERROR;
2108
0
    }
2109
2110
0
    if (sb.st_size > MAX_PUBKEY_SIZE) {
2111
0
        fclose(file);
2112
0
        return SSH_ERROR;
2113
0
    }
2114
2115
0
    key_buf = malloc(sb.st_size + 1);
2116
0
    if (key_buf == NULL) {
2117
0
        fclose(file);
2118
0
        SSH_LOG(SSH_LOG_TRACE, "Out of memory!");
2119
0
        return SSH_ERROR;
2120
0
    }
2121
2122
0
    size = fread(key_buf, 1, sb.st_size, file);
2123
0
    fclose(file);
2124
2125
0
    if (size != sb.st_size) {
2126
0
        SAFE_FREE(key_buf);
2127
0
        SSH_LOG(SSH_LOG_TRACE, "Error reading %s: %s",
2128
0
                filename, ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
2129
0
        return SSH_ERROR;
2130
0
    }
2131
0
    key_buf[size] = '\0';
2132
0
    buflen = strlen(key_buf);
2133
2134
    /* Test for new OpenSSH key format first */
2135
0
    cmp = strncmp(key_buf, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
2136
0
    if (cmp == 0) {
2137
0
        *pkey = ssh_pki_openssh_pubkey_import(key_buf);
2138
0
        SAFE_FREE(key_buf);
2139
0
        if (*pkey == NULL) {
2140
0
            SSH_LOG(SSH_LOG_TRACE, "Failed to import public key from OpenSSH"
2141
0
                                  " private key file");
2142
0
            return SSH_ERROR;
2143
0
        }
2144
0
        return SSH_OK;
2145
0
    }
2146
2147
    /*
2148
     * Try to parse key as PEM. Set empty passphrase, so user won't be prompted
2149
     * for passphrase. Don't try to decrypt encrypted private key.
2150
     */
2151
0
    priv_key = pki_private_key_from_base64(key_buf, "", NULL, NULL);
2152
0
    if (priv_key) {
2153
0
        rc = ssh_pki_export_privkey_to_pubkey(priv_key, pkey);
2154
0
        ssh_key_free(priv_key);
2155
0
        SAFE_FREE(key_buf);
2156
0
        if (rc != SSH_OK) {
2157
0
            SSH_LOG(SSH_LOG_WARN, "Failed to import public key from PEM"
2158
0
                                  " private key file");
2159
0
            return SSH_ERROR;
2160
0
        }
2161
0
        return SSH_OK;
2162
0
    }
2163
2164
    /* This the old one-line public key format */
2165
0
    q = p = key_buf;
2166
0
    for (i = 0; i < buflen; i++) {
2167
0
        if (isspace((int)p[i])) {
2168
0
            p[i] = '\0';
2169
0
            break;
2170
0
        }
2171
0
    }
2172
2173
0
    type = ssh_key_type_from_name(q);
2174
0
    if (type == SSH_KEYTYPE_UNKNOWN) {
2175
0
        SAFE_FREE(key_buf);
2176
0
        return SSH_ERROR;
2177
0
    }
2178
2179
0
    if (i >= buflen) {
2180
0
        SAFE_FREE(key_buf);
2181
0
        return SSH_ERROR;
2182
0
    }
2183
0
    q = &p[i + 1];
2184
0
    for (; i < buflen; i++) {
2185
0
        if (isspace((int)p[i])) {
2186
0
            p[i] = '\0';
2187
0
            break;
2188
0
        }
2189
0
    }
2190
2191
0
    rc = ssh_pki_import_pubkey_base64(q, type, pkey);
2192
0
    SAFE_FREE(key_buf);
2193
2194
0
    return rc;
2195
0
}
2196
2197
/**
2198
 * @brief Import a base64 formatted certificate from a memory c-string.
2199
 *
2200
 * Note that the certificate is just the base64 part (without the key
2201
 * type prefix and comment suffix you can find in the OpenSSH certificate
2202
 * file).
2203
 *
2204
 * @param[in]  b64_cert  The base64 cert to import.
2205
 * @param[in]  type     The type of the cert to import.
2206
 * @param[out] pkey     A pointer where the allocated certificate can be stored.
2207
 *                      You need to free the memory using ssh_key_free().
2208
 *
2209
 * @return              `SSH_OK` on success, `SSH_ERROR` on error.
2210
 *
2211
 * @see ssh_key_free()
2212
 */
2213
int ssh_pki_import_cert_base64(const char *b64_cert,
2214
                               enum ssh_keytypes_e type,
2215
                               ssh_key *pkey)
2216
0
{
2217
0
    return ssh_pki_import_pubkey_base64(b64_cert, type, pkey);
2218
0
}
2219
2220
/**
2221
 * @internal
2222
 *
2223
 * @brief Import a certificate from a ssh string.
2224
 *
2225
 * @param[in]  cert_blob The cert blob to import as specified in RFC 4253 section
2226
 *                      6.6 "Public Key Algorithms".
2227
 *
2228
 * @param[out] pkey     A pointer where the allocated key can be stored. You
2229
 *                      need to free the memory using ssh_key_free().
2230
 *
2231
 * @return              SSH_OK on success, SSH_ERROR on error.
2232
 *
2233
 * @see ssh_key_free()
2234
 */
2235
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
2236
                             ssh_key *pkey)
2237
0
{
2238
0
    return ssh_pki_import_pubkey_blob(cert_blob, pkey);
2239
0
}
2240
2241
/**
2242
 * @brief Import a certificate from the given filename.
2243
 *
2244
 * @param[in]  filename The path to the certificate.
2245
 *
2246
 * @param[out] pkey     A pointer to store the allocated certificate. You need to
2247
 *                      free the memory using ssh_key_free().
2248
 *
2249
 * @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
2250
 *          denied, SSH_ERROR otherwise.
2251
 *
2252
 * @see ssh_key_free()
2253
 */
2254
int ssh_pki_import_cert_file(const char *filename, ssh_key *pkey)
2255
0
{
2256
0
    int rc;
2257
2258
0
    rc = ssh_pki_import_pubkey_file(filename, pkey);
2259
0
    if (rc == SSH_OK) {
2260
        /* check the key is a cert type. */
2261
0
        if (!is_cert_type((*pkey)->type)) {
2262
0
            SSH_KEY_FREE(*pkey);
2263
0
            return SSH_ERROR;
2264
0
        }
2265
0
    }
2266
2267
0
    return rc;
2268
0
}
2269
2270
/**
2271
 * @internal
2272
 *
2273
 * @brief Internal function to generate a key pair.
2274
 *
2275
 * @param[in] type      Type of key to create
2276
 *
2277
 * @param[in] parameter Parameter to the creation of key:
2278
 *                      rsa : length of the key in bits (e.g. 1024, 2048, 4096)
2279
 *                      If parameter is 0, then the default size will be used.
2280
 * @param[out] pkey     A pointer to store the allocated private key. You need
2281
 *                      to free the memory using ssh_key_free().
2282
 *
2283
 * @return              SSH_OK on success, SSH_ERROR on error.
2284
 */
2285
static int pki_generate_key_internal(enum ssh_keytypes_e type,
2286
                                     int parameter,
2287
                                     ssh_key *pkey)
2288
0
{
2289
0
    int rc;
2290
0
    ssh_key key = NULL;
2291
2292
0
    if (pkey == NULL) {
2293
0
        return SSH_ERROR;
2294
0
    }
2295
2296
0
    key = ssh_key_new();
2297
0
    if (key == NULL) {
2298
0
        return SSH_ERROR;
2299
0
    }
2300
2301
0
    key->type = type;
2302
0
    key->type_c = ssh_key_type_to_char(type);
2303
0
    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
2304
2305
0
    switch(type){
2306
0
        case SSH_KEYTYPE_RSA:
2307
0
            if (parameter != 0 && parameter < RSA_MIN_KEY_SIZE) {
2308
0
                SSH_LOG(
2309
0
                    SSH_LOG_WARN,
2310
0
                    "RSA key size parameter (%d) is below minimum allowed (%d)",
2311
0
                    parameter,
2312
0
                    RSA_MIN_KEY_SIZE);
2313
0
                goto error;
2314
0
            }
2315
2316
0
            rc = pki_key_generate_rsa(key, parameter);
2317
0
            if(rc == SSH_ERROR)
2318
0
                goto error;
2319
0
            break;
2320
0
#ifdef HAVE_ECC
2321
0
        case SSH_KEYTYPE_ECDSA: /* deprecated */
2322
0
            rc = pki_key_generate_ecdsa(key, parameter);
2323
0
            if (rc == SSH_ERROR) {
2324
0
                goto error;
2325
0
            }
2326
2327
            /* Update key type */
2328
0
            key->type_c = ssh_pki_key_ecdsa_name(key);
2329
0
            break;
2330
0
        case SSH_KEYTYPE_ECDSA_P256:
2331
0
            rc = pki_key_generate_ecdsa(key, 256);
2332
0
            if (rc == SSH_ERROR) {
2333
0
                goto error;
2334
0
            }
2335
0
            break;
2336
0
        case SSH_KEYTYPE_ECDSA_P384:
2337
0
            rc = pki_key_generate_ecdsa(key, 384);
2338
0
            if (rc == SSH_ERROR) {
2339
0
                goto error;
2340
0
            }
2341
0
            break;
2342
0
        case SSH_KEYTYPE_ECDSA_P521:
2343
0
            rc = pki_key_generate_ecdsa(key, 521);
2344
0
            if (rc == SSH_ERROR) {
2345
0
                goto error;
2346
0
            }
2347
0
            break;
2348
0
#endif /* HAVE_ECC */
2349
0
        case SSH_KEYTYPE_ED25519:
2350
0
            rc = pki_key_generate_ed25519(key);
2351
0
            if (rc == SSH_ERROR) {
2352
0
                goto error;
2353
0
            }
2354
0
            break;
2355
0
        case SSH_KEYTYPE_RSA_CERT01:
2356
0
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
2357
0
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
2358
0
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
2359
0
        case SSH_KEYTYPE_ED25519_CERT01:
2360
0
        case SSH_KEYTYPE_SK_ECDSA:
2361
0
        case SSH_KEYTYPE_SK_ECDSA_CERT01:
2362
0
        case SSH_KEYTYPE_SK_ED25519:
2363
0
        case SSH_KEYTYPE_SK_ED25519_CERT01:
2364
0
        case SSH_KEYTYPE_RSA1:
2365
0
        case SSH_KEYTYPE_UNKNOWN:
2366
0
        default:
2367
0
            goto error;
2368
0
    }
2369
2370
0
    *pkey = key;
2371
0
    return SSH_OK;
2372
0
error:
2373
0
    ssh_key_free(key);
2374
0
    return SSH_ERROR;
2375
0
}
2376
2377
/**
2378
 * @brief Generates a key pair.
2379
 *
2380
 * @param[in] type      Type of key to create
2381
 *
2382
 * @param[in] parameter Parameter to the creation of key:
2383
 *                      rsa : length of the key in bits (e.g. 1024, 2048, 4096)
2384
 *                      If parameter is 0, then the default size will be used.
2385
 * @param[out] pkey     A pointer to store the allocated private key. You need
2386
 *                      to free the memory using ssh_key_free().
2387
 *
2388
 * @return              SSH_OK on success, SSH_ERROR on error.
2389
 *
2390
 * @warning             Generating a key pair may take some time.
2391
 *
2392
 * @see ssh_key_free()
2393
 */
2394
int ssh_pki_generate(enum ssh_keytypes_e type, int parameter, ssh_key *pkey)
2395
0
{
2396
0
    return pki_generate_key_internal(type, parameter, pkey);
2397
0
}
2398
2399
/**
2400
 * @brief Generates a key pair.
2401
 *
2402
 * @param[in] type        Type of key to create
2403
 *
2404
 * @param[in] pki_context PKI context containing various configuration
2405
 *                        parameters and sub-contexts. Can be NULL for
2406
 *                        standard SSH key types (RSA, ECDSA, ED25519) where
2407
 *                        defaults will be used. Can also be NULL for security
2408
 *                        key types (SK_*), in which case default callbacks and
2409
 *                        settings will be used automatically.
2410
 *
2411
 * @param[out] pkey       A pointer to store the allocated private key. You need
2412
 *                        to free the memory using ssh_key_free().
2413
 *
2414
 * @return              SSH_OK on success, SSH_ERROR on error.
2415
 *
2416
 * @see ssh_pki_ctx_new()
2417
 * @see ssh_key_free()
2418
 */
2419
int ssh_pki_generate_key(enum ssh_keytypes_e type,
2420
                         ssh_pki_ctx pki_context,
2421
                         ssh_key *pkey)
2422
0
{
2423
2424
    /* Handle Security Key types with the specialized function */
2425
0
    if (is_sk_key_type(type)) {
2426
#ifdef WITH_FIDO2
2427
        ssh_pki_ctx temp_ctx = NULL;
2428
        ssh_pki_ctx ctx_to_use = pki_context;
2429
        int rc;
2430
2431
        /* If no context provided, create a temporary default one */
2432
        if (pki_context == NULL) {
2433
            SSH_LOG(SSH_LOG_INFO,
2434
                    "No PKI context provided, using the default one");
2435
2436
            temp_ctx = ssh_pki_ctx_new();
2437
            if (temp_ctx == NULL) {
2438
                SSH_LOG(SSH_LOG_WARN, "Failed to create temporary PKI context");
2439
                return SSH_ERROR;
2440
            }
2441
            ctx_to_use = temp_ctx;
2442
        }
2443
2444
        /* Verify that we have valid SK callbacks */
2445
        if (ctx_to_use->sk_callbacks == NULL) {
2446
            SSH_LOG(SSH_LOG_WARN, "Missing SK callbacks in PKI context");
2447
            if (temp_ctx != NULL) {
2448
                SSH_PKI_CTX_FREE(temp_ctx);
2449
            }
2450
            return SSH_ERROR;
2451
        }
2452
2453
        rc = pki_sk_enroll_key(ctx_to_use, type, pkey);
2454
2455
        /* Clean up temporary context if we created one */
2456
        if (temp_ctx != NULL) {
2457
            SSH_PKI_CTX_FREE(temp_ctx);
2458
        }
2459
2460
        return rc;
2461
#else  /* WITH_FIDO2 */
2462
0
        SSH_LOG(SSH_LOG_WARN, SK_NOT_SUPPORTED_MSG);
2463
0
        return SSH_ERROR;
2464
0
#endif /* WITH_FIDO2 */
2465
0
    } else {
2466
0
        int parameter = 0;
2467
2468
0
        if (type == SSH_KEYTYPE_RSA && pki_context != NULL) {
2469
0
            parameter = pki_context->rsa_key_size;
2470
0
        }
2471
2472
0
        return pki_generate_key_internal(type, parameter, pkey);
2473
0
    }
2474
0
}
2475
2476
/**
2477
 * @brief Create a public key from a private key.
2478
 *
2479
 * @param[in]  privkey  The private key to get the public key from.
2480
 *
2481
 * @param[out] pkey     A pointer to store the newly allocated public key. You
2482
 *                      NEED to free the key using ssh_key_free().
2483
 *
2484
 * @return              SSH_OK on success, SSH_ERROR on error.
2485
 *
2486
 * @see ssh_key_free()
2487
 */
2488
int ssh_pki_export_privkey_to_pubkey(const ssh_key privkey,
2489
                                     ssh_key *pkey)
2490
0
{
2491
0
    ssh_key pubkey = NULL;
2492
2493
0
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
2494
0
        return SSH_ERROR;
2495
0
    }
2496
2497
0
    pubkey = pki_key_dup(privkey, 1);
2498
0
    if (pubkey == NULL) {
2499
0
        return SSH_ERROR;
2500
0
    }
2501
2502
0
    *pkey = pubkey;
2503
0
    return SSH_OK;
2504
0
}
2505
2506
/**
2507
 * @internal
2508
 *
2509
 * @brief Pack security key private data into a buffer.
2510
 *
2511
 * This function packs the common security key fields (application, flags,
2512
 * key handle, and reserved data) into a buffer.
2513
 * This is used for both ECDSA and Ed25519 security keys when exporting
2514
 * private key data.
2515
 *
2516
 * @param[in] buffer    The buffer to pack the security key data into.
2517
 *
2518
 * @param[in] key       The security key containing the data to pack.
2519
 *                      Must be a security key type (SK_ECDSA or SK_ED25519).
2520
 *
2521
 * @return              SSH_OK on success, SSH_ERROR on error.
2522
 *
2523
 * @see ssh_buffer_pack()
2524
 */
2525
int pki_buffer_pack_sk_priv_data(ssh_buffer buffer, ssh_key key)
2526
0
{
2527
0
    return ssh_buffer_pack(buffer,
2528
0
                           "SbSS",
2529
0
                           key->sk_application,
2530
0
                           key->sk_flags,
2531
0
                           key->sk_key_handle,
2532
0
                           key->sk_reserved);
2533
0
}
2534
2535
/**
2536
 * @internal
2537
 *
2538
 * @brief Unpack security key private data from a buffer.
2539
 *
2540
 * This function unpacks the common security key fields (application, flags,
2541
 * key handle, and reserved data) from a buffer.
2542
 * This is used for both ECDSA and Ed25519 security keys when importing
2543
 * private key data.
2544
 *
2545
 * @param[in] buffer    The buffer to unpack the security key data from.
2546
 *
2547
 * @param[in] key       The security key to store the unpacked data into.
2548
 *                      Must be a security key type (SK_ECDSA or SK_ED25519).
2549
 *
2550
 * @return              SSH_OK on success, SSH_ERROR on error.
2551
 *
2552
 * @see ssh_buffer_unpack()
2553
 */
2554
int pki_buffer_unpack_sk_priv_data(ssh_buffer buffer, ssh_key key)
2555
0
{
2556
0
    return ssh_buffer_unpack(buffer,
2557
0
                             "SbSS",
2558
0
                             &key->sk_application,
2559
0
                             &key->sk_flags,
2560
0
                             &key->sk_key_handle,
2561
0
                             &key->sk_reserved);
2562
0
}
2563
2564
/**
2565
 * @internal
2566
 *
2567
 * @brief Create a key_blob from a public key.
2568
 *
2569
 * The "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
2570
 * Algorithms" for any of the supported protocol 2 key types.
2571
 * Encoding of EC keys is described in RFC 5656 section 3.1 "Key
2572
 * Format".
2573
 *
2574
 * @param[in]  key      A public or private key to create the public ssh_string
2575
 *                      from.
2576
 *
2577
 * @param[out] pblob    A pointer to store the newly allocated key blob. You
2578
 *                      need to free it using ssh_string_free().
2579
 *
2580
 * @return              SSH_OK on success, SSH_ERROR otherwise.
2581
 *
2582
 * @see ssh_string_free()
2583
 */
2584
int ssh_pki_export_pubkey_blob(const ssh_key key,
2585
                               ssh_string *pblob)
2586
29
{
2587
29
    ssh_string blob = NULL;
2588
2589
29
    if (key == NULL) {
2590
0
        return SSH_OK;
2591
0
    }
2592
2593
29
    blob = pki_key_to_blob(key, SSH_KEY_PUBLIC);
2594
29
    if (blob == NULL) {
2595
0
        return SSH_ERROR;
2596
0
    }
2597
2598
29
    *pblob = blob;
2599
29
    return SSH_OK;
2600
29
}
2601
2602
/**
2603
 * @internal
2604
 *
2605
 * @brief Create a key_blob from a private key.
2606
 *
2607
 * The "key_blob" is encoded as per draft-miller-ssh-agent-08 section 4.2
2608
 * "Adding keys to the agent" for any of the supported key types.
2609
 *
2610
 * @param[in]  key      A private key to create the private ssh_string from.
2611
 *
2612
 * @param[out] pblob    A pointer to store the newly allocated key blob. You
2613
 *                      need to free it using ssh_string_free().
2614
 *
2615
 * @return              SSH_OK on success, SSH_ERROR otherwise.
2616
 *
2617
 * @see ssh_string_free()
2618
 */
2619
int ssh_pki_export_privkey_blob(const ssh_key key,
2620
                                ssh_string *pblob)
2621
0
{
2622
0
    ssh_string blob = NULL;
2623
2624
0
    if (key == NULL) {
2625
0
        return SSH_OK;
2626
0
    }
2627
2628
0
    blob = pki_key_to_blob(key, SSH_KEY_PRIVATE);
2629
0
    if (blob == NULL) {
2630
0
        return SSH_ERROR;
2631
0
    }
2632
2633
0
    *pblob = blob;
2634
0
    return SSH_OK;
2635
0
}
2636
2637
/**
2638
 * @brief Convert a public key to a base64 encoded key.
2639
 *
2640
 * @param[in] key       The key to hash
2641
 *
2642
 * @param[out] b64_key  A pointer to store the allocated base64 encoded key. You
2643
 *                      need to free the buffer using ssh_string_free_char()
2644
 *
2645
 * @return              SSH_OK on success, SSH_ERROR on error.
2646
 *
2647
 * @see ssh_string_free_char()
2648
 */
2649
int ssh_pki_export_pubkey_base64(const ssh_key key,
2650
                                 char **b64_key)
2651
0
{
2652
0
    ssh_string key_blob = NULL;
2653
0
    unsigned char *b64 = NULL;
2654
2655
0
    if (key == NULL || b64_key == NULL) {
2656
0
        return SSH_ERROR;
2657
0
    }
2658
2659
0
    key_blob = pki_key_to_blob(key, SSH_KEY_PUBLIC);
2660
0
    if (key_blob == NULL) {
2661
0
        return SSH_ERROR;
2662
0
    }
2663
2664
0
    b64 = bin_to_base64(ssh_string_data(key_blob), ssh_string_len(key_blob));
2665
0
    SSH_STRING_FREE(key_blob);
2666
0
    if (b64 == NULL) {
2667
0
        return SSH_ERROR;
2668
0
    }
2669
2670
0
    *b64_key = (char *)b64;
2671
2672
0
    return SSH_OK;
2673
0
}
2674
2675
/**
2676
 * @brief Export public key to file
2677
 *
2678
 * Exports the public key in AuthorizedKeysFile acceptable format.
2679
 * For more information see `man sshd`
2680
 *
2681
 * @param key A key to export
2682
 *
2683
 * @param filename The name of the output file
2684
 *
2685
 * @returns SSH_OK on success, SSH_ERROR otherwise.
2686
 */
2687
int ssh_pki_export_pubkey_file(const ssh_key key,
2688
                               const char *filename)
2689
0
{
2690
0
    char key_buf[MAX_LINE_SIZE];
2691
0
    char *host = NULL;
2692
0
    char *b64_key = NULL;
2693
0
    char *user = NULL;
2694
0
    FILE *fp = NULL;
2695
0
    int rc;
2696
2697
0
    if (key == NULL || filename == NULL || *filename == '\0') {
2698
0
        return SSH_ERROR;
2699
0
    }
2700
2701
0
    user = ssh_get_local_username();
2702
0
    if (user == NULL) {
2703
0
        return SSH_ERROR;
2704
0
    }
2705
2706
0
    host = ssh_get_local_hostname();
2707
0
    if (host == NULL) {
2708
0
        free(user);
2709
0
        return SSH_ERROR;
2710
0
    }
2711
2712
0
    rc = ssh_pki_export_pubkey_base64(key, &b64_key);
2713
0
    if (rc < 0) {
2714
0
        free(user);
2715
0
        free(host);
2716
0
        return SSH_ERROR;
2717
0
    }
2718
2719
0
    rc = snprintf(key_buf, sizeof(key_buf),
2720
0
                  "%s %s %s@%s\n",
2721
0
                  key->type_c,
2722
0
                  b64_key,
2723
0
                  user,
2724
0
                  host);
2725
0
    free(user);
2726
0
    free(host);
2727
0
    free(b64_key);
2728
0
    if (rc < 0) {
2729
0
        return SSH_ERROR;
2730
0
    }
2731
2732
0
    fp = fopen(filename, "wb+");
2733
0
    if (fp == NULL) {
2734
0
        return SSH_ERROR;
2735
0
    }
2736
0
    rc = fwrite(key_buf, strlen(key_buf), 1, fp);
2737
0
    if (rc != 1 || ferror(fp)) {
2738
0
        fclose(fp);
2739
0
        unlink(filename);
2740
0
        return SSH_ERROR;
2741
0
    }
2742
0
    fclose(fp);
2743
2744
0
    return SSH_OK;
2745
0
}
2746
2747
/**
2748
 * @brief Copy the certificate part of a public key into a private key.
2749
 *
2750
 * @param[in]  certkey  The certificate key.
2751
 *
2752
 * @param[in]  privkey  The target private key to copy the certificate to.
2753
 *
2754
 * @returns SSH_OK on success, SSH_ERROR otherwise.
2755
 **/
2756
int ssh_pki_copy_cert_to_privkey(const ssh_key certkey, ssh_key privkey)
2757
0
{
2758
0
    ssh_buffer cert_buffer = NULL;
2759
0
    int rc, cmp;
2760
2761
0
    if (certkey == NULL || privkey == NULL) {
2762
0
        return SSH_ERROR;
2763
0
    }
2764
2765
0
    if (privkey->cert != NULL) {
2766
0
        return SSH_ERROR;
2767
0
    }
2768
2769
0
    if (certkey->cert == NULL) {
2770
0
        return SSH_ERROR;
2771
0
    }
2772
2773
    /* make sure the public keys match */
2774
0
    cmp = ssh_key_cmp(certkey, privkey, SSH_KEY_CMP_PUBLIC);
2775
0
    if (cmp != 0) {
2776
0
        return SSH_ERROR;
2777
0
    }
2778
2779
0
    cert_buffer = ssh_buffer_new();
2780
0
    if (cert_buffer == NULL) {
2781
0
        return SSH_ERROR;
2782
0
    }
2783
2784
0
    rc = ssh_buffer_add_buffer(cert_buffer, certkey->cert);
2785
0
    if (rc != 0) {
2786
0
        SSH_BUFFER_FREE(cert_buffer);
2787
0
        return SSH_ERROR;
2788
0
    }
2789
2790
0
    privkey->cert = cert_buffer;
2791
0
    privkey->cert_type = certkey->type;
2792
0
    return SSH_OK;
2793
0
}
2794
2795
int ssh_pki_export_signature_blob(const ssh_signature sig,
2796
                                  ssh_string *sig_blob)
2797
0
{
2798
0
    ssh_buffer buf = NULL;
2799
0
    ssh_string str = NULL;
2800
0
    int rc;
2801
2802
0
    if (sig == NULL || sig_blob == NULL) {
2803
0
        return SSH_ERROR;
2804
0
    }
2805
2806
0
    buf = ssh_buffer_new();
2807
0
    if (buf == NULL) {
2808
0
        return SSH_ERROR;
2809
0
    }
2810
2811
0
    str = ssh_string_from_char(sig->type_c);
2812
0
    if (str == NULL) {
2813
0
        SSH_BUFFER_FREE(buf);
2814
0
        return SSH_ERROR;
2815
0
    }
2816
2817
0
    rc = ssh_buffer_add_ssh_string(buf, str);
2818
0
    SSH_STRING_FREE(str);
2819
0
    if (rc < 0) {
2820
0
        SSH_BUFFER_FREE(buf);
2821
0
        return SSH_ERROR;
2822
0
    }
2823
2824
0
    str = pki_signature_to_blob(sig);
2825
0
    if (str == NULL) {
2826
0
        SSH_BUFFER_FREE(buf);
2827
0
        return SSH_ERROR;
2828
0
    }
2829
2830
0
    rc = ssh_buffer_add_ssh_string(buf, str);
2831
0
    SSH_STRING_FREE(str);
2832
0
    if (rc < 0) {
2833
0
        SSH_BUFFER_FREE(buf);
2834
0
        return SSH_ERROR;
2835
0
    }
2836
2837
0
    if (is_sk_key_type(sig->type)) {
2838
        /* Add flags and counter for SK keys */
2839
0
        rc = ssh_buffer_pack(buf, "bd", sig->sk_flags, sig->sk_counter);
2840
0
        if (rc < 0) {
2841
0
            SSH_BUFFER_FREE(buf);
2842
0
            return SSH_ERROR;
2843
0
        }
2844
0
    }
2845
2846
0
    str = ssh_string_new(ssh_buffer_get_len(buf));
2847
0
    if (str == NULL) {
2848
0
        SSH_BUFFER_FREE(buf);
2849
0
        return SSH_ERROR;
2850
0
    }
2851
2852
0
    rc = ssh_string_fill(str, ssh_buffer_get(buf), ssh_buffer_get_len(buf));
2853
0
    SSH_BUFFER_FREE(buf);
2854
0
    if (rc < 0) {
2855
0
        SSH_STRING_FREE(str);
2856
0
        return SSH_ERROR;
2857
0
    }
2858
2859
0
    *sig_blob = str;
2860
2861
0
    return SSH_OK;
2862
0
}
2863
2864
int ssh_pki_import_signature_blob(const ssh_string sig_blob,
2865
                                  const ssh_key pubkey,
2866
                                  ssh_signature *psig)
2867
1
{
2868
1
    ssh_signature sig = NULL;
2869
1
    enum ssh_keytypes_e type;
2870
1
    enum ssh_digest_e hash_type;
2871
1
    ssh_string algorithm = NULL, blob = NULL;
2872
1
    ssh_buffer buf = NULL;
2873
1
    const char *alg = NULL;
2874
1
    uint8_t flags = 0;
2875
1
    uint32_t counter = 0;
2876
1
    int rc;
2877
2878
1
    if (sig_blob == NULL || psig == NULL) {
2879
0
        return SSH_ERROR;
2880
0
    }
2881
2882
1
    buf = ssh_buffer_new();
2883
1
    if (buf == NULL) {
2884
0
        return SSH_ERROR;
2885
0
    }
2886
2887
1
    rc = ssh_buffer_add_data(buf,
2888
1
                             ssh_string_data(sig_blob),
2889
1
                             (uint32_t)ssh_string_len(sig_blob));
2890
1
    if (rc < 0) {
2891
0
        SSH_BUFFER_FREE(buf);
2892
0
        return SSH_ERROR;
2893
0
    }
2894
2895
1
    algorithm = ssh_buffer_get_ssh_string(buf);
2896
1
    if (algorithm == NULL) {
2897
0
        SSH_BUFFER_FREE(buf);
2898
0
        return SSH_ERROR;
2899
0
    }
2900
2901
1
    alg = ssh_string_get_char(algorithm);
2902
1
    type = ssh_key_type_from_signature_name(alg);
2903
1
    hash_type = ssh_key_hash_from_name(alg);
2904
1
    SSH_STRING_FREE(algorithm);
2905
2906
1
    blob = ssh_buffer_get_ssh_string(buf);
2907
1
    if (blob == NULL) {
2908
0
        SSH_BUFFER_FREE(buf);
2909
0
        return SSH_ERROR;
2910
0
    }
2911
2912
1
    if (type == SSH_KEYTYPE_SK_ECDSA ||
2913
1
        type == SSH_KEYTYPE_SK_ED25519) {
2914
0
        rc = ssh_buffer_unpack(buf, "bd", &flags, &counter);
2915
0
        if (rc < 0) {
2916
0
            SSH_BUFFER_FREE(buf);
2917
0
            SSH_STRING_FREE(blob);
2918
0
            return SSH_ERROR;
2919
0
        }
2920
0
    }
2921
1
    SSH_BUFFER_FREE(buf);
2922
2923
1
    sig = pki_signature_from_blob(pubkey, blob, type, hash_type);
2924
1
    SSH_STRING_FREE(blob);
2925
1
    if (sig == NULL) {
2926
1
        return SSH_ERROR;
2927
1
    }
2928
2929
    /* Set SK specific values */
2930
0
    sig->sk_flags = flags;
2931
0
    sig->sk_counter = counter;
2932
2933
0
    *psig = sig;
2934
0
    return SSH_OK;
2935
1
}
2936
2937
/**
2938
 * @internal
2939
 *
2940
 * @brief Check if the provided key can be used with the provided hash type for
2941
 * data signing or signature verification.
2942
 *
2943
 * @param[in]   key         The key to be checked.
2944
 * @param[in]   hash_type   The digest algorithm to be checked.
2945
 *
2946
 * @return  SSH_OK if compatible; SSH_ERROR otherwise
2947
 */
2948
int pki_key_check_hash_compatible(ssh_key key,
2949
                                  enum ssh_digest_e hash_type)
2950
0
{
2951
0
    if (key == NULL) {
2952
0
        SSH_LOG(SSH_LOG_TRACE, "Null pointer provided as key to "
2953
0
                               "pki_key_check_hash_compatible()");
2954
0
        return SSH_ERROR;
2955
0
    }
2956
2957
0
    switch(key->type) {
2958
0
    case SSH_KEYTYPE_RSA_CERT01:
2959
0
    case SSH_KEYTYPE_RSA:
2960
0
        if (hash_type == SSH_DIGEST_SHA1) {
2961
0
            if (ssh_fips_mode()) {
2962
0
                SSH_LOG(SSH_LOG_TRACE, "SHA1 is not allowed in FIPS mode");
2963
0
                return SSH_ERROR;
2964
0
            } else {
2965
0
                return SSH_OK;
2966
0
            }
2967
0
        }
2968
2969
0
        if (hash_type == SSH_DIGEST_SHA256 ||
2970
0
            hash_type == SSH_DIGEST_SHA512)
2971
0
        {
2972
0
            return SSH_OK;
2973
0
        }
2974
0
        break;
2975
0
    case SSH_KEYTYPE_ECDSA_P256_CERT01:
2976
0
    case SSH_KEYTYPE_ECDSA_P256:
2977
0
    case SSH_KEYTYPE_SK_ECDSA_CERT01:
2978
0
    case SSH_KEYTYPE_SK_ECDSA:
2979
0
        if (hash_type == SSH_DIGEST_SHA256) {
2980
0
            return SSH_OK;
2981
0
        }
2982
0
        break;
2983
0
    case SSH_KEYTYPE_ECDSA_P384_CERT01:
2984
0
    case SSH_KEYTYPE_ECDSA_P384:
2985
0
        if (hash_type == SSH_DIGEST_SHA384) {
2986
0
            return SSH_OK;
2987
0
        }
2988
0
        break;
2989
0
    case SSH_KEYTYPE_ECDSA_P521_CERT01:
2990
0
    case SSH_KEYTYPE_ECDSA_P521:
2991
0
        if (hash_type == SSH_DIGEST_SHA512) {
2992
0
            return SSH_OK;
2993
0
        }
2994
0
        break;
2995
0
    case SSH_KEYTYPE_ED25519_CERT01:
2996
0
    case SSH_KEYTYPE_ED25519:
2997
0
    case SSH_KEYTYPE_SK_ED25519_CERT01:
2998
0
    case SSH_KEYTYPE_SK_ED25519:
2999
0
        if (hash_type == SSH_DIGEST_AUTO) {
3000
0
            return SSH_OK;
3001
0
        }
3002
0
        break;
3003
0
    case SSH_KEYTYPE_DSS:   /* deprecated */
3004
0
    case SSH_KEYTYPE_DSS_CERT01:    /* deprecated */
3005
0
    case SSH_KEYTYPE_RSA1:
3006
0
    case SSH_KEYTYPE_ECDSA:
3007
0
    case SSH_KEYTYPE_UNKNOWN:
3008
0
        SSH_LOG(SSH_LOG_TRACE, "Unknown key type %d", key->type);
3009
0
        return SSH_ERROR;
3010
0
    }
3011
3012
0
    SSH_LOG(SSH_LOG_TRACE, "Key type %d incompatible with hash type  %d",
3013
0
            key->type, hash_type);
3014
3015
0
    return SSH_ERROR;
3016
0
}
3017
3018
/**
3019
 * @brief Prepare buffer for FIDO2/U2F security key signature verification
3020
 *
3021
 * This function creates a buffer containing the application hash, flags,
3022
 * counter, and input hash for FIDO/U2F key signature verification.
3023
 *
3024
 * @param key          The SSH key containing sk_application
3025
 * @param sig          The signature containing sk_flags and sk_counter
3026
 * @param input        The input data to hash
3027
 * @param input_len    Length of the input data
3028
 * @param sk_buffer_out Pointer to store the created buffer
3029
 *
3030
 * @return SSH_OK on success, SSH_ERROR on error
3031
 */
3032
int pki_sk_signature_buffer_prepare(const ssh_key key,
3033
                                    const ssh_signature sig,
3034
                                    const unsigned char *input,
3035
                                    size_t input_len,
3036
                                    ssh_buffer *sk_buffer_out)
3037
0
{
3038
0
    ssh_buffer sk_buffer = NULL;
3039
0
    SHA256CTX ctx = NULL;
3040
0
    unsigned char application_hash[SHA256_DIGEST_LEN] = {0};
3041
0
    unsigned char input_hash[SHA256_DIGEST_LEN] = {0};
3042
0
    int rc, ret = SSH_ERROR;
3043
3044
0
    if (key == NULL || sig == NULL || input == NULL || sk_buffer_out == NULL) {
3045
0
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter(s) provided to %s()", __func__);
3046
0
        return SSH_ERROR;
3047
0
    }
3048
3049
0
    *sk_buffer_out = NULL;
3050
3051
    /* Calculate application hash */
3052
0
    ctx = sha256_init();
3053
0
    if (ctx == NULL) {
3054
0
        SSH_LOG(SSH_LOG_TRACE, "Can not create SHA256CTX for application hash");
3055
0
        return SSH_ERROR;
3056
0
    }
3057
0
    sha256_update(ctx,
3058
0
                  ssh_string_data(key->sk_application),
3059
0
                  ssh_string_len(key->sk_application));
3060
0
    sha256_final(application_hash, ctx);
3061
3062
    /* Calculate input hash */
3063
0
    ctx = sha256_init();
3064
0
    if (ctx == NULL) {
3065
0
        SSH_LOG(SSH_LOG_TRACE, "Can not create SHA256CTX for input hash");
3066
0
        goto out;
3067
0
    }
3068
0
    sha256_update(ctx, input, input_len);
3069
0
    sha256_final(input_hash, ctx);
3070
3071
    /* Create and pack the sk_buffer */
3072
0
    sk_buffer = ssh_buffer_new();
3073
0
    if (sk_buffer == NULL) {
3074
0
        goto out;
3075
0
    }
3076
3077
0
    rc = ssh_buffer_pack(sk_buffer,
3078
0
                         "PbdP",
3079
0
                         (size_t)SHA256_DIGEST_LEN,
3080
0
                         application_hash,
3081
0
                         sig->sk_flags,
3082
0
                         sig->sk_counter,
3083
0
                         (size_t)SHA256_DIGEST_LEN,
3084
0
                         input_hash);
3085
0
    if (rc != SSH_OK) {
3086
0
        goto out;
3087
0
    }
3088
3089
0
    *sk_buffer_out = sk_buffer;
3090
0
    sk_buffer = NULL;
3091
0
    ret = SSH_OK;
3092
3093
0
out:
3094
0
    SSH_BUFFER_FREE(sk_buffer);
3095
0
    ssh_burn(application_hash, SHA256_DIGEST_LEN);
3096
0
    ssh_burn(input_hash, SHA256_DIGEST_LEN);
3097
3098
0
    return ret;
3099
0
}
3100
3101
int ssh_pki_signature_verify(ssh_session session,
3102
                             ssh_signature sig,
3103
                             const ssh_key key,
3104
                             const unsigned char *input,
3105
                             size_t input_len)
3106
0
{
3107
0
    int rc;
3108
0
    bool allowed;
3109
0
    enum ssh_keytypes_e key_type;
3110
3111
0
    if (session == NULL || sig == NULL || key == NULL || input == NULL) {
3112
0
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter(s) provided to %s()", __func__);
3113
0
        return SSH_ERROR;
3114
0
    }
3115
0
    key_type = ssh_key_type_plain(key->type);
3116
3117
0
    SSH_LOG(SSH_LOG_FUNCTIONS,
3118
0
            "Going to verify a %s type signature",
3119
0
            sig->type_c);
3120
3121
0
    if (key_type != sig->type) {
3122
0
        SSH_LOG(SSH_LOG_TRACE,
3123
0
                "Can not verify %s signature with %s key",
3124
0
                sig->type_c, key->type_c);
3125
0
        return SSH_ERROR;
3126
0
    }
3127
3128
0
    allowed = ssh_key_size_allowed(session, key);
3129
0
    if (!allowed) {
3130
0
        ssh_set_error(session,
3131
0
                      SSH_FATAL,
3132
0
                      "The '%s' key of size %d is not allowed by RSA_MIN_SIZE",
3133
0
                      key->type_c,
3134
0
                      ssh_key_size(key));
3135
0
        return SSH_ERROR;
3136
0
    }
3137
3138
    /* Check if public key and hash type are compatible */
3139
0
    rc = pki_key_check_hash_compatible(key, sig->hash_type);
3140
0
    if (rc != SSH_OK) {
3141
0
        return SSH_ERROR;
3142
0
    }
3143
3144
0
    if (is_sk_key_type(key->type)) {
3145
0
        ssh_buffer sk_buffer = NULL;
3146
3147
0
        rc = pki_sk_signature_buffer_prepare(key,
3148
0
                                             sig,
3149
0
                                             input,
3150
0
                                             input_len,
3151
0
                                             &sk_buffer);
3152
0
        if (rc != SSH_OK) {
3153
0
            return SSH_ERROR;
3154
0
        }
3155
3156
0
        rc = pki_verify_data_signature(sig,
3157
0
                                       key,
3158
0
                                       ssh_buffer_get(sk_buffer),
3159
0
                                       ssh_buffer_get_len(sk_buffer));
3160
0
        SSH_BUFFER_FREE(sk_buffer);
3161
0
        return rc;
3162
0
    }
3163
3164
0
    return pki_verify_data_signature(sig, key, input, input_len);
3165
0
}
3166
3167
ssh_signature pki_do_sign(const ssh_key privkey,
3168
                          const unsigned char *input,
3169
                          size_t input_len,
3170
                          enum ssh_digest_e hash_type)
3171
0
{
3172
0
    int rc;
3173
3174
0
    if (privkey == NULL || input == NULL) {
3175
0
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
3176
0
                               "pki_do_sign()");
3177
0
        return NULL;
3178
0
    }
3179
3180
    /* Check if public key and hash type are compatible */
3181
0
    rc = pki_key_check_hash_compatible(privkey, hash_type);
3182
0
    if (rc != SSH_OK) {
3183
0
        return NULL;
3184
0
    }
3185
3186
0
    return pki_sign_data(privkey, hash_type, input, input_len);
3187
0
}
3188
3189
/**
3190
 * @brief Encodes a binary signature blob as an sshsig armored signature
3191
 *
3192
 * @param blob       The binary signature blob to encode
3193
 * @param out_str    Pointer to store the allocated base64 encoded string
3194
 *                   Must be freed with ssh_string_free_char()
3195
 *
3196
 * @return SSH_OK on success, SSH_ERROR on error
3197
 */
3198
static int sshsig_armor(ssh_buffer blob, char **out_str)
3199
0
{
3200
0
    char *b64_data = NULL;
3201
0
    char *armored = NULL;
3202
0
    const unsigned char *data = NULL;
3203
0
    size_t len, b64_len, armored_len, num_lines;
3204
0
    size_t i, j;
3205
3206
0
    if (blob == NULL || out_str == NULL) {
3207
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid input parameters");
3208
0
        return SSH_ERROR;
3209
0
    }
3210
3211
0
    *out_str = NULL;
3212
3213
0
    data = ssh_buffer_get(blob);
3214
0
    len = ssh_buffer_get_len(blob);
3215
3216
0
    b64_data = (char *)bin_to_base64(data, len);
3217
0
    if (b64_data == NULL) {
3218
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to base64 encode signature blob");
3219
0
        return SSH_ERROR;
3220
0
    }
3221
3222
0
    b64_len = strlen(b64_data);
3223
3224
    /* Calculate space needed: header + data with line breaks + footer */
3225
0
    num_lines = (b64_len + SSHSIG_LINE_LENGTH - 1) /
3226
0
                SSHSIG_LINE_LENGTH;                    /* Round up division */
3227
0
    armored_len = strlen(SSHSIG_BEGIN_SIGNATURE) + 1 + /* header + \n */
3228
0
                  b64_len + num_lines +                /* data + line breaks */
3229
0
                  strlen(SSHSIG_END_SIGNATURE) + 1;    /* footer + \0 */
3230
3231
0
    armored = calloc(armored_len, 1);
3232
0
    if (armored == NULL) {
3233
0
        SSH_LOG(SSH_LOG_TRACE,
3234
0
                "Failed to allocate %zu bytes for armored signature",
3235
0
                armored_len);
3236
0
        SAFE_FREE(b64_data);
3237
0
        return SSH_ERROR;
3238
0
    }
3239
3240
0
    j = snprintf(armored, armored_len, SSHSIG_BEGIN_SIGNATURE "\n");
3241
0
    for (i = 0; i < b64_len; i++) {
3242
0
        if (i > 0 && i % SSHSIG_LINE_LENGTH == 0) {
3243
0
            armored[j++] = '\n';
3244
0
        }
3245
0
        armored[j++] = b64_data[i];
3246
0
    }
3247
0
    armored[j++] = '\n';
3248
0
    snprintf(armored + j, armored_len - j, SSHSIG_END_SIGNATURE);
3249
3250
0
    SAFE_FREE(b64_data);
3251
3252
0
    *out_str = armored;
3253
0
    return SSH_OK;
3254
0
}
3255
3256
/**
3257
 * @brief Dearmor an sshsig signature from ASCII armored format to binary
3258
 *
3259
 * @param[in]  signature    The armored sshsig signature string
3260
 * @param[out] out          Pointer to store the allocated binary buffer
3261
 *
3262
 * @return SSH_OK on success, SSH_ERROR on error
3263
 */
3264
static int sshsig_dearmor(const char *signature, ssh_buffer *out)
3265
0
{
3266
0
    const char *begin = NULL;
3267
0
    const char *end = NULL;
3268
0
    char *clean_b64 = NULL;
3269
0
    ssh_buffer decoded_buffer = NULL;
3270
0
    int i, j;
3271
0
    int rc = SSH_ERROR;
3272
3273
0
    if (signature == NULL || out == NULL) {
3274
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid input parameters");
3275
0
        return SSH_ERROR;
3276
0
    }
3277
3278
0
    *out = NULL;
3279
3280
0
    rc = strncmp(signature,
3281
0
                 SSHSIG_BEGIN_SIGNATURE,
3282
0
                 strlen(SSHSIG_BEGIN_SIGNATURE));
3283
0
    if (rc != SSH_OK) {
3284
0
        SSH_LOG(SSH_LOG_TRACE, "Signature does not start with expected header");
3285
0
        return SSH_ERROR;
3286
0
    }
3287
3288
0
    begin = signature + strlen(SSHSIG_BEGIN_SIGNATURE);
3289
0
    while (isspace(*begin)) {
3290
0
        begin++;
3291
0
    }
3292
3293
0
    end = strstr(begin, SSHSIG_END_SIGNATURE);
3294
0
    if (end == NULL) {
3295
0
        SSH_LOG(SSH_LOG_TRACE, "Signature end marker not found");
3296
0
        return SSH_ERROR;
3297
0
    }
3298
3299
    /* Backtrack to find the real end of data */
3300
0
    while (end > begin && (isspace(*(end - 1)))) {
3301
0
        end--;
3302
0
    }
3303
3304
0
    clean_b64 = calloc(end - begin + 1, 1);
3305
0
    if (clean_b64 == NULL) {
3306
0
        SSH_LOG(SSH_LOG_TRACE,
3307
0
                "Failed to allocate %td bytes for clean base64 data",
3308
0
                end - begin + 1);
3309
0
        return SSH_ERROR;
3310
0
    }
3311
3312
0
    for (i = 0, j = 0; begin + i < end; i++) {
3313
0
        if (!isspace(begin[i])) {
3314
0
            clean_b64[j++] = begin[i];
3315
0
        }
3316
0
    }
3317
0
    clean_b64[j] = '\0';
3318
3319
0
    decoded_buffer = base64_to_bin(clean_b64);
3320
0
    SAFE_FREE(clean_b64);
3321
3322
0
    if (decoded_buffer == NULL) {
3323
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to decode base64 signature data");
3324
0
        return SSH_ERROR;
3325
0
    }
3326
3327
0
    *out = decoded_buffer;
3328
0
    return SSH_OK;
3329
0
}
3330
3331
/**
3332
 * @internal
3333
 * @brief Common helper function to prepare the data in sshsig format
3334
 *
3335
 * This function handles the common logic to prepare the sshsig format:
3336
 * 1. Hash the input data using the specified algorithm
3337
 * 2. Build the data buffer to sign
3338
 *
3339
 * @param data           The raw data to process
3340
 * @param data_length    The length of the data
3341
 * @param hash_alg       The hash algorithm to use (sha256 or sha512)
3342
 * @param sig_namespace  The signature namespace
3343
 * @param tosign_buf     Pointer to store the allocated to-sign buffer
3344
 *
3345
 * @return SSH_OK on success, SSH_ERROR on error
3346
 */
3347
static int sshsig_prepare_data(const void *data,
3348
                               size_t data_length,
3349
                               const char *hash_alg,
3350
                               const char *sig_namespace,
3351
                               ssh_buffer *tosign_buf)
3352
0
{
3353
0
    ssh_buffer tosign = NULL;
3354
0
    ssh_string hash_string = NULL;
3355
0
    char hash[SHA512_DIGEST_LEN];
3356
0
    size_t hash_len;
3357
0
    int rc = SSH_ERROR;
3358
3359
0
    if (data == NULL || hash_alg == NULL || sig_namespace == NULL ||
3360
0
        tosign_buf == NULL) {
3361
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid input parameters");
3362
0
        return SSH_ERROR;
3363
0
    }
3364
3365
0
    *tosign_buf = NULL;
3366
3367
0
    if (strcmp(hash_alg, "sha256") == 0) {
3368
0
        hash_len = SHA256_DIGEST_LEN;
3369
0
        rc = sha256(data, data_length, (unsigned char *)hash);
3370
0
    } else if (strcmp(hash_alg, "sha512") == 0) {
3371
0
        hash_len = SHA512_DIGEST_LEN;
3372
0
        rc = sha512(data, data_length, (unsigned char *)hash);
3373
0
    } else {
3374
0
        SSH_LOG(SSH_LOG_TRACE, "Unsupported hash algorithm: %s", hash_alg);
3375
0
        goto cleanup;
3376
0
    }
3377
0
    if (rc != SSH_OK) {
3378
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to compute %s hash of data", hash_alg);
3379
0
        goto cleanup;
3380
0
    }
3381
3382
0
    hash_string = ssh_string_new(hash_len);
3383
0
    if (hash_string == NULL) {
3384
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to allocate ssh_string for hash");
3385
0
        goto cleanup;
3386
0
    }
3387
3388
0
    rc = ssh_string_fill(hash_string, hash, hash_len);
3389
0
    if (rc != SSH_OK) {
3390
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to fill ssh_string with hash data");
3391
0
        goto cleanup;
3392
0
    }
3393
3394
0
    tosign = ssh_buffer_new();
3395
0
    if (tosign == NULL) {
3396
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to allocate buffer for signing data");
3397
0
        goto cleanup;
3398
0
    }
3399
3400
0
    rc = ssh_buffer_pack(tosign,
3401
0
                         "tsssS",
3402
0
                         SSHSIG_MAGIC_PREAMBLE,
3403
0
                         sig_namespace,
3404
0
                         "",
3405
0
                         hash_alg,
3406
0
                         hash_string);
3407
3408
0
    if (rc == SSH_OK) {
3409
0
        *tosign_buf = tosign;
3410
0
        tosign = NULL;
3411
0
    } else {
3412
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to pack signing data into buffer");
3413
0
    }
3414
3415
0
cleanup:
3416
0
    SSH_BUFFER_FREE(tosign);
3417
0
    SSH_STRING_FREE(hash_string);
3418
3419
0
    return rc;
3420
0
}
3421
3422
/**
3423
 * @brief Signs data in sshsig compatible format
3424
 *
3425
 * @param data            The data to sign
3426
 * @param data_length     The length of the data
3427
 * @param privkey         The private key to sign with
3428
 * @param pki_context     The PKI context. For non-SK keys, this parameter is
3429
 *                        ignored and can be NULL. For SK keys, can be NULL in
3430
 *                        which case a default context with default callbacks
3431
 *                        will be used. If provided, the context must have
3432
 *                        sk_callbacks set with a valid sign callback
3433
 *                        implementation. See ssh_pki_ctx_set_sk_callbacks().
3434
 * @param sig_namespace   The signature namespace (e.g. "file", "email", etc.)
3435
 * @param hash_alg        The hash algorithm to use (SSHSIG_DIGEST_SHA2_256 or
3436
 *                        SSHSIG_DIGEST_SHA2_512)
3437
 * @param signature       Pointer to store the allocated signature string in the
3438
 *                        armored format. Must be freed with
3439
 *                        ssh_string_free_char()
3440
 *
3441
 * @return SSH_OK on success, SSH_ERROR on error
3442
 */
3443
int sshsig_sign(const void *data,
3444
                size_t data_length,
3445
                ssh_key privkey,
3446
                ssh_pki_ctx pki_context,
3447
                const char *sig_namespace,
3448
                enum sshsig_digest_e hash_alg,
3449
                char **signature)
3450
0
{
3451
0
    ssh_buffer tosign = NULL;
3452
0
    ssh_buffer signature_blob = NULL;
3453
0
    ssh_signature sig = NULL;
3454
0
    ssh_string sig_string = NULL;
3455
0
    ssh_string pub_blob = NULL;
3456
0
    ssh_pki_ctx temp_ctx = NULL;
3457
0
    ssh_pki_ctx ctx_to_use = NULL;
3458
0
    enum ssh_digest_e digest_type;
3459
0
    const char *hash_alg_str = NULL;
3460
0
    int rc = SSH_ERROR;
3461
3462
0
    if (privkey == NULL || data == NULL || sig_namespace == NULL ||
3463
0
        signature == NULL) {
3464
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid parameters provided to sshsig_sign");
3465
0
        return SSH_ERROR;
3466
0
    }
3467
3468
0
    if (strlen(sig_namespace) == 0) {
3469
0
        SSH_LOG(SSH_LOG_TRACE,
3470
0
                "Invalid parameters provided to sshsig_sign: empty namespace "
3471
0
                "string");
3472
0
        return SSH_ERROR;
3473
0
    }
3474
3475
    /* Check if this is an SK key that requires a PKI context */
3476
0
    if (is_sk_key_type(privkey->type)) {
3477
        /* If no context provided, create a temporary default one */
3478
0
        if (pki_context == NULL) {
3479
0
            SSH_LOG(SSH_LOG_INFO,
3480
0
                    "No PKI context provided, using the default one");
3481
3482
0
            temp_ctx = ssh_pki_ctx_new();
3483
0
            if (temp_ctx == NULL) {
3484
0
                SSH_LOG(SSH_LOG_WARN, "Failed to create temporary PKI context");
3485
0
                return SSH_ERROR;
3486
0
            }
3487
0
            ctx_to_use = temp_ctx;
3488
0
        } else {
3489
0
            ctx_to_use = pki_context;
3490
0
        }
3491
3492
        /* Verify that we have valid SK callbacks */
3493
0
        if (ctx_to_use->sk_callbacks == NULL) {
3494
0
            SSH_LOG(SSH_LOG_WARN,
3495
0
                    "Security Key callbacks not configured in PKI context");
3496
0
            goto cleanup;
3497
0
        }
3498
0
    }
3499
3500
0
    *signature = NULL;
3501
3502
0
    if (hash_alg == SSHSIG_DIGEST_SHA2_256) {
3503
0
        hash_alg_str = "sha256";
3504
0
    } else if (hash_alg == SSHSIG_DIGEST_SHA2_512) {
3505
0
        hash_alg_str = "sha512";
3506
0
    } else {
3507
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid hash algorithm %d", hash_alg);
3508
0
        return SSH_ERROR;
3509
0
    }
3510
3511
0
    rc = sshsig_prepare_data(data,
3512
0
                             data_length,
3513
0
                             hash_alg_str,
3514
0
                             sig_namespace,
3515
0
                             &tosign);
3516
0
    if (rc != SSH_OK) {
3517
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to prepare data for sshsig signing");
3518
0
        goto cleanup;
3519
0
    }
3520
3521
    /* Use appropriate signing method based on key type */
3522
0
    if (is_sk_key_type(privkey->type)) {
3523
#ifdef WITH_FIDO2
3524
        sig = pki_sk_do_sign(ctx_to_use,
3525
                             privkey,
3526
                             ssh_buffer_get(tosign),
3527
                             ssh_buffer_get_len(tosign));
3528
#else
3529
0
        SSH_LOG(SSH_LOG_WARN, SK_NOT_SUPPORTED_MSG);
3530
0
        goto cleanup;
3531
0
#endif
3532
0
    } else {
3533
0
        digest_type = key_type_to_hash(ssh_key_type_plain(privkey->type));
3534
0
        sig = pki_sign_data(privkey,
3535
0
                            digest_type,
3536
0
                            ssh_buffer_get(tosign),
3537
0
                            ssh_buffer_get_len(tosign));
3538
0
    }
3539
0
    if (sig == NULL) {
3540
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to sign data with private key");
3541
0
        goto cleanup;
3542
0
    }
3543
3544
0
    rc = ssh_pki_export_pubkey_blob(privkey, &pub_blob);
3545
0
    if (rc != SSH_OK || pub_blob == NULL) {
3546
0
        SSH_LOG(SSH_LOG_TRACE,
3547
0
                "Failed to export public key blob from private key");
3548
0
        goto cleanup;
3549
0
    }
3550
3551
0
    rc = ssh_pki_export_signature_blob(sig, &sig_string);
3552
0
    if (rc != SSH_OK) {
3553
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to export signature blob");
3554
0
        goto cleanup;
3555
0
    }
3556
3557
0
    signature_blob = ssh_buffer_new();
3558
0
    if (signature_blob == NULL) {
3559
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to allocate signature buffer");
3560
0
        goto cleanup;
3561
0
    }
3562
3563
0
    rc = ssh_buffer_pack(signature_blob,
3564
0
                         "tdSsssS",
3565
0
                         SSHSIG_MAGIC_PREAMBLE,
3566
0
                         SSHSIG_VERSION,
3567
0
                         pub_blob,
3568
0
                         sig_namespace,
3569
0
                         "",
3570
0
                         hash_alg_str,
3571
0
                         sig_string);
3572
0
    if (rc != SSH_OK) {
3573
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to pack signature blob");
3574
0
        goto cleanup;
3575
0
    }
3576
3577
0
    rc = sshsig_armor(signature_blob, signature);
3578
0
    if (rc != SSH_OK) {
3579
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to armor signature blob");
3580
0
        goto cleanup;
3581
0
    }
3582
3583
0
cleanup:
3584
0
    SSH_BUFFER_FREE(tosign);
3585
0
    SSH_BUFFER_FREE(signature_blob);
3586
0
    SSH_SIGNATURE_FREE(sig);
3587
0
    SSH_STRING_FREE(sig_string);
3588
0
    SSH_STRING_FREE(pub_blob);
3589
3590
    /* Clean up temporary context if we created one */
3591
0
    if (temp_ctx != NULL) {
3592
0
        SSH_PKI_CTX_FREE(temp_ctx);
3593
0
    }
3594
3595
0
    return rc;
3596
0
}
3597
3598
/**
3599
 * @brief Verifies an sshsig formatted signature against data
3600
 *
3601
 * @param data           The data to verify
3602
 * @param data_length    The length of the data
3603
 * @param signature      The armored sshsig signature
3604
 * @param sig_namespace  The expected signature namespace
3605
 * @param sign_key       If not NULL, returns the allocated public key that was
3606
 *                       used for signing this data. Must be freed with
3607
 *                       ssh_key_free(). Note that this is an output parameter
3608
 *                       and is not checked against "allowed signers". The
3609
 *                       caller needs to compare it with expected signer key
3610
 *                       using ssh_key_cmp().
3611
 *
3612
 * @return SSH_OK on success, SSH_ERROR on verification failure
3613
 */
3614
int sshsig_verify(const void *data,
3615
                  size_t data_length,
3616
                  const char *signature,
3617
                  const char *sig_namespace,
3618
                  ssh_key *sign_key)
3619
0
{
3620
0
    ssh_buffer sig_buf = NULL;
3621
0
    ssh_buffer tosign = NULL;
3622
0
    ssh_key key = NULL;
3623
0
    char *hash_alg_str = NULL;
3624
0
    ssh_string sig_data = NULL;
3625
0
    ssh_string sig_namespace_str = NULL;
3626
0
    ssh_string reserved_str = NULL;
3627
0
    ssh_string pubkey_blob = NULL;
3628
0
    int rc = SSH_ERROR;
3629
0
    ssh_signature signature_obj = NULL;
3630
0
    uint32_t sig_version;
3631
3632
0
    if (sign_key != NULL) {
3633
0
        *sign_key = NULL;
3634
0
    }
3635
3636
0
    if (signature == NULL || data == NULL || sig_namespace == NULL) {
3637
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid parameters provided to sshsig_verify");
3638
0
        return SSH_ERROR;
3639
0
    }
3640
3641
0
    if (strlen(sig_namespace) == 0) {
3642
0
        SSH_LOG(SSH_LOG_TRACE,
3643
0
                "Invalid parameters provided to sshsig_verify: empty namespace "
3644
0
                "string");
3645
0
        return SSH_ERROR;
3646
0
    }
3647
3648
0
    rc = sshsig_dearmor(signature, &sig_buf);
3649
0
    if (rc != SSH_OK) {
3650
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to dearmor signature");
3651
0
        return SSH_ERROR;
3652
0
    }
3653
3654
0
    if (ssh_buffer_get_len(sig_buf) < SSHSIG_MAGIC_PREAMBLE_LEN ||
3655
0
        memcmp(ssh_buffer_get(sig_buf),
3656
0
               SSHSIG_MAGIC_PREAMBLE,
3657
0
               SSHSIG_MAGIC_PREAMBLE_LEN) != 0) {
3658
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid signature magic preamble");
3659
0
        SSH_BUFFER_FREE(sig_buf);
3660
0
        return SSH_ERROR;
3661
0
    }
3662
3663
0
    ssh_buffer_pass_bytes(sig_buf, SSHSIG_MAGIC_PREAMBLE_LEN);
3664
0
    rc = ssh_buffer_unpack(sig_buf,
3665
0
                           "dSSSsS",
3666
0
                           &sig_version,
3667
0
                           &pubkey_blob,
3668
0
                           &sig_namespace_str,
3669
0
                           &reserved_str,
3670
0
                           &hash_alg_str,
3671
0
                           &sig_data);
3672
3673
0
    if (rc != SSH_OK) {
3674
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to unpack signature buffer");
3675
0
        SSH_BUFFER_FREE(sig_buf);
3676
0
        return SSH_ERROR;
3677
0
    }
3678
3679
0
    if (sig_version != SSHSIG_VERSION) {
3680
0
        SSH_LOG(SSH_LOG_TRACE,
3681
0
                "Unsupported signature version %u, expected %u",
3682
0
                sig_version,
3683
0
                SSHSIG_VERSION);
3684
0
        rc = SSH_ERROR;
3685
0
        goto cleanup;
3686
0
    }
3687
3688
0
    rc = ssh_pki_import_pubkey_blob(pubkey_blob, &key);
3689
0
    if (rc != SSH_OK) {
3690
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to import public key from signature");
3691
0
        goto cleanup;
3692
0
    }
3693
3694
0
    if (ssh_string_len(sig_namespace_str) != strlen(sig_namespace) ||
3695
0
        memcmp(ssh_string_data(sig_namespace_str),
3696
0
               sig_namespace,
3697
0
               strlen(sig_namespace)) != 0) {
3698
0
        SSH_LOG(SSH_LOG_TRACE,
3699
0
                "Signature namespace mismatch: expected '%s', got '%s'",
3700
0
                sig_namespace,
3701
0
                ssh_string_get_char(sig_namespace_str));
3702
0
        rc = SSH_ERROR;
3703
0
        goto cleanup;
3704
0
    }
3705
3706
0
    if (strcmp(hash_alg_str, "sha256") != 0 &&
3707
0
        strcmp(hash_alg_str, "sha512") != 0) {
3708
0
        SSH_LOG(SSH_LOG_TRACE, "Unsupported hash algorithm '%s'", hash_alg_str);
3709
0
        rc = SSH_ERROR;
3710
0
        goto cleanup;
3711
0
    }
3712
3713
0
    rc = sshsig_prepare_data(data,
3714
0
                             data_length,
3715
0
                             hash_alg_str,
3716
0
                             sig_namespace,
3717
0
                             &tosign);
3718
0
    if (rc != SSH_OK) {
3719
0
        SSH_LOG(SSH_LOG_TRACE,
3720
0
                "Failed to prepare data for sshsig verification");
3721
0
        goto cleanup;
3722
0
    }
3723
3724
0
    rc = ssh_pki_import_signature_blob(sig_data, key, &signature_obj);
3725
0
    if (rc != SSH_OK) {
3726
0
        SSH_LOG(SSH_LOG_TRACE, "Failed to import signature blob");
3727
0
        goto cleanup;
3728
0
    }
3729
3730
0
    if (is_sk_key_type(key->type)) {
3731
0
        ssh_buffer sk_buffer = NULL;
3732
0
        rc = pki_sk_signature_buffer_prepare(key,
3733
0
                                             signature_obj,
3734
0
                                             ssh_buffer_get(tosign),
3735
0
                                             ssh_buffer_get_len(tosign),
3736
0
                                             &sk_buffer);
3737
0
        if (rc != SSH_OK) {
3738
0
            SSH_LOG(SSH_LOG_TRACE, "Failed to prepare sk signature buffer");
3739
0
            goto cleanup;
3740
0
        }
3741
3742
0
        rc = pki_verify_data_signature(signature_obj,
3743
0
                                       key,
3744
0
                                       ssh_buffer_get(sk_buffer),
3745
0
                                       ssh_buffer_get_len(sk_buffer));
3746
0
        SSH_BUFFER_FREE(sk_buffer);
3747
0
    } else {
3748
0
        rc = pki_verify_data_signature(signature_obj,
3749
0
                                       key,
3750
0
                                       ssh_buffer_get(tosign),
3751
0
                                       ssh_buffer_get_len(tosign));
3752
0
    }
3753
0
    if (rc != SSH_OK) {
3754
0
        SSH_LOG(SSH_LOG_TRACE, "Signature verification failed");
3755
0
        goto cleanup;
3756
0
    }
3757
3758
0
    if (sign_key != NULL) {
3759
0
        *sign_key = key;
3760
0
        key = NULL; /* Transferred ownership */
3761
0
    }
3762
3763
0
cleanup:
3764
0
    SSH_STRING_FREE(pubkey_blob);
3765
0
    SSH_STRING_FREE(sig_namespace_str);
3766
0
    SSH_STRING_FREE(reserved_str);
3767
0
    SSH_STRING_FREE(sig_data);
3768
0
    SSH_BUFFER_FREE(tosign);
3769
0
    SSH_BUFFER_FREE(sig_buf);
3770
0
    SSH_KEY_FREE(key);
3771
0
    SAFE_FREE(hash_alg_str);
3772
0
    SSH_SIGNATURE_FREE(signature_obj);
3773
3774
0
    return rc;
3775
0
}
3776
3777
/*
3778
 * This function signs the session id as a string then
3779
 * the content of sigbuf */
3780
ssh_string ssh_pki_do_sign(ssh_session session,
3781
                           ssh_buffer sigbuf,
3782
                           const ssh_key privkey,
3783
                           enum ssh_digest_e hash_type)
3784
0
{
3785
0
    struct ssh_crypto_struct *crypto = NULL;
3786
3787
0
    ssh_signature sig = NULL;
3788
0
    ssh_string sig_blob = NULL;
3789
3790
0
    ssh_string session_id = NULL;
3791
0
    ssh_buffer sign_input = NULL;
3792
3793
0
    int rc;
3794
3795
0
    if (session == NULL || sigbuf == NULL || privkey == NULL ||
3796
0
        !ssh_key_is_private(privkey))
3797
0
    {
3798
0
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
3799
0
                               "ssh_pki_do_sign()");
3800
0
        return NULL;
3801
0
    }
3802
3803
0
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
3804
0
    if (crypto == NULL) {
3805
0
        return NULL;
3806
0
    }
3807
3808
    /* Get the session ID */
3809
0
    session_id = ssh_string_new(crypto->session_id_len);
3810
0
    if (session_id == NULL) {
3811
0
        return NULL;
3812
0
    }
3813
0
    rc = ssh_string_fill(session_id, crypto->session_id, crypto->session_id_len);
3814
0
    if (rc < 0) {
3815
0
        goto end;
3816
0
    }
3817
3818
    /* Fill the input */
3819
0
    sign_input = ssh_buffer_new();
3820
0
    if (sign_input == NULL) {
3821
0
        goto end;
3822
0
    }
3823
0
    ssh_buffer_set_secure(sign_input);
3824
3825
0
    rc = ssh_buffer_pack(sign_input,
3826
0
                         "SP",
3827
0
                         session_id,
3828
0
                         (size_t)ssh_buffer_get_len(sigbuf),
3829
0
                         ssh_buffer_get(sigbuf));
3830
0
    if (rc != SSH_OK) {
3831
0
        goto end;
3832
0
    }
3833
3834
    /* Generate the signature */
3835
0
    if (is_sk_key_type(privkey->type)) {
3836
#ifdef WITH_FIDO2
3837
        if (session->pki_context == NULL ||
3838
            session->pki_context->sk_callbacks == NULL) {
3839
            SSH_LOG(SSH_LOG_WARN, "Missing PKI context or SK callbacks");
3840
            goto end;
3841
        }
3842
3843
        rc = pki_key_check_hash_compatible(privkey, hash_type);
3844
        if (rc != SSH_OK) {
3845
            SSH_LOG(SSH_LOG_WARN,
3846
                    "Incompatible hash type %d for sk key type %d",
3847
                    hash_type,
3848
                    privkey->type);
3849
            goto end;
3850
        }
3851
3852
        sig = pki_sk_do_sign(session->pki_context,
3853
                             privkey,
3854
                             ssh_buffer_get(sign_input),
3855
                             ssh_buffer_get_len(sign_input));
3856
#else
3857
0
        SSH_LOG(SSH_LOG_WARN, SK_NOT_SUPPORTED_MSG);
3858
0
        goto end;
3859
0
#endif /* WITH_FIDO2 */
3860
0
    } else {
3861
0
        sig = pki_do_sign(privkey,
3862
0
                          ssh_buffer_get(sign_input),
3863
0
                          ssh_buffer_get_len(sign_input),
3864
0
                          hash_type);
3865
0
    }
3866
3867
0
    if (sig == NULL) {
3868
0
        goto end;
3869
0
    }
3870
3871
    /* Convert the signature to blob */
3872
0
    rc = ssh_pki_export_signature_blob(sig, &sig_blob);
3873
0
    if (rc < 0) {
3874
0
        sig_blob = NULL;
3875
0
    }
3876
3877
0
end:
3878
0
    ssh_signature_free(sig);
3879
0
    SSH_BUFFER_FREE(sign_input);
3880
0
    SSH_STRING_FREE(session_id);
3881
3882
0
    return sig_blob;
3883
0
}
3884
3885
ssh_string ssh_pki_do_sign_agent(ssh_session session,
3886
                                 struct ssh_buffer_struct *buf,
3887
                                 const ssh_key pubkey)
3888
0
{
3889
0
    struct ssh_crypto_struct *crypto = NULL;
3890
0
    ssh_string session_id = NULL;
3891
0
    ssh_string sig_blob = NULL;
3892
0
    ssh_buffer sig_buf = NULL;
3893
0
    int rc;
3894
3895
0
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
3896
0
    if (crypto == NULL) {
3897
0
        return NULL;
3898
0
    }
3899
3900
    /* prepend session identifier */
3901
0
    session_id = ssh_string_new(crypto->session_id_len);
3902
0
    if (session_id == NULL) {
3903
0
        return NULL;
3904
0
    }
3905
0
    rc = ssh_string_fill(session_id, crypto->session_id, crypto->session_id_len);
3906
0
    if (rc < 0) {
3907
0
        SSH_STRING_FREE(session_id);
3908
0
        return NULL;
3909
0
    }
3910
3911
0
    sig_buf = ssh_buffer_new();
3912
0
    if (sig_buf == NULL) {
3913
0
        SSH_STRING_FREE(session_id);
3914
0
        return NULL;
3915
0
    }
3916
3917
0
    rc = ssh_buffer_add_ssh_string(sig_buf, session_id);
3918
0
    if (rc < 0) {
3919
0
        SSH_STRING_FREE(session_id);
3920
0
        SSH_BUFFER_FREE(sig_buf);
3921
0
        return NULL;
3922
0
    }
3923
0
    SSH_STRING_FREE(session_id);
3924
3925
    /* append out buffer */
3926
0
    if (ssh_buffer_add_buffer(sig_buf, buf) < 0) {
3927
0
        SSH_BUFFER_FREE(sig_buf);
3928
0
        return NULL;
3929
0
    }
3930
3931
    /* create signature */
3932
0
    sig_blob = ssh_agent_sign_data(session, pubkey, sig_buf);
3933
3934
0
    SSH_BUFFER_FREE(sig_buf);
3935
3936
0
    return sig_blob;
3937
0
}
3938
3939
#ifdef WITH_SERVER
3940
ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
3941
                                         const ssh_key privkey,
3942
                                         const enum ssh_digest_e digest)
3943
0
{
3944
0
    struct ssh_crypto_struct *crypto = NULL;
3945
0
    bool allowed;
3946
0
    ssh_signature sig = NULL;
3947
0
    ssh_string sig_blob = NULL;
3948
3949
0
    ssh_buffer sign_input = NULL;
3950
3951
0
    int rc;
3952
3953
0
    if (session == NULL || privkey == NULL || !ssh_key_is_private(privkey)) {
3954
0
        return NULL;
3955
0
    }
3956
3957
0
    allowed = ssh_key_size_allowed(session, privkey);
3958
0
    if (!allowed) {
3959
0
        ssh_set_error(session, SSH_FATAL, "The hostkey size too small");
3960
0
        return NULL;
3961
0
    }
3962
3963
0
    crypto = session->next_crypto ? session->next_crypto :
3964
0
                                    session->current_crypto;
3965
3966
0
    if (crypto->secret_hash == NULL){
3967
0
        ssh_set_error(session, SSH_FATAL, "Missing secret_hash");
3968
0
        return NULL;
3969
0
    }
3970
3971
    /* Fill the input */
3972
0
    sign_input = ssh_buffer_new();
3973
0
    if (sign_input == NULL) {
3974
0
        goto end;
3975
0
    }
3976
0
    ssh_buffer_set_secure(sign_input);
3977
3978
0
    rc = ssh_buffer_pack(sign_input,
3979
0
                         "P",
3980
0
                         crypto->digest_len,
3981
0
                         crypto->secret_hash);
3982
0
    if (rc != SSH_OK) {
3983
0
        goto end;
3984
0
    }
3985
3986
    /* Generate the signature */
3987
0
    sig = pki_do_sign(privkey,
3988
0
                      ssh_buffer_get(sign_input),
3989
0
                      ssh_buffer_get_len(sign_input),
3990
0
                      digest);
3991
0
    if (sig == NULL) {
3992
0
        goto end;
3993
0
    }
3994
3995
    /* Convert the signature to blob */
3996
0
    rc = ssh_pki_export_signature_blob(sig, &sig_blob);
3997
0
    if (rc < 0) {
3998
0
        sig_blob = NULL;
3999
0
    }
4000
4001
0
end:
4002
0
    ssh_signature_free(sig);
4003
0
    SSH_BUFFER_FREE(sign_input);
4004
4005
0
    return sig_blob;
4006
0
}
4007
#endif /* WITH_SERVER */
4008
4009
/**
4010
 * @}
4011
 */