blob: fb987d6b70b313d4e996ab306b61e2d45f217a9d [file] [log] [blame]
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001/* $OpenBSD: sshkey.c,v 1.60 2018/02/07 02:06:51 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);
Damien Miller86687062014-07-02 15:28:02 +1000423 explicit_bzero(cert, sizeof(*cert));
424 free(cert);
425}
426
427static struct sshkey_cert *
428cert_new(void)
429{
430 struct sshkey_cert *cert;
431
432 if ((cert = calloc(1, sizeof(*cert))) == NULL)
433 return NULL;
434 if ((cert->certblob = sshbuf_new()) == NULL ||
435 (cert->critical = sshbuf_new()) == NULL ||
436 (cert->extensions = sshbuf_new()) == NULL) {
437 cert_free(cert);
438 return NULL;
439 }
440 cert->key_id = NULL;
441 cert->principals = NULL;
442 cert->signature_key = NULL;
443 return cert;
444}
445
446struct sshkey *
447sshkey_new(int type)
448{
449 struct sshkey *k;
450#ifdef WITH_OPENSSL
451 RSA *rsa;
452 DSA *dsa;
453#endif /* WITH_OPENSSL */
454
455 if ((k = calloc(1, sizeof(*k))) == NULL)
456 return NULL;
457 k->type = type;
458 k->ecdsa = NULL;
459 k->ecdsa_nid = -1;
460 k->dsa = NULL;
461 k->rsa = NULL;
462 k->cert = NULL;
463 k->ed25519_sk = NULL;
464 k->ed25519_pk = NULL;
465 switch (k->type) {
466#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000467 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +1000468 case KEY_RSA_CERT:
469 if ((rsa = RSA_new()) == NULL ||
470 (rsa->n = BN_new()) == NULL ||
471 (rsa->e = BN_new()) == NULL) {
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000472 RSA_free(rsa);
Damien Miller86687062014-07-02 15:28:02 +1000473 free(k);
474 return NULL;
475 }
476 k->rsa = rsa;
477 break;
478 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +1000479 case KEY_DSA_CERT:
480 if ((dsa = DSA_new()) == NULL ||
481 (dsa->p = BN_new()) == NULL ||
482 (dsa->q = BN_new()) == NULL ||
483 (dsa->g = BN_new()) == NULL ||
484 (dsa->pub_key = BN_new()) == NULL) {
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000485 DSA_free(dsa);
Damien Miller86687062014-07-02 15:28:02 +1000486 free(k);
487 return NULL;
488 }
489 k->dsa = dsa;
490 break;
491 case KEY_ECDSA:
492 case KEY_ECDSA_CERT:
493 /* Cannot do anything until we know the group */
494 break;
495#endif /* WITH_OPENSSL */
496 case KEY_ED25519:
497 case KEY_ED25519_CERT:
498 /* no need to prealloc */
499 break;
500 case KEY_UNSPEC:
501 break;
502 default:
503 free(k);
504 return NULL;
Damien Miller86687062014-07-02 15:28:02 +1000505 }
506
507 if (sshkey_is_cert(k)) {
508 if ((k->cert = cert_new()) == NULL) {
509 sshkey_free(k);
510 return NULL;
511 }
512 }
513
514 return k;
515}
516
517int
518sshkey_add_private(struct sshkey *k)
519{
520 switch (k->type) {
521#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000522 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +1000523 case KEY_RSA_CERT:
524#define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL)
525 if (bn_maybe_alloc_failed(k->rsa->d) ||
526 bn_maybe_alloc_failed(k->rsa->iqmp) ||
527 bn_maybe_alloc_failed(k->rsa->q) ||
528 bn_maybe_alloc_failed(k->rsa->p) ||
529 bn_maybe_alloc_failed(k->rsa->dmq1) ||
530 bn_maybe_alloc_failed(k->rsa->dmp1))
531 return SSH_ERR_ALLOC_FAIL;
532 break;
533 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +1000534 case KEY_DSA_CERT:
535 if (bn_maybe_alloc_failed(k->dsa->priv_key))
536 return SSH_ERR_ALLOC_FAIL;
537 break;
538#undef bn_maybe_alloc_failed
539 case KEY_ECDSA:
540 case KEY_ECDSA_CERT:
541 /* Cannot do anything until we know the group */
542 break;
543#endif /* WITH_OPENSSL */
544 case KEY_ED25519:
545 case KEY_ED25519_CERT:
546 /* no need to prealloc */
547 break;
548 case KEY_UNSPEC:
549 break;
550 default:
551 return SSH_ERR_INVALID_ARGUMENT;
552 }
553 return 0;
554}
555
556struct sshkey *
557sshkey_new_private(int type)
558{
559 struct sshkey *k = sshkey_new(type);
560
561 if (k == NULL)
562 return NULL;
563 if (sshkey_add_private(k) != 0) {
564 sshkey_free(k);
565 return NULL;
566 }
567 return k;
568}
569
570void
571sshkey_free(struct sshkey *k)
572{
573 if (k == NULL)
574 return;
575 switch (k->type) {
576#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000577 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +1000578 case KEY_RSA_CERT:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000579 RSA_free(k->rsa);
Damien Miller86687062014-07-02 15:28:02 +1000580 k->rsa = NULL;
581 break;
582 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +1000583 case KEY_DSA_CERT:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000584 DSA_free(k->dsa);
Damien Miller86687062014-07-02 15:28:02 +1000585 k->dsa = NULL;
586 break;
587# ifdef OPENSSL_HAS_ECC
588 case KEY_ECDSA:
589 case KEY_ECDSA_CERT:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +0000590 EC_KEY_free(k->ecdsa);
Damien Miller86687062014-07-02 15:28:02 +1000591 k->ecdsa = NULL;
592 break;
593# endif /* OPENSSL_HAS_ECC */
594#endif /* WITH_OPENSSL */
595 case KEY_ED25519:
596 case KEY_ED25519_CERT:
597 if (k->ed25519_pk) {
598 explicit_bzero(k->ed25519_pk, ED25519_PK_SZ);
599 free(k->ed25519_pk);
600 k->ed25519_pk = NULL;
601 }
602 if (k->ed25519_sk) {
603 explicit_bzero(k->ed25519_sk, ED25519_SK_SZ);
604 free(k->ed25519_sk);
605 k->ed25519_sk = NULL;
606 }
607 break;
608 case KEY_UNSPEC:
609 break;
610 default:
611 break;
612 }
613 if (sshkey_is_cert(k))
614 cert_free(k->cert);
615 explicit_bzero(k, sizeof(*k));
616 free(k);
617}
618
619static int
620cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
621{
622 if (a == NULL && b == NULL)
623 return 1;
624 if (a == NULL || b == NULL)
625 return 0;
626 if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob))
627 return 0;
628 if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob),
629 sshbuf_len(a->certblob)) != 0)
630 return 0;
631 return 1;
632}
633
634/*
635 * Compare public portions of key only, allowing comparisons between
636 * certificates and plain keys too.
637 */
638int
639sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
640{
Darren Tucker948a1772014-07-22 01:07:11 +1000641#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
Damien Miller86687062014-07-02 15:28:02 +1000642 BN_CTX *bnctx;
Darren Tucker948a1772014-07-22 01:07:11 +1000643#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +1000644
645 if (a == NULL || b == NULL ||
646 sshkey_type_plain(a->type) != sshkey_type_plain(b->type))
647 return 0;
648
649 switch (a->type) {
650#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000651 case KEY_RSA_CERT:
652 case KEY_RSA:
653 return a->rsa != NULL && b->rsa != NULL &&
654 BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
655 BN_cmp(a->rsa->n, b->rsa->n) == 0;
Damien Miller86687062014-07-02 15:28:02 +1000656 case KEY_DSA_CERT:
657 case KEY_DSA:
658 return a->dsa != NULL && b->dsa != NULL &&
659 BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
660 BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
661 BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
662 BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
663# ifdef OPENSSL_HAS_ECC
664 case KEY_ECDSA_CERT:
665 case KEY_ECDSA:
666 if (a->ecdsa == NULL || b->ecdsa == NULL ||
667 EC_KEY_get0_public_key(a->ecdsa) == NULL ||
668 EC_KEY_get0_public_key(b->ecdsa) == NULL)
669 return 0;
670 if ((bnctx = BN_CTX_new()) == NULL)
671 return 0;
672 if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
673 EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
674 EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
675 EC_KEY_get0_public_key(a->ecdsa),
676 EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
677 BN_CTX_free(bnctx);
678 return 0;
679 }
680 BN_CTX_free(bnctx);
681 return 1;
682# endif /* OPENSSL_HAS_ECC */
683#endif /* WITH_OPENSSL */
684 case KEY_ED25519:
685 case KEY_ED25519_CERT:
686 return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
687 memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
688 default:
689 return 0;
690 }
691 /* NOTREACHED */
692}
693
694int
695sshkey_equal(const struct sshkey *a, const struct sshkey *b)
696{
697 if (a == NULL || b == NULL || a->type != b->type)
698 return 0;
699 if (sshkey_is_cert(a)) {
700 if (!cert_compare(a->cert, b->cert))
701 return 0;
702 }
703 return sshkey_equal_public(a, b);
704}
705
706static int
707to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
708{
709 int type, ret = SSH_ERR_INTERNAL_ERROR;
710 const char *typename;
711
712 if (key == NULL)
713 return SSH_ERR_INVALID_ARGUMENT;
714
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +0000715 if (sshkey_is_cert(key)) {
716 if (key->cert == NULL)
717 return SSH_ERR_EXPECTED_CERT;
718 if (sshbuf_len(key->cert->certblob) == 0)
719 return SSH_ERR_KEY_LACKS_CERTBLOB;
720 }
Damien Miller86687062014-07-02 15:28:02 +1000721 type = force_plain ? sshkey_type_plain(key->type) : key->type;
722 typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
723
724 switch (type) {
725#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000726 case KEY_DSA_CERT:
727 case KEY_ECDSA_CERT:
728 case KEY_RSA_CERT:
729#endif /* WITH_OPENSSL */
730 case KEY_ED25519_CERT:
731 /* Use the existing blob */
732 /* XXX modified flag? */
733 if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
734 return ret;
735 break;
736#ifdef WITH_OPENSSL
737 case KEY_DSA:
738 if (key->dsa == NULL)
739 return SSH_ERR_INVALID_ARGUMENT;
740 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
741 (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
742 (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
743 (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
744 (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0)
745 return ret;
746 break;
Darren Tuckerd1a04212014-07-19 07:23:55 +1000747# ifdef OPENSSL_HAS_ECC
Damien Miller86687062014-07-02 15:28:02 +1000748 case KEY_ECDSA:
749 if (key->ecdsa == NULL)
750 return SSH_ERR_INVALID_ARGUMENT;
751 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
752 (ret = sshbuf_put_cstring(b,
753 sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
754 (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0)
755 return ret;
756 break;
Darren Tuckerd1a04212014-07-19 07:23:55 +1000757# endif
Damien Miller86687062014-07-02 15:28:02 +1000758 case KEY_RSA:
759 if (key->rsa == NULL)
760 return SSH_ERR_INVALID_ARGUMENT;
761 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
762 (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
763 (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0)
764 return ret;
765 break;
766#endif /* WITH_OPENSSL */
767 case KEY_ED25519:
768 if (key->ed25519_pk == NULL)
769 return SSH_ERR_INVALID_ARGUMENT;
770 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
771 (ret = sshbuf_put_string(b,
772 key->ed25519_pk, ED25519_PK_SZ)) != 0)
773 return ret;
774 break;
775 default:
776 return SSH_ERR_KEY_TYPE_UNKNOWN;
777 }
778 return 0;
779}
780
781int
djm@openbsd.org60b18252015-01-26 02:59:11 +0000782sshkey_putb(const struct sshkey *key, struct sshbuf *b)
Damien Miller86687062014-07-02 15:28:02 +1000783{
784 return to_blob_buf(key, b, 0);
785}
786
787int
djm@openbsd.org60b18252015-01-26 02:59:11 +0000788sshkey_puts(const struct sshkey *key, struct sshbuf *b)
789{
790 struct sshbuf *tmp;
791 int r;
792
793 if ((tmp = sshbuf_new()) == NULL)
794 return SSH_ERR_ALLOC_FAIL;
795 r = to_blob_buf(key, tmp, 0);
796 if (r == 0)
797 r = sshbuf_put_stringb(b, tmp);
798 sshbuf_free(tmp);
799 return r;
800}
801
802int
803sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
Damien Miller86687062014-07-02 15:28:02 +1000804{
805 return to_blob_buf(key, b, 1);
806}
807
808static int
809to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
810{
811 int ret = SSH_ERR_INTERNAL_ERROR;
812 size_t len;
813 struct sshbuf *b = NULL;
814
815 if (lenp != NULL)
816 *lenp = 0;
817 if (blobp != NULL)
818 *blobp = NULL;
819 if ((b = sshbuf_new()) == NULL)
820 return SSH_ERR_ALLOC_FAIL;
821 if ((ret = to_blob_buf(key, b, force_plain)) != 0)
822 goto out;
823 len = sshbuf_len(b);
824 if (lenp != NULL)
825 *lenp = len;
826 if (blobp != NULL) {
827 if ((*blobp = malloc(len)) == NULL) {
828 ret = SSH_ERR_ALLOC_FAIL;
829 goto out;
830 }
831 memcpy(*blobp, sshbuf_ptr(b), len);
832 }
833 ret = 0;
834 out:
835 sshbuf_free(b);
836 return ret;
837}
838
839int
840sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
841{
842 return to_blob(key, blobp, lenp, 0);
843}
844
845int
846sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
847{
848 return to_blob(key, blobp, lenp, 1);
849}
850
851int
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000852sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
Damien Miller86687062014-07-02 15:28:02 +1000853 u_char **retp, size_t *lenp)
854{
855 u_char *blob = NULL, *ret = NULL;
856 size_t blob_len = 0;
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000857 int r = SSH_ERR_INTERNAL_ERROR;
Damien Miller86687062014-07-02 15:28:02 +1000858
859 if (retp != NULL)
860 *retp = NULL;
861 if (lenp != NULL)
862 *lenp = 0;
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000863 if (ssh_digest_bytes(dgst_alg) == 0) {
Damien Miller86687062014-07-02 15:28:02 +1000864 r = SSH_ERR_INVALID_ARGUMENT;
865 goto out;
866 }
djm@openbsd.org873d3e72017-04-30 23:18:44 +0000867 if ((r = to_blob(k, &blob, &blob_len, 1)) != 0)
Damien Miller86687062014-07-02 15:28:02 +1000868 goto out;
869 if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
870 r = SSH_ERR_ALLOC_FAIL;
871 goto out;
872 }
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000873 if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
Damien Miller86687062014-07-02 15:28:02 +1000874 ret, SSH_DIGEST_MAX_LENGTH)) != 0)
875 goto out;
876 /* success */
877 if (retp != NULL) {
878 *retp = ret;
879 ret = NULL;
880 }
881 if (lenp != NULL)
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000882 *lenp = ssh_digest_bytes(dgst_alg);
Damien Miller86687062014-07-02 15:28:02 +1000883 r = 0;
884 out:
885 free(ret);
886 if (blob != NULL) {
887 explicit_bzero(blob, blob_len);
888 free(blob);
889 }
890 return r;
891}
892
893static char *
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000894fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
Damien Miller86687062014-07-02 15:28:02 +1000895{
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000896 char *ret;
897 size_t plen = strlen(alg) + 1;
898 size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
899 int r;
Damien Miller86687062014-07-02 15:28:02 +1000900
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000901 if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
Damien Miller86687062014-07-02 15:28:02 +1000902 return NULL;
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000903 strlcpy(ret, alg, rlen);
904 strlcat(ret, ":", rlen);
905 if (dgst_raw_len == 0)
906 return ret;
907 if ((r = b64_ntop(dgst_raw, dgst_raw_len,
908 ret + plen, rlen - plen)) == -1) {
909 explicit_bzero(ret, rlen);
910 free(ret);
911 return NULL;
Damien Miller86687062014-07-02 15:28:02 +1000912 }
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000913 /* Trim padding characters from end */
914 ret[strcspn(ret, "=")] = '\0';
915 return ret;
916}
Damien Miller86687062014-07-02 15:28:02 +1000917
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000918static char *
919fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
920{
921 char *retval, hex[5];
922 size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
923
924 if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
925 return NULL;
926 strlcpy(retval, alg, rlen);
927 strlcat(retval, ":", rlen);
928 for (i = 0; i < dgst_raw_len; i++) {
929 snprintf(hex, sizeof(hex), "%s%02x",
930 i > 0 ? ":" : "", dgst_raw[i]);
931 strlcat(retval, hex, rlen);
932 }
Damien Miller86687062014-07-02 15:28:02 +1000933 return retval;
934}
935
936static char *
937fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
938{
939 char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
940 char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
941 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
942 u_int i, j = 0, rounds, seed = 1;
943 char *retval;
944
945 rounds = (dgst_raw_len / 2) + 1;
946 if ((retval = calloc(rounds, 6)) == NULL)
947 return NULL;
948 retval[j++] = 'x';
949 for (i = 0; i < rounds; i++) {
950 u_int idx0, idx1, idx2, idx3, idx4;
951 if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
952 idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
953 seed) % 6;
954 idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
955 idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
956 (seed / 6)) % 6;
957 retval[j++] = vowels[idx0];
958 retval[j++] = consonants[idx1];
959 retval[j++] = vowels[idx2];
960 if ((i + 1) < rounds) {
961 idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
962 idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
963 retval[j++] = consonants[idx3];
964 retval[j++] = '-';
965 retval[j++] = consonants[idx4];
966 seed = ((seed * 5) +
967 ((((u_int)(dgst_raw[2 * i])) * 7) +
968 ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
969 }
970 } else {
971 idx0 = seed % 6;
972 idx1 = 16;
973 idx2 = seed / 6;
974 retval[j++] = vowels[idx0];
975 retval[j++] = consonants[idx1];
976 retval[j++] = vowels[idx2];
977 }
978 }
979 retval[j++] = 'x';
980 retval[j++] = '\0';
981 return retval;
982}
983
984/*
985 * Draw an ASCII-Art representing the fingerprint so human brain can
986 * profit from its built-in pattern recognition ability.
987 * This technique is called "random art" and can be found in some
988 * scientific publications like this original paper:
989 *
990 * "Hash Visualization: a New Technique to improve Real-World Security",
991 * Perrig A. and Song D., 1999, International Workshop on Cryptographic
992 * Techniques and E-Commerce (CrypTEC '99)
993 * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
994 *
995 * The subject came up in a talk by Dan Kaminsky, too.
996 *
997 * If you see the picture is different, the key is different.
998 * If the picture looks the same, you still know nothing.
999 *
1000 * The algorithm used here is a worm crawling over a discrete plane,
1001 * leaving a trace (augmenting the field) everywhere it goes.
1002 * Movement is taken from dgst_raw 2bit-wise. Bumping into walls
1003 * makes the respective movement vector be ignored for this turn.
1004 * Graphs are not unambiguous, because circles in graphs can be
1005 * walked in either direction.
1006 */
1007
1008/*
1009 * Field sizes for the random art. Have to be odd, so the starting point
1010 * can be in the exact middle of the picture, and FLDBASE should be >=8 .
1011 * Else pictures would be too dense, and drawing the frame would
1012 * fail, too, because the key type would not fit in anymore.
1013 */
1014#define FLDBASE 8
1015#define FLDSIZE_Y (FLDBASE + 1)
1016#define FLDSIZE_X (FLDBASE * 2 + 1)
1017static char *
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001018fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
Damien Miller86687062014-07-02 15:28:02 +10001019 const struct sshkey *k)
1020{
1021 /*
1022 * Chars to be used after each other every time the worm
1023 * intersects with itself. Matter of taste.
1024 */
1025 char *augmentation_string = " .o+=*BOX@%&#/^SE";
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001026 char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
Damien Miller86687062014-07-02 15:28:02 +10001027 u_char field[FLDSIZE_X][FLDSIZE_Y];
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001028 size_t i, tlen, hlen;
Damien Miller86687062014-07-02 15:28:02 +10001029 u_int b;
Damien Miller61e28e52014-07-03 21:22:22 +10001030 int x, y, r;
Damien Miller86687062014-07-02 15:28:02 +10001031 size_t len = strlen(augmentation_string) - 1;
1032
1033 if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
1034 return NULL;
1035
1036 /* initialize field */
1037 memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
1038 x = FLDSIZE_X / 2;
1039 y = FLDSIZE_Y / 2;
1040
1041 /* process raw key */
1042 for (i = 0; i < dgst_raw_len; i++) {
1043 int input;
1044 /* each byte conveys four 2-bit move commands */
1045 input = dgst_raw[i];
1046 for (b = 0; b < 4; b++) {
1047 /* evaluate 2 bit, rest is shifted later */
1048 x += (input & 0x1) ? 1 : -1;
1049 y += (input & 0x2) ? 1 : -1;
1050
1051 /* assure we are still in bounds */
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +00001052 x = MAXIMUM(x, 0);
1053 y = MAXIMUM(y, 0);
1054 x = MINIMUM(x, FLDSIZE_X - 1);
1055 y = MINIMUM(y, FLDSIZE_Y - 1);
Damien Miller86687062014-07-02 15:28:02 +10001056
1057 /* augment the field */
1058 if (field[x][y] < len - 2)
1059 field[x][y]++;
1060 input = input >> 2;
1061 }
1062 }
1063
1064 /* mark starting point and end point*/
1065 field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
1066 field[x][y] = len;
1067
Damien Miller61e28e52014-07-03 21:22:22 +10001068 /* assemble title */
1069 r = snprintf(title, sizeof(title), "[%s %u]",
1070 sshkey_type(k), sshkey_size(k));
1071 /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
1072 if (r < 0 || r > (int)sizeof(title))
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001073 r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
1074 tlen = (r <= 0) ? 0 : strlen(title);
1075
1076 /* assemble hash ID. */
1077 r = snprintf(hash, sizeof(hash), "[%s]", alg);
1078 hlen = (r <= 0) ? 0 : strlen(hash);
Damien Miller86687062014-07-02 15:28:02 +10001079
1080 /* output upper border */
Damien Miller61e28e52014-07-03 21:22:22 +10001081 p = retval;
1082 *p++ = '+';
1083 for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
1084 *p++ = '-';
1085 memcpy(p, title, tlen);
1086 p += tlen;
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001087 for (i += tlen; i < FLDSIZE_X; i++)
Damien Miller86687062014-07-02 15:28:02 +10001088 *p++ = '-';
1089 *p++ = '+';
1090 *p++ = '\n';
1091
1092 /* output content */
1093 for (y = 0; y < FLDSIZE_Y; y++) {
1094 *p++ = '|';
1095 for (x = 0; x < FLDSIZE_X; x++)
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +00001096 *p++ = augmentation_string[MINIMUM(field[x][y], len)];
Damien Miller86687062014-07-02 15:28:02 +10001097 *p++ = '|';
1098 *p++ = '\n';
1099 }
1100
1101 /* output lower border */
1102 *p++ = '+';
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001103 for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
1104 *p++ = '-';
1105 memcpy(p, hash, hlen);
1106 p += hlen;
1107 for (i += hlen; i < FLDSIZE_X; i++)
Damien Miller86687062014-07-02 15:28:02 +10001108 *p++ = '-';
1109 *p++ = '+';
1110
1111 return retval;
1112}
1113
1114char *
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001115sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
Damien Miller86687062014-07-02 15:28:02 +10001116 enum sshkey_fp_rep dgst_rep)
1117{
1118 char *retval = NULL;
1119 u_char *dgst_raw;
1120 size_t dgst_raw_len;
1121
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001122 if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001123 return NULL;
1124 switch (dgst_rep) {
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001125 case SSH_FP_DEFAULT:
1126 if (dgst_alg == SSH_DIGEST_MD5) {
1127 retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1128 dgst_raw, dgst_raw_len);
1129 } else {
1130 retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1131 dgst_raw, dgst_raw_len);
1132 }
1133 break;
Damien Miller86687062014-07-02 15:28:02 +10001134 case SSH_FP_HEX:
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001135 retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1136 dgst_raw, dgst_raw_len);
1137 break;
1138 case SSH_FP_BASE64:
1139 retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1140 dgst_raw, dgst_raw_len);
Damien Miller86687062014-07-02 15:28:02 +10001141 break;
1142 case SSH_FP_BUBBLEBABBLE:
1143 retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
1144 break;
1145 case SSH_FP_RANDOMART:
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001146 retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
1147 dgst_raw, dgst_raw_len, k);
Damien Miller86687062014-07-02 15:28:02 +10001148 break;
1149 default:
1150 explicit_bzero(dgst_raw, dgst_raw_len);
1151 free(dgst_raw);
1152 return NULL;
1153 }
1154 explicit_bzero(dgst_raw, dgst_raw_len);
1155 free(dgst_raw);
1156 return retval;
1157}
1158
Damien Miller86687062014-07-02 15:28:02 +10001159
1160/* returns 0 ok, and < 0 error */
1161int
1162sshkey_read(struct sshkey *ret, char **cpp)
1163{
1164 struct sshkey *k;
1165 int retval = SSH_ERR_INVALID_FORMAT;
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001166 char *ep, *cp, *space;
Damien Miller86687062014-07-02 15:28:02 +10001167 int r, type, curve_nid = -1;
1168 struct sshbuf *blob;
Damien Miller86687062014-07-02 15:28:02 +10001169
dtucker@openbsd.org7fadbb62017-03-10 03:48:57 +00001170 if (ret == NULL)
1171 return SSH_ERR_INVALID_ARGUMENT;
1172
Damien Miller86687062014-07-02 15:28:02 +10001173 cp = *cpp;
1174
1175 switch (ret->type) {
Damien Miller86687062014-07-02 15:28:02 +10001176 case KEY_UNSPEC:
1177 case KEY_RSA:
1178 case KEY_DSA:
1179 case KEY_ECDSA:
1180 case KEY_ED25519:
Damien Miller86687062014-07-02 15:28:02 +10001181 case KEY_DSA_CERT:
1182 case KEY_ECDSA_CERT:
1183 case KEY_RSA_CERT:
1184 case KEY_ED25519_CERT:
1185 space = strchr(cp, ' ');
1186 if (space == NULL)
1187 return SSH_ERR_INVALID_FORMAT;
1188 *space = '\0';
1189 type = sshkey_type_from_name(cp);
1190 if (sshkey_type_plain(type) == KEY_ECDSA &&
1191 (curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1)
1192 return SSH_ERR_EC_CURVE_INVALID;
1193 *space = ' ';
1194 if (type == KEY_UNSPEC)
1195 return SSH_ERR_INVALID_FORMAT;
1196 cp = space+1;
1197 if (*cp == '\0')
1198 return SSH_ERR_INVALID_FORMAT;
djm@openbsd.orgd2d51002014-11-18 01:02:25 +00001199 if (ret->type != KEY_UNSPEC && ret->type != type)
Damien Miller86687062014-07-02 15:28:02 +10001200 return SSH_ERR_KEY_TYPE_MISMATCH;
1201 if ((blob = sshbuf_new()) == NULL)
1202 return SSH_ERR_ALLOC_FAIL;
1203 /* trim comment */
1204 space = strchr(cp, ' ');
markus@openbsd.org816d1532015-01-12 20:13:27 +00001205 if (space) {
1206 /* advance 'space': skip whitespace */
1207 *space++ = '\0';
1208 while (*space == ' ' || *space == '\t')
1209 space++;
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001210 ep = space;
markus@openbsd.org816d1532015-01-12 20:13:27 +00001211 } else
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001212 ep = cp + strlen(cp);
Damien Miller86687062014-07-02 15:28:02 +10001213 if ((r = sshbuf_b64tod(blob, cp)) != 0) {
1214 sshbuf_free(blob);
1215 return r;
1216 }
1217 if ((r = sshkey_from_blob(sshbuf_ptr(blob),
1218 sshbuf_len(blob), &k)) != 0) {
1219 sshbuf_free(blob);
1220 return r;
1221 }
1222 sshbuf_free(blob);
1223 if (k->type != type) {
1224 sshkey_free(k);
1225 return SSH_ERR_KEY_TYPE_MISMATCH;
1226 }
1227 if (sshkey_type_plain(type) == KEY_ECDSA &&
1228 curve_nid != k->ecdsa_nid) {
1229 sshkey_free(k);
1230 return SSH_ERR_EC_CURVE_MISMATCH;
1231 }
djm@openbsd.orgd2d51002014-11-18 01:02:25 +00001232 ret->type = type;
Damien Miller86687062014-07-02 15:28:02 +10001233 if (sshkey_is_cert(ret)) {
1234 if (!sshkey_is_cert(k)) {
1235 sshkey_free(k);
1236 return SSH_ERR_EXPECTED_CERT;
1237 }
1238 if (ret->cert != NULL)
1239 cert_free(ret->cert);
1240 ret->cert = k->cert;
1241 k->cert = NULL;
1242 }
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001243 switch (sshkey_type_plain(ret->type)) {
Damien Miller86687062014-07-02 15:28:02 +10001244#ifdef WITH_OPENSSL
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001245 case KEY_RSA:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001246 RSA_free(ret->rsa);
Damien Miller86687062014-07-02 15:28:02 +10001247 ret->rsa = k->rsa;
1248 k->rsa = NULL;
1249#ifdef DEBUG_PK
1250 RSA_print_fp(stderr, ret->rsa, 8);
1251#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001252 break;
1253 case KEY_DSA:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001254 DSA_free(ret->dsa);
Damien Miller86687062014-07-02 15:28:02 +10001255 ret->dsa = k->dsa;
1256 k->dsa = NULL;
1257#ifdef DEBUG_PK
1258 DSA_print_fp(stderr, ret->dsa, 8);
1259#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001260 break;
Damien Miller86687062014-07-02 15:28:02 +10001261# ifdef OPENSSL_HAS_ECC
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001262 case KEY_ECDSA:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001263 EC_KEY_free(ret->ecdsa);
Damien Miller86687062014-07-02 15:28:02 +10001264 ret->ecdsa = k->ecdsa;
1265 ret->ecdsa_nid = k->ecdsa_nid;
1266 k->ecdsa = NULL;
1267 k->ecdsa_nid = -1;
1268#ifdef DEBUG_PK
1269 sshkey_dump_ec_key(ret->ecdsa);
1270#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001271 break;
Damien Miller86687062014-07-02 15:28:02 +10001272# endif /* OPENSSL_HAS_ECC */
1273#endif /* WITH_OPENSSL */
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001274 case KEY_ED25519:
Damien Miller86687062014-07-02 15:28:02 +10001275 free(ret->ed25519_pk);
1276 ret->ed25519_pk = k->ed25519_pk;
1277 k->ed25519_pk = NULL;
1278#ifdef DEBUG_PK
1279 /* XXX */
1280#endif
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001281 break;
Damien Miller86687062014-07-02 15:28:02 +10001282 }
djm@openbsd.org3a9f84b2015-11-16 22:50:01 +00001283 *cpp = ep;
Damien Miller86687062014-07-02 15:28:02 +10001284 retval = 0;
1285/*XXXX*/
1286 sshkey_free(k);
1287 if (retval != 0)
1288 break;
Damien Miller86687062014-07-02 15:28:02 +10001289 break;
1290 default:
1291 return SSH_ERR_INVALID_ARGUMENT;
1292 }
1293 return retval;
1294}
1295
1296int
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001297sshkey_to_base64(const struct sshkey *key, char **b64p)
Damien Miller86687062014-07-02 15:28:02 +10001298{
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001299 int r = SSH_ERR_INTERNAL_ERROR;
1300 struct sshbuf *b = NULL;
Damien Miller86687062014-07-02 15:28:02 +10001301 char *uu = NULL;
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001302
1303 if (b64p != NULL)
1304 *b64p = NULL;
1305 if ((b = sshbuf_new()) == NULL)
1306 return SSH_ERR_ALLOC_FAIL;
1307 if ((r = sshkey_putb(key, b)) != 0)
1308 goto out;
1309 if ((uu = sshbuf_dtob64(b)) == NULL) {
1310 r = SSH_ERR_ALLOC_FAIL;
1311 goto out;
1312 }
1313 /* Success */
1314 if (b64p != NULL) {
1315 *b64p = uu;
1316 uu = NULL;
1317 }
1318 r = 0;
1319 out:
1320 sshbuf_free(b);
1321 free(uu);
1322 return r;
1323}
1324
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00001325int
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001326sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
1327{
1328 int r = SSH_ERR_INTERNAL_ERROR;
1329 char *uu = NULL;
1330
djm@openbsd.org873d3e72017-04-30 23:18:44 +00001331 if ((r = sshkey_to_base64(key, &uu)) != 0)
1332 goto out;
1333 if ((r = sshbuf_putf(b, "%s %s",
1334 sshkey_ssh_name(key), uu)) != 0)
1335 goto out;
djm@openbsd.orgd80fbe42015-05-21 04:55:51 +00001336 r = 0;
1337 out:
1338 free(uu);
1339 return r;
1340}
1341
1342int
1343sshkey_write(const struct sshkey *key, FILE *f)
1344{
1345 struct sshbuf *b = NULL;
1346 int r = SSH_ERR_INTERNAL_ERROR;
1347
1348 if ((b = sshbuf_new()) == NULL)
1349 return SSH_ERR_ALLOC_FAIL;
1350 if ((r = sshkey_format_text(key, b)) != 0)
1351 goto out;
1352 if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1353 if (feof(f))
1354 errno = EPIPE;
1355 r = SSH_ERR_SYSTEM_ERROR;
1356 goto out;
1357 }
1358 /* Success */
1359 r = 0;
1360 out:
1361 sshbuf_free(b);
1362 return r;
Damien Miller86687062014-07-02 15:28:02 +10001363}
1364
1365const char *
1366sshkey_cert_type(const struct sshkey *k)
1367{
1368 switch (k->cert->type) {
1369 case SSH2_CERT_TYPE_USER:
1370 return "user";
1371 case SSH2_CERT_TYPE_HOST:
1372 return "host";
1373 default:
1374 return "unknown";
1375 }
1376}
1377
1378#ifdef WITH_OPENSSL
1379static int
1380rsa_generate_private_key(u_int bits, RSA **rsap)
1381{
1382 RSA *private = NULL;
1383 BIGNUM *f4 = NULL;
1384 int ret = SSH_ERR_INTERNAL_ERROR;
1385
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001386 if (rsap == NULL)
Damien Miller86687062014-07-02 15:28:02 +10001387 return SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001388 if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
1389 bits > SSHBUF_MAX_BIGNUM * 8)
1390 return SSH_ERR_KEY_LENGTH;
Damien Miller86687062014-07-02 15:28:02 +10001391 *rsap = NULL;
1392 if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
1393 ret = SSH_ERR_ALLOC_FAIL;
1394 goto out;
1395 }
1396 if (!BN_set_word(f4, RSA_F4) ||
1397 !RSA_generate_key_ex(private, bits, f4, NULL)) {
1398 ret = SSH_ERR_LIBCRYPTO_ERROR;
1399 goto out;
1400 }
1401 *rsap = private;
1402 private = NULL;
1403 ret = 0;
1404 out:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001405 RSA_free(private);
1406 BN_free(f4);
Damien Miller86687062014-07-02 15:28:02 +10001407 return ret;
1408}
1409
1410static int
1411dsa_generate_private_key(u_int bits, DSA **dsap)
1412{
1413 DSA *private;
1414 int ret = SSH_ERR_INTERNAL_ERROR;
1415
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001416 if (dsap == NULL)
Damien Miller86687062014-07-02 15:28:02 +10001417 return SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001418 if (bits != 1024)
1419 return SSH_ERR_KEY_LENGTH;
Damien Miller86687062014-07-02 15:28:02 +10001420 if ((private = DSA_new()) == NULL) {
1421 ret = SSH_ERR_ALLOC_FAIL;
1422 goto out;
1423 }
1424 *dsap = NULL;
1425 if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
1426 NULL, NULL) || !DSA_generate_key(private)) {
Damien Miller86687062014-07-02 15:28:02 +10001427 ret = SSH_ERR_LIBCRYPTO_ERROR;
1428 goto out;
1429 }
1430 *dsap = private;
1431 private = NULL;
1432 ret = 0;
1433 out:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001434 DSA_free(private);
Damien Miller86687062014-07-02 15:28:02 +10001435 return ret;
1436}
1437
1438# ifdef OPENSSL_HAS_ECC
1439int
1440sshkey_ecdsa_key_to_nid(EC_KEY *k)
1441{
1442 EC_GROUP *eg;
1443 int nids[] = {
1444 NID_X9_62_prime256v1,
1445 NID_secp384r1,
1446# ifdef OPENSSL_HAS_NISTP521
1447 NID_secp521r1,
1448# endif /* OPENSSL_HAS_NISTP521 */
1449 -1
1450 };
1451 int nid;
1452 u_int i;
1453 BN_CTX *bnctx;
1454 const EC_GROUP *g = EC_KEY_get0_group(k);
1455
1456 /*
1457 * The group may be stored in a ASN.1 encoded private key in one of two
1458 * ways: as a "named group", which is reconstituted by ASN.1 object ID
1459 * or explicit group parameters encoded into the key blob. Only the
1460 * "named group" case sets the group NID for us, but we can figure
1461 * it out for the other case by comparing against all the groups that
1462 * are supported.
1463 */
1464 if ((nid = EC_GROUP_get_curve_name(g)) > 0)
1465 return nid;
1466 if ((bnctx = BN_CTX_new()) == NULL)
1467 return -1;
1468 for (i = 0; nids[i] != -1; i++) {
1469 if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) {
1470 BN_CTX_free(bnctx);
1471 return -1;
1472 }
1473 if (EC_GROUP_cmp(g, eg, bnctx) == 0)
1474 break;
1475 EC_GROUP_free(eg);
1476 }
1477 BN_CTX_free(bnctx);
1478 if (nids[i] != -1) {
1479 /* Use the group with the NID attached */
1480 EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
1481 if (EC_KEY_set_group(k, eg) != 1) {
1482 EC_GROUP_free(eg);
1483 return -1;
1484 }
1485 }
1486 return nids[i];
1487}
1488
1489static int
1490ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
1491{
1492 EC_KEY *private;
1493 int ret = SSH_ERR_INTERNAL_ERROR;
1494
djm@openbsd.org5f02bb12017-05-08 06:11:06 +00001495 if (nid == NULL || ecdsap == NULL)
Damien Miller86687062014-07-02 15:28:02 +10001496 return SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.org5f02bb12017-05-08 06:11:06 +00001497 if ((*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
1498 return SSH_ERR_KEY_LENGTH;
Damien Miller86687062014-07-02 15:28:02 +10001499 *ecdsap = NULL;
1500 if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) {
1501 ret = SSH_ERR_ALLOC_FAIL;
1502 goto out;
1503 }
1504 if (EC_KEY_generate_key(private) != 1) {
1505 ret = SSH_ERR_LIBCRYPTO_ERROR;
1506 goto out;
1507 }
1508 EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
1509 *ecdsap = private;
1510 private = NULL;
1511 ret = 0;
1512 out:
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001513 EC_KEY_free(private);
Damien Miller86687062014-07-02 15:28:02 +10001514 return ret;
1515}
1516# endif /* OPENSSL_HAS_ECC */
1517#endif /* WITH_OPENSSL */
1518
1519int
1520sshkey_generate(int type, u_int bits, struct sshkey **keyp)
1521{
1522 struct sshkey *k;
1523 int ret = SSH_ERR_INTERNAL_ERROR;
1524
1525 if (keyp == NULL)
1526 return SSH_ERR_INVALID_ARGUMENT;
1527 *keyp = NULL;
1528 if ((k = sshkey_new(KEY_UNSPEC)) == NULL)
1529 return SSH_ERR_ALLOC_FAIL;
1530 switch (type) {
1531 case KEY_ED25519:
1532 if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL ||
1533 (k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) {
1534 ret = SSH_ERR_ALLOC_FAIL;
1535 break;
1536 }
1537 crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
1538 ret = 0;
1539 break;
1540#ifdef WITH_OPENSSL
1541 case KEY_DSA:
1542 ret = dsa_generate_private_key(bits, &k->dsa);
1543 break;
1544# ifdef OPENSSL_HAS_ECC
1545 case KEY_ECDSA:
1546 ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid,
1547 &k->ecdsa);
1548 break;
1549# endif /* OPENSSL_HAS_ECC */
1550 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10001551 ret = rsa_generate_private_key(bits, &k->rsa);
1552 break;
1553#endif /* WITH_OPENSSL */
1554 default:
1555 ret = SSH_ERR_INVALID_ARGUMENT;
1556 }
1557 if (ret == 0) {
1558 k->type = type;
1559 *keyp = k;
1560 } else
1561 sshkey_free(k);
1562 return ret;
1563}
1564
1565int
1566sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
1567{
1568 u_int i;
1569 const struct sshkey_cert *from;
1570 struct sshkey_cert *to;
1571 int ret = SSH_ERR_INTERNAL_ERROR;
1572
1573 if (to_key->cert != NULL) {
1574 cert_free(to_key->cert);
1575 to_key->cert = NULL;
1576 }
1577
1578 if ((from = from_key->cert) == NULL)
1579 return SSH_ERR_INVALID_ARGUMENT;
1580
1581 if ((to = to_key->cert = cert_new()) == NULL)
1582 return SSH_ERR_ALLOC_FAIL;
1583
1584 if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
1585 (ret = sshbuf_putb(to->critical, from->critical)) != 0 ||
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00001586 (ret = sshbuf_putb(to->extensions, from->extensions)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001587 return ret;
1588
1589 to->serial = from->serial;
1590 to->type = from->type;
1591 if (from->key_id == NULL)
1592 to->key_id = NULL;
1593 else if ((to->key_id = strdup(from->key_id)) == NULL)
1594 return SSH_ERR_ALLOC_FAIL;
1595 to->valid_after = from->valid_after;
1596 to->valid_before = from->valid_before;
1597 if (from->signature_key == NULL)
1598 to->signature_key = NULL;
1599 else if ((ret = sshkey_from_private(from->signature_key,
1600 &to->signature_key)) != 0)
1601 return ret;
1602
1603 if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS)
1604 return SSH_ERR_INVALID_ARGUMENT;
1605 if (from->nprincipals > 0) {
1606 if ((to->principals = calloc(from->nprincipals,
1607 sizeof(*to->principals))) == NULL)
1608 return SSH_ERR_ALLOC_FAIL;
1609 for (i = 0; i < from->nprincipals; i++) {
1610 to->principals[i] = strdup(from->principals[i]);
1611 if (to->principals[i] == NULL) {
1612 to->nprincipals = i;
1613 return SSH_ERR_ALLOC_FAIL;
1614 }
1615 }
1616 }
1617 to->nprincipals = from->nprincipals;
1618 return 0;
1619}
1620
1621int
1622sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
1623{
1624 struct sshkey *n = NULL;
1625 int ret = SSH_ERR_INTERNAL_ERROR;
1626
djm@openbsd.org1a2663a2015-10-15 23:08:23 +00001627 *pkp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10001628 switch (k->type) {
1629#ifdef WITH_OPENSSL
1630 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +10001631 case KEY_DSA_CERT:
1632 if ((n = sshkey_new(k->type)) == NULL)
1633 return SSH_ERR_ALLOC_FAIL;
1634 if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
1635 (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
1636 (BN_copy(n->dsa->g, k->dsa->g) == NULL) ||
1637 (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) {
1638 sshkey_free(n);
1639 return SSH_ERR_ALLOC_FAIL;
1640 }
1641 break;
1642# ifdef OPENSSL_HAS_ECC
1643 case KEY_ECDSA:
1644 case KEY_ECDSA_CERT:
1645 if ((n = sshkey_new(k->type)) == NULL)
1646 return SSH_ERR_ALLOC_FAIL;
1647 n->ecdsa_nid = k->ecdsa_nid;
1648 n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
1649 if (n->ecdsa == NULL) {
1650 sshkey_free(n);
1651 return SSH_ERR_ALLOC_FAIL;
1652 }
1653 if (EC_KEY_set_public_key(n->ecdsa,
1654 EC_KEY_get0_public_key(k->ecdsa)) != 1) {
1655 sshkey_free(n);
1656 return SSH_ERR_LIBCRYPTO_ERROR;
1657 }
1658 break;
1659# endif /* OPENSSL_HAS_ECC */
1660 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10001661 case KEY_RSA_CERT:
1662 if ((n = sshkey_new(k->type)) == NULL)
1663 return SSH_ERR_ALLOC_FAIL;
1664 if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
1665 (BN_copy(n->rsa->e, k->rsa->e) == NULL)) {
1666 sshkey_free(n);
1667 return SSH_ERR_ALLOC_FAIL;
1668 }
1669 break;
1670#endif /* WITH_OPENSSL */
1671 case KEY_ED25519:
1672 case KEY_ED25519_CERT:
1673 if ((n = sshkey_new(k->type)) == NULL)
1674 return SSH_ERR_ALLOC_FAIL;
1675 if (k->ed25519_pk != NULL) {
1676 if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
1677 sshkey_free(n);
1678 return SSH_ERR_ALLOC_FAIL;
1679 }
1680 memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
1681 }
1682 break;
1683 default:
1684 return SSH_ERR_KEY_TYPE_UNKNOWN;
1685 }
1686 if (sshkey_is_cert(k)) {
1687 if ((ret = sshkey_cert_copy(k, n)) != 0) {
1688 sshkey_free(n);
1689 return ret;
1690 }
1691 }
1692 *pkp = n;
1693 return 0;
1694}
1695
1696static int
djm@openbsd.org60b18252015-01-26 02:59:11 +00001697cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
Damien Miller86687062014-07-02 15:28:02 +10001698{
djm@openbsd.org60b18252015-01-26 02:59:11 +00001699 struct sshbuf *principals = NULL, *crit = NULL;
1700 struct sshbuf *exts = NULL, *ca = NULL;
1701 u_char *sig = NULL;
1702 size_t signed_len = 0, slen = 0, kidlen = 0;
Damien Miller86687062014-07-02 15:28:02 +10001703 int ret = SSH_ERR_INTERNAL_ERROR;
Damien Miller86687062014-07-02 15:28:02 +10001704
1705 /* Copy the entire key blob for verification and later serialisation */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001706 if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001707 return ret;
1708
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00001709 /* Parse body of certificate up to signature */
1710 if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10001711 (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 ||
1712 (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 ||
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001713 (ret = sshbuf_froms(b, &principals)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10001714 (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 ||
1715 (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 ||
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001716 (ret = sshbuf_froms(b, &crit)) != 0 ||
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00001717 (ret = sshbuf_froms(b, &exts)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10001718 (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 ||
djm@openbsd.org60b18252015-01-26 02:59:11 +00001719 (ret = sshbuf_froms(b, &ca)) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001720 /* XXX debug print error for ret */
1721 ret = SSH_ERR_INVALID_FORMAT;
1722 goto out;
1723 }
1724
1725 /* Signature is left in the buffer so we can calculate this length */
1726 signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b);
1727
1728 if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) {
1729 ret = SSH_ERR_INVALID_FORMAT;
1730 goto out;
1731 }
1732
1733 if (key->cert->type != SSH2_CERT_TYPE_USER &&
1734 key->cert->type != SSH2_CERT_TYPE_HOST) {
1735 ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
1736 goto out;
1737 }
1738
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001739 /* Parse principals section */
1740 while (sshbuf_len(principals) > 0) {
1741 char *principal = NULL;
1742 char **oprincipals = NULL;
1743
Damien Miller86687062014-07-02 15:28:02 +10001744 if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) {
1745 ret = SSH_ERR_INVALID_FORMAT;
1746 goto out;
1747 }
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001748 if ((ret = sshbuf_get_cstring(principals, &principal,
1749 NULL)) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001750 ret = SSH_ERR_INVALID_FORMAT;
1751 goto out;
1752 }
1753 oprincipals = key->cert->principals;
deraadt@openbsd.org9e509d42017-05-31 09:15:42 +00001754 key->cert->principals = recallocarray(key->cert->principals,
1755 key->cert->nprincipals, key->cert->nprincipals + 1,
1756 sizeof(*key->cert->principals));
Damien Miller86687062014-07-02 15:28:02 +10001757 if (key->cert->principals == NULL) {
1758 free(principal);
1759 key->cert->principals = oprincipals;
1760 ret = SSH_ERR_ALLOC_FAIL;
1761 goto out;
1762 }
1763 key->cert->principals[key->cert->nprincipals++] = principal;
1764 }
1765
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001766 /*
1767 * Stash a copies of the critical options and extensions sections
1768 * for later use.
1769 */
1770 if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 ||
1771 (exts != NULL &&
1772 (ret = sshbuf_putb(key->cert->extensions, exts)) != 0))
Damien Miller86687062014-07-02 15:28:02 +10001773 goto out;
1774
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001775 /*
1776 * Validate critical options and extensions sections format.
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001777 */
1778 while (sshbuf_len(crit) != 0) {
1779 if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 ||
1780 (ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) {
1781 sshbuf_reset(key->cert->critical);
Damien Miller86687062014-07-02 15:28:02 +10001782 ret = SSH_ERR_INVALID_FORMAT;
1783 goto out;
1784 }
1785 }
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001786 while (exts != NULL && sshbuf_len(exts) != 0) {
1787 if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 ||
1788 (ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) {
1789 sshbuf_reset(key->cert->extensions);
Damien Miller86687062014-07-02 15:28:02 +10001790 ret = SSH_ERR_INVALID_FORMAT;
1791 goto out;
1792 }
1793 }
Damien Miller86687062014-07-02 15:28:02 +10001794
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001795 /* Parse CA key and check signature */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001796 if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001797 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1798 goto out;
1799 }
1800 if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
1801 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1802 goto out;
1803 }
Damien Miller86687062014-07-02 15:28:02 +10001804 if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
djm@openbsd.org04c7e282017-12-18 02:25:15 +00001805 sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001806 goto out;
Damien Miller86687062014-07-02 15:28:02 +10001807
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001808 /* Success */
1809 ret = 0;
Damien Miller86687062014-07-02 15:28:02 +10001810 out:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001811 sshbuf_free(ca);
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00001812 sshbuf_free(crit);
1813 sshbuf_free(exts);
1814 sshbuf_free(principals);
Damien Miller86687062014-07-02 15:28:02 +10001815 free(sig);
1816 return ret;
1817}
1818
1819static int
djm@openbsd.org60b18252015-01-26 02:59:11 +00001820sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
1821 int allow_cert)
Damien Miller86687062014-07-02 15:28:02 +10001822{
djm@openbsd.org54924b52015-01-14 10:46:28 +00001823 int type, ret = SSH_ERR_INTERNAL_ERROR;
Damien Miller86687062014-07-02 15:28:02 +10001824 char *ktype = NULL, *curve = NULL;
1825 struct sshkey *key = NULL;
1826 size_t len;
1827 u_char *pk = NULL;
djm@openbsd.org60b18252015-01-26 02:59:11 +00001828 struct sshbuf *copy;
Damien Miller86687062014-07-02 15:28:02 +10001829#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
1830 EC_POINT *q = NULL;
1831#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
1832
1833#ifdef DEBUG_PK /* XXX */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001834 sshbuf_dump(b, stderr);
Damien Miller86687062014-07-02 15:28:02 +10001835#endif
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00001836 if (keyp != NULL)
1837 *keyp = NULL;
djm@openbsd.org60b18252015-01-26 02:59:11 +00001838 if ((copy = sshbuf_fromb(b)) == NULL) {
1839 ret = SSH_ERR_ALLOC_FAIL;
1840 goto out;
1841 }
Damien Miller86687062014-07-02 15:28:02 +10001842 if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
1843 ret = SSH_ERR_INVALID_FORMAT;
1844 goto out;
1845 }
1846
1847 type = sshkey_type_from_name(ktype);
Damien Miller86687062014-07-02 15:28:02 +10001848 if (!allow_cert && sshkey_type_is_cert(type)) {
1849 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1850 goto out;
1851 }
1852 switch (type) {
1853#ifdef WITH_OPENSSL
1854 case KEY_RSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001855 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001856 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1857 ret = SSH_ERR_INVALID_FORMAT;
1858 goto out;
1859 }
1860 /* FALLTHROUGH */
1861 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10001862 if ((key = sshkey_new(type)) == NULL) {
1863 ret = SSH_ERR_ALLOC_FAIL;
1864 goto out;
1865 }
djm@openbsd.org3f4ea3c2015-04-03 22:17:27 +00001866 if (sshbuf_get_bignum2(b, key->rsa->e) != 0 ||
1867 sshbuf_get_bignum2(b, key->rsa->n) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001868 ret = SSH_ERR_INVALID_FORMAT;
1869 goto out;
1870 }
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00001871 if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
1872 ret = SSH_ERR_KEY_LENGTH;
1873 goto out;
1874 }
Damien Miller86687062014-07-02 15:28:02 +10001875#ifdef DEBUG_PK
1876 RSA_print_fp(stderr, key->rsa, 8);
1877#endif
1878 break;
1879 case KEY_DSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001880 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001881 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1882 ret = SSH_ERR_INVALID_FORMAT;
1883 goto out;
1884 }
1885 /* FALLTHROUGH */
1886 case KEY_DSA:
Damien Miller86687062014-07-02 15:28:02 +10001887 if ((key = sshkey_new(type)) == NULL) {
1888 ret = SSH_ERR_ALLOC_FAIL;
1889 goto out;
1890 }
djm@openbsd.org3f4ea3c2015-04-03 22:17:27 +00001891 if (sshbuf_get_bignum2(b, key->dsa->p) != 0 ||
1892 sshbuf_get_bignum2(b, key->dsa->q) != 0 ||
1893 sshbuf_get_bignum2(b, key->dsa->g) != 0 ||
1894 sshbuf_get_bignum2(b, key->dsa->pub_key) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10001895 ret = SSH_ERR_INVALID_FORMAT;
1896 goto out;
1897 }
1898#ifdef DEBUG_PK
1899 DSA_print_fp(stderr, key->dsa, 8);
1900#endif
1901 break;
1902 case KEY_ECDSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001903 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001904 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1905 ret = SSH_ERR_INVALID_FORMAT;
1906 goto out;
1907 }
1908 /* FALLTHROUGH */
1909# ifdef OPENSSL_HAS_ECC
1910 case KEY_ECDSA:
1911 if ((key = sshkey_new(type)) == NULL) {
1912 ret = SSH_ERR_ALLOC_FAIL;
1913 goto out;
1914 }
djm@openbsd.org54924b52015-01-14 10:46:28 +00001915 key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype);
Damien Miller86687062014-07-02 15:28:02 +10001916 if (sshbuf_get_cstring(b, &curve, NULL) != 0) {
1917 ret = SSH_ERR_INVALID_FORMAT;
1918 goto out;
1919 }
1920 if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
1921 ret = SSH_ERR_EC_CURVE_MISMATCH;
1922 goto out;
1923 }
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00001924 EC_KEY_free(key->ecdsa);
Damien Miller86687062014-07-02 15:28:02 +10001925 if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
1926 == NULL) {
1927 ret = SSH_ERR_EC_CURVE_INVALID;
1928 goto out;
1929 }
1930 if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
1931 ret = SSH_ERR_ALLOC_FAIL;
1932 goto out;
1933 }
1934 if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
1935 ret = SSH_ERR_INVALID_FORMAT;
1936 goto out;
1937 }
1938 if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
1939 q) != 0) {
1940 ret = SSH_ERR_KEY_INVALID_EC_VALUE;
1941 goto out;
1942 }
1943 if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
1944 /* XXX assume it is a allocation error */
1945 ret = SSH_ERR_ALLOC_FAIL;
1946 goto out;
1947 }
1948#ifdef DEBUG_PK
1949 sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
1950#endif
1951 break;
1952# endif /* OPENSSL_HAS_ECC */
1953#endif /* WITH_OPENSSL */
1954 case KEY_ED25519_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001955 /* Skip nonce */
Damien Miller86687062014-07-02 15:28:02 +10001956 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1957 ret = SSH_ERR_INVALID_FORMAT;
1958 goto out;
1959 }
1960 /* FALLTHROUGH */
1961 case KEY_ED25519:
1962 if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
1963 goto out;
1964 if (len != ED25519_PK_SZ) {
1965 ret = SSH_ERR_INVALID_FORMAT;
1966 goto out;
1967 }
1968 if ((key = sshkey_new(type)) == NULL) {
1969 ret = SSH_ERR_ALLOC_FAIL;
1970 goto out;
1971 }
1972 key->ed25519_pk = pk;
1973 pk = NULL;
1974 break;
1975 case KEY_UNSPEC:
Damien Miller86687062014-07-02 15:28:02 +10001976 default:
1977 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
1978 goto out;
1979 }
1980
1981 /* Parse certificate potion */
djm@openbsd.org60b18252015-01-26 02:59:11 +00001982 if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10001983 goto out;
1984
1985 if (key != NULL && sshbuf_len(b) != 0) {
1986 ret = SSH_ERR_INVALID_FORMAT;
1987 goto out;
1988 }
1989 ret = 0;
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00001990 if (keyp != NULL) {
1991 *keyp = key;
1992 key = NULL;
1993 }
Damien Miller86687062014-07-02 15:28:02 +10001994 out:
djm@openbsd.org60b18252015-01-26 02:59:11 +00001995 sshbuf_free(copy);
Damien Miller86687062014-07-02 15:28:02 +10001996 sshkey_free(key);
1997 free(ktype);
1998 free(curve);
1999 free(pk);
2000#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00002001 EC_POINT_free(q);
Damien Miller86687062014-07-02 15:28:02 +10002002#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2003 return ret;
2004}
2005
2006int
2007sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
2008{
djm@openbsd.org60b18252015-01-26 02:59:11 +00002009 struct sshbuf *b;
2010 int r;
2011
2012 if ((b = sshbuf_from(blob, blen)) == NULL)
2013 return SSH_ERR_ALLOC_FAIL;
2014 r = sshkey_from_blob_internal(b, keyp, 1);
2015 sshbuf_free(b);
2016 return r;
2017}
2018
2019int
2020sshkey_fromb(struct sshbuf *b, struct sshkey **keyp)
2021{
2022 return sshkey_from_blob_internal(b, keyp, 1);
2023}
2024
2025int
2026sshkey_froms(struct sshbuf *buf, struct sshkey **keyp)
2027{
2028 struct sshbuf *b;
2029 int r;
2030
2031 if ((r = sshbuf_froms(buf, &b)) != 0)
2032 return r;
2033 r = sshkey_from_blob_internal(b, keyp, 1);
2034 sshbuf_free(b);
2035 return r;
Damien Miller86687062014-07-02 15:28:02 +10002036}
2037
2038int
djm@openbsd.org931c78d2017-12-18 02:22:29 +00002039sshkey_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
2040{
2041 int r;
2042 struct sshbuf *b = NULL;
2043 char *sigtype = NULL;
2044
2045 if (sigtypep != NULL)
2046 *sigtypep = NULL;
2047 if ((b = sshbuf_from(sig, siglen)) == NULL)
2048 return SSH_ERR_ALLOC_FAIL;
2049 if ((r = sshbuf_get_cstring(b, &sigtype, NULL)) != 0)
2050 goto out;
2051 /* success */
2052 if (sigtypep != NULL) {
2053 *sigtypep = sigtype;
2054 sigtype = NULL;
2055 }
2056 r = 0;
2057 out:
2058 free(sigtype);
2059 sshbuf_free(b);
2060 return r;
2061}
2062
2063int
Damien Miller86687062014-07-02 15:28:02 +10002064sshkey_sign(const struct sshkey *key,
2065 u_char **sigp, size_t *lenp,
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +00002066 const u_char *data, size_t datalen, const char *alg, u_int compat)
Damien Miller86687062014-07-02 15:28:02 +10002067{
2068 if (sigp != NULL)
2069 *sigp = NULL;
2070 if (lenp != NULL)
2071 *lenp = 0;
2072 if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
2073 return SSH_ERR_INVALID_ARGUMENT;
2074 switch (key->type) {
2075#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002076 case KEY_DSA_CERT:
2077 case KEY_DSA:
2078 return ssh_dss_sign(key, sigp, lenp, data, datalen, compat);
2079# ifdef OPENSSL_HAS_ECC
2080 case KEY_ECDSA_CERT:
2081 case KEY_ECDSA:
2082 return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat);
2083# endif /* OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +10002084 case KEY_RSA_CERT:
2085 case KEY_RSA:
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +00002086 return ssh_rsa_sign(key, sigp, lenp, data, datalen, alg);
Damien Miller86687062014-07-02 15:28:02 +10002087#endif /* WITH_OPENSSL */
2088 case KEY_ED25519:
2089 case KEY_ED25519_CERT:
2090 return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat);
2091 default:
2092 return SSH_ERR_KEY_TYPE_UNKNOWN;
2093 }
2094}
2095
2096/*
2097 * ssh_key_verify returns 0 for a correct signature and < 0 on error.
djm@openbsd.org04c7e282017-12-18 02:25:15 +00002098 * If "alg" specified, then the signature must use that algorithm.
Damien Miller86687062014-07-02 15:28:02 +10002099 */
2100int
2101sshkey_verify(const struct sshkey *key,
2102 const u_char *sig, size_t siglen,
djm@openbsd.org04c7e282017-12-18 02:25:15 +00002103 const u_char *data, size_t dlen, const char *alg, u_int compat)
Damien Miller86687062014-07-02 15:28:02 +10002104{
djm@openbsd.org4cf87f42014-12-10 01:24:09 +00002105 if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
Damien Miller86687062014-07-02 15:28:02 +10002106 return SSH_ERR_INVALID_ARGUMENT;
2107 switch (key->type) {
2108#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002109 case KEY_DSA_CERT:
2110 case KEY_DSA:
2111 return ssh_dss_verify(key, sig, siglen, data, dlen, compat);
2112# ifdef OPENSSL_HAS_ECC
2113 case KEY_ECDSA_CERT:
2114 case KEY_ECDSA:
2115 return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat);
2116# endif /* OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +10002117 case KEY_RSA_CERT:
2118 case KEY_RSA:
djm@openbsd.org04c7e282017-12-18 02:25:15 +00002119 return ssh_rsa_verify(key, sig, siglen, data, dlen, alg);
Damien Miller86687062014-07-02 15:28:02 +10002120#endif /* WITH_OPENSSL */
2121 case KEY_ED25519:
2122 case KEY_ED25519_CERT:
2123 return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
2124 default:
2125 return SSH_ERR_KEY_TYPE_UNKNOWN;
2126 }
2127}
2128
2129/* Converts a private to a public key */
2130int
2131sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
2132{
2133 struct sshkey *pk;
2134 int ret = SSH_ERR_INTERNAL_ERROR;
2135
djm@openbsd.org1a2663a2015-10-15 23:08:23 +00002136 *dkp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002137 if ((pk = calloc(1, sizeof(*pk))) == NULL)
2138 return SSH_ERR_ALLOC_FAIL;
2139 pk->type = k->type;
2140 pk->flags = k->flags;
2141 pk->ecdsa_nid = k->ecdsa_nid;
2142 pk->dsa = NULL;
2143 pk->ecdsa = NULL;
2144 pk->rsa = NULL;
2145 pk->ed25519_pk = NULL;
2146 pk->ed25519_sk = NULL;
2147
2148 switch (k->type) {
2149#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002150 case KEY_RSA_CERT:
2151 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2152 goto fail;
2153 /* FALLTHROUGH */
Damien Miller86687062014-07-02 15:28:02 +10002154 case KEY_RSA:
2155 if ((pk->rsa = RSA_new()) == NULL ||
2156 (pk->rsa->e = BN_dup(k->rsa->e)) == NULL ||
2157 (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) {
2158 ret = SSH_ERR_ALLOC_FAIL;
2159 goto fail;
2160 }
2161 break;
Damien Miller86687062014-07-02 15:28:02 +10002162 case KEY_DSA_CERT:
2163 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2164 goto fail;
2165 /* FALLTHROUGH */
2166 case KEY_DSA:
2167 if ((pk->dsa = DSA_new()) == NULL ||
2168 (pk->dsa->p = BN_dup(k->dsa->p)) == NULL ||
2169 (pk->dsa->q = BN_dup(k->dsa->q)) == NULL ||
2170 (pk->dsa->g = BN_dup(k->dsa->g)) == NULL ||
2171 (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) {
2172 ret = SSH_ERR_ALLOC_FAIL;
2173 goto fail;
2174 }
2175 break;
2176 case KEY_ECDSA_CERT:
2177 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2178 goto fail;
2179 /* FALLTHROUGH */
2180# ifdef OPENSSL_HAS_ECC
2181 case KEY_ECDSA:
2182 pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid);
2183 if (pk->ecdsa == NULL) {
2184 ret = SSH_ERR_ALLOC_FAIL;
2185 goto fail;
2186 }
2187 if (EC_KEY_set_public_key(pk->ecdsa,
2188 EC_KEY_get0_public_key(k->ecdsa)) != 1) {
2189 ret = SSH_ERR_LIBCRYPTO_ERROR;
2190 goto fail;
2191 }
2192 break;
2193# endif /* OPENSSL_HAS_ECC */
2194#endif /* WITH_OPENSSL */
2195 case KEY_ED25519_CERT:
2196 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2197 goto fail;
2198 /* FALLTHROUGH */
2199 case KEY_ED25519:
2200 if (k->ed25519_pk != NULL) {
2201 if ((pk->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
2202 ret = SSH_ERR_ALLOC_FAIL;
2203 goto fail;
2204 }
2205 memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
2206 }
2207 break;
2208 default:
2209 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
2210 fail:
2211 sshkey_free(pk);
2212 return ret;
2213 }
2214 *dkp = pk;
2215 return 0;
2216}
2217
2218/* Convert a plain key to their _CERT equivalent */
2219int
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002220sshkey_to_certified(struct sshkey *k)
Damien Miller86687062014-07-02 15:28:02 +10002221{
2222 int newtype;
2223
2224 switch (k->type) {
2225#ifdef WITH_OPENSSL
2226 case KEY_RSA:
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002227 newtype = KEY_RSA_CERT;
Damien Miller86687062014-07-02 15:28:02 +10002228 break;
2229 case KEY_DSA:
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002230 newtype = KEY_DSA_CERT;
Damien Miller86687062014-07-02 15:28:02 +10002231 break;
2232 case KEY_ECDSA:
Damien Miller86687062014-07-02 15:28:02 +10002233 newtype = KEY_ECDSA_CERT;
2234 break;
2235#endif /* WITH_OPENSSL */
2236 case KEY_ED25519:
Damien Miller86687062014-07-02 15:28:02 +10002237 newtype = KEY_ED25519_CERT;
2238 break;
2239 default:
2240 return SSH_ERR_INVALID_ARGUMENT;
2241 }
2242 if ((k->cert = cert_new()) == NULL)
2243 return SSH_ERR_ALLOC_FAIL;
2244 k->type = newtype;
2245 return 0;
2246}
2247
2248/* Convert a certificate to its raw key equivalent */
2249int
2250sshkey_drop_cert(struct sshkey *k)
2251{
2252 if (!sshkey_type_is_cert(k->type))
2253 return SSH_ERR_KEY_TYPE_UNKNOWN;
2254 cert_free(k->cert);
2255 k->cert = NULL;
2256 k->type = sshkey_type_plain(k->type);
2257 return 0;
2258}
2259
2260/* Sign a certified key, (re-)generating the signed certblob. */
2261int
djm@openbsd.orga98339e2017-06-28 01:09:22 +00002262sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
2263 sshkey_certify_signer *signer, void *signer_ctx)
Damien Miller86687062014-07-02 15:28:02 +10002264{
2265 struct sshbuf *principals = NULL;
2266 u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
2267 size_t i, ca_len, sig_len;
2268 int ret = SSH_ERR_INTERNAL_ERROR;
2269 struct sshbuf *cert;
2270
2271 if (k == NULL || k->cert == NULL ||
2272 k->cert->certblob == NULL || ca == NULL)
2273 return SSH_ERR_INVALID_ARGUMENT;
2274 if (!sshkey_is_cert(k))
2275 return SSH_ERR_KEY_TYPE_UNKNOWN;
2276 if (!sshkey_type_is_valid_ca(ca->type))
2277 return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2278
2279 if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0)
2280 return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2281
2282 cert = k->cert->certblob; /* for readability */
2283 sshbuf_reset(cert);
2284 if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0)
2285 goto out;
2286
2287 /* -v01 certs put nonce first */
2288 arc4random_buf(&nonce, sizeof(nonce));
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002289 if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
2290 goto out;
Damien Miller86687062014-07-02 15:28:02 +10002291
2292 /* XXX this substantially duplicates to_blob(); refactor */
2293 switch (k->type) {
2294#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10002295 case KEY_DSA_CERT:
2296 if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 ||
2297 (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 ||
2298 (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 ||
2299 (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0)
2300 goto out;
2301 break;
2302# ifdef OPENSSL_HAS_ECC
2303 case KEY_ECDSA_CERT:
2304 if ((ret = sshbuf_put_cstring(cert,
2305 sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 ||
2306 (ret = sshbuf_put_ec(cert,
2307 EC_KEY_get0_public_key(k->ecdsa),
2308 EC_KEY_get0_group(k->ecdsa))) != 0)
2309 goto out;
2310 break;
2311# endif /* OPENSSL_HAS_ECC */
Damien Miller86687062014-07-02 15:28:02 +10002312 case KEY_RSA_CERT:
2313 if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 ||
2314 (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0)
2315 goto out;
2316 break;
2317#endif /* WITH_OPENSSL */
2318 case KEY_ED25519_CERT:
2319 if ((ret = sshbuf_put_string(cert,
2320 k->ed25519_pk, ED25519_PK_SZ)) != 0)
2321 goto out;
2322 break;
2323 default:
2324 ret = SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.org55e5bde2015-03-06 01:40:56 +00002325 goto out;
Damien Miller86687062014-07-02 15:28:02 +10002326 }
2327
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002328 if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 ||
2329 (ret = sshbuf_put_u32(cert, k->cert->type)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002330 (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0)
2331 goto out;
2332
2333 if ((principals = sshbuf_new()) == NULL) {
2334 ret = SSH_ERR_ALLOC_FAIL;
2335 goto out;
2336 }
2337 for (i = 0; i < k->cert->nprincipals; i++) {
2338 if ((ret = sshbuf_put_cstring(principals,
2339 k->cert->principals[i])) != 0)
2340 goto out;
2341 }
2342 if ((ret = sshbuf_put_stringb(cert, principals)) != 0 ||
2343 (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 ||
2344 (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 ||
djm@openbsd.orgc28fc622015-07-03 03:43:18 +00002345 (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 ||
2346 (ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 ||
2347 (ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */
Damien Miller86687062014-07-02 15:28:02 +10002348 (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0)
2349 goto out;
2350
2351 /* Sign the whole mess */
djm@openbsd.orga98339e2017-06-28 01:09:22 +00002352 if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
2353 sshbuf_len(cert), alg, 0, signer_ctx)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10002354 goto out;
2355
2356 /* Append signature and we are done */
2357 if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
2358 goto out;
2359 ret = 0;
2360 out:
2361 if (ret != 0)
2362 sshbuf_reset(cert);
mmcc@openbsd.orgd59ce082015-12-10 17:08:40 +00002363 free(sig_blob);
2364 free(ca_blob);
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002365 sshbuf_free(principals);
Damien Miller86687062014-07-02 15:28:02 +10002366 return ret;
2367}
2368
djm@openbsd.orga98339e2017-06-28 01:09:22 +00002369static int
2370default_key_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
2371 const u_char *data, size_t datalen,
2372 const char *alg, u_int compat, void *ctx)
2373{
2374 if (ctx != NULL)
2375 return SSH_ERR_INVALID_ARGUMENT;
2376 return sshkey_sign(key, sigp, lenp, data, datalen, alg, compat);
2377}
2378
2379int
2380sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
2381{
2382 return sshkey_certify_custom(k, ca, alg, default_key_sign, NULL);
2383}
2384
Damien Miller86687062014-07-02 15:28:02 +10002385int
2386sshkey_cert_check_authority(const struct sshkey *k,
2387 int want_host, int require_principal,
2388 const char *name, const char **reason)
2389{
2390 u_int i, principal_matches;
2391 time_t now = time(NULL);
2392
2393 if (reason != NULL)
2394 *reason = NULL;
2395
2396 if (want_host) {
2397 if (k->cert->type != SSH2_CERT_TYPE_HOST) {
2398 *reason = "Certificate invalid: not a host certificate";
2399 return SSH_ERR_KEY_CERT_INVALID;
2400 }
2401 } else {
2402 if (k->cert->type != SSH2_CERT_TYPE_USER) {
2403 *reason = "Certificate invalid: not a user certificate";
2404 return SSH_ERR_KEY_CERT_INVALID;
2405 }
2406 }
2407 if (now < 0) {
2408 /* yikes - system clock before epoch! */
2409 *reason = "Certificate invalid: not yet valid";
2410 return SSH_ERR_KEY_CERT_INVALID;
2411 }
2412 if ((u_int64_t)now < k->cert->valid_after) {
2413 *reason = "Certificate invalid: not yet valid";
2414 return SSH_ERR_KEY_CERT_INVALID;
2415 }
2416 if ((u_int64_t)now >= k->cert->valid_before) {
2417 *reason = "Certificate invalid: expired";
2418 return SSH_ERR_KEY_CERT_INVALID;
2419 }
2420 if (k->cert->nprincipals == 0) {
2421 if (require_principal) {
2422 *reason = "Certificate lacks principal list";
2423 return SSH_ERR_KEY_CERT_INVALID;
2424 }
2425 } else if (name != NULL) {
2426 principal_matches = 0;
2427 for (i = 0; i < k->cert->nprincipals; i++) {
2428 if (strcmp(name, k->cert->principals[i]) == 0) {
2429 principal_matches = 1;
2430 break;
2431 }
2432 }
2433 if (!principal_matches) {
2434 *reason = "Certificate invalid: name is not a listed "
2435 "principal";
2436 return SSH_ERR_KEY_CERT_INVALID;
2437 }
2438 }
2439 return 0;
2440}
2441
djm@openbsd.org499cf362015-11-19 01:08:55 +00002442size_t
2443sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
2444{
2445 char from[32], to[32], ret[64];
2446 time_t tt;
2447 struct tm *tm;
2448
2449 *from = *to = '\0';
2450 if (cert->valid_after == 0 &&
2451 cert->valid_before == 0xffffffffffffffffULL)
2452 return strlcpy(s, "forever", l);
2453
2454 if (cert->valid_after != 0) {
2455 /* XXX revisit INT_MAX in 2038 :) */
2456 tt = cert->valid_after > INT_MAX ?
2457 INT_MAX : cert->valid_after;
2458 tm = localtime(&tt);
2459 strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
2460 }
2461 if (cert->valid_before != 0xffffffffffffffffULL) {
2462 /* XXX revisit INT_MAX in 2038 :) */
2463 tt = cert->valid_before > INT_MAX ?
2464 INT_MAX : cert->valid_before;
2465 tm = localtime(&tt);
2466 strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
2467 }
2468
2469 if (cert->valid_after == 0)
2470 snprintf(ret, sizeof(ret), "before %s", to);
2471 else if (cert->valid_before == 0xffffffffffffffffULL)
2472 snprintf(ret, sizeof(ret), "after %s", from);
2473 else
2474 snprintf(ret, sizeof(ret), "from %s to %s", from, to);
2475
2476 return strlcpy(s, ret, l);
2477}
2478
Damien Miller86687062014-07-02 15:28:02 +10002479int
2480sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
2481{
2482 int r = SSH_ERR_INTERNAL_ERROR;
2483
2484 if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0)
2485 goto out;
2486 switch (key->type) {
2487#ifdef WITH_OPENSSL
2488 case KEY_RSA:
2489 if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 ||
2490 (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
2491 (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
2492 (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
2493 (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
2494 (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
2495 goto out;
2496 break;
Damien Miller86687062014-07-02 15:28:02 +10002497 case KEY_RSA_CERT:
2498 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2499 r = SSH_ERR_INVALID_ARGUMENT;
2500 goto out;
2501 }
2502 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2503 (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
2504 (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
2505 (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
2506 (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
2507 goto out;
2508 break;
2509 case KEY_DSA:
2510 if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
2511 (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
2512 (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
2513 (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 ||
2514 (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
2515 goto out;
2516 break;
Damien Miller86687062014-07-02 15:28:02 +10002517 case KEY_DSA_CERT:
2518 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2519 r = SSH_ERR_INVALID_ARGUMENT;
2520 goto out;
2521 }
2522 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2523 (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
2524 goto out;
2525 break;
2526# ifdef OPENSSL_HAS_ECC
2527 case KEY_ECDSA:
2528 if ((r = sshbuf_put_cstring(b,
2529 sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
2530 (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 ||
2531 (r = sshbuf_put_bignum2(b,
2532 EC_KEY_get0_private_key(key->ecdsa))) != 0)
2533 goto out;
2534 break;
2535 case KEY_ECDSA_CERT:
2536 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2537 r = SSH_ERR_INVALID_ARGUMENT;
2538 goto out;
2539 }
2540 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2541 (r = sshbuf_put_bignum2(b,
2542 EC_KEY_get0_private_key(key->ecdsa))) != 0)
2543 goto out;
2544 break;
2545# endif /* OPENSSL_HAS_ECC */
2546#endif /* WITH_OPENSSL */
2547 case KEY_ED25519:
2548 if ((r = sshbuf_put_string(b, key->ed25519_pk,
2549 ED25519_PK_SZ)) != 0 ||
2550 (r = sshbuf_put_string(b, key->ed25519_sk,
2551 ED25519_SK_SZ)) != 0)
2552 goto out;
2553 break;
2554 case KEY_ED25519_CERT:
2555 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2556 r = SSH_ERR_INVALID_ARGUMENT;
2557 goto out;
2558 }
2559 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2560 (r = sshbuf_put_string(b, key->ed25519_pk,
2561 ED25519_PK_SZ)) != 0 ||
2562 (r = sshbuf_put_string(b, key->ed25519_sk,
2563 ED25519_SK_SZ)) != 0)
2564 goto out;
2565 break;
2566 default:
2567 r = SSH_ERR_INVALID_ARGUMENT;
2568 goto out;
2569 }
2570 /* success */
2571 r = 0;
2572 out:
2573 return r;
2574}
2575
2576int
2577sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2578{
2579 char *tname = NULL, *curve = NULL;
2580 struct sshkey *k = NULL;
djm@openbsd.org60b18252015-01-26 02:59:11 +00002581 size_t pklen = 0, sklen = 0;
Damien Miller86687062014-07-02 15:28:02 +10002582 int type, r = SSH_ERR_INTERNAL_ERROR;
2583 u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
2584#ifdef WITH_OPENSSL
2585 BIGNUM *exponent = NULL;
2586#endif /* WITH_OPENSSL */
2587
2588 if (kp != NULL)
2589 *kp = NULL;
2590 if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0)
2591 goto out;
2592 type = sshkey_type_from_name(tname);
2593 switch (type) {
2594#ifdef WITH_OPENSSL
2595 case KEY_DSA:
2596 if ((k = sshkey_new_private(type)) == NULL) {
2597 r = SSH_ERR_ALLOC_FAIL;
2598 goto out;
2599 }
2600 if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 ||
2601 (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 ||
2602 (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 ||
2603 (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 ||
2604 (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
2605 goto out;
2606 break;
Damien Miller86687062014-07-02 15:28:02 +10002607 case KEY_DSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00002608 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002609 (r = sshkey_add_private(k)) != 0 ||
2610 (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
2611 goto out;
2612 break;
2613# ifdef OPENSSL_HAS_ECC
2614 case KEY_ECDSA:
2615 if ((k = sshkey_new_private(type)) == NULL) {
2616 r = SSH_ERR_ALLOC_FAIL;
2617 goto out;
2618 }
2619 if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
2620 r = SSH_ERR_INVALID_ARGUMENT;
2621 goto out;
2622 }
2623 if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
2624 goto out;
2625 if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
2626 r = SSH_ERR_EC_CURVE_MISMATCH;
2627 goto out;
2628 }
2629 k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
2630 if (k->ecdsa == NULL || (exponent = BN_new()) == NULL) {
2631 r = SSH_ERR_LIBCRYPTO_ERROR;
2632 goto out;
2633 }
2634 if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 ||
2635 (r = sshbuf_get_bignum2(buf, exponent)))
2636 goto out;
2637 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2638 r = SSH_ERR_LIBCRYPTO_ERROR;
2639 goto out;
2640 }
2641 if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00002642 EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002643 (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2644 goto out;
2645 break;
2646 case KEY_ECDSA_CERT:
2647 if ((exponent = BN_new()) == NULL) {
2648 r = SSH_ERR_LIBCRYPTO_ERROR;
2649 goto out;
2650 }
djm@openbsd.org60b18252015-01-26 02:59:11 +00002651 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002652 (r = sshkey_add_private(k)) != 0 ||
2653 (r = sshbuf_get_bignum2(buf, exponent)) != 0)
2654 goto out;
2655 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2656 r = SSH_ERR_LIBCRYPTO_ERROR;
2657 goto out;
2658 }
2659 if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00002660 EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002661 (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2662 goto out;
2663 break;
2664# endif /* OPENSSL_HAS_ECC */
2665 case KEY_RSA:
2666 if ((k = sshkey_new_private(type)) == NULL) {
2667 r = SSH_ERR_ALLOC_FAIL;
2668 goto out;
2669 }
2670 if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 ||
2671 (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 ||
2672 (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
2673 (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
2674 (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
2675 (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
djm@openbsd.org83fa3a02017-07-01 13:50:45 +00002676 (r = ssh_rsa_generate_additional_parameters(k)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10002677 goto out;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00002678 if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
2679 r = SSH_ERR_KEY_LENGTH;
2680 goto out;
2681 }
Damien Miller86687062014-07-02 15:28:02 +10002682 break;
Damien Miller86687062014-07-02 15:28:02 +10002683 case KEY_RSA_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00002684 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002685 (r = sshkey_add_private(k)) != 0 ||
jsg@openbsd.orgf3a3ea12015-09-02 07:51:12 +00002686 (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
2687 (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
2688 (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
2689 (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
djm@openbsd.org83fa3a02017-07-01 13:50:45 +00002690 (r = ssh_rsa_generate_additional_parameters(k)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10002691 goto out;
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00002692 if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
2693 r = SSH_ERR_KEY_LENGTH;
2694 goto out;
2695 }
Damien Miller86687062014-07-02 15:28:02 +10002696 break;
2697#endif /* WITH_OPENSSL */
2698 case KEY_ED25519:
2699 if ((k = sshkey_new_private(type)) == NULL) {
2700 r = SSH_ERR_ALLOC_FAIL;
2701 goto out;
2702 }
2703 if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
2704 (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
2705 goto out;
2706 if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
2707 r = SSH_ERR_INVALID_FORMAT;
2708 goto out;
2709 }
2710 k->ed25519_pk = ed25519_pk;
2711 k->ed25519_sk = ed25519_sk;
2712 ed25519_pk = ed25519_sk = NULL;
2713 break;
2714 case KEY_ED25519_CERT:
djm@openbsd.org60b18252015-01-26 02:59:11 +00002715 if ((r = sshkey_froms(buf, &k)) != 0 ||
Damien Miller86687062014-07-02 15:28:02 +10002716 (r = sshkey_add_private(k)) != 0 ||
2717 (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
2718 (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
2719 goto out;
2720 if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
2721 r = SSH_ERR_INVALID_FORMAT;
2722 goto out;
2723 }
2724 k->ed25519_pk = ed25519_pk;
2725 k->ed25519_sk = ed25519_sk;
2726 ed25519_pk = ed25519_sk = NULL;
2727 break;
2728 default:
2729 r = SSH_ERR_KEY_TYPE_UNKNOWN;
2730 goto out;
2731 }
2732#ifdef WITH_OPENSSL
2733 /* enable blinding */
2734 switch (k->type) {
2735 case KEY_RSA:
Damien Miller86687062014-07-02 15:28:02 +10002736 case KEY_RSA_CERT:
Damien Miller86687062014-07-02 15:28:02 +10002737 if (RSA_blinding_on(k->rsa, NULL) != 1) {
2738 r = SSH_ERR_LIBCRYPTO_ERROR;
2739 goto out;
2740 }
2741 break;
2742 }
2743#endif /* WITH_OPENSSL */
2744 /* success */
2745 r = 0;
2746 if (kp != NULL) {
2747 *kp = k;
2748 k = NULL;
2749 }
2750 out:
2751 free(tname);
2752 free(curve);
2753#ifdef WITH_OPENSSL
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00002754 BN_clear_free(exponent);
Damien Miller86687062014-07-02 15:28:02 +10002755#endif /* WITH_OPENSSL */
2756 sshkey_free(k);
2757 if (ed25519_pk != NULL) {
2758 explicit_bzero(ed25519_pk, pklen);
2759 free(ed25519_pk);
2760 }
2761 if (ed25519_sk != NULL) {
2762 explicit_bzero(ed25519_sk, sklen);
2763 free(ed25519_sk);
2764 }
2765 return r;
2766}
2767
2768#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
2769int
2770sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
2771{
2772 BN_CTX *bnctx;
2773 EC_POINT *nq = NULL;
2774 BIGNUM *order, *x, *y, *tmp;
2775 int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2776
djm@openbsd.orga571dbc2016-10-04 21:34:40 +00002777 /*
2778 * NB. This assumes OpenSSL has already verified that the public
2779 * point lies on the curve. This is done by EC_POINT_oct2point()
2780 * implicitly calling EC_POINT_is_on_curve(). If this code is ever
2781 * reachable with public points not unmarshalled using
2782 * EC_POINT_oct2point then the caller will need to explicitly check.
2783 */
2784
Damien Miller86687062014-07-02 15:28:02 +10002785 if ((bnctx = BN_CTX_new()) == NULL)
2786 return SSH_ERR_ALLOC_FAIL;
2787 BN_CTX_start(bnctx);
2788
2789 /*
2790 * We shouldn't ever hit this case because bignum_get_ecpoint()
2791 * refuses to load GF2m points.
2792 */
2793 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2794 NID_X9_62_prime_field)
2795 goto out;
2796
2797 /* Q != infinity */
2798 if (EC_POINT_is_at_infinity(group, public))
2799 goto out;
2800
2801 if ((x = BN_CTX_get(bnctx)) == NULL ||
2802 (y = BN_CTX_get(bnctx)) == NULL ||
2803 (order = BN_CTX_get(bnctx)) == NULL ||
2804 (tmp = BN_CTX_get(bnctx)) == NULL) {
2805 ret = SSH_ERR_ALLOC_FAIL;
2806 goto out;
2807 }
2808
2809 /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
2810 if (EC_GROUP_get_order(group, order, bnctx) != 1 ||
2811 EC_POINT_get_affine_coordinates_GFp(group, public,
2812 x, y, bnctx) != 1) {
2813 ret = SSH_ERR_LIBCRYPTO_ERROR;
2814 goto out;
2815 }
2816 if (BN_num_bits(x) <= BN_num_bits(order) / 2 ||
2817 BN_num_bits(y) <= BN_num_bits(order) / 2)
2818 goto out;
2819
2820 /* nQ == infinity (n == order of subgroup) */
2821 if ((nq = EC_POINT_new(group)) == NULL) {
2822 ret = SSH_ERR_ALLOC_FAIL;
2823 goto out;
2824 }
2825 if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) {
2826 ret = SSH_ERR_LIBCRYPTO_ERROR;
2827 goto out;
2828 }
2829 if (EC_POINT_is_at_infinity(group, nq) != 1)
2830 goto out;
2831
2832 /* x < order - 1, y < order - 1 */
2833 if (!BN_sub(tmp, order, BN_value_one())) {
2834 ret = SSH_ERR_LIBCRYPTO_ERROR;
2835 goto out;
2836 }
2837 if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0)
2838 goto out;
2839 ret = 0;
2840 out:
2841 BN_CTX_free(bnctx);
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00002842 EC_POINT_free(nq);
Damien Miller86687062014-07-02 15:28:02 +10002843 return ret;
2844}
2845
2846int
2847sshkey_ec_validate_private(const EC_KEY *key)
2848{
2849 BN_CTX *bnctx;
2850 BIGNUM *order, *tmp;
2851 int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2852
2853 if ((bnctx = BN_CTX_new()) == NULL)
2854 return SSH_ERR_ALLOC_FAIL;
2855 BN_CTX_start(bnctx);
2856
2857 if ((order = BN_CTX_get(bnctx)) == NULL ||
2858 (tmp = BN_CTX_get(bnctx)) == NULL) {
2859 ret = SSH_ERR_ALLOC_FAIL;
2860 goto out;
2861 }
2862
2863 /* log2(private) > log2(order)/2 */
2864 if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) {
2865 ret = SSH_ERR_LIBCRYPTO_ERROR;
2866 goto out;
2867 }
2868 if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
2869 BN_num_bits(order) / 2)
2870 goto out;
2871
2872 /* private < order - 1 */
2873 if (!BN_sub(tmp, order, BN_value_one())) {
2874 ret = SSH_ERR_LIBCRYPTO_ERROR;
2875 goto out;
2876 }
2877 if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0)
2878 goto out;
2879 ret = 0;
2880 out:
2881 BN_CTX_free(bnctx);
2882 return ret;
2883}
2884
2885void
2886sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
2887{
2888 BIGNUM *x, *y;
2889 BN_CTX *bnctx;
2890
2891 if (point == NULL) {
2892 fputs("point=(NULL)\n", stderr);
2893 return;
2894 }
2895 if ((bnctx = BN_CTX_new()) == NULL) {
2896 fprintf(stderr, "%s: BN_CTX_new failed\n", __func__);
2897 return;
2898 }
2899 BN_CTX_start(bnctx);
2900 if ((x = BN_CTX_get(bnctx)) == NULL ||
2901 (y = BN_CTX_get(bnctx)) == NULL) {
2902 fprintf(stderr, "%s: BN_CTX_get failed\n", __func__);
2903 return;
2904 }
2905 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2906 NID_X9_62_prime_field) {
2907 fprintf(stderr, "%s: group is not a prime field\n", __func__);
2908 return;
2909 }
2910 if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y,
2911 bnctx) != 1) {
2912 fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n",
2913 __func__);
2914 return;
2915 }
2916 fputs("x=", stderr);
2917 BN_print_fp(stderr, x);
2918 fputs("\ny=", stderr);
2919 BN_print_fp(stderr, y);
2920 fputs("\n", stderr);
2921 BN_CTX_free(bnctx);
2922}
2923
2924void
2925sshkey_dump_ec_key(const EC_KEY *key)
2926{
2927 const BIGNUM *exponent;
2928
2929 sshkey_dump_ec_point(EC_KEY_get0_group(key),
2930 EC_KEY_get0_public_key(key));
2931 fputs("exponent=", stderr);
2932 if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
2933 fputs("(NULL)", stderr);
2934 else
2935 BN_print_fp(stderr, EC_KEY_get0_private_key(key));
2936 fputs("\n", stderr);
2937}
2938#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2939
2940static int
2941sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob,
2942 const char *passphrase, const char *comment, const char *ciphername,
2943 int rounds)
2944{
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00002945 u_char *cp, *key = NULL, *pubkeyblob = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002946 u_char salt[SALT_LEN];
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00002947 char *b64 = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002948 size_t i, pubkeylen, keylen, ivlen, blocksize, authlen;
2949 u_int check;
2950 int r = SSH_ERR_INTERNAL_ERROR;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00002951 struct sshcipher_ctx *ciphercontext = NULL;
Damien Miller86687062014-07-02 15:28:02 +10002952 const struct sshcipher *cipher;
2953 const char *kdfname = KDFNAME;
2954 struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL;
2955
Damien Miller86687062014-07-02 15:28:02 +10002956 if (rounds <= 0)
2957 rounds = DEFAULT_ROUNDS;
2958 if (passphrase == NULL || !strlen(passphrase)) {
2959 ciphername = "none";
2960 kdfname = "none";
2961 } else if (ciphername == NULL)
2962 ciphername = DEFAULT_CIPHERNAME;
Damien Miller86687062014-07-02 15:28:02 +10002963 if ((cipher = cipher_by_name(ciphername)) == NULL) {
djm@openbsd.orgcdccebd2017-04-30 23:15:04 +00002964 r = SSH_ERR_INVALID_ARGUMENT;
Damien Miller86687062014-07-02 15:28:02 +10002965 goto out;
2966 }
2967
2968 if ((kdf = sshbuf_new()) == NULL ||
2969 (encoded = sshbuf_new()) == NULL ||
2970 (encrypted = sshbuf_new()) == NULL) {
2971 r = SSH_ERR_ALLOC_FAIL;
2972 goto out;
2973 }
2974 blocksize = cipher_blocksize(cipher);
2975 keylen = cipher_keylen(cipher);
2976 ivlen = cipher_ivlen(cipher);
2977 authlen = cipher_authlen(cipher);
2978 if ((key = calloc(1, keylen + ivlen)) == NULL) {
2979 r = SSH_ERR_ALLOC_FAIL;
2980 goto out;
2981 }
2982 if (strcmp(kdfname, "bcrypt") == 0) {
2983 arc4random_buf(salt, SALT_LEN);
2984 if (bcrypt_pbkdf(passphrase, strlen(passphrase),
2985 salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) {
2986 r = SSH_ERR_INVALID_ARGUMENT;
2987 goto out;
2988 }
2989 if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 ||
2990 (r = sshbuf_put_u32(kdf, rounds)) != 0)
2991 goto out;
2992 } else if (strcmp(kdfname, "none") != 0) {
2993 /* Unsupported KDF type */
2994 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
2995 goto out;
2996 }
2997 if ((r = cipher_init(&ciphercontext, cipher, key, keylen,
2998 key + keylen, ivlen, 1)) != 0)
2999 goto out;
3000
3001 if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 ||
3002 (r = sshbuf_put_cstring(encoded, ciphername)) != 0 ||
3003 (r = sshbuf_put_cstring(encoded, kdfname)) != 0 ||
3004 (r = sshbuf_put_stringb(encoded, kdf)) != 0 ||
3005 (r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */
3006 (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 ||
3007 (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0)
3008 goto out;
3009
3010 /* set up the buffer that will be encrypted */
3011
3012 /* Random check bytes */
3013 check = arc4random();
3014 if ((r = sshbuf_put_u32(encrypted, check)) != 0 ||
3015 (r = sshbuf_put_u32(encrypted, check)) != 0)
3016 goto out;
3017
3018 /* append private key and comment*/
3019 if ((r = sshkey_private_serialize(prv, encrypted)) != 0 ||
3020 (r = sshbuf_put_cstring(encrypted, comment)) != 0)
3021 goto out;
3022
3023 /* padding */
3024 i = 0;
3025 while (sshbuf_len(encrypted) % blocksize) {
3026 if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0)
3027 goto out;
3028 }
3029
3030 /* length in destination buffer */
3031 if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0)
3032 goto out;
3033
3034 /* encrypt */
3035 if ((r = sshbuf_reserve(encoded,
3036 sshbuf_len(encrypted) + authlen, &cp)) != 0)
3037 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003038 if ((r = cipher_crypt(ciphercontext, 0, cp,
Damien Miller86687062014-07-02 15:28:02 +10003039 sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0)
3040 goto out;
3041
3042 /* uuencode */
3043 if ((b64 = sshbuf_dtob64(encoded)) == NULL) {
3044 r = SSH_ERR_ALLOC_FAIL;
3045 goto out;
3046 }
3047
3048 sshbuf_reset(blob);
3049 if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0)
3050 goto out;
3051 for (i = 0; i < strlen(b64); i++) {
3052 if ((r = sshbuf_put_u8(blob, b64[i])) != 0)
3053 goto out;
3054 /* insert line breaks */
3055 if (i % 70 == 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3056 goto out;
3057 }
3058 if (i % 70 != 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3059 goto out;
3060 if ((r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0)
3061 goto out;
3062
3063 /* success */
3064 r = 0;
3065
3066 out:
3067 sshbuf_free(kdf);
3068 sshbuf_free(encoded);
3069 sshbuf_free(encrypted);
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003070 cipher_free(ciphercontext);
Damien Miller86687062014-07-02 15:28:02 +10003071 explicit_bzero(salt, sizeof(salt));
3072 if (key != NULL) {
3073 explicit_bzero(key, keylen + ivlen);
3074 free(key);
3075 }
3076 if (pubkeyblob != NULL) {
3077 explicit_bzero(pubkeyblob, pubkeylen);
3078 free(pubkeyblob);
3079 }
3080 if (b64 != NULL) {
3081 explicit_bzero(b64, strlen(b64));
3082 free(b64);
3083 }
3084 return r;
3085}
3086
3087static int
3088sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
3089 struct sshkey **keyp, char **commentp)
3090{
3091 char *comment = NULL, *ciphername = NULL, *kdfname = NULL;
3092 const struct sshcipher *cipher = NULL;
3093 const u_char *cp;
3094 int r = SSH_ERR_INTERNAL_ERROR;
3095 size_t encoded_len;
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003096 size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0;
Damien Miller86687062014-07-02 15:28:02 +10003097 struct sshbuf *encoded = NULL, *decoded = NULL;
3098 struct sshbuf *kdf = NULL, *decrypted = NULL;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003099 struct sshcipher_ctx *ciphercontext = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003100 struct sshkey *k = NULL;
3101 u_char *key = NULL, *salt = NULL, *dp, pad, last;
3102 u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
3103
Damien Miller86687062014-07-02 15:28:02 +10003104 if (keyp != NULL)
3105 *keyp = NULL;
3106 if (commentp != NULL)
3107 *commentp = NULL;
3108
3109 if ((encoded = sshbuf_new()) == NULL ||
3110 (decoded = sshbuf_new()) == NULL ||
3111 (decrypted = sshbuf_new()) == NULL) {
3112 r = SSH_ERR_ALLOC_FAIL;
3113 goto out;
3114 }
3115
3116 /* check preamble */
3117 cp = sshbuf_ptr(blob);
3118 encoded_len = sshbuf_len(blob);
3119 if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) ||
3120 memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) {
3121 r = SSH_ERR_INVALID_FORMAT;
3122 goto out;
3123 }
3124 cp += MARK_BEGIN_LEN;
3125 encoded_len -= MARK_BEGIN_LEN;
3126
3127 /* Look for end marker, removing whitespace as we go */
3128 while (encoded_len > 0) {
3129 if (*cp != '\n' && *cp != '\r') {
3130 if ((r = sshbuf_put_u8(encoded, *cp)) != 0)
3131 goto out;
3132 }
3133 last = *cp;
3134 encoded_len--;
3135 cp++;
3136 if (last == '\n') {
3137 if (encoded_len >= MARK_END_LEN &&
3138 memcmp(cp, MARK_END, MARK_END_LEN) == 0) {
3139 /* \0 terminate */
3140 if ((r = sshbuf_put_u8(encoded, 0)) != 0)
3141 goto out;
3142 break;
3143 }
3144 }
3145 }
3146 if (encoded_len == 0) {
3147 r = SSH_ERR_INVALID_FORMAT;
3148 goto out;
3149 }
3150
3151 /* decode base64 */
djm@openbsd.org3cc1fbb2014-10-08 21:45:48 +00003152 if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0)
Damien Miller86687062014-07-02 15:28:02 +10003153 goto out;
3154
3155 /* check magic */
3156 if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) ||
3157 memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
3158 r = SSH_ERR_INVALID_FORMAT;
3159 goto out;
3160 }
3161 /* parse public portion of key */
3162 if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
3163 (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
3164 (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
3165 (r = sshbuf_froms(decoded, &kdf)) != 0 ||
3166 (r = sshbuf_get_u32(decoded, &nkeys)) != 0 ||
3167 (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */
3168 (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
3169 goto out;
3170
3171 if ((cipher = cipher_by_name(ciphername)) == NULL) {
3172 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3173 goto out;
3174 }
3175 if ((passphrase == NULL || strlen(passphrase) == 0) &&
3176 strcmp(ciphername, "none") != 0) {
3177 /* passphrase required */
3178 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3179 goto out;
3180 }
3181 if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
3182 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3183 goto out;
3184 }
3185 if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
3186 r = SSH_ERR_INVALID_FORMAT;
3187 goto out;
3188 }
3189 if (nkeys != 1) {
3190 /* XXX only one key supported */
3191 r = SSH_ERR_INVALID_FORMAT;
3192 goto out;
3193 }
3194
3195 /* check size of encrypted key blob */
3196 blocksize = cipher_blocksize(cipher);
3197 if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
3198 r = SSH_ERR_INVALID_FORMAT;
3199 goto out;
3200 }
3201
3202 /* setup key */
3203 keylen = cipher_keylen(cipher);
3204 ivlen = cipher_ivlen(cipher);
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003205 authlen = cipher_authlen(cipher);
Damien Miller86687062014-07-02 15:28:02 +10003206 if ((key = calloc(1, keylen + ivlen)) == NULL) {
3207 r = SSH_ERR_ALLOC_FAIL;
3208 goto out;
3209 }
3210 if (strcmp(kdfname, "bcrypt") == 0) {
3211 if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
3212 (r = sshbuf_get_u32(kdf, &rounds)) != 0)
3213 goto out;
3214 if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
3215 key, keylen + ivlen, rounds) < 0) {
3216 r = SSH_ERR_INVALID_FORMAT;
3217 goto out;
3218 }
3219 }
3220
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003221 /* check that an appropriate amount of auth data is present */
3222 if (sshbuf_len(decoded) < encrypted_len + authlen) {
3223 r = SSH_ERR_INVALID_FORMAT;
3224 goto out;
3225 }
3226
Damien Miller86687062014-07-02 15:28:02 +10003227 /* decrypt private portion of key */
3228 if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 ||
3229 (r = cipher_init(&ciphercontext, cipher, key, keylen,
3230 key + keylen, ivlen, 0)) != 0)
3231 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003232 if ((r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(decoded),
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003233 encrypted_len, 0, authlen)) != 0) {
Damien Miller86687062014-07-02 15:28:02 +10003234 /* an integrity error here indicates an incorrect passphrase */
3235 if (r == SSH_ERR_MAC_INVALID)
3236 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3237 goto out;
3238 }
djm@openbsd.org63ebf012015-05-08 03:17:49 +00003239 if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0)
Damien Miller86687062014-07-02 15:28:02 +10003240 goto out;
3241 /* there should be no trailing data */
3242 if (sshbuf_len(decoded) != 0) {
3243 r = SSH_ERR_INVALID_FORMAT;
3244 goto out;
3245 }
3246
3247 /* check check bytes */
3248 if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 ||
3249 (r = sshbuf_get_u32(decrypted, &check2)) != 0)
3250 goto out;
3251 if (check1 != check2) {
3252 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3253 goto out;
3254 }
3255
3256 /* Load the private key and comment */
3257 if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
3258 (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
3259 goto out;
3260
3261 /* Check deterministic padding */
3262 i = 0;
3263 while (sshbuf_len(decrypted)) {
3264 if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
3265 goto out;
3266 if (pad != (++i & 0xff)) {
3267 r = SSH_ERR_INVALID_FORMAT;
3268 goto out;
3269 }
3270 }
3271
3272 /* XXX decode pubkey and check against private */
3273
3274 /* success */
3275 r = 0;
3276 if (keyp != NULL) {
3277 *keyp = k;
3278 k = NULL;
3279 }
3280 if (commentp != NULL) {
3281 *commentp = comment;
3282 comment = NULL;
3283 }
3284 out:
3285 pad = 0;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00003286 cipher_free(ciphercontext);
Damien Miller86687062014-07-02 15:28:02 +10003287 free(ciphername);
3288 free(kdfname);
3289 free(comment);
3290 if (salt != NULL) {
3291 explicit_bzero(salt, slen);
3292 free(salt);
3293 }
3294 if (key != NULL) {
3295 explicit_bzero(key, keylen + ivlen);
3296 free(key);
3297 }
3298 sshbuf_free(encoded);
3299 sshbuf_free(decoded);
3300 sshbuf_free(kdf);
3301 sshbuf_free(decrypted);
3302 sshkey_free(k);
3303 return r;
3304}
3305
Damien Miller86687062014-07-02 15:28:02 +10003306
3307#ifdef WITH_OPENSSL
3308/* convert SSH v2 key in OpenSSL PEM format */
3309static int
3310sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob,
3311 const char *_passphrase, const char *comment)
3312{
3313 int success, r;
3314 int blen, len = strlen(_passphrase);
3315 u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
Darren Tucker8fed0a52017-03-29 10:16:15 +11003316 const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
djm@openbsd.org224f1932017-10-13 06:24:51 +00003317 char *bptr;
Damien Miller86687062014-07-02 15:28:02 +10003318 BIO *bio = NULL;
3319
3320 if (len > 0 && len <= 4)
3321 return SSH_ERR_PASSPHRASE_TOO_SHORT;
3322 if ((bio = BIO_new(BIO_s_mem())) == NULL)
3323 return SSH_ERR_ALLOC_FAIL;
3324
3325 switch (key->type) {
3326 case KEY_DSA:
3327 success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
3328 cipher, passphrase, len, NULL, NULL);
3329 break;
3330#ifdef OPENSSL_HAS_ECC
3331 case KEY_ECDSA:
3332 success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
3333 cipher, passphrase, len, NULL, NULL);
3334 break;
3335#endif
3336 case KEY_RSA:
3337 success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
3338 cipher, passphrase, len, NULL, NULL);
3339 break;
3340 default:
3341 success = 0;
3342 break;
3343 }
3344 if (success == 0) {
3345 r = SSH_ERR_LIBCRYPTO_ERROR;
3346 goto out;
3347 }
3348 if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) {
3349 r = SSH_ERR_INTERNAL_ERROR;
3350 goto out;
3351 }
3352 if ((r = sshbuf_put(blob, bptr, blen)) != 0)
3353 goto out;
3354 r = 0;
3355 out:
3356 BIO_free(bio);
3357 return r;
3358}
3359#endif /* WITH_OPENSSL */
3360
3361/* Serialise "key" to buffer "blob" */
3362int
3363sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
3364 const char *passphrase, const char *comment,
3365 int force_new_format, const char *new_format_cipher, int new_format_rounds)
3366{
3367 switch (key->type) {
markus@openbsd.orgf067cca2015-01-12 13:29:27 +00003368#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10003369 case KEY_DSA:
3370 case KEY_ECDSA:
3371 case KEY_RSA:
3372 if (force_new_format) {
3373 return sshkey_private_to_blob2(key, blob, passphrase,
3374 comment, new_format_cipher, new_format_rounds);
3375 }
3376 return sshkey_private_pem_to_blob(key, blob,
3377 passphrase, comment);
3378#endif /* WITH_OPENSSL */
3379 case KEY_ED25519:
3380 return sshkey_private_to_blob2(key, blob, passphrase,
3381 comment, new_format_cipher, new_format_rounds);
3382 default:
3383 return SSH_ERR_KEY_TYPE_UNKNOWN;
3384 }
3385}
3386
Damien Miller86687062014-07-02 15:28:02 +10003387
3388#ifdef WITH_OPENSSL
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003389static int
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00003390translate_libcrypto_error(unsigned long pem_err)
3391{
3392 int pem_reason = ERR_GET_REASON(pem_err);
3393
3394 switch (ERR_GET_LIB(pem_err)) {
3395 case ERR_LIB_PEM:
3396 switch (pem_reason) {
3397 case PEM_R_BAD_PASSWORD_READ:
3398 case PEM_R_PROBLEMS_GETTING_PASSWORD:
3399 case PEM_R_BAD_DECRYPT:
3400 return SSH_ERR_KEY_WRONG_PASSPHRASE;
3401 default:
3402 return SSH_ERR_INVALID_FORMAT;
3403 }
3404 case ERR_LIB_EVP:
3405 switch (pem_reason) {
3406 case EVP_R_BAD_DECRYPT:
3407 return SSH_ERR_KEY_WRONG_PASSPHRASE;
3408 case EVP_R_BN_DECODE_ERROR:
3409 case EVP_R_DECODE_ERROR:
3410#ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
3411 case EVP_R_PRIVATE_KEY_DECODE_ERROR:
3412#endif
3413 return SSH_ERR_INVALID_FORMAT;
3414 default:
3415 return SSH_ERR_LIBCRYPTO_ERROR;
3416 }
3417 case ERR_LIB_ASN1:
3418 return SSH_ERR_INVALID_FORMAT;
3419 }
3420 return SSH_ERR_LIBCRYPTO_ERROR;
3421}
3422
3423static void
3424clear_libcrypto_errors(void)
3425{
3426 while (ERR_get_error() != 0)
3427 ;
3428}
3429
3430/*
3431 * Translate OpenSSL error codes to determine whether
3432 * passphrase is required/incorrect.
3433 */
3434static int
3435convert_libcrypto_error(void)
3436{
3437 /*
3438 * Some password errors are reported at the beginning
3439 * of the error queue.
3440 */
3441 if (translate_libcrypto_error(ERR_peek_error()) ==
3442 SSH_ERR_KEY_WRONG_PASSPHRASE)
3443 return SSH_ERR_KEY_WRONG_PASSPHRASE;
3444 return translate_libcrypto_error(ERR_peek_last_error());
3445}
3446
3447static int
Damien Miller86687062014-07-02 15:28:02 +10003448sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003449 const char *passphrase, struct sshkey **keyp)
Damien Miller86687062014-07-02 15:28:02 +10003450{
3451 EVP_PKEY *pk = NULL;
3452 struct sshkey *prv = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003453 BIO *bio = NULL;
3454 int r;
3455
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00003456 if (keyp != NULL)
3457 *keyp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003458
3459 if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
3460 return SSH_ERR_ALLOC_FAIL;
3461 if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) !=
3462 (int)sshbuf_len(blob)) {
3463 r = SSH_ERR_ALLOC_FAIL;
3464 goto out;
3465 }
3466
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00003467 clear_libcrypto_errors();
Damien Miller86687062014-07-02 15:28:02 +10003468 if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL,
3469 (char *)passphrase)) == NULL) {
djm@openbsd.org2076e4a2017-06-09 06:40:24 +00003470 r = convert_libcrypto_error();
Damien Miller86687062014-07-02 15:28:02 +10003471 goto out;
3472 }
3473 if (pk->type == EVP_PKEY_RSA &&
3474 (type == KEY_UNSPEC || type == KEY_RSA)) {
3475 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3476 r = SSH_ERR_ALLOC_FAIL;
3477 goto out;
3478 }
3479 prv->rsa = EVP_PKEY_get1_RSA(pk);
3480 prv->type = KEY_RSA;
Damien Miller86687062014-07-02 15:28:02 +10003481#ifdef DEBUG_PK
3482 RSA_print_fp(stderr, prv->rsa, 8);
3483#endif
3484 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
3485 r = SSH_ERR_LIBCRYPTO_ERROR;
3486 goto out;
3487 }
djm@openbsd.orgbd636f42017-05-07 23:15:59 +00003488 if (BN_num_bits(prv->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
3489 r = SSH_ERR_KEY_LENGTH;
3490 goto out;
3491 }
Damien Miller86687062014-07-02 15:28:02 +10003492 } else if (pk->type == EVP_PKEY_DSA &&
3493 (type == KEY_UNSPEC || type == KEY_DSA)) {
3494 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3495 r = SSH_ERR_ALLOC_FAIL;
3496 goto out;
3497 }
3498 prv->dsa = EVP_PKEY_get1_DSA(pk);
3499 prv->type = KEY_DSA;
Damien Miller86687062014-07-02 15:28:02 +10003500#ifdef DEBUG_PK
3501 DSA_print_fp(stderr, prv->dsa, 8);
3502#endif
3503#ifdef OPENSSL_HAS_ECC
3504 } else if (pk->type == EVP_PKEY_EC &&
3505 (type == KEY_UNSPEC || type == KEY_ECDSA)) {
3506 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3507 r = SSH_ERR_ALLOC_FAIL;
3508 goto out;
3509 }
3510 prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
3511 prv->type = KEY_ECDSA;
3512 prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
3513 if (prv->ecdsa_nid == -1 ||
3514 sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
3515 sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
3516 EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
3517 sshkey_ec_validate_private(prv->ecdsa) != 0) {
3518 r = SSH_ERR_INVALID_FORMAT;
3519 goto out;
3520 }
Damien Miller86687062014-07-02 15:28:02 +10003521# ifdef DEBUG_PK
3522 if (prv != NULL && prv->ecdsa != NULL)
3523 sshkey_dump_ec_key(prv->ecdsa);
3524# endif
3525#endif /* OPENSSL_HAS_ECC */
3526 } else {
3527 r = SSH_ERR_INVALID_FORMAT;
3528 goto out;
3529 }
Damien Miller86687062014-07-02 15:28:02 +10003530 r = 0;
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00003531 if (keyp != NULL) {
3532 *keyp = prv;
3533 prv = NULL;
3534 }
Damien Miller86687062014-07-02 15:28:02 +10003535 out:
3536 BIO_free(bio);
jsing@openbsd.org7cd31632018-02-07 02:06:50 +00003537 EVP_PKEY_free(pk);
mmcc@openbsd.org89540b62015-12-11 02:31:47 +00003538 sshkey_free(prv);
Damien Miller86687062014-07-02 15:28:02 +10003539 return r;
3540}
3541#endif /* WITH_OPENSSL */
3542
3543int
3544sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
3545 const char *passphrase, struct sshkey **keyp, char **commentp)
3546{
djm@openbsd.org155d5402017-02-10 04:34:50 +00003547 int r = SSH_ERR_INTERNAL_ERROR;
3548
djm@openbsd.orgdce19bf2016-04-09 12:39:30 +00003549 if (keyp != NULL)
3550 *keyp = NULL;
Damien Miller86687062014-07-02 15:28:02 +10003551 if (commentp != NULL)
3552 *commentp = NULL;
3553
3554 switch (type) {
markus@openbsd.orgf067cca2015-01-12 13:29:27 +00003555#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +10003556 case KEY_DSA:
3557 case KEY_ECDSA:
3558 case KEY_RSA:
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003559 return sshkey_parse_private_pem_fileblob(blob, type,
3560 passphrase, keyp);
Damien Miller86687062014-07-02 15:28:02 +10003561#endif /* WITH_OPENSSL */
3562 case KEY_ED25519:
3563 return sshkey_parse_private2(blob, type, passphrase,
3564 keyp, commentp);
3565 case KEY_UNSPEC:
djm@openbsd.org155d5402017-02-10 04:34:50 +00003566 r = sshkey_parse_private2(blob, type, passphrase, keyp,
3567 commentp);
3568 /* Do not fallback to PEM parser if only passphrase is wrong. */
3569 if (r == 0 || r == SSH_ERR_KEY_WRONG_PASSPHRASE)
3570 return r;
Damien Miller86687062014-07-02 15:28:02 +10003571#ifdef WITH_OPENSSL
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00003572 return sshkey_parse_private_pem_fileblob(blob, type,
3573 passphrase, keyp);
Damien Miller86687062014-07-02 15:28:02 +10003574#else
3575 return SSH_ERR_INVALID_FORMAT;
3576#endif /* WITH_OPENSSL */
3577 default:
3578 return SSH_ERR_KEY_TYPE_UNKNOWN;
3579 }
3580}
3581
3582int
3583sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
tim@openbsd.org3c019a92015-09-13 14:39:16 +00003584 struct sshkey **keyp, char **commentp)
Damien Miller86687062014-07-02 15:28:02 +10003585{
Damien Miller86687062014-07-02 15:28:02 +10003586 if (keyp != NULL)
3587 *keyp = NULL;
3588 if (commentp != NULL)
3589 *commentp = NULL;
3590
tim@openbsd.org3c019a92015-09-13 14:39:16 +00003591 return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
3592 passphrase, keyp, commentp);
Damien Miller86687062014-07-02 15:28:02 +10003593}