blob: 0e146d4d6d2cdc073c0c17046f8694230382b035 [file] [log] [blame]
jsing@openbsd.org4270efa2018-02-14 16:03:32 +00001/* $OpenBSD: sshkey.c,v 1.61 2018/02/14 16:03:32 jsing Exp $ */
Damien Miller86687062014-07-02 15:28:02 +10002/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
5 * Copyright (c) 2010,2011 Damien Miller. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "includes.h"
29
Damien Miller86687062014-07-02 15:28:02 +100030#include <sys/types.h>
djm@openbsd.org56d1c832014-12-21 22:27:55 +000031#include <netinet/in.h>
Damien Miller86687062014-07-02 15:28:02 +100032
djm@openbsd.org54924b52015-01-14 10:46:28 +000033#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +100034#include <openssl/evp.h>
35#include <openssl/err.h>
36#include <openssl/pem.h>
djm@openbsd.org54924b52015-01-14 10:46:28 +000037#endif
Damien Miller86687062014-07-02 15:28:02 +100038
39#include "crypto_api.h"
40
41#include <errno.h>
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +000042#include <limits.h>
Damien Miller86687062014-07-02 15:28:02 +100043#include <stdio.h>
44#include <string.h>
Damien Millerd16bdd82014-12-22 10:18:09 +110045#include <resolv.h>
Damien Miller82b24822014-07-02 17:43:41 +100046#ifdef HAVE_UTIL_H
Damien Miller86687062014-07-02 15:28:02 +100047#include <util.h>
Damien Miller82b24822014-07-02 17:43:41 +100048#endif /* HAVE_UTIL_H */
Damien Miller86687062014-07-02 15:28:02 +100049
50#include "ssh2.h"
51#include "ssherr.h"
52#include "misc.h"
53#include "sshbuf.h"
Damien Miller86687062014-07-02 15:28:02 +100054#include "cipher.h"
55#include "digest.h"
56#define SSHKEY_INTERNAL
57#include "sshkey.h"
djm@openbsd.org1f729f02015-01-13 07:39:19 +000058#include "match.h"
Damien Miller86687062014-07-02 15:28:02 +100059
60/* openssh private key file format */
61#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
62#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
63#define MARK_BEGIN_LEN (sizeof(MARK_BEGIN) - 1)
64#define MARK_END_LEN (sizeof(MARK_END) - 1)
65#define KDFNAME "bcrypt"
66#define AUTH_MAGIC "openssh-key-v1"
67#define SALT_LEN 16
djm@openbsd.org0f345532017-08-12 06:42:52 +000068#define DEFAULT_CIPHERNAME "aes256-ctr"
Damien Miller86687062014-07-02 15:28:02 +100069#define DEFAULT_ROUNDS 16
70
71/* Version identification string for SSH v1 identity files. */
72#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n"
73
djm@openbsd.org60b18252015-01-26 02:59:11 +000074static int sshkey_from_blob_internal(struct sshbuf *buf,
Damien Miller86687062014-07-02 15:28:02 +100075 struct sshkey **keyp, int allow_cert);
76
77/* Supported key types */
78struct keytype {
79 const char *name;
80 const char *shortname;
81 int type;
82 int nid;
83 int cert;
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +000084 int sigonly;
Damien Miller86687062014-07-02 15:28:02 +100085};
86static const struct keytype keytypes[] = {
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +000087 { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 },
Damien Miller86687062014-07-02 15:28:02 +100088 { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +000089 KEY_ED25519_CERT, 0, 1, 0 },
Damien Miller86687062014-07-02 15:28:02 +100090#ifdef WITH_OPENSSL
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +000091 { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 },
92 { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 },
93 { "rsa-sha2-512", "RSA", KEY_RSA, 0, 0, 1 },
94 { "ssh-dss", "DSA", KEY_DSA, 0, 0, 0 },
Damien Miller86687062014-07-02 15:28:02 +100095# ifdef OPENSSL_HAS_ECC
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +000096 { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 },
97 { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0, 0 },
Damien Miller86687062014-07-02 15:28:02 +100098# ifdef OPENSSL_HAS_NISTP521
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +000099 { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0, 0 },
Damien Miller86687062014-07-02 15:28:02 +1000100# endif /* OPENSSL_HAS_NISTP521 */
101# endif /* OPENSSL_HAS_ECC */
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000102 { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1, 0 },
103 { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1, 0 },
Damien Miller86687062014-07-02 15:28:02 +1000104# ifdef OPENSSL_HAS_ECC
105 { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT",
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000106 KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 },
Damien Miller86687062014-07-02 15:28:02 +1000107 { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000108 KEY_ECDSA_CERT, NID_secp384r1, 1, 0 },
Damien Miller86687062014-07-02 15:28:02 +1000109# ifdef OPENSSL_HAS_NISTP521
110 { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000111 KEY_ECDSA_CERT, NID_secp521r1, 1, 0 },
Damien Miller86687062014-07-02 15:28:02 +1000112# endif /* OPENSSL_HAS_NISTP521 */
113# endif /* OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +1000114#endif /* WITH_OPENSSL */
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000115 { NULL, NULL, -1, -1, 0, 0 }
Damien Miller86687062014-07-02 15:28:02 +1000116};
117
118const char *
119sshkey_type(const struct sshkey *k)
120{
121 const struct keytype *kt;
122
123 for (kt = keytypes; kt->type != -1; kt++) {
124 if (kt->type == k->type)
125 return kt->shortname;
126 }
127 return "unknown";
128}
129
130static const char *
131sshkey_ssh_name_from_type_nid(int type, int nid)
132{
133 const struct keytype *kt;
134
135 for (kt = keytypes; kt->type != -1; kt++) {
136 if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
137 return kt->name;
138 }
139 return "ssh-unknown";
140}
141
142int
143sshkey_type_is_cert(int type)
144{
145 const struct keytype *kt;
146
147 for (kt = keytypes; kt->type != -1; kt++) {
148 if (kt->type == type)
149 return kt->cert;
150 }
151 return 0;
152}
153
154const char *
155sshkey_ssh_name(const struct sshkey *k)
156{
157 return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
158}
159
160const char *
161sshkey_ssh_name_plain(const struct sshkey *k)
162{
163 return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type),
164 k->ecdsa_nid);
165}
166
167int
168sshkey_type_from_name(const char *name)
169{
170 const struct keytype *kt;
171
172 for (kt = keytypes; kt->type != -1; kt++) {
173 /* Only allow shortname matches for plain key types */
174 if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
175 (!kt->cert && strcasecmp(kt->shortname, name) == 0))
176 return kt->type;
177 }
178 return KEY_UNSPEC;
179}
180
181int
182sshkey_ecdsa_nid_from_name(const char *name)
183{
184 const struct keytype *kt;
185
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +0000186 for (kt = keytypes; kt->type != -1; kt++) {
187 if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT)
188 continue;
189 if (kt->name != NULL && strcmp(name, kt->name) == 0)
190 return kt->nid;
191 }
Damien Miller86687062014-07-02 15:28:02 +1000192 return -1;
193}
194
195char *
djm@openbsd.org183ba552017-03-10 04:07:20 +0000196sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
Damien Miller86687062014-07-02 15:28:02 +1000197{
198 char *tmp, *ret = NULL;
199 size_t nlen, rlen = 0;
200 const struct keytype *kt;
201
202 for (kt = keytypes; kt->type != -1; kt++) {
djm@openbsd.org183ba552017-03-10 04:07:20 +0000203 if (kt->name == NULL)
204 continue;
205 if (!include_sigonly && kt->sigonly)
Damien Miller86687062014-07-02 15:28:02 +1000206 continue;
207 if ((certs_only && !kt->cert) || (plain_only && kt->cert))
208 continue;
209 if (ret != NULL)
djm@openbsd.org130f5df2016-09-12 23:31:27 +0000210 ret[rlen++] = sep;
Damien Miller86687062014-07-02 15:28:02 +1000211 nlen = strlen(kt->name);
212 if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
213 free(ret);
214 return NULL;
215 }
216 ret = tmp;
217 memcpy(ret + rlen, kt->name, nlen + 1);
218 rlen += nlen;
219 }
220 return ret;
221}
222
223int
djm@openbsd.org1f729f02015-01-13 07:39:19 +0000224sshkey_names_valid2(const char *names, int allow_wildcard)
Damien Miller86687062014-07-02 15:28:02 +1000225{
226 char *s, *cp, *p;
djm@openbsd.org1f729f02015-01-13 07:39:19 +0000227 const struct keytype *kt;
228 int type;
Damien Miller86687062014-07-02 15:28:02 +1000229
230 if (names == NULL || strcmp(names, "") == 0)
231 return 0;
232 if ((s = cp = strdup(names)) == NULL)
233 return 0;
234 for ((p = strsep(&cp, ",")); p && *p != '\0';
235 (p = strsep(&cp, ","))) {
djm@openbsd.org1f729f02015-01-13 07:39:19 +0000236 type = sshkey_type_from_name(p);
djm@openbsd.org1f729f02015-01-13 07:39:19 +0000237 if (type == KEY_UNSPEC) {
238 if (allow_wildcard) {
239 /*
240 * Try matching key types against the string.
241 * If any has a positive or negative match then
242 * the component is accepted.
243 */
244 for (kt = keytypes; kt->type != -1; kt++) {
djm@openbsd.org1f729f02015-01-13 07:39:19 +0000245 if (match_pattern_list(kt->name,
djm@openbsd.orge661a862015-05-04 06:10:48 +0000246 p, 0) != 0)
djm@openbsd.org1f729f02015-01-13 07:39:19 +0000247 break;
248 }
249 if (kt->type != -1)
250 continue;
251 }
Damien Miller86687062014-07-02 15:28:02 +1000252 free(s);
253 return 0;
254 }
255 }
256 free(s);
257 return 1;
258}
259
260u_int
261sshkey_size(const struct sshkey *k)
262{
263 switch (k->type) {
264#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000265 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +1000266 case KEY_RSA_CERT:
267 return BN_num_bits(k->rsa->n);
268 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +1000269 case KEY_DSA_CERT:
270 return BN_num_bits(k->dsa->p);
271 case KEY_ECDSA:
272 case KEY_ECDSA_CERT:
273 return sshkey_curve_nid_to_bits(k->ecdsa_nid);
274#endif /* WITH_OPENSSL */
275 case KEY_ED25519:
276 case KEY_ED25519_CERT:
277 return 256; /* XXX */
278 }
279 return 0;
280}
281
Damien Miller86687062014-07-02 15:28:02 +1000282static int
283sshkey_type_is_valid_ca(int type)
284{
285 switch (type) {
286 case KEY_RSA:
287 case KEY_DSA:
288 case KEY_ECDSA:
289 case KEY_ED25519:
290 return 1;
291 default:
292 return 0;
293 }
294}
295
296int
297sshkey_is_cert(const struct sshkey *k)
298{
299 if (k == NULL)
300 return 0;
301 return sshkey_type_is_cert(k->type);
302}
303
304/* Return the cert-less equivalent to a certified key type */
305int
306sshkey_type_plain(int type)
307{
308 switch (type) {
Damien Miller86687062014-07-02 15:28:02 +1000309 case KEY_RSA_CERT:
310 return KEY_RSA;
Damien Miller86687062014-07-02 15:28:02 +1000311 case KEY_DSA_CERT:
312 return KEY_DSA;
313 case KEY_ECDSA_CERT:
314 return KEY_ECDSA;
315 case KEY_ED25519_CERT:
316 return KEY_ED25519;
317 default:
318 return type;
319 }
320}
321
322#ifdef WITH_OPENSSL
323/* XXX: these are really begging for a table-driven approach */
324int
325sshkey_curve_name_to_nid(const char *name)
326{
327 if (strcmp(name, "nistp256") == 0)
328 return NID_X9_62_prime256v1;
329 else if (strcmp(name, "nistp384") == 0)
330 return NID_secp384r1;
331# ifdef OPENSSL_HAS_NISTP521
332 else if (strcmp(name, "nistp521") == 0)
333 return NID_secp521r1;
334# endif /* OPENSSL_HAS_NISTP521 */
335 else
336 return -1;
337}
338
339u_int
340sshkey_curve_nid_to_bits(int nid)
341{
342 switch (nid) {
343 case NID_X9_62_prime256v1:
344 return 256;
345 case NID_secp384r1:
346 return 384;
347# ifdef OPENSSL_HAS_NISTP521
348 case NID_secp521r1:
349 return 521;
350# endif /* OPENSSL_HAS_NISTP521 */
351 default:
352 return 0;
353 }
354}
355
356int
357sshkey_ecdsa_bits_to_nid(int bits)
358{
359 switch (bits) {
360 case 256:
361 return NID_X9_62_prime256v1;
362 case 384:
363 return NID_secp384r1;
364# ifdef OPENSSL_HAS_NISTP521
365 case 521:
366 return NID_secp521r1;
367# endif /* OPENSSL_HAS_NISTP521 */
368 default:
369 return -1;
370 }
371}
372
373const char *
374sshkey_curve_nid_to_name(int nid)
375{
376 switch (nid) {
377 case NID_X9_62_prime256v1:
378 return "nistp256";
379 case NID_secp384r1:
380 return "nistp384";
381# ifdef OPENSSL_HAS_NISTP521
382 case NID_secp521r1:
383 return "nistp521";
384# endif /* OPENSSL_HAS_NISTP521 */
385 default:
386 return NULL;
387 }
388}
389
390int
391sshkey_ec_nid_to_hash_alg(int nid)
392{
393 int kbits = sshkey_curve_nid_to_bits(nid);
394
395 if (kbits <= 0)
396 return -1;
397
398 /* RFC5656 section 6.2.1 */
399 if (kbits <= 256)
400 return SSH_DIGEST_SHA256;
401 else if (kbits <= 384)
402 return SSH_DIGEST_SHA384;
403 else
404 return SSH_DIGEST_SHA512;
405}
406#endif /* WITH_OPENSSL */
407
408static void
409cert_free(struct sshkey_cert *cert)
410{
411 u_int i;
412
413 if (cert == NULL)
414 return;
mmcc@openbsd.org52d70782015-12-11 04:21:11 +0000415 sshbuf_free(cert->certblob);
416 sshbuf_free(cert->critical);
417 sshbuf_free(cert->extensions);
mmcc@openbsd.orgd59ce082015-12-10 17:08:40 +0000418 free(cert->key_id);
Damien Miller86687062014-07-02 15:28:02 +1000419 for (i = 0; i < cert->nprincipals; i++)
420 free(cert->principals[i]);
mmcc@openbsd.orgd59ce082015-12-10 17:08:40 +0000421 free(cert->principals);
mmcc@openbsd.org89540b62015-12-11 02:31:47 +0000422 sshkey_free(cert->signature_key);
jsing@openbsd.org4270efa2018-02-14 16:03:32 +0000423 freezero(cert, sizeof(*cert));
Damien Miller86687062014-07-02 15:28:02 +1000424}
425
426static struct sshkey_cert *
427cert_new(void)
428{
429 struct sshkey_cert *cert;
430
431 if ((cert = calloc(1, sizeof(*cert))) == NULL)
432 return NULL;
433 if ((cert->certblob = sshbuf_new()) == NULL ||
434 (cert->critical = sshbuf_new()) == NULL ||
435 (cert->extensions = sshbuf_new()) == NULL) {
436 cert_free(cert);
437 return NULL;
438 }
439 cert->key_id = NULL;
440 cert->principals = NULL;
441 cert->signature_key = NULL;
442 return cert;
443}
444
445struct sshkey *
446sshkey_new(int type)
447{
448 struct sshkey *k;
449#ifdef WITH_OPENSSL
450 RSA *rsa;
451 DSA *dsa;
452#endif /* WITH_OPENSSL */
453
454 if ((k = calloc(1, sizeof(*k))) == NULL)
455 return NULL;
456 k->type = type;
457 k->ecdsa = NULL;
458 k->ecdsa_nid = -1;
459 k->dsa = NULL;
460 k->rsa = NULL;
461 k->cert = NULL;
462 k->ed25519_sk = NULL;
463 k->ed25519_pk = NULL;
464 switch (k->type) {
465#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000466 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +1000467 case KEY_RSA_CERT:
468 if ((rsa = RSA_new()) == NULL ||
469 (rsa->n = BN_new()) == NULL ||
470 (rsa->e = BN_new()) == NULL) {
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000471 RSA_free(rsa);
Damien Miller86687062014-07-02 15:28:02 +1000472 free(k);
473 return NULL;
474 }
475 k->rsa = rsa;
476 break;
477 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +1000478 case KEY_DSA_CERT:
479 if ((dsa = DSA_new()) == NULL ||
480 (dsa->p = BN_new()) == NULL ||
481 (dsa->q = BN_new()) == NULL ||
482 (dsa->g = BN_new()) == NULL ||
483 (dsa->pub_key = BN_new()) == NULL) {
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000484 DSA_free(dsa);
Damien Miller86687062014-07-02 15:28:02 +1000485 free(k);
486 return NULL;
487 }
488 k->dsa = dsa;
489 break;
490 case KEY_ECDSA:
491 case KEY_ECDSA_CERT:
492 /* Cannot do anything until we know the group */
493 break;
494#endif /* WITH_OPENSSL */
495 case KEY_ED25519:
496 case KEY_ED25519_CERT:
497 /* no need to prealloc */
498 break;
499 case KEY_UNSPEC:
500 break;
501 default:
502 free(k);
503 return NULL;
Damien Miller86687062014-07-02 15:28:02 +1000504 }
505
506 if (sshkey_is_cert(k)) {
507 if ((k->cert = cert_new()) == NULL) {
508 sshkey_free(k);
509 return NULL;
510 }
511 }
512
513 return k;
514}
515
516int
517sshkey_add_private(struct sshkey *k)
518{
519 switch (k->type) {
520#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000521 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +1000522 case KEY_RSA_CERT:
523#define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL)
524 if (bn_maybe_alloc_failed(k->rsa->d) ||
525 bn_maybe_alloc_failed(k->rsa->iqmp) ||
526 bn_maybe_alloc_failed(k->rsa->q) ||
527 bn_maybe_alloc_failed(k->rsa->p) ||
528 bn_maybe_alloc_failed(k->rsa->dmq1) ||
529 bn_maybe_alloc_failed(k->rsa->dmp1))
530 return SSH_ERR_ALLOC_FAIL;
531 break;
532 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +1000533 case KEY_DSA_CERT:
534 if (bn_maybe_alloc_failed(k->dsa->priv_key))
535 return SSH_ERR_ALLOC_FAIL;
536 break;
537#undef bn_maybe_alloc_failed
538 case KEY_ECDSA:
539 case KEY_ECDSA_CERT:
540 /* Cannot do anything until we know the group */
541 break;
542#endif /* WITH_OPENSSL */
543 case KEY_ED25519:
544 case KEY_ED25519_CERT:
545 /* no need to prealloc */
546 break;
547 case KEY_UNSPEC:
548 break;
549 default:
550 return SSH_ERR_INVALID_ARGUMENT;
551 }
552 return 0;
553}
554
555struct sshkey *
556sshkey_new_private(int type)
557{
558 struct sshkey *k = sshkey_new(type);
559
560 if (k == NULL)
561 return NULL;
562 if (sshkey_add_private(k) != 0) {
563 sshkey_free(k);
564 return NULL;
565 }
566 return k;
567}
568
569void
570sshkey_free(struct sshkey *k)
571{
572 if (k == NULL)
573 return;
574 switch (k->type) {
575#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000576 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +1000577 case KEY_RSA_CERT:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000578 RSA_free(k->rsa);
Damien Miller86687062014-07-02 15:28:02 +1000579 k->rsa = NULL;
580 break;
581 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +1000582 case KEY_DSA_CERT:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000583 DSA_free(k->dsa);
Damien Miller86687062014-07-02 15:28:02 +1000584 k->dsa = NULL;
585 break;
586# ifdef OPENSSL_HAS_ECC
587 case KEY_ECDSA:
588 case KEY_ECDSA_CERT:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000589 EC_KEY_free(k->ecdsa);
Damien Miller86687062014-07-02 15:28:02 +1000590 k->ecdsa = NULL;
591 break;
592# endif /* OPENSSL_HAS_ECC */
593#endif /* WITH_OPENSSL */
594 case KEY_ED25519:
595 case KEY_ED25519_CERT:
jsing@openbsd.org4270efa2018-02-14 16:03:32 +0000596 freezero(k->ed25519_pk, ED25519_PK_SZ);
597 k->ed25519_pk = NULL;
598 freezero(k->ed25519_sk, ED25519_SK_SZ);
599 k->ed25519_sk = NULL;
Damien Miller86687062014-07-02 15:28:02 +1000600 break;
601 case KEY_UNSPEC:
602 break;
603 default:
604 break;
605 }
606 if (sshkey_is_cert(k))
607 cert_free(k->cert);
jsing@openbsd.org4270efa2018-02-14 16:03:32 +0000608 freezero(k, sizeof(*k));
Damien Miller86687062014-07-02 15:28:02 +1000609}
610
611static int
612cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
613{
614 if (a == NULL && b == NULL)
615 return 1;
616 if (a == NULL || b == NULL)
617 return 0;
618 if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob))
619 return 0;
620 if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob),
621 sshbuf_len(a->certblob)) != 0)
622 return 0;
623 return 1;
624}
625
626/*
627 * Compare public portions of key only, allowing comparisons between
628 * certificates and plain keys too.
629 */
630int
631sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
632{
Darren Tucker948a1772014-07-22 01:07:11 +1000633#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
Damien Miller86687062014-07-02 15:28:02 +1000634 BN_CTX *bnctx;
Darren Tucker948a1772014-07-22 01:07:11 +1000635#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +1000636
637 if (a == NULL || b == NULL ||
638 sshkey_type_plain(a->type) != sshkey_type_plain(b->type))
639 return 0;
640
641 switch (a->type) {
642#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000643 case KEY_RSA_CERT:
644 case KEY_RSA:
645 return a->rsa != NULL && b->rsa != NULL &&
646 BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
647 BN_cmp(a->rsa->n, b->rsa->n) == 0;
Damien Miller86687062014-07-02 15:28:02 +1000648 case KEY_DSA_CERT:
649 case KEY_DSA:
650 return a->dsa != NULL && b->dsa != NULL &&
651 BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
652 BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
653 BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
654 BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
655# ifdef OPENSSL_HAS_ECC
656 case KEY_ECDSA_CERT:
657 case KEY_ECDSA:
658 if (a->ecdsa == NULL || b->ecdsa == NULL ||
659 EC_KEY_get0_public_key(a->ecdsa) == NULL ||
660 EC_KEY_get0_public_key(b->ecdsa) == NULL)
661 return 0;
662 if ((bnctx = BN_CTX_new()) == NULL)
663 return 0;
664 if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
665 EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
666 EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
667 EC_KEY_get0_public_key(a->ecdsa),
668 EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
669 BN_CTX_free(bnctx);
670 return 0;
671 }
672 BN_CTX_free(bnctx);
673 return 1;
674# endif /* OPENSSL_HAS_ECC */
675#endif /* WITH_OPENSSL */
676 case KEY_ED25519:
677 case KEY_ED25519_CERT:
678 return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
679 memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
680 default:
681 return 0;
682 }
683 /* NOTREACHED */
684}
685
686int
687sshkey_equal(const struct sshkey *a, const struct sshkey *b)
688{
689 if (a == NULL || b == NULL || a->type != b->type)
690 return 0;
691 if (sshkey_is_cert(a)) {
692 if (!cert_compare(a->cert, b->cert))
693 return 0;
694 }
695 return sshkey_equal_public(a, b);
696}
697
698static int
699to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
700{
701 int type, ret = SSH_ERR_INTERNAL_ERROR;
702 const char *typename;
703
704 if (key == NULL)
705 return SSH_ERR_INVALID_ARGUMENT;
706
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +0000707 if (sshkey_is_cert(key)) {
708 if (key->cert == NULL)
709 return SSH_ERR_EXPECTED_CERT;
710 if (sshbuf_len(key->cert->certblob) == 0)
711 return SSH_ERR_KEY_LACKS_CERTBLOB;
712 }
Damien Miller86687062014-07-02 15:28:02 +1000713 type = force_plain ? sshkey_type_plain(key->type) : key->type;
714 typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
715
716 switch (type) {
717#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000718 case KEY_DSA_CERT:
719 case KEY_ECDSA_CERT:
720 case KEY_RSA_CERT:
721#endif /* WITH_OPENSSL */
722 case KEY_ED25519_CERT:
723 /* Use the existing blob */
724 /* XXX modified flag? */
725 if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
726 return ret;
727 break;
728#ifdef WITH_OPENSSL
729 case KEY_DSA:
730 if (key->dsa == NULL)
731 return SSH_ERR_INVALID_ARGUMENT;
732 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
733 (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
734 (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
735 (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
736 (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0)
737 return ret;
738 break;
Darren Tuckerd1a04212014-07-19 07:23:55 +1000739# ifdef OPENSSL_HAS_ECC
Damien Miller86687062014-07-02 15:28:02 +1000740 case KEY_ECDSA:
741 if (key->ecdsa == NULL)
742 return SSH_ERR_INVALID_ARGUMENT;
743 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
744 (ret = sshbuf_put_cstring(b,
745 sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
746 (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0)
747 return ret;
748 break;
Darren Tuckerd1a04212014-07-19 07:23:55 +1000749# endif
Damien Miller86687062014-07-02 15:28:02 +1000750 case KEY_RSA:
751 if (key->rsa == NULL)
752 return SSH_ERR_INVALID_ARGUMENT;
753 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
754 (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
755 (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0)
756 return ret;
757 break;
758#endif /* WITH_OPENSSL */
759 case KEY_ED25519:
760 if (key->ed25519_pk == NULL)
761 return SSH_ERR_INVALID_ARGUMENT;
762 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
763 (ret = sshbuf_put_string(b,
764 key->ed25519_pk, ED25519_PK_SZ)) != 0)
765 return ret;
766 break;
767 default:
768 return SSH_ERR_KEY_TYPE_UNKNOWN;
769 }
770 return 0;
771}
772
773int
djm@openbsd.org60b18252015-01-26 02:59:11 +0000774sshkey_putb(const struct sshkey *key, struct sshbuf *b)
Damien Miller86687062014-07-02 15:28:02 +1000775{
776 return to_blob_buf(key, b, 0);
777}
778
779int
djm@openbsd.org60b18252015-01-26 02:59:11 +0000780sshkey_puts(const struct sshkey *key, struct sshbuf *b)
781{
782 struct sshbuf *tmp;
783 int r;
784
785 if ((tmp = sshbuf_new()) == NULL)
786 return SSH_ERR_ALLOC_FAIL;
787 r = to_blob_buf(key, tmp, 0);
788 if (r == 0)
789 r = sshbuf_put_stringb(b, tmp);
790 sshbuf_free(tmp);
791 return r;
792}
793
794int
795sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
Damien Miller86687062014-07-02 15:28:02 +1000796{
797 return to_blob_buf(key, b, 1);
798}
799
800static int
801to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
802{
803 int ret = SSH_ERR_INTERNAL_ERROR;
804 size_t len;
805 struct sshbuf *b = NULL;
806
807 if (lenp != NULL)
808 *lenp = 0;
809 if (blobp != NULL)
810 *blobp = NULL;
811 if ((b = sshbuf_new()) == NULL)
812 return SSH_ERR_ALLOC_FAIL;
813 if ((ret = to_blob_buf(key, b, force_plain)) != 0)
814 goto out;
815 len = sshbuf_len(b);
816 if (lenp != NULL)
817 *lenp = len;
818 if (blobp != NULL) {
819 if ((*blobp = malloc(len)) == NULL) {
820 ret = SSH_ERR_ALLOC_FAIL;
821 goto out;
822 }
823 memcpy(*blobp, sshbuf_ptr(b), len);
824 }
825 ret = 0;
826 out:
827 sshbuf_free(b);
828 return ret;
829}
830
831int
832sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
833{
834 return to_blob(key, blobp, lenp, 0);
835}
836
837int
838sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
839{
840 return to_blob(key, blobp, lenp, 1);
841}
842
843int
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000844sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
Damien Miller86687062014-07-02 15:28:02 +1000845 u_char **retp, size_t *lenp)
846{
847 u_char *blob = NULL, *ret = NULL;
848 size_t blob_len = 0;
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000849 int r = SSH_ERR_INTERNAL_ERROR;
Damien Miller86687062014-07-02 15:28:02 +1000850
851 if (retp != NULL)
852 *retp = NULL;
853 if (lenp != NULL)
854 *lenp = 0;
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000855 if (ssh_digest_bytes(dgst_alg) == 0) {
Damien Miller86687062014-07-02 15:28:02 +1000856 r = SSH_ERR_INVALID_ARGUMENT;
857 goto out;
858 }
djm@openbsd.org873d3e72017-04-30 23:18:44 +0000859 if ((r = to_blob(k, &blob, &blob_len, 1)) != 0)
Damien Miller86687062014-07-02 15:28:02 +1000860 goto out;
861 if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
862 r = SSH_ERR_ALLOC_FAIL;
863 goto out;
864 }
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000865 if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
Damien Miller86687062014-07-02 15:28:02 +1000866 ret, SSH_DIGEST_MAX_LENGTH)) != 0)
867 goto out;
868 /* success */
869 if (retp != NULL) {
870 *retp = ret;
871 ret = NULL;
872 }
873 if (lenp != NULL)
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000874 *lenp = ssh_digest_bytes(dgst_alg);
Damien Miller86687062014-07-02 15:28:02 +1000875 r = 0;
876 out:
877 free(ret);
878 if (blob != NULL) {
879 explicit_bzero(blob, blob_len);
880 free(blob);
881 }
882 return r;
883}
884
885static char *
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000886fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
Damien Miller86687062014-07-02 15:28:02 +1000887{
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000888 char *ret;
889 size_t plen = strlen(alg) + 1;
890 size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
891 int r;
Damien Miller86687062014-07-02 15:28:02 +1000892
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000893 if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
Damien Miller86687062014-07-02 15:28:02 +1000894 return NULL;
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000895 strlcpy(ret, alg, rlen);
896 strlcat(ret, ":", rlen);
897 if (dgst_raw_len == 0)
898 return ret;
899 if ((r = b64_ntop(dgst_raw, dgst_raw_len,
900 ret + plen, rlen - plen)) == -1) {
jsing@openbsd.org4270efa2018-02-14 16:03:32 +0000901 freezero(ret, rlen);
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000902 return NULL;
Damien Miller86687062014-07-02 15:28:02 +1000903 }
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000904 /* Trim padding characters from end */
905 ret[strcspn(ret, "=")] = '\0';
906 return ret;
907}
Damien Miller86687062014-07-02 15:28:02 +1000908
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000909static char *
910fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
911{
912 char *retval, hex[5];
913 size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
914
915 if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
916 return NULL;
917 strlcpy(retval, alg, rlen);
918 strlcat(retval, ":", rlen);
919 for (i = 0; i < dgst_raw_len; i++) {
920 snprintf(hex, sizeof(hex), "%s%02x",
921 i > 0 ? ":" : "", dgst_raw[i]);
922 strlcat(retval, hex, rlen);
923 }
Damien Miller86687062014-07-02 15:28:02 +1000924 return retval;
925}
926
927static char *
928fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
929{
930 char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
931 char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
932 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
933 u_int i, j = 0, rounds, seed = 1;
934 char *retval;
935
936 rounds = (dgst_raw_len / 2) + 1;
937 if ((retval = calloc(rounds, 6)) == NULL)
938 return NULL;
939 retval[j++] = 'x';
940 for (i = 0; i < rounds; i++) {
941 u_int idx0, idx1, idx2, idx3, idx4;
942 if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
943 idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
944 seed) % 6;
945 idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
946 idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
947 (seed / 6)) % 6;
948 retval[j++] = vowels[idx0];
949 retval[j++] = consonants[idx1];
950 retval[j++] = vowels[idx2];
951 if ((i + 1) < rounds) {
952 idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
953 idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
954 retval[j++] = consonants[idx3];
955 retval[j++] = '-';
956 retval[j++] = consonants[idx4];
957 seed = ((seed * 5) +
958 ((((u_int)(dgst_raw[2 * i])) * 7) +
959 ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
960 }
961 } else {
962 idx0 = seed % 6;
963 idx1 = 16;
964 idx2 = seed / 6;
965 retval[j++] = vowels[idx0];
966 retval[j++] = consonants[idx1];
967 retval[j++] = vowels[idx2];
968 }
969 }
970 retval[j++] = 'x';
971 retval[j++] = '\0';
972 return retval;
973}
974
975/*
976 * Draw an ASCII-Art representing the fingerprint so human brain can
977 * profit from its built-in pattern recognition ability.
978 * This technique is called "random art" and can be found in some
979 * scientific publications like this original paper:
980 *
981 * "Hash Visualization: a New Technique to improve Real-World Security",
982 * Perrig A. and Song D., 1999, International Workshop on Cryptographic
983 * Techniques and E-Commerce (CrypTEC '99)
984 * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
985 *
986 * The subject came up in a talk by Dan Kaminsky, too.
987 *
988 * If you see the picture is different, the key is different.
989 * If the picture looks the same, you still know nothing.
990 *
991 * The algorithm used here is a worm crawling over a discrete plane,
992 * leaving a trace (augmenting the field) everywhere it goes.
993 * Movement is taken from dgst_raw 2bit-wise. Bumping into walls
994 * makes the respective movement vector be ignored for this turn.
995 * Graphs are not unambiguous, because circles in graphs can be
996 * walked in either direction.
997 */
998
999/*
1000 * Field sizes for the random art. Have to be odd, so the starting point
1001 * can be in the exact middle of the picture, and FLDBASE should be >=8 .
1002 * Else pictures would be too dense, and drawing the frame would
1003 * fail, too, because the key type would not fit in anymore.
1004 */
1005#define FLDBASE 8
1006#define FLDSIZE_Y (FLDBASE + 1)
1007#define FLDSIZE_X (FLDBASE * 2 + 1)
1008static char *
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001009fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
Damien Miller86687062014-07-02 15:28:02 +10001010 const struct sshkey *k)
1011{
1012 /*
1013 * Chars to be used after each other every time the worm
1014 * intersects with itself. Matter of taste.
1015 */
1016 char *augmentation_string = " .o+=*BOX@%&#/^SE";
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001017 char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
Damien Miller86687062014-07-02 15:28:02 +10001018 u_char field[FLDSIZE_X][FLDSIZE_Y];
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001019 size_t i, tlen, hlen;
Damien Miller86687062014-07-02 15:28:02 +10001020 u_int b;
Damien Miller61e28e52014-07-03 21:22:22 +10001021 int x, y, r;
Damien Miller86687062014-07-02 15:28:02 +10001022 size_t len = strlen(augmentation_string) - 1;
1023
1024 if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
1025 return NULL;
1026
1027 /* initialize field */
1028 memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
1029 x = FLDSIZE_X / 2;
1030 y = FLDSIZE_Y / 2;
1031
1032 /* process raw key */
1033 for (i = 0; i < dgst_raw_len; i++) {
1034 int input;
1035 /* each byte conveys four 2-bit move commands */
1036 input = dgst_raw[i];
1037 for (b = 0; b < 4; b++) {
1038 /* evaluate 2 bit, rest is shifted later */
1039 x += (input & 0x1) ? 1 : -1;
1040 y += (input & 0x2) ? 1 : -1;
1041
1042 /* assure we are still in bounds */
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +00001043 x = MAXIMUM(x, 0);
1044 y = MAXIMUM(y, 0);
1045 x = MINIMUM(x, FLDSIZE_X - 1);
1046 y = MINIMUM(y, FLDSIZE_Y - 1);
Damien Miller86687062014-07-02 15:28:02 +10001047
1048 /* augment the field */
1049 if (field[x][y] < len - 2)
1050 field[x][y]++;
1051 input = input >> 2;
1052 }
1053 }
1054
1055 /* mark starting point and end point*/
1056 field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
1057 field[x][y] = len;
1058
Damien Miller61e28e52014-07-03 21:22:22 +10001059 /* assemble title */
1060 r = snprintf(title, sizeof(title), "[%s %u]",
1061 sshkey_type(k), sshkey_size(k));
1062 /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
1063 if (r < 0 || r > (int)sizeof(title))
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001064 r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
1065 tlen = (r <= 0) ? 0 : strlen(title);
1066
1067 /* assemble hash ID. */
1068 r = snprintf(hash, sizeof(hash), "[%s]", alg);
1069 hlen = (r <= 0) ? 0 : strlen(hash);
Damien Miller86687062014-07-02 15:28:02 +10001070
1071 /* output upper border */
Damien Miller61e28e52014-07-03 21:22:22 +10001072 p = retval;
1073 *p++ = '+';
1074 for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
1075 *p++ = '-';
1076 memcpy(p, title, tlen);
1077 p += tlen;
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001078 for (i += tlen; i < FLDSIZE_X; i++)
Damien Miller86687062014-07-02 15:28:02 +10001079 *p++ = '-';
1080 *p++ = '+';
1081 *p++ = '\n';
1082
1083 /* output content */
1084 for (y = 0; y < FLDSIZE_Y; y++) {
1085 *p++ = '|';
1086 for (x = 0; x < FLDSIZE_X; x++)
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +00001087 *p++ = augmentation_string[MINIMUM(field[x][y], len)];
Damien Miller86687062014-07-02 15:28:02 +10001088 *p++ = '|';
1089 *p++ = '\n';
1090 }
1091
1092 /* output lower border */
1093 *p++ = '+';
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001094 for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
1095 *p++ = '-';
1096 memcpy(p, hash, hlen);
1097 p += hlen;
1098 for (i += hlen; i < FLDSIZE_X; i++)
Damien Miller86687062014-07-02 15:28:02 +10001099 *p++ = '-';
1100 *p++ = '+';
1101
1102 return retval;
1103}
1104
1105char *
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001106sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
Damien Miller86687062014-07-02 15:28:02 +10001107 enum sshkey_fp_rep dgst_rep)
1108{
1109 char *retval = NULL;
1110 u_char *dgst_raw;
1111 size_t dgst_raw_len;
1112
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001113 if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001114 return NULL;
1115 switch (dgst_rep) {
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001116 case SSH_FP_DEFAULT:
1117 if (dgst_alg == SSH_DIGEST_MD5) {
1118 retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1119 dgst_raw, dgst_raw_len);
1120 } else {
1121 retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1122 dgst_raw, dgst_raw_len);
1123 }
1124 break;
Damien Miller86687062014-07-02 15:28:02 +10001125 case SSH_FP_HEX:
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001126 retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1127 dgst_raw, dgst_raw_len);
1128 break;
1129 case SSH_FP_BASE64:
1130 retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1131 dgst_raw, dgst_raw_len);
Damien Miller86687062014-07-02 15:28:02 +10001132 break;
1133 case SSH_FP_BUBBLEBABBLE:
1134 retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
1135 break;
1136 case SSH_FP_RANDOMART:
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001137 retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
1138 dgst_raw, dgst_raw_len, k);
Damien Miller86687062014-07-02 15:28:02 +10001139 break;
1140 default:
1141 explicit_bzero(dgst_raw, dgst_raw_len);
1142 free(dgst_raw);
1143 return NULL;
1144 }
1145 explicit_bzero(dgst_raw, dgst_raw_len);
1146 free(dgst_raw);
1147 return retval;
1148}
1149
Damien Miller86687062014-07-02 15:28:02 +10001150
1151/* returns 0 ok, and < 0 error */
1152int
1153sshkey_read(struct sshkey *ret, char **cpp)
1154{
1155 struct sshkey *k;
1156 int retval = SSH_ERR_INVALID_FORMAT;
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001157 char *ep, *cp, *space;
Damien Miller86687062014-07-02 15:28:02 +10001158 int r, type, curve_nid = -1;
1159 struct sshbuf *blob;
Damien Miller86687062014-07-02 15:28:02 +10001160
dtucker@openbsd.org7fadbb62017-03-10 03:48:57 +00001161 if (ret == NULL)
1162 return SSH_ERR_INVALID_ARGUMENT;
1163
Damien Miller86687062014-07-02 15:28:02 +10001164 cp = *cpp;
1165
1166 switch (ret->type) {
Damien Miller86687062014-07-02 15:28:02 +10001167 case KEY_UNSPEC:
1168 case KEY_RSA:
1169 case KEY_DSA:
1170 case KEY_ECDSA:
1171 case KEY_ED25519:
Damien Miller86687062014-07-02 15:28:02 +10001172 case KEY_DSA_CERT:
1173 case KEY_ECDSA_CERT:
1174 case KEY_RSA_CERT:
1175 case KEY_ED25519_CERT:
1176 space = strchr(cp, ' ');
1177 if (space == NULL)
1178 return SSH_ERR_INVALID_FORMAT;
1179 *space = '\0';
1180 type = sshkey_type_from_name(cp);
1181 if (sshkey_type_plain(type) == KEY_ECDSA &&
1182 (curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1)
1183 return SSH_ERR_EC_CURVE_INVALID;
1184 *space = ' ';
1185 if (type == KEY_UNSPEC)
1186 return SSH_ERR_INVALID_FORMAT;
1187 cp = space+1;
1188 if (*cp == '\0')
1189 return SSH_ERR_INVALID_FORMAT;
djm@openbsd.orgd2d51002014-11-18 01:02:25 +00001190 if (ret->type != KEY_UNSPEC && ret->type != type)
Damien Miller86687062014-07-02 15:28:02 +10001191 return SSH_ERR_KEY_TYPE_MISMATCH;
1192 if ((blob = sshbuf_new()) == NULL)
1193 return SSH_ERR_ALLOC_FAIL;
1194 /* trim comment */
1195 space = strchr(cp, ' ');
markus@openbsd.org816d1532015-01-12 20:13:27 +00001196 if (space) {
1197 /* advance 'space': skip whitespace */
1198 *space++ = '\0';
1199 while (*space == ' ' || *space == '\t')
1200 space++;
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001201 ep = space;
markus@openbsd.org816d1532015-01-12 20:13:27 +00001202 } else
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001203 ep = cp + strlen(cp);
Damien Miller86687062014-07-02 15:28:02 +10001204 if ((r = sshbuf_b64tod(blob, cp)) != 0) {
1205 sshbuf_free(blob);
1206 return r;
1207 }
1208 if ((r = sshkey_from_blob(sshbuf_ptr(blob),
1209 sshbuf_len(blob), &k)) != 0) {
1210 sshbuf_free(blob);
1211 return r;
1212 }
1213 sshbuf_free(blob);
1214 if (k->type != type) {
1215 sshkey_free(k);
1216 return SSH_ERR_KEY_TYPE_MISMATCH;
1217 }
1218 if (sshkey_type_plain(type) == KEY_ECDSA &&
1219 curve_nid != k->ecdsa_nid) {
1220 sshkey_free(k);
1221 return SSH_ERR_EC_CURVE_MISMATCH;
1222 }
djm@openbsd.orgd2d51002014-11-18 01:02:25 +00001223 ret->type = type;
Damien Miller86687062014-07-02 15:28:02 +10001224 if (sshkey_is_cert(ret)) {
1225 if (!sshkey_is_cert(k)) {
1226 sshkey_free(k);
1227 return SSH_ERR_EXPECTED_CERT;
1228 }
1229 if (ret->cert != NULL)
1230 cert_free(ret->cert);
1231 ret->cert = k->cert;
1232 k->cert = NULL;
1233 }
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001234 switch (sshkey_type_plain(ret->type)) {
Damien Miller86687062014-07-02 15:28:02 +10001235#ifdef WITH_OPENSSL
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001236 case KEY_RSA:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001237 RSA_free(ret->rsa);
Damien Miller86687062014-07-02 15:28:02 +10001238 ret->rsa = k->rsa;
1239 k->rsa = NULL;
1240#ifdef DEBUG_PK
1241 RSA_print_fp(stderr, ret->rsa, 8);
1242#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001243 break;
1244 case KEY_DSA:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001245 DSA_free(ret->dsa);
Damien Miller86687062014-07-02 15:28:02 +10001246 ret->dsa = k->dsa;
1247 k->dsa = NULL;
1248#ifdef DEBUG_PK
1249 DSA_print_fp(stderr, ret->dsa, 8);
1250#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001251 break;
Damien Miller86687062014-07-02 15:28:02 +10001252# ifdef OPENSSL_HAS_ECC
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001253 case KEY_ECDSA:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001254 EC_KEY_free(ret->ecdsa);
Damien Miller86687062014-07-02 15:28:02 +10001255 ret->ecdsa = k->ecdsa;
1256 ret->ecdsa_nid = k->ecdsa_nid;
1257 k->ecdsa = NULL;
1258 k->ecdsa_nid = -1;
1259#ifdef DEBUG_PK
1260 sshkey_dump_ec_key(ret->ecdsa);
1261#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001262 break;
Damien Miller86687062014-07-02 15:28:02 +10001263# endif /* OPENSSL_HAS_ECC */
1264#endif /* WITH_OPENSSL */
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001265 case KEY_ED25519:
jsing@openbsd.org4270efa2018-02-14 16:03:32 +00001266 freezero(ret->ed25519_pk, ED25519_PK_SZ);
Damien Miller86687062014-07-02 15:28:02 +10001267 ret->ed25519_pk = k->ed25519_pk;
1268 k->ed25519_pk = NULL;
1269#ifdef DEBUG_PK
1270 /* XXX */
1271#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001272 break;
Damien Miller86687062014-07-02 15:28:02 +10001273 }
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001274 *cpp = ep;
Damien Miller86687062014-07-02 15:28:02 +10001275 retval = 0;
1276/*XXXX*/
1277 sshkey_free(k);
1278 if (retval != 0)
1279 break;
Damien Miller86687062014-07-02 15:28:02 +10001280 break;
1281 default:
1282 return SSH_ERR_INVALID_ARGUMENT;
1283 }
1284 return retval;
1285}
1286
1287int
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001288sshkey_to_base64(const struct sshkey *key, char **b64p)
Damien Miller86687062014-07-02 15:28:02 +10001289{
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001290 int r = SSH_ERR_INTERNAL_ERROR;
1291 struct sshbuf *b = NULL;
Damien Miller86687062014-07-02 15:28:02 +10001292 char *uu = NULL;
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001293
1294 if (b64p != NULL)
1295 *b64p = NULL;
1296 if ((b = sshbuf_new()) == NULL)
1297 return SSH_ERR_ALLOC_FAIL;
1298 if ((r = sshkey_putb(key, b)) != 0)
1299 goto out;
1300 if ((uu = sshbuf_dtob64(b)) == NULL) {
1301 r = SSH_ERR_ALLOC_FAIL;
1302 goto out;
1303 }
1304 /* Success */
1305 if (b64p != NULL) {
1306 *b64p = uu;
1307 uu = NULL;
1308 }
1309 r = 0;
1310 out:
1311 sshbuf_free(b);
1312 free(uu);
1313 return r;
1314}
1315
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00001316int
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001317sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
1318{
1319 int r = SSH_ERR_INTERNAL_ERROR;
1320 char *uu = NULL;
1321
djm@openbsd.org873d3e72017-04-30 23:18:44 +00001322 if ((r = sshkey_to_base64(key, &uu)) != 0)
1323 goto out;
1324 if ((r = sshbuf_putf(b, "%s %s",
1325 sshkey_ssh_name(key), uu)) != 0)
1326 goto out;
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001327 r = 0;
1328 out:
1329 free(uu);
1330 return r;
1331}
1332
1333int
1334sshkey_write(const struct sshkey *key, FILE *f)
1335{
1336 struct sshbuf *b = NULL;
1337 int r = SSH_ERR_INTERNAL_ERROR;
1338
1339 if ((b = sshbuf_new()) == NULL)
1340 return SSH_ERR_ALLOC_FAIL;
1341 if ((r = sshkey_format_text(key, b)) != 0)
1342 goto out;
1343 if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1344 if (feof(f))
1345 errno = EPIPE;
1346 r = SSH_ERR_SYSTEM_ERROR;
1347 goto out;
1348 }
1349 /* Success */
1350 r = 0;
1351 out:
1352 sshbuf_free(b);
1353 return r;
Damien Miller86687062014-07-02 15:28:02 +10001354}
1355
1356const char *
1357sshkey_cert_type(const struct sshkey *k)
1358{
1359 switch (k->cert->type) {
1360 case SSH2_CERT_TYPE_USER:
1361 return "user";
1362 case SSH2_CERT_TYPE_HOST:
1363 return "host";
1364 default:
1365 return "unknown";
1366 }
1367}
1368
1369#ifdef WITH_OPENSSL
1370static int
1371rsa_generate_private_key(u_int bits, RSA **rsap)
1372{
1373 RSA *private = NULL;
1374 BIGNUM *f4 = NULL;
1375 int ret = SSH_ERR_INTERNAL_ERROR;
1376
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001377 if (rsap == NULL)
Damien Miller86687062014-07-02 15:28:02 +10001378 return SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001379 if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
1380 bits > SSHBUF_MAX_BIGNUM * 8)
1381 return SSH_ERR_KEY_LENGTH;
Damien Miller86687062014-07-02 15:28:02 +10001382 *rsap = NULL;
1383 if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
1384 ret = SSH_ERR_ALLOC_FAIL;
1385 goto out;
1386 }
1387 if (!BN_set_word(f4, RSA_F4) ||
1388 !RSA_generate_key_ex(private, bits, f4, NULL)) {
1389 ret = SSH_ERR_LIBCRYPTO_ERROR;
1390 goto out;
1391 }
1392 *rsap = private;
1393 private = NULL;
1394 ret = 0;
1395 out:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001396 RSA_free(private);
1397 BN_free(f4);
Damien Miller86687062014-07-02 15:28:02 +10001398 return ret;
1399}
1400
1401static int
1402dsa_generate_private_key(u_int bits, DSA **dsap)
1403{
1404 DSA *private;
1405 int ret = SSH_ERR_INTERNAL_ERROR;
1406
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001407 if (dsap == NULL)
Damien Miller86687062014-07-02 15:28:02 +10001408 return SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001409 if (bits != 1024)
1410 return SSH_ERR_KEY_LENGTH;
Damien Miller86687062014-07-02 15:28:02 +10001411 if ((private = DSA_new()) == NULL) {
1412 ret = SSH_ERR_ALLOC_FAIL;
1413 goto out;
1414 }
1415 *dsap = NULL;
1416 if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
1417 NULL, NULL) || !DSA_generate_key(private)) {
Damien Miller86687062014-07-02 15:28:02 +10001418 ret = SSH_ERR_LIBCRYPTO_ERROR;
1419 goto out;
1420 }
1421 *dsap = private;
1422 private = NULL;
1423 ret = 0;
1424 out:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001425 DSA_free(private);
Damien Miller86687062014-07-02 15:28:02 +10001426 return ret;
1427}
1428
1429# ifdef OPENSSL_HAS_ECC
1430int
1431sshkey_ecdsa_key_to_nid(EC_KEY *k)
1432{
1433 EC_GROUP *eg;
1434 int nids[] = {
1435 NID_X9_62_prime256v1,
1436 NID_secp384r1,
1437# ifdef OPENSSL_HAS_NISTP521
1438 NID_secp521r1,
1439# endif /* OPENSSL_HAS_NISTP521 */
1440 -1
1441 };
1442 int nid;
1443 u_int i;
1444 BN_CTX *bnctx;
1445 const EC_GROUP *g = EC_KEY_get0_group(k);
1446
1447 /*
1448 * The group may be stored in a ASN.1 encoded private key in one of two
1449 * ways: as a "named group", which is reconstituted by ASN.1 object ID
1450 * or explicit group parameters encoded into the key blob. Only the
1451 * "named group" case sets the group NID for us, but we can figure
1452 * it out for the other case by comparing against all the groups that
1453 * are supported.
1454 */
1455 if ((nid = EC_GROUP_get_curve_name(g)) > 0)
1456 return nid;
1457 if ((bnctx = BN_CTX_new()) == NULL)
1458 return -1;
1459 for (i = 0; nids[i] != -1; i++) {
1460 if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) {
1461 BN_CTX_free(bnctx);
1462 return -1;
1463 }
1464 if (EC_GROUP_cmp(g, eg, bnctx) == 0)
1465 break;
1466 EC_GROUP_free(eg);
1467 }
1468 BN_CTX_free(bnctx);
1469 if (nids[i] != -1) {
1470 /* Use the group with the NID attached */
1471 EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
1472 if (EC_KEY_set_group(k, eg) != 1) {
1473 EC_GROUP_free(eg);
1474 return -1;
1475 }
1476 }
1477 return nids[i];
1478}
1479
1480static int
1481ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
1482{
1483 EC_KEY *private;
1484 int ret = SSH_ERR_INTERNAL_ERROR;
1485
djm@openbsd.org5f02bb12017-05-08 06:11:06 +00001486 if (nid == NULL || ecdsap == NULL)
Damien Miller86687062014-07-02 15:28:02 +10001487 return SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.org5f02bb12017-05-08 06:11:06 +00001488 if ((*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
1489 return SSH_ERR_KEY_LENGTH;
Damien Miller86687062014-07-02 15:28:02 +10001490 *ecdsap = NULL;
1491 if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) {
1492 ret = SSH_ERR_ALLOC_FAIL;
1493 goto out;
1494 }
1495 if (EC_KEY_generate_key(private) != 1) {
1496 ret = SSH_ERR_LIBCRYPTO_ERROR;
1497 goto out;
1498 }
1499 EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
1500 *ecdsap = private;
1501 private = NULL;
1502 ret = 0;
1503 out:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001504 EC_KEY_free(private);
Damien Miller86687062014-07-02 15:28:02 +10001505 return ret;
1506}
1507# endif /* OPENSSL_HAS_ECC */
1508#endif /* WITH_OPENSSL */
1509
1510int
1511sshkey_generate(int type, u_int bits, struct sshkey **keyp)
1512{
1513 struct sshkey *k;
1514 int ret = SSH_ERR_INTERNAL_ERROR;
1515
1516 if (keyp == NULL)
1517 return SSH_ERR_INVALID_ARGUMENT;
1518 *keyp = NULL;
1519 if ((k = sshkey_new(KEY_UNSPEC)) == NULL)
1520 return SSH_ERR_ALLOC_FAIL;
1521 switch (type) {
1522 case KEY_ED25519:
1523 if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL ||
1524 (k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) {
1525 ret = SSH_ERR_ALLOC_FAIL;
1526 break;
1527 }
1528 crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
1529 ret = 0;
1530 break;
1531#ifdef WITH_OPENSSL
1532 case KEY_DSA:
1533 ret = dsa_generate_private_key(bits, &k->dsa);
1534 break;
1535# ifdef OPENSSL_HAS_ECC
1536 case KEY_ECDSA:
1537 ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid,
1538 &k->ecdsa);
1539 break;
1540# endif /* OPENSSL_HAS_ECC */
1541 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10001542 ret = rsa_generate_private_key(bits, &k->rsa);
1543 break;
1544#endif /* WITH_OPENSSL */
1545 default:
1546 ret = SSH_ERR_INVALID_ARGUMENT;
1547 }
1548 if (ret == 0) {
1549 k->type = type;
1550 *keyp = k;
1551 } else
1552 sshkey_free(k);
1553 return ret;
1554}
1555
1556int
1557sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
1558{
1559 u_int i;
1560 const struct sshkey_cert *from;
1561 struct sshkey_cert *to;
1562 int ret = SSH_ERR_INTERNAL_ERROR;
1563
1564 if (to_key->cert != NULL) {
1565 cert_free(to_key->cert);
1566 to_key->cert = NULL;
1567 }
1568
1569 if ((from = from_key->cert) == NULL)
1570 return SSH_ERR_INVALID_ARGUMENT;
1571
1572 if ((to = to_key->cert = cert_new()) == NULL)
1573 return SSH_ERR_ALLOC_FAIL;
1574
1575 if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
1576 (ret = sshbuf_putb(to->critical, from->critical)) != 0 ||
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00001577 (ret = sshbuf_putb(to->extensions, from->extensions)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001578 return ret;
1579
1580 to->serial = from->serial;
1581 to->type = from->type;
1582 if (from->key_id == NULL)
1583 to->key_id = NULL;
1584 else if ((to->key_id = strdup(from->key_id)) == NULL)
1585 return SSH_ERR_ALLOC_FAIL;
1586 to->valid_after = from->valid_after;
1587 to->valid_before = from->valid_before;
1588 if (from->signature_key == NULL)
1589 to->signature_key = NULL;
1590 else if ((ret = sshkey_from_private(from->signature_key,
1591 &to->signature_key)) != 0)
1592 return ret;
1593
1594 if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS)
1595 return SSH_ERR_INVALID_ARGUMENT;
1596 if (from->nprincipals > 0) {
1597 if ((to->principals = calloc(from->nprincipals,
1598 sizeof(*to->principals))) == NULL)
1599 return SSH_ERR_ALLOC_FAIL;
1600 for (i = 0; i < from->nprincipals; i++) {
1601 to->principals[i] = strdup(from->principals[i]);
1602 if (to->principals[i] == NULL) {
1603 to->nprincipals = i;
1604 return SSH_ERR_ALLOC_FAIL;
1605 }
1606 }
1607 }
1608 to->nprincipals = from->nprincipals;
1609 return 0;
1610}
1611
1612int
1613sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
1614{
1615 struct sshkey *n = NULL;
1616 int ret = SSH_ERR_INTERNAL_ERROR;
1617
djm@openbsd.org1a2663a2015-10-15 23:08:23 +00001618 *pkp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10001619 switch (k->type) {
1620#ifdef WITH_OPENSSL
1621 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +10001622 case KEY_DSA_CERT:
1623 if ((n = sshkey_new(k->type)) == NULL)
1624 return SSH_ERR_ALLOC_FAIL;
1625 if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
1626 (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
1627 (BN_copy(n->dsa->g, k->dsa->g) == NULL) ||
1628 (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) {
1629 sshkey_free(n);
1630 return SSH_ERR_ALLOC_FAIL;
1631 }
1632 break;
1633# ifdef OPENSSL_HAS_ECC
1634 case KEY_ECDSA:
1635 case KEY_ECDSA_CERT:
1636 if ((n = sshkey_new(k->type)) == NULL)
1637 return SSH_ERR_ALLOC_FAIL;
1638 n->ecdsa_nid = k->ecdsa_nid;
1639 n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
1640 if (n->ecdsa == NULL) {
1641 sshkey_free(n);
1642 return SSH_ERR_ALLOC_FAIL;
1643 }
1644 if (EC_KEY_set_public_key(n->ecdsa,
1645 EC_KEY_get0_public_key(k->ecdsa)) != 1) {
1646 sshkey_free(n);
1647 return SSH_ERR_LIBCRYPTO_ERROR;
1648 }
1649 break;
1650# endif /* OPENSSL_HAS_ECC */
1651 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10001652 case KEY_RSA_CERT:
1653 if ((n = sshkey_new(k->type)) == NULL)
1654 return SSH_ERR_ALLOC_FAIL;
1655 if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
1656 (BN_copy(n->rsa->e, k->rsa->e) == NULL)) {
1657 sshkey_free(n);
1658 return SSH_ERR_ALLOC_FAIL;
1659 }
1660 break;
1661#endif /* WITH_OPENSSL */
1662 case KEY_ED25519:
1663 case KEY_ED25519_CERT:
1664 if ((n = sshkey_new(k->type)) == NULL)
1665 return SSH_ERR_ALLOC_FAIL;
1666 if (k->ed25519_pk != NULL) {
1667 if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
1668 sshkey_free(n);
1669 return SSH_ERR_ALLOC_FAIL;
1670 }
1671 memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
1672 }
1673 break;
1674 default:
1675 return SSH_ERR_KEY_TYPE_UNKNOWN;
1676 }
1677 if (sshkey_is_cert(k)) {
1678 if ((ret = sshkey_cert_copy(k, n)) != 0) {
1679 sshkey_free(n);
1680 return ret;
1681 }
1682 }
1683 *pkp = n;
1684 return 0;
1685}
1686
1687static int
djm@openbsd.org60b18252015-01-26 02:59:11 +00001688cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
Damien Miller86687062014-07-02 15:28:02 +10001689{
djm@openbsd.org60b18252015-01-26 02:59:11 +00001690 struct sshbuf *principals = NULL, *crit = NULL;
1691 struct sshbuf *exts = NULL, *ca = NULL;
1692 u_char *sig = NULL;
1693 size_t signed_len = 0, slen = 0, kidlen = 0;
Damien Miller86687062014-07-02 15:28:02 +10001694 int ret = SSH_ERR_INTERNAL_ERROR;
Damien Miller86687062014-07-02 15:28:02 +10001695
1696 /* Copy the entire key blob for verification and later serialisation */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001697 if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001698 return ret;
1699
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00001700 /* Parse body of certificate up to signature */
1701 if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10001702 (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 ||
1703 (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 ||
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001704 (ret = sshbuf_froms(b, &principals)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10001705 (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 ||
1706 (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 ||
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001707 (ret = sshbuf_froms(b, &crit)) != 0 ||
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00001708 (ret = sshbuf_froms(b, &exts)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10001709 (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 ||
djm@openbsd.org60b18252015-01-26 02:59:11 +00001710 (ret = sshbuf_froms(b, &ca)) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001711 /* XXX debug print error for ret */
1712 ret = SSH_ERR_INVALID_FORMAT;
1713 goto out;
1714 }
1715
1716 /* Signature is left in the buffer so we can calculate this length */
1717 signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b);
1718
1719 if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) {
1720 ret = SSH_ERR_INVALID_FORMAT;
1721 goto out;
1722 }
1723
1724 if (key->cert->type != SSH2_CERT_TYPE_USER &&
1725 key->cert->type != SSH2_CERT_TYPE_HOST) {
1726 ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
1727 goto out;
1728 }
1729
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001730 /* Parse principals section */
1731 while (sshbuf_len(principals) > 0) {
1732 char *principal = NULL;
1733 char **oprincipals = NULL;
1734
Damien Miller86687062014-07-02 15:28:02 +10001735 if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) {
1736 ret = SSH_ERR_INVALID_FORMAT;
1737 goto out;
1738 }
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001739 if ((ret = sshbuf_get_cstring(principals, &principal,
1740 NULL)) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001741 ret = SSH_ERR_INVALID_FORMAT;
1742 goto out;
1743 }
1744 oprincipals = key->cert->principals;
deraadt@openbsd.org9e509d42017-05-31 09:15:42 +00001745 key->cert->principals = recallocarray(key->cert->principals,
1746 key->cert->nprincipals, key->cert->nprincipals + 1,
1747 sizeof(*key->cert->principals));
Damien Miller86687062014-07-02 15:28:02 +10001748 if (key->cert->principals == NULL) {
1749 free(principal);
1750 key->cert->principals = oprincipals;
1751 ret = SSH_ERR_ALLOC_FAIL;
1752 goto out;
1753 }
1754 key->cert->principals[key->cert->nprincipals++] = principal;
1755 }
1756
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001757 /*
1758 * Stash a copies of the critical options and extensions sections
1759 * for later use.
1760 */
1761 if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 ||
1762 (exts != NULL &&
1763 (ret = sshbuf_putb(key->cert->extensions, exts)) != 0))
Damien Miller86687062014-07-02 15:28:02 +10001764 goto out;
1765
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001766 /*
1767 * Validate critical options and extensions sections format.
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001768 */
1769 while (sshbuf_len(crit) != 0) {
1770 if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 ||
1771 (ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) {
1772 sshbuf_reset(key->cert->critical);
Damien Miller86687062014-07-02 15:28:02 +10001773 ret = SSH_ERR_INVALID_FORMAT;
1774 goto out;
1775 }
1776 }
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001777 while (exts != NULL && sshbuf_len(exts) != 0) {
1778 if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 ||
1779 (ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) {
1780 sshbuf_reset(key->cert->extensions);
Damien Miller86687062014-07-02 15:28:02 +10001781 ret = SSH_ERR_INVALID_FORMAT;
1782 goto out;
1783 }
1784 }
Damien Miller86687062014-07-02 15:28:02 +10001785
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001786 /* Parse CA key and check signature */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001787 if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001788 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1789 goto out;
1790 }
1791 if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
1792 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1793 goto out;
1794 }
Damien Miller86687062014-07-02 15:28:02 +10001795 if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
djm@openbsd.org04c7e282017-12-18 02:25:15 +00001796 sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001797 goto out;
Damien Miller86687062014-07-02 15:28:02 +10001798
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001799 /* Success */
1800 ret = 0;
Damien Miller86687062014-07-02 15:28:02 +10001801 out:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001802 sshbuf_free(ca);
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001803 sshbuf_free(crit);
1804 sshbuf_free(exts);
1805 sshbuf_free(principals);
Damien Miller86687062014-07-02 15:28:02 +10001806 free(sig);
1807 return ret;
1808}
1809
1810static int
djm@openbsd.org60b18252015-01-26 02:59:11 +00001811sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
1812 int allow_cert)
Damien Miller86687062014-07-02 15:28:02 +10001813{
djm@openbsd.org54924b52015-01-14 10:46:28 +00001814 int type, ret = SSH_ERR_INTERNAL_ERROR;
Damien Miller86687062014-07-02 15:28:02 +10001815 char *ktype = NULL, *curve = NULL;
1816 struct sshkey *key = NULL;
1817 size_t len;
1818 u_char *pk = NULL;
djm@openbsd.org60b18252015-01-26 02:59:11 +00001819 struct sshbuf *copy;
Damien Miller86687062014-07-02 15:28:02 +10001820#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
1821 EC_POINT *q = NULL;
1822#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
1823
1824#ifdef DEBUG_PK /* XXX */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001825 sshbuf_dump(b, stderr);
Damien Miller86687062014-07-02 15:28:02 +10001826#endif
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00001827 if (keyp != NULL)
1828 *keyp = NULL;
djm@openbsd.org60b18252015-01-26 02:59:11 +00001829 if ((copy = sshbuf_fromb(b)) == NULL) {
1830 ret = SSH_ERR_ALLOC_FAIL;
1831 goto out;
1832 }
Damien Miller86687062014-07-02 15:28:02 +10001833 if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
1834 ret = SSH_ERR_INVALID_FORMAT;
1835 goto out;
1836 }
1837
1838 type = sshkey_type_from_name(ktype);
Damien Miller86687062014-07-02 15:28:02 +10001839 if (!allow_cert && sshkey_type_is_cert(type)) {
1840 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1841 goto out;
1842 }
1843 switch (type) {
1844#ifdef WITH_OPENSSL
1845 case KEY_RSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001846 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001847 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1848 ret = SSH_ERR_INVALID_FORMAT;
1849 goto out;
1850 }
1851 /* FALLTHROUGH */
1852 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10001853 if ((key = sshkey_new(type)) == NULL) {
1854 ret = SSH_ERR_ALLOC_FAIL;
1855 goto out;
1856 }
djm@openbsd.org3f4ea3c2015-04-03 22:17:27 +00001857 if (sshbuf_get_bignum2(b, key->rsa->e) != 0 ||
1858 sshbuf_get_bignum2(b, key->rsa->n) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001859 ret = SSH_ERR_INVALID_FORMAT;
1860 goto out;
1861 }
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001862 if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
1863 ret = SSH_ERR_KEY_LENGTH;
1864 goto out;
1865 }
Damien Miller86687062014-07-02 15:28:02 +10001866#ifdef DEBUG_PK
1867 RSA_print_fp(stderr, key->rsa, 8);
1868#endif
1869 break;
1870 case KEY_DSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001871 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001872 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1873 ret = SSH_ERR_INVALID_FORMAT;
1874 goto out;
1875 }
1876 /* FALLTHROUGH */
1877 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +10001878 if ((key = sshkey_new(type)) == NULL) {
1879 ret = SSH_ERR_ALLOC_FAIL;
1880 goto out;
1881 }
djm@openbsd.org3f4ea3c2015-04-03 22:17:27 +00001882 if (sshbuf_get_bignum2(b, key->dsa->p) != 0 ||
1883 sshbuf_get_bignum2(b, key->dsa->q) != 0 ||
1884 sshbuf_get_bignum2(b, key->dsa->g) != 0 ||
1885 sshbuf_get_bignum2(b, key->dsa->pub_key) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001886 ret = SSH_ERR_INVALID_FORMAT;
1887 goto out;
1888 }
1889#ifdef DEBUG_PK
1890 DSA_print_fp(stderr, key->dsa, 8);
1891#endif
1892 break;
1893 case KEY_ECDSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001894 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001895 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1896 ret = SSH_ERR_INVALID_FORMAT;
1897 goto out;
1898 }
1899 /* FALLTHROUGH */
1900# ifdef OPENSSL_HAS_ECC
1901 case KEY_ECDSA:
1902 if ((key = sshkey_new(type)) == NULL) {
1903 ret = SSH_ERR_ALLOC_FAIL;
1904 goto out;
1905 }
djm@openbsd.org54924b52015-01-14 10:46:28 +00001906 key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype);
Damien Miller86687062014-07-02 15:28:02 +10001907 if (sshbuf_get_cstring(b, &curve, NULL) != 0) {
1908 ret = SSH_ERR_INVALID_FORMAT;
1909 goto out;
1910 }
1911 if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
1912 ret = SSH_ERR_EC_CURVE_MISMATCH;
1913 goto out;
1914 }
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001915 EC_KEY_free(key->ecdsa);
Damien Miller86687062014-07-02 15:28:02 +10001916 if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
1917 == NULL) {
1918 ret = SSH_ERR_EC_CURVE_INVALID;
1919 goto out;
1920 }
1921 if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
1922 ret = SSH_ERR_ALLOC_FAIL;
1923 goto out;
1924 }
1925 if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
1926 ret = SSH_ERR_INVALID_FORMAT;
1927 goto out;
1928 }
1929 if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
1930 q) != 0) {
1931 ret = SSH_ERR_KEY_INVALID_EC_VALUE;
1932 goto out;
1933 }
1934 if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
1935 /* XXX assume it is a allocation error */
1936 ret = SSH_ERR_ALLOC_FAIL;
1937 goto out;
1938 }
1939#ifdef DEBUG_PK
1940 sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
1941#endif
1942 break;
1943# endif /* OPENSSL_HAS_ECC */
1944#endif /* WITH_OPENSSL */
1945 case KEY_ED25519_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001946 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001947 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1948 ret = SSH_ERR_INVALID_FORMAT;
1949 goto out;
1950 }
1951 /* FALLTHROUGH */
1952 case KEY_ED25519:
1953 if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
1954 goto out;
1955 if (len != ED25519_PK_SZ) {
1956 ret = SSH_ERR_INVALID_FORMAT;
1957 goto out;
1958 }
1959 if ((key = sshkey_new(type)) == NULL) {
1960 ret = SSH_ERR_ALLOC_FAIL;
1961 goto out;
1962 }
1963 key->ed25519_pk = pk;
1964 pk = NULL;
1965 break;
1966 case KEY_UNSPEC:
Damien Miller86687062014-07-02 15:28:02 +10001967 default:
1968 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
1969 goto out;
1970 }
1971
1972 /* Parse certificate potion */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001973 if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001974 goto out;
1975
1976 if (key != NULL && sshbuf_len(b) != 0) {
1977 ret = SSH_ERR_INVALID_FORMAT;
1978 goto out;
1979 }
1980 ret = 0;
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00001981 if (keyp != NULL) {
1982 *keyp = key;
1983 key = NULL;
1984 }
Damien Miller86687062014-07-02 15:28:02 +10001985 out:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001986 sshbuf_free(copy);
Damien Miller86687062014-07-02 15:28:02 +10001987 sshkey_free(key);
1988 free(ktype);
1989 free(curve);
1990 free(pk);
1991#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001992 EC_POINT_free(q);
Damien Miller86687062014-07-02 15:28:02 +10001993#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
1994 return ret;
1995}
1996
1997int
1998sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
1999{
djm@openbsd.org60b18252015-01-26 02:59:11 +00002000 struct sshbuf *b;
2001 int r;
2002
2003 if ((b = sshbuf_from(blob, blen)) == NULL)
2004 return SSH_ERR_ALLOC_FAIL;
2005 r = sshkey_from_blob_internal(b, keyp, 1);
2006 sshbuf_free(b);
2007 return r;
2008}
2009
2010int
2011sshkey_fromb(struct sshbuf *b, struct sshkey **keyp)
2012{
2013 return sshkey_from_blob_internal(b, keyp, 1);
2014}
2015
2016int
2017sshkey_froms(struct sshbuf *buf, struct sshkey **keyp)
2018{
2019 struct sshbuf *b;
2020 int r;
2021
2022 if ((r = sshbuf_froms(buf, &b)) != 0)
2023 return r;
2024 r = sshkey_from_blob_internal(b, keyp, 1);
2025 sshbuf_free(b);
2026 return r;
Damien Miller86687062014-07-02 15:28:02 +10002027}
2028
2029int
djm@openbsd.org931c78d2017-12-18 02:22:29 +00002030sshkey_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
2031{
2032 int r;
2033 struct sshbuf *b = NULL;
2034 char *sigtype = NULL;
2035
2036 if (sigtypep != NULL)
2037 *sigtypep = NULL;
2038 if ((b = sshbuf_from(sig, siglen)) == NULL)
2039 return SSH_ERR_ALLOC_FAIL;
2040 if ((r = sshbuf_get_cstring(b, &sigtype, NULL)) != 0)
2041 goto out;
2042 /* success */
2043 if (sigtypep != NULL) {
2044 *sigtypep = sigtype;
2045 sigtype = NULL;
2046 }
2047 r = 0;
2048 out:
2049 free(sigtype);
2050 sshbuf_free(b);
2051 return r;
2052}
2053
2054int
Damien Miller86687062014-07-02 15:28:02 +10002055sshkey_sign(const struct sshkey *key,
2056 u_char **sigp, size_t *lenp,
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +00002057 const u_char *data, size_t datalen, const char *alg, u_int compat)
Damien Miller86687062014-07-02 15:28:02 +10002058{
2059 if (sigp != NULL)
2060 *sigp = NULL;
2061 if (lenp != NULL)
2062 *lenp = 0;
2063 if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
2064 return SSH_ERR_INVALID_ARGUMENT;
2065 switch (key->type) {
2066#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002067 case KEY_DSA_CERT:
2068 case KEY_DSA:
2069 return ssh_dss_sign(key, sigp, lenp, data, datalen, compat);
2070# ifdef OPENSSL_HAS_ECC
2071 case KEY_ECDSA_CERT:
2072 case KEY_ECDSA:
2073 return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat);
2074# endif /* OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +10002075 case KEY_RSA_CERT:
2076 case KEY_RSA:
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +00002077 return ssh_rsa_sign(key, sigp, lenp, data, datalen, alg);
Damien Miller86687062014-07-02 15:28:02 +10002078#endif /* WITH_OPENSSL */
2079 case KEY_ED25519:
2080 case KEY_ED25519_CERT:
2081 return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat);
2082 default:
2083 return SSH_ERR_KEY_TYPE_UNKNOWN;
2084 }
2085}
2086
2087/*
2088 * ssh_key_verify returns 0 for a correct signature and < 0 on error.
djm@openbsd.org04c7e282017-12-18 02:25:15 +00002089 * If "alg" specified, then the signature must use that algorithm.
Damien Miller86687062014-07-02 15:28:02 +10002090 */
2091int
2092sshkey_verify(const struct sshkey *key,
2093 const u_char *sig, size_t siglen,
djm@openbsd.org04c7e282017-12-18 02:25:15 +00002094 const u_char *data, size_t dlen, const char *alg, u_int compat)
Damien Miller86687062014-07-02 15:28:02 +10002095{
djm@openbsd.org4cf87f42014-12-10 01:24:09 +00002096 if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
Damien Miller86687062014-07-02 15:28:02 +10002097 return SSH_ERR_INVALID_ARGUMENT;
2098 switch (key->type) {
2099#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002100 case KEY_DSA_CERT:
2101 case KEY_DSA:
2102 return ssh_dss_verify(key, sig, siglen, data, dlen, compat);
2103# ifdef OPENSSL_HAS_ECC
2104 case KEY_ECDSA_CERT:
2105 case KEY_ECDSA:
2106 return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat);
2107# endif /* OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +10002108 case KEY_RSA_CERT:
2109 case KEY_RSA:
djm@openbsd.org04c7e282017-12-18 02:25:15 +00002110 return ssh_rsa_verify(key, sig, siglen, data, dlen, alg);
Damien Miller86687062014-07-02 15:28:02 +10002111#endif /* WITH_OPENSSL */
2112 case KEY_ED25519:
2113 case KEY_ED25519_CERT:
2114 return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
2115 default:
2116 return SSH_ERR_KEY_TYPE_UNKNOWN;
2117 }
2118}
2119
2120/* Converts a private to a public key */
2121int
2122sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
2123{
2124 struct sshkey *pk;
2125 int ret = SSH_ERR_INTERNAL_ERROR;
2126
djm@openbsd.org1a2663a2015-10-15 23:08:23 +00002127 *dkp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002128 if ((pk = calloc(1, sizeof(*pk))) == NULL)
2129 return SSH_ERR_ALLOC_FAIL;
2130 pk->type = k->type;
2131 pk->flags = k->flags;
2132 pk->ecdsa_nid = k->ecdsa_nid;
2133 pk->dsa = NULL;
2134 pk->ecdsa = NULL;
2135 pk->rsa = NULL;
2136 pk->ed25519_pk = NULL;
2137 pk->ed25519_sk = NULL;
2138
2139 switch (k->type) {
2140#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002141 case KEY_RSA_CERT:
2142 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2143 goto fail;
2144 /* FALLTHROUGH */
Damien Miller86687062014-07-02 15:28:02 +10002145 case KEY_RSA:
2146 if ((pk->rsa = RSA_new()) == NULL ||
2147 (pk->rsa->e = BN_dup(k->rsa->e)) == NULL ||
2148 (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) {
2149 ret = SSH_ERR_ALLOC_FAIL;
2150 goto fail;
2151 }
2152 break;
Damien Miller86687062014-07-02 15:28:02 +10002153 case KEY_DSA_CERT:
2154 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2155 goto fail;
2156 /* FALLTHROUGH */
2157 case KEY_DSA:
2158 if ((pk->dsa = DSA_new()) == NULL ||
2159 (pk->dsa->p = BN_dup(k->dsa->p)) == NULL ||
2160 (pk->dsa->q = BN_dup(k->dsa->q)) == NULL ||
2161 (pk->dsa->g = BN_dup(k->dsa->g)) == NULL ||
2162 (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) {
2163 ret = SSH_ERR_ALLOC_FAIL;
2164 goto fail;
2165 }
2166 break;
2167 case KEY_ECDSA_CERT:
2168 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2169 goto fail;
2170 /* FALLTHROUGH */
2171# ifdef OPENSSL_HAS_ECC
2172 case KEY_ECDSA:
2173 pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid);
2174 if (pk->ecdsa == NULL) {
2175 ret = SSH_ERR_ALLOC_FAIL;
2176 goto fail;
2177 }
2178 if (EC_KEY_set_public_key(pk->ecdsa,
2179 EC_KEY_get0_public_key(k->ecdsa)) != 1) {
2180 ret = SSH_ERR_LIBCRYPTO_ERROR;
2181 goto fail;
2182 }
2183 break;
2184# endif /* OPENSSL_HAS_ECC */
2185#endif /* WITH_OPENSSL */
2186 case KEY_ED25519_CERT:
2187 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2188 goto fail;
2189 /* FALLTHROUGH */
2190 case KEY_ED25519:
2191 if (k->ed25519_pk != NULL) {
2192 if ((pk->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
2193 ret = SSH_ERR_ALLOC_FAIL;
2194 goto fail;
2195 }
2196 memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
2197 }
2198 break;
2199 default:
2200 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
2201 fail:
2202 sshkey_free(pk);
2203 return ret;
2204 }
2205 *dkp = pk;
2206 return 0;
2207}
2208
2209/* Convert a plain key to their _CERT equivalent */
2210int
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002211sshkey_to_certified(struct sshkey *k)
Damien Miller86687062014-07-02 15:28:02 +10002212{
2213 int newtype;
2214
2215 switch (k->type) {
2216#ifdef WITH_OPENSSL
2217 case KEY_RSA:
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002218 newtype = KEY_RSA_CERT;
Damien Miller86687062014-07-02 15:28:02 +10002219 break;
2220 case KEY_DSA:
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002221 newtype = KEY_DSA_CERT;
Damien Miller86687062014-07-02 15:28:02 +10002222 break;
2223 case KEY_ECDSA:
Damien Miller86687062014-07-02 15:28:02 +10002224 newtype = KEY_ECDSA_CERT;
2225 break;
2226#endif /* WITH_OPENSSL */
2227 case KEY_ED25519:
Damien Miller86687062014-07-02 15:28:02 +10002228 newtype = KEY_ED25519_CERT;
2229 break;
2230 default:
2231 return SSH_ERR_INVALID_ARGUMENT;
2232 }
2233 if ((k->cert = cert_new()) == NULL)
2234 return SSH_ERR_ALLOC_FAIL;
2235 k->type = newtype;
2236 return 0;
2237}
2238
2239/* Convert a certificate to its raw key equivalent */
2240int
2241sshkey_drop_cert(struct sshkey *k)
2242{
2243 if (!sshkey_type_is_cert(k->type))
2244 return SSH_ERR_KEY_TYPE_UNKNOWN;
2245 cert_free(k->cert);
2246 k->cert = NULL;
2247 k->type = sshkey_type_plain(k->type);
2248 return 0;
2249}
2250
2251/* Sign a certified key, (re-)generating the signed certblob. */
2252int
djm@openbsd.orga98339e2017-06-28 01:09:22 +00002253sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
2254 sshkey_certify_signer *signer, void *signer_ctx)
Damien Miller86687062014-07-02 15:28:02 +10002255{
2256 struct sshbuf *principals = NULL;
2257 u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
2258 size_t i, ca_len, sig_len;
2259 int ret = SSH_ERR_INTERNAL_ERROR;
2260 struct sshbuf *cert;
2261
2262 if (k == NULL || k->cert == NULL ||
2263 k->cert->certblob == NULL || ca == NULL)
2264 return SSH_ERR_INVALID_ARGUMENT;
2265 if (!sshkey_is_cert(k))
2266 return SSH_ERR_KEY_TYPE_UNKNOWN;
2267 if (!sshkey_type_is_valid_ca(ca->type))
2268 return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2269
2270 if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0)
2271 return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2272
2273 cert = k->cert->certblob; /* for readability */
2274 sshbuf_reset(cert);
2275 if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0)
2276 goto out;
2277
2278 /* -v01 certs put nonce first */
2279 arc4random_buf(&nonce, sizeof(nonce));
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002280 if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
2281 goto out;
Damien Miller86687062014-07-02 15:28:02 +10002282
2283 /* XXX this substantially duplicates to_blob(); refactor */
2284 switch (k->type) {
2285#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002286 case KEY_DSA_CERT:
2287 if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 ||
2288 (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 ||
2289 (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 ||
2290 (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0)
2291 goto out;
2292 break;
2293# ifdef OPENSSL_HAS_ECC
2294 case KEY_ECDSA_CERT:
2295 if ((ret = sshbuf_put_cstring(cert,
2296 sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 ||
2297 (ret = sshbuf_put_ec(cert,
2298 EC_KEY_get0_public_key(k->ecdsa),
2299 EC_KEY_get0_group(k->ecdsa))) != 0)
2300 goto out;
2301 break;
2302# endif /* OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +10002303 case KEY_RSA_CERT:
2304 if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 ||
2305 (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0)
2306 goto out;
2307 break;
2308#endif /* WITH_OPENSSL */
2309 case KEY_ED25519_CERT:
2310 if ((ret = sshbuf_put_string(cert,
2311 k->ed25519_pk, ED25519_PK_SZ)) != 0)
2312 goto out;
2313 break;
2314 default:
2315 ret = SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.org55e5bde2015-03-06 01:40:56 +00002316 goto out;
Damien Miller86687062014-07-02 15:28:02 +10002317 }
2318
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002319 if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 ||
2320 (ret = sshbuf_put_u32(cert, k->cert->type)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002321 (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0)
2322 goto out;
2323
2324 if ((principals = sshbuf_new()) == NULL) {
2325 ret = SSH_ERR_ALLOC_FAIL;
2326 goto out;
2327 }
2328 for (i = 0; i < k->cert->nprincipals; i++) {
2329 if ((ret = sshbuf_put_cstring(principals,
2330 k->cert->principals[i])) != 0)
2331 goto out;
2332 }
2333 if ((ret = sshbuf_put_stringb(cert, principals)) != 0 ||
2334 (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 ||
2335 (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 ||
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002336 (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 ||
2337 (ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 ||
2338 (ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */
Damien Miller86687062014-07-02 15:28:02 +10002339 (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0)
2340 goto out;
2341
2342 /* Sign the whole mess */
djm@openbsd.orga98339e2017-06-28 01:09:22 +00002343 if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
2344 sshbuf_len(cert), alg, 0, signer_ctx)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10002345 goto out;
2346
2347 /* Append signature and we are done */
2348 if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
2349 goto out;
2350 ret = 0;
2351 out:
2352 if (ret != 0)
2353 sshbuf_reset(cert);
mmcc@openbsd.orgd59ce082015-12-10 17:08:40 +00002354 free(sig_blob);
2355 free(ca_blob);
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002356 sshbuf_free(principals);
Damien Miller86687062014-07-02 15:28:02 +10002357 return ret;
2358}
2359
djm@openbsd.orga98339e2017-06-28 01:09:22 +00002360static int
2361default_key_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
2362 const u_char *data, size_t datalen,
2363 const char *alg, u_int compat, void *ctx)
2364{
2365 if (ctx != NULL)
2366 return SSH_ERR_INVALID_ARGUMENT;
2367 return sshkey_sign(key, sigp, lenp, data, datalen, alg, compat);
2368}
2369
2370int
2371sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
2372{
2373 return sshkey_certify_custom(k, ca, alg, default_key_sign, NULL);
2374}
2375
Damien Miller86687062014-07-02 15:28:02 +10002376int
2377sshkey_cert_check_authority(const struct sshkey *k,
2378 int want_host, int require_principal,
2379 const char *name, const char **reason)
2380{
2381 u_int i, principal_matches;
2382 time_t now = time(NULL);
2383
2384 if (reason != NULL)
2385 *reason = NULL;
2386
2387 if (want_host) {
2388 if (k->cert->type != SSH2_CERT_TYPE_HOST) {
2389 *reason = "Certificate invalid: not a host certificate";
2390 return SSH_ERR_KEY_CERT_INVALID;
2391 }
2392 } else {
2393 if (k->cert->type != SSH2_CERT_TYPE_USER) {
2394 *reason = "Certificate invalid: not a user certificate";
2395 return SSH_ERR_KEY_CERT_INVALID;
2396 }
2397 }
2398 if (now < 0) {
2399 /* yikes - system clock before epoch! */
2400 *reason = "Certificate invalid: not yet valid";
2401 return SSH_ERR_KEY_CERT_INVALID;
2402 }
2403 if ((u_int64_t)now < k->cert->valid_after) {
2404 *reason = "Certificate invalid: not yet valid";
2405 return SSH_ERR_KEY_CERT_INVALID;
2406 }
2407 if ((u_int64_t)now >= k->cert->valid_before) {
2408 *reason = "Certificate invalid: expired";
2409 return SSH_ERR_KEY_CERT_INVALID;
2410 }
2411 if (k->cert->nprincipals == 0) {
2412 if (require_principal) {
2413 *reason = "Certificate lacks principal list";
2414 return SSH_ERR_KEY_CERT_INVALID;
2415 }
2416 } else if (name != NULL) {
2417 principal_matches = 0;
2418 for (i = 0; i < k->cert->nprincipals; i++) {
2419 if (strcmp(name, k->cert->principals[i]) == 0) {
2420 principal_matches = 1;
2421 break;
2422 }
2423 }
2424 if (!principal_matches) {
2425 *reason = "Certificate invalid: name is not a listed "
2426 "principal";
2427 return SSH_ERR_KEY_CERT_INVALID;
2428 }
2429 }
2430 return 0;
2431}
2432
djm@openbsd.org499cf362015-11-19 01:08:55 +00002433size_t
2434sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
2435{
2436 char from[32], to[32], ret[64];
2437 time_t tt;
2438 struct tm *tm;
2439
2440 *from = *to = '\0';
2441 if (cert->valid_after == 0 &&
2442 cert->valid_before == 0xffffffffffffffffULL)
2443 return strlcpy(s, "forever", l);
2444
2445 if (cert->valid_after != 0) {
2446 /* XXX revisit INT_MAX in 2038 :) */
2447 tt = cert->valid_after > INT_MAX ?
2448 INT_MAX : cert->valid_after;
2449 tm = localtime(&tt);
2450 strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
2451 }
2452 if (cert->valid_before != 0xffffffffffffffffULL) {
2453 /* XXX revisit INT_MAX in 2038 :) */
2454 tt = cert->valid_before > INT_MAX ?
2455 INT_MAX : cert->valid_before;
2456 tm = localtime(&tt);
2457 strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
2458 }
2459
2460 if (cert->valid_after == 0)
2461 snprintf(ret, sizeof(ret), "before %s", to);
2462 else if (cert->valid_before == 0xffffffffffffffffULL)
2463 snprintf(ret, sizeof(ret), "after %s", from);
2464 else
2465 snprintf(ret, sizeof(ret), "from %s to %s", from, to);
2466
2467 return strlcpy(s, ret, l);
2468}
2469
Damien Miller86687062014-07-02 15:28:02 +10002470int
2471sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
2472{
2473 int r = SSH_ERR_INTERNAL_ERROR;
2474
2475 if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0)
2476 goto out;
2477 switch (key->type) {
2478#ifdef WITH_OPENSSL
2479 case KEY_RSA:
2480 if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 ||
2481 (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
2482 (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
2483 (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
2484 (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
2485 (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
2486 goto out;
2487 break;
Damien Miller86687062014-07-02 15:28:02 +10002488 case KEY_RSA_CERT:
2489 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2490 r = SSH_ERR_INVALID_ARGUMENT;
2491 goto out;
2492 }
2493 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2494 (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
2495 (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
2496 (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
2497 (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
2498 goto out;
2499 break;
2500 case KEY_DSA:
2501 if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
2502 (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
2503 (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
2504 (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 ||
2505 (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
2506 goto out;
2507 break;
Damien Miller86687062014-07-02 15:28:02 +10002508 case KEY_DSA_CERT:
2509 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2510 r = SSH_ERR_INVALID_ARGUMENT;
2511 goto out;
2512 }
2513 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2514 (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
2515 goto out;
2516 break;
2517# ifdef OPENSSL_HAS_ECC
2518 case KEY_ECDSA:
2519 if ((r = sshbuf_put_cstring(b,
2520 sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
2521 (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 ||
2522 (r = sshbuf_put_bignum2(b,
2523 EC_KEY_get0_private_key(key->ecdsa))) != 0)
2524 goto out;
2525 break;
2526 case KEY_ECDSA_CERT:
2527 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2528 r = SSH_ERR_INVALID_ARGUMENT;
2529 goto out;
2530 }
2531 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2532 (r = sshbuf_put_bignum2(b,
2533 EC_KEY_get0_private_key(key->ecdsa))) != 0)
2534 goto out;
2535 break;
2536# endif /* OPENSSL_HAS_ECC */
2537#endif /* WITH_OPENSSL */
2538 case KEY_ED25519:
2539 if ((r = sshbuf_put_string(b, key->ed25519_pk,
2540 ED25519_PK_SZ)) != 0 ||
2541 (r = sshbuf_put_string(b, key->ed25519_sk,
2542 ED25519_SK_SZ)) != 0)
2543 goto out;
2544 break;
2545 case KEY_ED25519_CERT:
2546 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2547 r = SSH_ERR_INVALID_ARGUMENT;
2548 goto out;
2549 }
2550 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2551 (r = sshbuf_put_string(b, key->ed25519_pk,
2552 ED25519_PK_SZ)) != 0 ||
2553 (r = sshbuf_put_string(b, key->ed25519_sk,
2554 ED25519_SK_SZ)) != 0)
2555 goto out;
2556 break;
2557 default:
2558 r = SSH_ERR_INVALID_ARGUMENT;
2559 goto out;
2560 }
2561 /* success */
2562 r = 0;
2563 out:
2564 return r;
2565}
2566
2567int
2568sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2569{
2570 char *tname = NULL, *curve = NULL;
2571 struct sshkey *k = NULL;
djm@openbsd.org60b18252015-01-26 02:59:11 +00002572 size_t pklen = 0, sklen = 0;
Damien Miller86687062014-07-02 15:28:02 +10002573 int type, r = SSH_ERR_INTERNAL_ERROR;
2574 u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
2575#ifdef WITH_OPENSSL
2576 BIGNUM *exponent = NULL;
2577#endif /* WITH_OPENSSL */
2578
2579 if (kp != NULL)
2580 *kp = NULL;
2581 if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0)
2582 goto out;
2583 type = sshkey_type_from_name(tname);
2584 switch (type) {
2585#ifdef WITH_OPENSSL
2586 case KEY_DSA:
2587 if ((k = sshkey_new_private(type)) == NULL) {
2588 r = SSH_ERR_ALLOC_FAIL;
2589 goto out;
2590 }
2591 if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 ||
2592 (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 ||
2593 (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 ||
2594 (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 ||
2595 (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
2596 goto out;
2597 break;
Damien Miller86687062014-07-02 15:28:02 +10002598 case KEY_DSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00002599 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002600 (r = sshkey_add_private(k)) != 0 ||
2601 (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
2602 goto out;
2603 break;
2604# ifdef OPENSSL_HAS_ECC
2605 case KEY_ECDSA:
2606 if ((k = sshkey_new_private(type)) == NULL) {
2607 r = SSH_ERR_ALLOC_FAIL;
2608 goto out;
2609 }
2610 if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
2611 r = SSH_ERR_INVALID_ARGUMENT;
2612 goto out;
2613 }
2614 if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
2615 goto out;
2616 if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
2617 r = SSH_ERR_EC_CURVE_MISMATCH;
2618 goto out;
2619 }
2620 k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
2621 if (k->ecdsa == NULL || (exponent = BN_new()) == NULL) {
2622 r = SSH_ERR_LIBCRYPTO_ERROR;
2623 goto out;
2624 }
2625 if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 ||
2626 (r = sshbuf_get_bignum2(buf, exponent)))
2627 goto out;
2628 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2629 r = SSH_ERR_LIBCRYPTO_ERROR;
2630 goto out;
2631 }
2632 if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00002633 EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002634 (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2635 goto out;
2636 break;
2637 case KEY_ECDSA_CERT:
2638 if ((exponent = BN_new()) == NULL) {
2639 r = SSH_ERR_LIBCRYPTO_ERROR;
2640 goto out;
2641 }
djm@openbsd.org60b18252015-01-26 02:59:11 +00002642 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002643 (r = sshkey_add_private(k)) != 0 ||
2644 (r = sshbuf_get_bignum2(buf, exponent)) != 0)
2645 goto out;
2646 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2647 r = SSH_ERR_LIBCRYPTO_ERROR;
2648 goto out;
2649 }
2650 if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00002651 EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002652 (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2653 goto out;
2654 break;
2655# endif /* OPENSSL_HAS_ECC */
2656 case KEY_RSA:
2657 if ((k = sshkey_new_private(type)) == NULL) {
2658 r = SSH_ERR_ALLOC_FAIL;
2659 goto out;
2660 }
2661 if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 ||
2662 (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 ||
2663 (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
2664 (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
2665 (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
2666 (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
djm@openbsd.org83fa3a02017-07-01 13:50:45 +00002667 (r = ssh_rsa_generate_additional_parameters(k)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10002668 goto out;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00002669 if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
2670 r = SSH_ERR_KEY_LENGTH;
2671 goto out;
2672 }
Damien Miller86687062014-07-02 15:28:02 +10002673 break;
Damien Miller86687062014-07-02 15:28:02 +10002674 case KEY_RSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00002675 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002676 (r = sshkey_add_private(k)) != 0 ||
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00002677 (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
2678 (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
2679 (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
2680 (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
djm@openbsd.org83fa3a02017-07-01 13:50:45 +00002681 (r = ssh_rsa_generate_additional_parameters(k)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10002682 goto out;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00002683 if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
2684 r = SSH_ERR_KEY_LENGTH;
2685 goto out;
2686 }
Damien Miller86687062014-07-02 15:28:02 +10002687 break;
2688#endif /* WITH_OPENSSL */
2689 case KEY_ED25519:
2690 if ((k = sshkey_new_private(type)) == NULL) {
2691 r = SSH_ERR_ALLOC_FAIL;
2692 goto out;
2693 }
2694 if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
2695 (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
2696 goto out;
2697 if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
2698 r = SSH_ERR_INVALID_FORMAT;
2699 goto out;
2700 }
2701 k->ed25519_pk = ed25519_pk;
2702 k->ed25519_sk = ed25519_sk;
2703 ed25519_pk = ed25519_sk = NULL;
2704 break;
2705 case KEY_ED25519_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00002706 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002707 (r = sshkey_add_private(k)) != 0 ||
2708 (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
2709 (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
2710 goto out;
2711 if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
2712 r = SSH_ERR_INVALID_FORMAT;
2713 goto out;
2714 }
2715 k->ed25519_pk = ed25519_pk;
2716 k->ed25519_sk = ed25519_sk;
2717 ed25519_pk = ed25519_sk = NULL;
2718 break;
2719 default:
2720 r = SSH_ERR_KEY_TYPE_UNKNOWN;
2721 goto out;
2722 }
2723#ifdef WITH_OPENSSL
2724 /* enable blinding */
2725 switch (k->type) {
2726 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10002727 case KEY_RSA_CERT:
Damien Miller86687062014-07-02 15:28:02 +10002728 if (RSA_blinding_on(k->rsa, NULL) != 1) {
2729 r = SSH_ERR_LIBCRYPTO_ERROR;
2730 goto out;
2731 }
2732 break;
2733 }
2734#endif /* WITH_OPENSSL */
2735 /* success */
2736 r = 0;
2737 if (kp != NULL) {
2738 *kp = k;
2739 k = NULL;
2740 }
2741 out:
2742 free(tname);
2743 free(curve);
2744#ifdef WITH_OPENSSL
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00002745 BN_clear_free(exponent);
Damien Miller86687062014-07-02 15:28:02 +10002746#endif /* WITH_OPENSSL */
2747 sshkey_free(k);
jsing@openbsd.org4270efa2018-02-14 16:03:32 +00002748 freezero(ed25519_pk, pklen);
2749 freezero(ed25519_sk, sklen);
Damien Miller86687062014-07-02 15:28:02 +10002750 return r;
2751}
2752
2753#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
2754int
2755sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
2756{
2757 BN_CTX *bnctx;
2758 EC_POINT *nq = NULL;
2759 BIGNUM *order, *x, *y, *tmp;
2760 int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2761
djm@openbsd.orga571dbc2016-10-04 21:34:40 +00002762 /*
2763 * NB. This assumes OpenSSL has already verified that the public
2764 * point lies on the curve. This is done by EC_POINT_oct2point()
2765 * implicitly calling EC_POINT_is_on_curve(). If this code is ever
2766 * reachable with public points not unmarshalled using
2767 * EC_POINT_oct2point then the caller will need to explicitly check.
2768 */
2769
Damien Miller86687062014-07-02 15:28:02 +10002770 if ((bnctx = BN_CTX_new()) == NULL)
2771 return SSH_ERR_ALLOC_FAIL;
2772 BN_CTX_start(bnctx);
2773
2774 /*
2775 * We shouldn't ever hit this case because bignum_get_ecpoint()
2776 * refuses to load GF2m points.
2777 */
2778 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2779 NID_X9_62_prime_field)
2780 goto out;
2781
2782 /* Q != infinity */
2783 if (EC_POINT_is_at_infinity(group, public))
2784 goto out;
2785
2786 if ((x = BN_CTX_get(bnctx)) == NULL ||
2787 (y = BN_CTX_get(bnctx)) == NULL ||
2788 (order = BN_CTX_get(bnctx)) == NULL ||
2789 (tmp = BN_CTX_get(bnctx)) == NULL) {
2790 ret = SSH_ERR_ALLOC_FAIL;
2791 goto out;
2792 }
2793
2794 /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
2795 if (EC_GROUP_get_order(group, order, bnctx) != 1 ||
2796 EC_POINT_get_affine_coordinates_GFp(group, public,
2797 x, y, bnctx) != 1) {
2798 ret = SSH_ERR_LIBCRYPTO_ERROR;
2799 goto out;
2800 }
2801 if (BN_num_bits(x) <= BN_num_bits(order) / 2 ||
2802 BN_num_bits(y) <= BN_num_bits(order) / 2)
2803 goto out;
2804
2805 /* nQ == infinity (n == order of subgroup) */
2806 if ((nq = EC_POINT_new(group)) == NULL) {
2807 ret = SSH_ERR_ALLOC_FAIL;
2808 goto out;
2809 }
2810 if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) {
2811 ret = SSH_ERR_LIBCRYPTO_ERROR;
2812 goto out;
2813 }
2814 if (EC_POINT_is_at_infinity(group, nq) != 1)
2815 goto out;
2816
2817 /* x < order - 1, y < order - 1 */
2818 if (!BN_sub(tmp, order, BN_value_one())) {
2819 ret = SSH_ERR_LIBCRYPTO_ERROR;
2820 goto out;
2821 }
2822 if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0)
2823 goto out;
2824 ret = 0;
2825 out:
2826 BN_CTX_free(bnctx);
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00002827 EC_POINT_free(nq);
Damien Miller86687062014-07-02 15:28:02 +10002828 return ret;
2829}
2830
2831int
2832sshkey_ec_validate_private(const EC_KEY *key)
2833{
2834 BN_CTX *bnctx;
2835 BIGNUM *order, *tmp;
2836 int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2837
2838 if ((bnctx = BN_CTX_new()) == NULL)
2839 return SSH_ERR_ALLOC_FAIL;
2840 BN_CTX_start(bnctx);
2841
2842 if ((order = BN_CTX_get(bnctx)) == NULL ||
2843 (tmp = BN_CTX_get(bnctx)) == NULL) {
2844 ret = SSH_ERR_ALLOC_FAIL;
2845 goto out;
2846 }
2847
2848 /* log2(private) > log2(order)/2 */
2849 if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) {
2850 ret = SSH_ERR_LIBCRYPTO_ERROR;
2851 goto out;
2852 }
2853 if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
2854 BN_num_bits(order) / 2)
2855 goto out;
2856
2857 /* private < order - 1 */
2858 if (!BN_sub(tmp, order, BN_value_one())) {
2859 ret = SSH_ERR_LIBCRYPTO_ERROR;
2860 goto out;
2861 }
2862 if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0)
2863 goto out;
2864 ret = 0;
2865 out:
2866 BN_CTX_free(bnctx);
2867 return ret;
2868}
2869
2870void
2871sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
2872{
2873 BIGNUM *x, *y;
2874 BN_CTX *bnctx;
2875
2876 if (point == NULL) {
2877 fputs("point=(NULL)\n", stderr);
2878 return;
2879 }
2880 if ((bnctx = BN_CTX_new()) == NULL) {
2881 fprintf(stderr, "%s: BN_CTX_new failed\n", __func__);
2882 return;
2883 }
2884 BN_CTX_start(bnctx);
2885 if ((x = BN_CTX_get(bnctx)) == NULL ||
2886 (y = BN_CTX_get(bnctx)) == NULL) {
2887 fprintf(stderr, "%s: BN_CTX_get failed\n", __func__);
2888 return;
2889 }
2890 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2891 NID_X9_62_prime_field) {
2892 fprintf(stderr, "%s: group is not a prime field\n", __func__);
2893 return;
2894 }
2895 if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y,
2896 bnctx) != 1) {
2897 fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n",
2898 __func__);
2899 return;
2900 }
2901 fputs("x=", stderr);
2902 BN_print_fp(stderr, x);
2903 fputs("\ny=", stderr);
2904 BN_print_fp(stderr, y);
2905 fputs("\n", stderr);
2906 BN_CTX_free(bnctx);
2907}
2908
2909void
2910sshkey_dump_ec_key(const EC_KEY *key)
2911{
2912 const BIGNUM *exponent;
2913
2914 sshkey_dump_ec_point(EC_KEY_get0_group(key),
2915 EC_KEY_get0_public_key(key));
2916 fputs("exponent=", stderr);
2917 if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
2918 fputs("(NULL)", stderr);
2919 else
2920 BN_print_fp(stderr, EC_KEY_get0_private_key(key));
2921 fputs("\n", stderr);
2922}
2923#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2924
2925static int
2926sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob,
2927 const char *passphrase, const char *comment, const char *ciphername,
2928 int rounds)
2929{
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00002930 u_char *cp, *key = NULL, *pubkeyblob = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002931 u_char salt[SALT_LEN];
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00002932 char *b64 = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002933 size_t i, pubkeylen, keylen, ivlen, blocksize, authlen;
2934 u_int check;
2935 int r = SSH_ERR_INTERNAL_ERROR;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00002936 struct sshcipher_ctx *ciphercontext = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002937 const struct sshcipher *cipher;
2938 const char *kdfname = KDFNAME;
2939 struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL;
2940
Damien Miller86687062014-07-02 15:28:02 +10002941 if (rounds <= 0)
2942 rounds = DEFAULT_ROUNDS;
2943 if (passphrase == NULL || !strlen(passphrase)) {
2944 ciphername = "none";
2945 kdfname = "none";
2946 } else if (ciphername == NULL)
2947 ciphername = DEFAULT_CIPHERNAME;
Damien Miller86687062014-07-02 15:28:02 +10002948 if ((cipher = cipher_by_name(ciphername)) == NULL) {
djm@openbsd.orgcdccebd2017-04-30 23:15:04 +00002949 r = SSH_ERR_INVALID_ARGUMENT;
Damien Miller86687062014-07-02 15:28:02 +10002950 goto out;
2951 }
2952
2953 if ((kdf = sshbuf_new()) == NULL ||
2954 (encoded = sshbuf_new()) == NULL ||
2955 (encrypted = sshbuf_new()) == NULL) {
2956 r = SSH_ERR_ALLOC_FAIL;
2957 goto out;
2958 }
2959 blocksize = cipher_blocksize(cipher);
2960 keylen = cipher_keylen(cipher);
2961 ivlen = cipher_ivlen(cipher);
2962 authlen = cipher_authlen(cipher);
2963 if ((key = calloc(1, keylen + ivlen)) == NULL) {
2964 r = SSH_ERR_ALLOC_FAIL;
2965 goto out;
2966 }
2967 if (strcmp(kdfname, "bcrypt") == 0) {
2968 arc4random_buf(salt, SALT_LEN);
2969 if (bcrypt_pbkdf(passphrase, strlen(passphrase),
2970 salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) {
2971 r = SSH_ERR_INVALID_ARGUMENT;
2972 goto out;
2973 }
2974 if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 ||
2975 (r = sshbuf_put_u32(kdf, rounds)) != 0)
2976 goto out;
2977 } else if (strcmp(kdfname, "none") != 0) {
2978 /* Unsupported KDF type */
2979 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
2980 goto out;
2981 }
2982 if ((r = cipher_init(&ciphercontext, cipher, key, keylen,
2983 key + keylen, ivlen, 1)) != 0)
2984 goto out;
2985
2986 if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 ||
2987 (r = sshbuf_put_cstring(encoded, ciphername)) != 0 ||
2988 (r = sshbuf_put_cstring(encoded, kdfname)) != 0 ||
2989 (r = sshbuf_put_stringb(encoded, kdf)) != 0 ||
2990 (r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */
2991 (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 ||
2992 (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0)
2993 goto out;
2994
2995 /* set up the buffer that will be encrypted */
2996
2997 /* Random check bytes */
2998 check = arc4random();
2999 if ((r = sshbuf_put_u32(encrypted, check)) != 0 ||
3000 (r = sshbuf_put_u32(encrypted, check)) != 0)
3001 goto out;
3002
3003 /* append private key and comment*/
3004 if ((r = sshkey_private_serialize(prv, encrypted)) != 0 ||
3005 (r = sshbuf_put_cstring(encrypted, comment)) != 0)
3006 goto out;
3007
3008 /* padding */
3009 i = 0;
3010 while (sshbuf_len(encrypted) % blocksize) {
3011 if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0)
3012 goto out;
3013 }
3014
3015 /* length in destination buffer */
3016 if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0)
3017 goto out;
3018
3019 /* encrypt */
3020 if ((r = sshbuf_reserve(encoded,
3021 sshbuf_len(encrypted) + authlen, &cp)) != 0)
3022 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003023 if ((r = cipher_crypt(ciphercontext, 0, cp,
Damien Miller86687062014-07-02 15:28:02 +10003024 sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0)
3025 goto out;
3026
3027 /* uuencode */
3028 if ((b64 = sshbuf_dtob64(encoded)) == NULL) {
3029 r = SSH_ERR_ALLOC_FAIL;
3030 goto out;
3031 }
3032
3033 sshbuf_reset(blob);
3034 if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0)
3035 goto out;
3036 for (i = 0; i < strlen(b64); i++) {
3037 if ((r = sshbuf_put_u8(blob, b64[i])) != 0)
3038 goto out;
3039 /* insert line breaks */
3040 if (i % 70 == 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3041 goto out;
3042 }
3043 if (i % 70 != 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3044 goto out;
3045 if ((r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0)
3046 goto out;
3047
3048 /* success */
3049 r = 0;
3050
3051 out:
3052 sshbuf_free(kdf);
3053 sshbuf_free(encoded);
3054 sshbuf_free(encrypted);
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003055 cipher_free(ciphercontext);
Damien Miller86687062014-07-02 15:28:02 +10003056 explicit_bzero(salt, sizeof(salt));
3057 if (key != NULL) {
3058 explicit_bzero(key, keylen + ivlen);
3059 free(key);
3060 }
3061 if (pubkeyblob != NULL) {
3062 explicit_bzero(pubkeyblob, pubkeylen);
3063 free(pubkeyblob);
3064 }
3065 if (b64 != NULL) {
3066 explicit_bzero(b64, strlen(b64));
3067 free(b64);
3068 }
3069 return r;
3070}
3071
3072static int
3073sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
3074 struct sshkey **keyp, char **commentp)
3075{
3076 char *comment = NULL, *ciphername = NULL, *kdfname = NULL;
3077 const struct sshcipher *cipher = NULL;
3078 const u_char *cp;
3079 int r = SSH_ERR_INTERNAL_ERROR;
3080 size_t encoded_len;
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003081 size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0;
Damien Miller86687062014-07-02 15:28:02 +10003082 struct sshbuf *encoded = NULL, *decoded = NULL;
3083 struct sshbuf *kdf = NULL, *decrypted = NULL;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003084 struct sshcipher_ctx *ciphercontext = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003085 struct sshkey *k = NULL;
3086 u_char *key = NULL, *salt = NULL, *dp, pad, last;
3087 u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
3088
Damien Miller86687062014-07-02 15:28:02 +10003089 if (keyp != NULL)
3090 *keyp = NULL;
3091 if (commentp != NULL)
3092 *commentp = NULL;
3093
3094 if ((encoded = sshbuf_new()) == NULL ||
3095 (decoded = sshbuf_new()) == NULL ||
3096 (decrypted = sshbuf_new()) == NULL) {
3097 r = SSH_ERR_ALLOC_FAIL;
3098 goto out;
3099 }
3100
3101 /* check preamble */
3102 cp = sshbuf_ptr(blob);
3103 encoded_len = sshbuf_len(blob);
3104 if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) ||
3105 memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) {
3106 r = SSH_ERR_INVALID_FORMAT;
3107 goto out;
3108 }
3109 cp += MARK_BEGIN_LEN;
3110 encoded_len -= MARK_BEGIN_LEN;
3111
3112 /* Look for end marker, removing whitespace as we go */
3113 while (encoded_len > 0) {
3114 if (*cp != '\n' && *cp != '\r') {
3115 if ((r = sshbuf_put_u8(encoded, *cp)) != 0)
3116 goto out;
3117 }
3118 last = *cp;
3119 encoded_len--;
3120 cp++;
3121 if (last == '\n') {
3122 if (encoded_len >= MARK_END_LEN &&
3123 memcmp(cp, MARK_END, MARK_END_LEN) == 0) {
3124 /* \0 terminate */
3125 if ((r = sshbuf_put_u8(encoded, 0)) != 0)
3126 goto out;
3127 break;
3128 }
3129 }
3130 }
3131 if (encoded_len == 0) {
3132 r = SSH_ERR_INVALID_FORMAT;
3133 goto out;
3134 }
3135
3136 /* decode base64 */
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00003137 if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0)
Damien Miller86687062014-07-02 15:28:02 +10003138 goto out;
3139
3140 /* check magic */
3141 if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) ||
3142 memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
3143 r = SSH_ERR_INVALID_FORMAT;
3144 goto out;
3145 }
3146 /* parse public portion of key */
3147 if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
3148 (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
3149 (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
3150 (r = sshbuf_froms(decoded, &kdf)) != 0 ||
3151 (r = sshbuf_get_u32(decoded, &nkeys)) != 0 ||
3152 (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */
3153 (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
3154 goto out;
3155
3156 if ((cipher = cipher_by_name(ciphername)) == NULL) {
3157 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3158 goto out;
3159 }
3160 if ((passphrase == NULL || strlen(passphrase) == 0) &&
3161 strcmp(ciphername, "none") != 0) {
3162 /* passphrase required */
3163 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3164 goto out;
3165 }
3166 if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
3167 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3168 goto out;
3169 }
3170 if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
3171 r = SSH_ERR_INVALID_FORMAT;
3172 goto out;
3173 }
3174 if (nkeys != 1) {
3175 /* XXX only one key supported */
3176 r = SSH_ERR_INVALID_FORMAT;
3177 goto out;
3178 }
3179
3180 /* check size of encrypted key blob */
3181 blocksize = cipher_blocksize(cipher);
3182 if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
3183 r = SSH_ERR_INVALID_FORMAT;
3184 goto out;
3185 }
3186
3187 /* setup key */
3188 keylen = cipher_keylen(cipher);
3189 ivlen = cipher_ivlen(cipher);
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003190 authlen = cipher_authlen(cipher);
Damien Miller86687062014-07-02 15:28:02 +10003191 if ((key = calloc(1, keylen + ivlen)) == NULL) {
3192 r = SSH_ERR_ALLOC_FAIL;
3193 goto out;
3194 }
3195 if (strcmp(kdfname, "bcrypt") == 0) {
3196 if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
3197 (r = sshbuf_get_u32(kdf, &rounds)) != 0)
3198 goto out;
3199 if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
3200 key, keylen + ivlen, rounds) < 0) {
3201 r = SSH_ERR_INVALID_FORMAT;
3202 goto out;
3203 }
3204 }
3205
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003206 /* check that an appropriate amount of auth data is present */
3207 if (sshbuf_len(decoded) < encrypted_len + authlen) {
3208 r = SSH_ERR_INVALID_FORMAT;
3209 goto out;
3210 }
3211
Damien Miller86687062014-07-02 15:28:02 +10003212 /* decrypt private portion of key */
3213 if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 ||
3214 (r = cipher_init(&ciphercontext, cipher, key, keylen,
3215 key + keylen, ivlen, 0)) != 0)
3216 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003217 if ((r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(decoded),
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003218 encrypted_len, 0, authlen)) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10003219 /* an integrity error here indicates an incorrect passphrase */
3220 if (r == SSH_ERR_MAC_INVALID)
3221 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3222 goto out;
3223 }
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003224 if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10003225 goto out;
3226 /* there should be no trailing data */
3227 if (sshbuf_len(decoded) != 0) {
3228 r = SSH_ERR_INVALID_FORMAT;
3229 goto out;
3230 }
3231
3232 /* check check bytes */
3233 if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 ||
3234 (r = sshbuf_get_u32(decrypted, &check2)) != 0)
3235 goto out;
3236 if (check1 != check2) {
3237 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3238 goto out;
3239 }
3240
3241 /* Load the private key and comment */
3242 if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
3243 (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
3244 goto out;
3245
3246 /* Check deterministic padding */
3247 i = 0;
3248 while (sshbuf_len(decrypted)) {
3249 if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
3250 goto out;
3251 if (pad != (++i & 0xff)) {
3252 r = SSH_ERR_INVALID_FORMAT;
3253 goto out;
3254 }
3255 }
3256
3257 /* XXX decode pubkey and check against private */
3258
3259 /* success */
3260 r = 0;
3261 if (keyp != NULL) {
3262 *keyp = k;
3263 k = NULL;
3264 }
3265 if (commentp != NULL) {
3266 *commentp = comment;
3267 comment = NULL;
3268 }
3269 out:
3270 pad = 0;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003271 cipher_free(ciphercontext);
Damien Miller86687062014-07-02 15:28:02 +10003272 free(ciphername);
3273 free(kdfname);
3274 free(comment);
3275 if (salt != NULL) {
3276 explicit_bzero(salt, slen);
3277 free(salt);
3278 }
3279 if (key != NULL) {
3280 explicit_bzero(key, keylen + ivlen);
3281 free(key);
3282 }
3283 sshbuf_free(encoded);
3284 sshbuf_free(decoded);
3285 sshbuf_free(kdf);
3286 sshbuf_free(decrypted);
3287 sshkey_free(k);
3288 return r;
3289}
3290
Damien Miller86687062014-07-02 15:28:02 +10003291
3292#ifdef WITH_OPENSSL
3293/* convert SSH v2 key in OpenSSL PEM format */
3294static int
3295sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob,
3296 const char *_passphrase, const char *comment)
3297{
3298 int success, r;
3299 int blen, len = strlen(_passphrase);
3300 u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
Darren Tucker8fed0a52017-03-29 10:16:15 +11003301 const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
djm@openbsd.org224f1932017-10-13 06:24:51 +00003302 char *bptr;
Damien Miller86687062014-07-02 15:28:02 +10003303 BIO *bio = NULL;
3304
3305 if (len > 0 && len <= 4)
3306 return SSH_ERR_PASSPHRASE_TOO_SHORT;
3307 if ((bio = BIO_new(BIO_s_mem())) == NULL)
3308 return SSH_ERR_ALLOC_FAIL;
3309
3310 switch (key->type) {
3311 case KEY_DSA:
3312 success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
3313 cipher, passphrase, len, NULL, NULL);
3314 break;
3315#ifdef OPENSSL_HAS_ECC
3316 case KEY_ECDSA:
3317 success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
3318 cipher, passphrase, len, NULL, NULL);
3319 break;
3320#endif
3321 case KEY_RSA:
3322 success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
3323 cipher, passphrase, len, NULL, NULL);
3324 break;
3325 default:
3326 success = 0;
3327 break;
3328 }
3329 if (success == 0) {
3330 r = SSH_ERR_LIBCRYPTO_ERROR;
3331 goto out;
3332 }
3333 if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) {
3334 r = SSH_ERR_INTERNAL_ERROR;
3335 goto out;
3336 }
3337 if ((r = sshbuf_put(blob, bptr, blen)) != 0)
3338 goto out;
3339 r = 0;
3340 out:
3341 BIO_free(bio);
3342 return r;
3343}
3344#endif /* WITH_OPENSSL */
3345
3346/* Serialise "key" to buffer "blob" */
3347int
3348sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
3349 const char *passphrase, const char *comment,
3350 int force_new_format, const char *new_format_cipher, int new_format_rounds)
3351{
3352 switch (key->type) {
markus@openbsd.orgf067cca2015-01-12 13:29:27 +00003353#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10003354 case KEY_DSA:
3355 case KEY_ECDSA:
3356 case KEY_RSA:
3357 if (force_new_format) {
3358 return sshkey_private_to_blob2(key, blob, passphrase,
3359 comment, new_format_cipher, new_format_rounds);
3360 }
3361 return sshkey_private_pem_to_blob(key, blob,
3362 passphrase, comment);
3363#endif /* WITH_OPENSSL */
3364 case KEY_ED25519:
3365 return sshkey_private_to_blob2(key, blob, passphrase,
3366 comment, new_format_cipher, new_format_rounds);
3367 default:
3368 return SSH_ERR_KEY_TYPE_UNKNOWN;
3369 }
3370}
3371
Damien Miller86687062014-07-02 15:28:02 +10003372
3373#ifdef WITH_OPENSSL
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003374static int
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00003375translate_libcrypto_error(unsigned long pem_err)
3376{
3377 int pem_reason = ERR_GET_REASON(pem_err);
3378
3379 switch (ERR_GET_LIB(pem_err)) {
3380 case ERR_LIB_PEM:
3381 switch (pem_reason) {
3382 case PEM_R_BAD_PASSWORD_READ:
3383 case PEM_R_PROBLEMS_GETTING_PASSWORD:
3384 case PEM_R_BAD_DECRYPT:
3385 return SSH_ERR_KEY_WRONG_PASSPHRASE;
3386 default:
3387 return SSH_ERR_INVALID_FORMAT;
3388 }
3389 case ERR_LIB_EVP:
3390 switch (pem_reason) {
3391 case EVP_R_BAD_DECRYPT:
3392 return SSH_ERR_KEY_WRONG_PASSPHRASE;
3393 case EVP_R_BN_DECODE_ERROR:
3394 case EVP_R_DECODE_ERROR:
3395#ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
3396 case EVP_R_PRIVATE_KEY_DECODE_ERROR:
3397#endif
3398 return SSH_ERR_INVALID_FORMAT;
3399 default:
3400 return SSH_ERR_LIBCRYPTO_ERROR;
3401 }
3402 case ERR_LIB_ASN1:
3403 return SSH_ERR_INVALID_FORMAT;
3404 }
3405 return SSH_ERR_LIBCRYPTO_ERROR;
3406}
3407
3408static void
3409clear_libcrypto_errors(void)
3410{
3411 while (ERR_get_error() != 0)
3412 ;
3413}
3414
3415/*
3416 * Translate OpenSSL error codes to determine whether
3417 * passphrase is required/incorrect.
3418 */
3419static int
3420convert_libcrypto_error(void)
3421{
3422 /*
3423 * Some password errors are reported at the beginning
3424 * of the error queue.
3425 */
3426 if (translate_libcrypto_error(ERR_peek_error()) ==
3427 SSH_ERR_KEY_WRONG_PASSPHRASE)
3428 return SSH_ERR_KEY_WRONG_PASSPHRASE;
3429 return translate_libcrypto_error(ERR_peek_last_error());
3430}
3431
3432static int
Damien Miller86687062014-07-02 15:28:02 +10003433sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003434 const char *passphrase, struct sshkey **keyp)
Damien Miller86687062014-07-02 15:28:02 +10003435{
3436 EVP_PKEY *pk = NULL;
3437 struct sshkey *prv = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003438 BIO *bio = NULL;
3439 int r;
3440
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00003441 if (keyp != NULL)
3442 *keyp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003443
3444 if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
3445 return SSH_ERR_ALLOC_FAIL;
3446 if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) !=
3447 (int)sshbuf_len(blob)) {
3448 r = SSH_ERR_ALLOC_FAIL;
3449 goto out;
3450 }
3451
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00003452 clear_libcrypto_errors();
Damien Miller86687062014-07-02 15:28:02 +10003453 if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL,
3454 (char *)passphrase)) == NULL) {
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00003455 r = convert_libcrypto_error();
Damien Miller86687062014-07-02 15:28:02 +10003456 goto out;
3457 }
3458 if (pk->type == EVP_PKEY_RSA &&
3459 (type == KEY_UNSPEC || type == KEY_RSA)) {
3460 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3461 r = SSH_ERR_ALLOC_FAIL;
3462 goto out;
3463 }
3464 prv->rsa = EVP_PKEY_get1_RSA(pk);
3465 prv->type = KEY_RSA;
Damien Miller86687062014-07-02 15:28:02 +10003466#ifdef DEBUG_PK
3467 RSA_print_fp(stderr, prv->rsa, 8);
3468#endif
3469 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
3470 r = SSH_ERR_LIBCRYPTO_ERROR;
3471 goto out;
3472 }
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00003473 if (BN_num_bits(prv->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
3474 r = SSH_ERR_KEY_LENGTH;
3475 goto out;
3476 }
Damien Miller86687062014-07-02 15:28:02 +10003477 } else if (pk->type == EVP_PKEY_DSA &&
3478 (type == KEY_UNSPEC || type == KEY_DSA)) {
3479 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3480 r = SSH_ERR_ALLOC_FAIL;
3481 goto out;
3482 }
3483 prv->dsa = EVP_PKEY_get1_DSA(pk);
3484 prv->type = KEY_DSA;
Damien Miller86687062014-07-02 15:28:02 +10003485#ifdef DEBUG_PK
3486 DSA_print_fp(stderr, prv->dsa, 8);
3487#endif
3488#ifdef OPENSSL_HAS_ECC
3489 } else if (pk->type == EVP_PKEY_EC &&
3490 (type == KEY_UNSPEC || type == KEY_ECDSA)) {
3491 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3492 r = SSH_ERR_ALLOC_FAIL;
3493 goto out;
3494 }
3495 prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
3496 prv->type = KEY_ECDSA;
3497 prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
3498 if (prv->ecdsa_nid == -1 ||
3499 sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
3500 sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
3501 EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
3502 sshkey_ec_validate_private(prv->ecdsa) != 0) {
3503 r = SSH_ERR_INVALID_FORMAT;
3504 goto out;
3505 }
Damien Miller86687062014-07-02 15:28:02 +10003506# ifdef DEBUG_PK
3507 if (prv != NULL && prv->ecdsa != NULL)
3508 sshkey_dump_ec_key(prv->ecdsa);
3509# endif
3510#endif /* OPENSSL_HAS_ECC */
3511 } else {
3512 r = SSH_ERR_INVALID_FORMAT;
3513 goto out;
3514 }
Damien Miller86687062014-07-02 15:28:02 +10003515 r = 0;
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00003516 if (keyp != NULL) {
3517 *keyp = prv;
3518 prv = NULL;
3519 }
Damien Miller86687062014-07-02 15:28:02 +10003520 out:
3521 BIO_free(bio);
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00003522 EVP_PKEY_free(pk);
mmcc@openbsd.org89540b62015-12-11 02:31:47 +00003523 sshkey_free(prv);
Damien Miller86687062014-07-02 15:28:02 +10003524 return r;
3525}
3526#endif /* WITH_OPENSSL */
3527
3528int
3529sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
3530 const char *passphrase, struct sshkey **keyp, char **commentp)
3531{
djm@openbsd.org155d5402017-02-10 04:34:50 +00003532 int r = SSH_ERR_INTERNAL_ERROR;
3533
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00003534 if (keyp != NULL)
3535 *keyp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003536 if (commentp != NULL)
3537 *commentp = NULL;
3538
3539 switch (type) {
markus@openbsd.orgf067cca2015-01-12 13:29:27 +00003540#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10003541 case KEY_DSA:
3542 case KEY_ECDSA:
3543 case KEY_RSA:
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003544 return sshkey_parse_private_pem_fileblob(blob, type,
3545 passphrase, keyp);
Damien Miller86687062014-07-02 15:28:02 +10003546#endif /* WITH_OPENSSL */
3547 case KEY_ED25519:
3548 return sshkey_parse_private2(blob, type, passphrase,
3549 keyp, commentp);
3550 case KEY_UNSPEC:
djm@openbsd.org155d5402017-02-10 04:34:50 +00003551 r = sshkey_parse_private2(blob, type, passphrase, keyp,
3552 commentp);
3553 /* Do not fallback to PEM parser if only passphrase is wrong. */
3554 if (r == 0 || r == SSH_ERR_KEY_WRONG_PASSPHRASE)
3555 return r;
Damien Miller86687062014-07-02 15:28:02 +10003556#ifdef WITH_OPENSSL
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003557 return sshkey_parse_private_pem_fileblob(blob, type,
3558 passphrase, keyp);
Damien Miller86687062014-07-02 15:28:02 +10003559#else
3560 return SSH_ERR_INVALID_FORMAT;
3561#endif /* WITH_OPENSSL */
3562 default:
3563 return SSH_ERR_KEY_TYPE_UNKNOWN;
3564 }
3565}
3566
3567int
3568sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
tim@openbsd.org3c019a92015-09-13 14:39:16 +00003569 struct sshkey **keyp, char **commentp)
Damien Miller86687062014-07-02 15:28:02 +10003570{
Damien Miller86687062014-07-02 15:28:02 +10003571 if (keyp != NULL)
3572 *keyp = NULL;
3573 if (commentp != NULL)
3574 *commentp = NULL;
3575
tim@openbsd.org3c019a92015-09-13 14:39:16 +00003576 return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
3577 passphrase, keyp, commentp);
Damien Miller86687062014-07-02 15:28:02 +10003578}