Annotation of src/usr.bin/ssh/sshkey.c, Revision 1.141
1.141 ! jsg 1: /* $OpenBSD: sshkey.c,v 1.140 2023/10/16 08:40:00 dtucker Exp $ */
1.1 djm 2: /*
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 <sys/types.h>
1.7 djm 29: #include <netinet/in.h>
1.1 djm 30:
1.12 djm 31: #ifdef WITH_OPENSSL
1.1 djm 32: #include <openssl/evp.h>
33: #include <openssl/err.h>
34: #include <openssl/pem.h>
1.12 djm 35: #endif
1.1 djm 36:
37: #include "crypto_api.h"
38:
39: #include <errno.h>
40: #include <stdio.h>
1.138 djm 41: #include <stdlib.h>
1.1 djm 42: #include <string.h>
43: #include <util.h>
1.13 deraadt 44: #include <limits.h>
1.7 djm 45: #include <resolv.h>
1.1 djm 46:
47: #include "ssh2.h"
48: #include "ssherr.h"
49: #include "misc.h"
50: #include "sshbuf.h"
51: #include "cipher.h"
52: #include "digest.h"
53: #define SSHKEY_INTERNAL
54: #include "sshkey.h"
1.11 djm 55: #include "match.h"
1.86 djm 56: #include "ssh-sk.h"
1.1 djm 57:
1.74 dtucker 58: #ifdef WITH_XMSS
59: #include "sshkey-xmss.h"
1.62 markus 60: #include "xmss_fast.h"
1.74 dtucker 61: #endif
1.62 markus 62:
1.1 djm 63: /* openssh private key file format */
64: #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
65: #define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
66: #define MARK_BEGIN_LEN (sizeof(MARK_BEGIN) - 1)
67: #define MARK_END_LEN (sizeof(MARK_END) - 1)
68: #define KDFNAME "bcrypt"
69: #define AUTH_MAGIC "openssh-key-v1"
70: #define SALT_LEN 16
1.56 djm 71: #define DEFAULT_CIPHERNAME "aes256-ctr"
1.137 djm 72: #define DEFAULT_ROUNDS 24
1.1 djm 73:
74: /* Version identification string for SSH v1 identity files. */
75: #define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n"
76:
1.76 djm 77: /*
78: * Constants relating to "shielding" support; protection of keys expected
79: * to remain in memory for long durations
80: */
81: #define SSHKEY_SHIELD_PREKEY_LEN (16 * 1024)
82: #define SSHKEY_SHIELD_CIPHER "aes256-ctr" /* XXX want AES-EME* */
83: #define SSHKEY_SHIELD_PREKEY_HASH SSH_DIGEST_SHA512
84:
85: int sshkey_private_serialize_opt(struct sshkey *key,
1.62 markus 86: struct sshbuf *buf, enum sshkey_serialize_rep);
1.14 djm 87: static int sshkey_from_blob_internal(struct sshbuf *buf,
1.1 djm 88: struct sshkey **keyp, int allow_cert);
89:
90: /* Supported key types */
1.123 djm 91: extern const struct sshkey_impl sshkey_ed25519_impl;
92: extern const struct sshkey_impl sshkey_ed25519_cert_impl;
93: extern const struct sshkey_impl sshkey_ed25519_sk_impl;
94: extern const struct sshkey_impl sshkey_ed25519_sk_cert_impl;
95: #ifdef WITH_OPENSSL
96: extern const struct sshkey_impl sshkey_ecdsa_sk_impl;
97: extern const struct sshkey_impl sshkey_ecdsa_sk_cert_impl;
98: extern const struct sshkey_impl sshkey_ecdsa_sk_webauthn_impl;
99: extern const struct sshkey_impl sshkey_ecdsa_nistp256_impl;
100: extern const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl;
101: extern const struct sshkey_impl sshkey_ecdsa_nistp384_impl;
102: extern const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl;
103: extern const struct sshkey_impl sshkey_ecdsa_nistp521_impl;
104: extern const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl;
105: extern const struct sshkey_impl sshkey_rsa_impl;
106: extern const struct sshkey_impl sshkey_rsa_cert_impl;
107: extern const struct sshkey_impl sshkey_rsa_sha256_impl;
108: extern const struct sshkey_impl sshkey_rsa_sha256_cert_impl;
109: extern const struct sshkey_impl sshkey_rsa_sha512_impl;
110: extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl;
111: extern const struct sshkey_impl sshkey_dss_impl;
112: extern const struct sshkey_impl sshkey_dsa_cert_impl;
113: #endif /* WITH_OPENSSL */
1.62 markus 114: #ifdef WITH_XMSS
1.123 djm 115: extern const struct sshkey_impl sshkey_xmss_impl;
116: extern const struct sshkey_impl sshkey_xmss_cert_impl;
117: #endif
118:
119: const struct sshkey_impl * const keyimpls[] = {
120: &sshkey_ed25519_impl,
121: &sshkey_ed25519_cert_impl,
122: &sshkey_ed25519_sk_impl,
123: &sshkey_ed25519_sk_cert_impl,
124: #ifdef WITH_OPENSSL
125: &sshkey_ecdsa_nistp256_impl,
126: &sshkey_ecdsa_nistp256_cert_impl,
127: &sshkey_ecdsa_nistp384_impl,
128: &sshkey_ecdsa_nistp384_cert_impl,
129: &sshkey_ecdsa_nistp521_impl,
130: &sshkey_ecdsa_nistp521_cert_impl,
131: &sshkey_ecdsa_sk_impl,
132: &sshkey_ecdsa_sk_cert_impl,
133: &sshkey_ecdsa_sk_webauthn_impl,
134: &sshkey_dss_impl,
135: &sshkey_dsa_cert_impl,
136: &sshkey_rsa_impl,
137: &sshkey_rsa_cert_impl,
138: &sshkey_rsa_sha256_impl,
139: &sshkey_rsa_sha256_cert_impl,
140: &sshkey_rsa_sha512_impl,
141: &sshkey_rsa_sha512_cert_impl,
1.1 djm 142: #endif /* WITH_OPENSSL */
1.123 djm 143: #ifdef WITH_XMSS
144: &sshkey_xmss_impl,
145: &sshkey_xmss_cert_impl,
146: #endif
147: NULL
1.1 djm 148: };
149:
1.123 djm 150: static const struct sshkey_impl *
151: sshkey_impl_from_type(int type)
152: {
153: int i;
154:
155: for (i = 0; keyimpls[i] != NULL; i++) {
156: if (keyimpls[i]->type == type)
157: return keyimpls[i];
158: }
159: return NULL;
160: }
161:
162: static const struct sshkey_impl *
163: sshkey_impl_from_type_nid(int type, int nid)
164: {
165: int i;
166:
167: for (i = 0; keyimpls[i] != NULL; i++) {
168: if (keyimpls[i]->type == type &&
169: (keyimpls[i]->nid == 0 || keyimpls[i]->nid == nid))
170: return keyimpls[i];
171: }
172: return NULL;
173: }
174:
1.126 djm 175: static const struct sshkey_impl *
176: sshkey_impl_from_key(const struct sshkey *k)
177: {
178: if (k == NULL)
179: return NULL;
180: return sshkey_impl_from_type_nid(k->type, k->ecdsa_nid);
181: }
182:
1.1 djm 183: const char *
184: sshkey_type(const struct sshkey *k)
185: {
1.123 djm 186: const struct sshkey_impl *impl;
1.1 djm 187:
1.126 djm 188: if ((impl = sshkey_impl_from_key(k)) == NULL)
1.123 djm 189: return "unknown";
190: return impl->shortname;
1.1 djm 191: }
192:
193: static const char *
194: sshkey_ssh_name_from_type_nid(int type, int nid)
195: {
1.123 djm 196: const struct sshkey_impl *impl;
1.1 djm 197:
1.123 djm 198: if ((impl = sshkey_impl_from_type_nid(type, nid)) == NULL)
199: return "ssh-unknown";
200: return impl->name;
1.1 djm 201: }
202:
203: int
204: sshkey_type_is_cert(int type)
205: {
1.123 djm 206: const struct sshkey_impl *impl;
1.1 djm 207:
1.123 djm 208: if ((impl = sshkey_impl_from_type(type)) == NULL)
209: return 0;
210: return impl->cert;
1.1 djm 211: }
212:
213: const char *
214: sshkey_ssh_name(const struct sshkey *k)
215: {
216: return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
217: }
218:
219: const char *
220: sshkey_ssh_name_plain(const struct sshkey *k)
221: {
222: return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type),
223: k->ecdsa_nid);
224: }
225:
226: int
227: sshkey_type_from_name(const char *name)
228: {
1.123 djm 229: int i;
230: const struct sshkey_impl *impl;
1.1 djm 231:
1.123 djm 232: for (i = 0; keyimpls[i] != NULL; i++) {
233: impl = keyimpls[i];
1.1 djm 234: /* Only allow shortname matches for plain key types */
1.123 djm 235: if ((impl->name != NULL && strcmp(name, impl->name) == 0) ||
236: (!impl->cert && strcasecmp(impl->shortname, name) == 0))
237: return impl->type;
1.1 djm 238: }
239: return KEY_UNSPEC;
240: }
241:
1.85 djm 242: static int
243: key_type_is_ecdsa_variant(int type)
244: {
245: switch (type) {
246: case KEY_ECDSA:
247: case KEY_ECDSA_CERT:
248: case KEY_ECDSA_SK:
249: case KEY_ECDSA_SK_CERT:
250: return 1;
251: }
252: return 0;
253: }
254:
1.1 djm 255: int
256: sshkey_ecdsa_nid_from_name(const char *name)
257: {
1.123 djm 258: int i;
1.1 djm 259:
1.123 djm 260: for (i = 0; keyimpls[i] != NULL; i++) {
261: if (!key_type_is_ecdsa_variant(keyimpls[i]->type))
1.4 djm 262: continue;
1.123 djm 263: if (keyimpls[i]->name != NULL &&
264: strcmp(name, keyimpls[i]->name) == 0)
265: return keyimpls[i]->nid;
1.4 djm 266: }
1.1 djm 267: return -1;
1.120 djm 268: }
269:
270: int
271: sshkey_match_keyname_to_sigalgs(const char *keyname, const char *sigalgs)
272: {
273: int ktype;
274:
275: if (sigalgs == NULL || *sigalgs == '\0' ||
276: (ktype = sshkey_type_from_name(keyname)) == KEY_UNSPEC)
277: return 0;
278: else if (ktype == KEY_RSA) {
279: return match_pattern_list("ssh-rsa", sigalgs, 0) == 1 ||
280: match_pattern_list("rsa-sha2-256", sigalgs, 0) == 1 ||
281: match_pattern_list("rsa-sha2-512", sigalgs, 0) == 1;
282: } else if (ktype == KEY_RSA_CERT) {
283: return match_pattern_list("ssh-rsa-cert-v01@openssh.com",
284: sigalgs, 0) == 1 ||
285: match_pattern_list("rsa-sha2-256-cert-v01@openssh.com",
286: sigalgs, 0) == 1 ||
287: match_pattern_list("rsa-sha2-512-cert-v01@openssh.com",
288: sigalgs, 0) == 1;
289: } else
290: return match_pattern_list(keyname, sigalgs, 0) == 1;
1.1 djm 291: }
292:
293: char *
1.45 djm 294: sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
1.1 djm 295: {
296: char *tmp, *ret = NULL;
1.123 djm 297: size_t i, nlen, rlen = 0;
298: const struct sshkey_impl *impl;
1.1 djm 299:
1.123 djm 300: for (i = 0; keyimpls[i] != NULL; i++) {
301: impl = keyimpls[i];
302: if (impl->name == NULL)
1.45 djm 303: continue;
1.123 djm 304: if (!include_sigonly && impl->sigonly)
1.1 djm 305: continue;
1.123 djm 306: if ((certs_only && !impl->cert) || (plain_only && impl->cert))
1.1 djm 307: continue;
308: if (ret != NULL)
1.38 djm 309: ret[rlen++] = sep;
1.123 djm 310: nlen = strlen(impl->name);
1.1 djm 311: if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
312: free(ret);
313: return NULL;
314: }
315: ret = tmp;
1.123 djm 316: memcpy(ret + rlen, impl->name, nlen + 1);
1.1 djm 317: rlen += nlen;
318: }
319: return ret;
320: }
321:
322: int
1.136 djm 323: sshkey_names_valid2(const char *names, int allow_wildcard, int plain_only)
1.1 djm 324: {
325: char *s, *cp, *p;
1.123 djm 326: const struct sshkey_impl *impl;
327: int i, type;
1.1 djm 328:
329: if (names == NULL || strcmp(names, "") == 0)
330: return 0;
331: if ((s = cp = strdup(names)) == NULL)
332: return 0;
333: for ((p = strsep(&cp, ",")); p && *p != '\0';
334: (p = strsep(&cp, ","))) {
1.11 djm 335: type = sshkey_type_from_name(p);
336: if (type == KEY_UNSPEC) {
337: if (allow_wildcard) {
338: /*
339: * Try matching key types against the string.
340: * If any has a positive or negative match then
341: * the component is accepted.
342: */
1.123 djm 343: impl = NULL;
344: for (i = 0; keyimpls[i] != NULL; i++) {
345: if (match_pattern_list(
346: keyimpls[i]->name, p, 0) != 0) {
347: impl = keyimpls[i];
1.11 djm 348: break;
1.123 djm 349: }
1.11 djm 350: }
1.123 djm 351: if (impl != NULL)
1.11 djm 352: continue;
353: }
1.136 djm 354: free(s);
355: return 0;
356: } else if (plain_only && sshkey_type_is_cert(type)) {
1.1 djm 357: free(s);
358: return 0;
359: }
360: }
361: free(s);
362: return 1;
363: }
364:
365: u_int
366: sshkey_size(const struct sshkey *k)
367: {
1.123 djm 368: const struct sshkey_impl *impl;
1.69 djm 369:
1.126 djm 370: if ((impl = sshkey_impl_from_key(k)) == NULL)
1.123 djm 371: return 0;
372: if (impl->funcs->size != NULL)
373: return impl->funcs->size(k);
374: return impl->keybits;
1.1 djm 375: }
376:
377: static int
378: sshkey_type_is_valid_ca(int type)
379: {
1.123 djm 380: const struct sshkey_impl *impl;
381:
382: if ((impl = sshkey_impl_from_type(type)) == NULL)
1.1 djm 383: return 0;
1.123 djm 384: /* All non-certificate types may act as CAs */
385: return !impl->cert;
1.1 djm 386: }
387:
388: int
389: sshkey_is_cert(const struct sshkey *k)
390: {
391: if (k == NULL)
392: return 0;
393: return sshkey_type_is_cert(k->type);
394: }
395:
1.90 markus 396: int
397: sshkey_is_sk(const struct sshkey *k)
398: {
399: if (k == NULL)
400: return 0;
401: switch (sshkey_type_plain(k->type)) {
402: case KEY_ECDSA_SK:
403: case KEY_ED25519_SK:
404: return 1;
405: default:
406: return 0;
407: }
408: }
409:
1.1 djm 410: /* Return the cert-less equivalent to a certified key type */
411: int
412: sshkey_type_plain(int type)
413: {
414: switch (type) {
415: case KEY_RSA_CERT:
416: return KEY_RSA;
417: case KEY_DSA_CERT:
418: return KEY_DSA;
419: case KEY_ECDSA_CERT:
420: return KEY_ECDSA;
1.85 djm 421: case KEY_ECDSA_SK_CERT:
422: return KEY_ECDSA_SK;
1.1 djm 423: case KEY_ED25519_CERT:
424: return KEY_ED25519;
1.90 markus 425: case KEY_ED25519_SK_CERT:
426: return KEY_ED25519_SK;
1.62 markus 427: case KEY_XMSS_CERT:
428: return KEY_XMSS;
1.1 djm 429: default:
430: return type;
431: }
432: }
433:
1.131 djm 434: /* Return the cert equivalent to a plain key type */
435: static int
436: sshkey_type_certified(int type)
437: {
438: switch (type) {
439: case KEY_RSA:
440: return KEY_RSA_CERT;
441: case KEY_DSA:
442: return KEY_DSA_CERT;
443: case KEY_ECDSA:
444: return KEY_ECDSA_CERT;
445: case KEY_ECDSA_SK:
446: return KEY_ECDSA_SK_CERT;
447: case KEY_ED25519:
448: return KEY_ED25519_CERT;
449: case KEY_ED25519_SK:
450: return KEY_ED25519_SK_CERT;
451: case KEY_XMSS:
452: return KEY_XMSS_CERT;
453: default:
454: return -1;
455: }
456: }
457:
1.1 djm 458: #ifdef WITH_OPENSSL
459: /* XXX: these are really begging for a table-driven approach */
460: int
461: sshkey_curve_name_to_nid(const char *name)
462: {
463: if (strcmp(name, "nistp256") == 0)
464: return NID_X9_62_prime256v1;
465: else if (strcmp(name, "nistp384") == 0)
466: return NID_secp384r1;
467: else if (strcmp(name, "nistp521") == 0)
468: return NID_secp521r1;
469: else
470: return -1;
471: }
472:
473: u_int
474: sshkey_curve_nid_to_bits(int nid)
475: {
476: switch (nid) {
477: case NID_X9_62_prime256v1:
478: return 256;
479: case NID_secp384r1:
480: return 384;
481: case NID_secp521r1:
482: return 521;
483: default:
484: return 0;
485: }
486: }
487:
488: int
489: sshkey_ecdsa_bits_to_nid(int bits)
490: {
491: switch (bits) {
492: case 256:
493: return NID_X9_62_prime256v1;
494: case 384:
495: return NID_secp384r1;
496: case 521:
497: return NID_secp521r1;
498: default:
499: return -1;
500: }
501: }
502:
503: const char *
504: sshkey_curve_nid_to_name(int nid)
505: {
506: switch (nid) {
507: case NID_X9_62_prime256v1:
508: return "nistp256";
509: case NID_secp384r1:
510: return "nistp384";
511: case NID_secp521r1:
512: return "nistp521";
513: default:
514: return NULL;
515: }
516: }
517:
518: int
519: sshkey_ec_nid_to_hash_alg(int nid)
520: {
521: int kbits = sshkey_curve_nid_to_bits(nid);
522:
523: if (kbits <= 0)
524: return -1;
525:
526: /* RFC5656 section 6.2.1 */
527: if (kbits <= 256)
528: return SSH_DIGEST_SHA256;
529: else if (kbits <= 384)
530: return SSH_DIGEST_SHA384;
531: else
532: return SSH_DIGEST_SHA512;
533: }
534: #endif /* WITH_OPENSSL */
535:
536: static void
537: cert_free(struct sshkey_cert *cert)
538: {
539: u_int i;
540:
541: if (cert == NULL)
542: return;
1.31 mmcc 543: sshbuf_free(cert->certblob);
544: sshbuf_free(cert->critical);
545: sshbuf_free(cert->extensions);
1.29 mmcc 546: free(cert->key_id);
1.1 djm 547: for (i = 0; i < cert->nprincipals; i++)
548: free(cert->principals[i]);
1.29 mmcc 549: free(cert->principals);
1.30 mmcc 550: sshkey_free(cert->signature_key);
1.67 djm 551: free(cert->signature_type);
1.61 jsing 552: freezero(cert, sizeof(*cert));
1.1 djm 553: }
554:
555: static struct sshkey_cert *
556: cert_new(void)
557: {
558: struct sshkey_cert *cert;
559:
560: if ((cert = calloc(1, sizeof(*cert))) == NULL)
561: return NULL;
562: if ((cert->certblob = sshbuf_new()) == NULL ||
563: (cert->critical = sshbuf_new()) == NULL ||
564: (cert->extensions = sshbuf_new()) == NULL) {
565: cert_free(cert);
566: return NULL;
567: }
568: cert->key_id = NULL;
569: cert->principals = NULL;
570: cert->signature_key = NULL;
1.67 djm 571: cert->signature_type = NULL;
1.1 djm 572: return cert;
573: }
574:
575: struct sshkey *
576: sshkey_new(int type)
577: {
578: struct sshkey *k;
1.123 djm 579: const struct sshkey_impl *impl = NULL;
580:
581: if (type != KEY_UNSPEC &&
582: (impl = sshkey_impl_from_type(type)) == NULL)
583: return NULL;
1.1 djm 584:
1.123 djm 585: /* All non-certificate types may act as CAs */
1.1 djm 586: if ((k = calloc(1, sizeof(*k))) == NULL)
587: return NULL;
588: k->type = type;
589: k->ecdsa_nid = -1;
1.123 djm 590: if (impl != NULL && impl->funcs->alloc != NULL) {
591: if (impl->funcs->alloc(k) != 0) {
1.1 djm 592: free(k);
593: return NULL;
594: }
595: }
596: if (sshkey_is_cert(k)) {
597: if ((k->cert = cert_new()) == NULL) {
598: sshkey_free(k);
599: return NULL;
600: }
601: }
602:
603: return k;
604: }
605:
1.124 djm 606: /* Frees common FIDO fields */
607: void
608: sshkey_sk_cleanup(struct sshkey *k)
609: {
610: free(k->sk_application);
611: sshbuf_free(k->sk_key_handle);
612: sshbuf_free(k->sk_reserved);
613: k->sk_application = NULL;
614: k->sk_key_handle = k->sk_reserved = NULL;
615: }
616:
1.126 djm 617: static void
618: sshkey_free_contents(struct sshkey *k)
1.1 djm 619: {
1.123 djm 620: const struct sshkey_impl *impl;
621:
1.1 djm 622: if (k == NULL)
623: return;
1.123 djm 624: if ((impl = sshkey_impl_from_type(k->type)) != NULL &&
625: impl->funcs->cleanup != NULL)
626: impl->funcs->cleanup(k);
1.1 djm 627: if (sshkey_is_cert(k))
628: cert_free(k->cert);
1.76 djm 629: freezero(k->shielded_private, k->shielded_len);
630: freezero(k->shield_prekey, k->shield_prekey_len);
1.126 djm 631: }
632:
633: void
634: sshkey_free(struct sshkey *k)
635: {
636: sshkey_free_contents(k);
1.61 jsing 637: freezero(k, sizeof(*k));
1.1 djm 638: }
639:
640: static int
641: cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
642: {
643: if (a == NULL && b == NULL)
644: return 1;
645: if (a == NULL || b == NULL)
646: return 0;
647: if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob))
648: return 0;
649: if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob),
650: sshbuf_len(a->certblob)) != 0)
651: return 0;
652: return 1;
653: }
654:
1.124 djm 655: /* Compares FIDO-specific pubkey fields only */
656: int
657: sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b)
658: {
659: if (a->sk_application == NULL || b->sk_application == NULL)
660: return 0;
661: if (strcmp(a->sk_application, b->sk_application) != 0)
662: return 0;
663: return 1;
664: }
665:
1.1 djm 666: /*
667: * Compare public portions of key only, allowing comparisons between
668: * certificates and plain keys too.
669: */
670: int
671: sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
672: {
1.124 djm 673: const struct sshkey_impl *impl;
1.1 djm 674:
675: if (a == NULL || b == NULL ||
676: sshkey_type_plain(a->type) != sshkey_type_plain(b->type))
677: return 0;
1.124 djm 678: if ((impl = sshkey_impl_from_type(a->type)) == NULL)
1.1 djm 679: return 0;
1.124 djm 680: return impl->funcs->equal(a, b);
1.1 djm 681: }
682:
683: int
684: sshkey_equal(const struct sshkey *a, const struct sshkey *b)
685: {
686: if (a == NULL || b == NULL || a->type != b->type)
687: return 0;
688: if (sshkey_is_cert(a)) {
689: if (!cert_compare(a->cert, b->cert))
690: return 0;
691: }
692: return sshkey_equal_public(a, b);
693: }
694:
1.125 djm 695:
696: /* Serialise common FIDO key parts */
697: int
698: sshkey_serialize_sk(const struct sshkey *key, struct sshbuf *b)
699: {
700: int r;
701:
702: if ((r = sshbuf_put_cstring(b, key->sk_application)) != 0)
703: return r;
704:
705: return 0;
706: }
707:
1.1 djm 708: static int
1.62 markus 709: to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
710: enum sshkey_serialize_rep opts)
1.1 djm 711: {
712: int type, ret = SSH_ERR_INTERNAL_ERROR;
713: const char *typename;
1.125 djm 714: const struct sshkey_impl *impl;
1.1 djm 715:
716: if (key == NULL)
717: return SSH_ERR_INVALID_ARGUMENT;
718:
1.125 djm 719: type = force_plain ? sshkey_type_plain(key->type) : key->type;
720:
721: if (sshkey_type_is_cert(type)) {
1.19 djm 722: if (key->cert == NULL)
723: return SSH_ERR_EXPECTED_CERT;
724: if (sshbuf_len(key->cert->certblob) == 0)
725: return SSH_ERR_KEY_LACKS_CERTBLOB;
1.1 djm 726: /* Use the existing blob */
727: if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
728: return ret;
1.125 djm 729: return 0;
730: }
731: if ((impl = sshkey_impl_from_type(type)) == NULL)
1.1 djm 732: return SSH_ERR_KEY_TYPE_UNKNOWN;
1.125 djm 733:
734: typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
1.129 djm 735: if ((ret = sshbuf_put_cstring(b, typename)) != 0)
736: return ret;
737: return impl->funcs->serialize_public(key, b, opts);
1.1 djm 738: }
739:
740: int
1.14 djm 741: sshkey_putb(const struct sshkey *key, struct sshbuf *b)
1.1 djm 742: {
1.62 markus 743: return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
1.1 djm 744: }
745:
746: int
1.62 markus 747: sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
748: enum sshkey_serialize_rep opts)
1.14 djm 749: {
750: struct sshbuf *tmp;
751: int r;
752:
753: if ((tmp = sshbuf_new()) == NULL)
754: return SSH_ERR_ALLOC_FAIL;
1.62 markus 755: r = to_blob_buf(key, tmp, 0, opts);
1.14 djm 756: if (r == 0)
757: r = sshbuf_put_stringb(b, tmp);
758: sshbuf_free(tmp);
759: return r;
760: }
761:
762: int
1.62 markus 763: sshkey_puts(const struct sshkey *key, struct sshbuf *b)
764: {
765: return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT);
766: }
767:
768: int
1.14 djm 769: sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
1.1 djm 770: {
1.62 markus 771: return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
1.1 djm 772: }
773:
774: static int
1.62 markus 775: to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
776: enum sshkey_serialize_rep opts)
1.1 djm 777: {
778: int ret = SSH_ERR_INTERNAL_ERROR;
779: size_t len;
780: struct sshbuf *b = NULL;
781:
782: if (lenp != NULL)
783: *lenp = 0;
784: if (blobp != NULL)
785: *blobp = NULL;
786: if ((b = sshbuf_new()) == NULL)
787: return SSH_ERR_ALLOC_FAIL;
1.62 markus 788: if ((ret = to_blob_buf(key, b, force_plain, opts)) != 0)
1.1 djm 789: goto out;
790: len = sshbuf_len(b);
791: if (lenp != NULL)
792: *lenp = len;
793: if (blobp != NULL) {
794: if ((*blobp = malloc(len)) == NULL) {
795: ret = SSH_ERR_ALLOC_FAIL;
796: goto out;
797: }
798: memcpy(*blobp, sshbuf_ptr(b), len);
799: }
800: ret = 0;
801: out:
802: sshbuf_free(b);
803: return ret;
804: }
805:
806: int
807: sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
808: {
1.62 markus 809: return to_blob(key, blobp, lenp, 0, SSHKEY_SERIALIZE_DEFAULT);
1.1 djm 810: }
811:
812: int
813: sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
814: {
1.62 markus 815: return to_blob(key, blobp, lenp, 1, SSHKEY_SERIALIZE_DEFAULT);
1.1 djm 816: }
817:
818: int
1.7 djm 819: sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
1.1 djm 820: u_char **retp, size_t *lenp)
821: {
822: u_char *blob = NULL, *ret = NULL;
823: size_t blob_len = 0;
1.7 djm 824: int r = SSH_ERR_INTERNAL_ERROR;
1.1 djm 825:
826: if (retp != NULL)
827: *retp = NULL;
828: if (lenp != NULL)
829: *lenp = 0;
1.7 djm 830: if (ssh_digest_bytes(dgst_alg) == 0) {
1.1 djm 831: r = SSH_ERR_INVALID_ARGUMENT;
832: goto out;
833: }
1.62 markus 834: if ((r = to_blob(k, &blob, &blob_len, 1, SSHKEY_SERIALIZE_DEFAULT))
835: != 0)
1.1 djm 836: goto out;
837: if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
838: r = SSH_ERR_ALLOC_FAIL;
839: goto out;
840: }
1.7 djm 841: if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
1.1 djm 842: ret, SSH_DIGEST_MAX_LENGTH)) != 0)
843: goto out;
844: /* success */
845: if (retp != NULL) {
846: *retp = ret;
847: ret = NULL;
848: }
849: if (lenp != NULL)
1.7 djm 850: *lenp = ssh_digest_bytes(dgst_alg);
1.1 djm 851: r = 0;
852: out:
853: free(ret);
1.100 jsg 854: if (blob != NULL)
855: freezero(blob, blob_len);
1.1 djm 856: return r;
857: }
858:
859: static char *
1.7 djm 860: fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
861: {
862: char *ret;
863: size_t plen = strlen(alg) + 1;
864: size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
865:
866: if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
867: return NULL;
868: strlcpy(ret, alg, rlen);
869: strlcat(ret, ":", rlen);
870: if (dgst_raw_len == 0)
871: return ret;
1.79 dtucker 872: if (b64_ntop(dgst_raw, dgst_raw_len, ret + plen, rlen - plen) == -1) {
1.61 jsing 873: freezero(ret, rlen);
1.7 djm 874: return NULL;
875: }
876: /* Trim padding characters from end */
877: ret[strcspn(ret, "=")] = '\0';
878: return ret;
879: }
880:
881: static char *
882: fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
1.1 djm 883: {
1.7 djm 884: char *retval, hex[5];
885: size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
1.1 djm 886:
1.7 djm 887: if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
1.1 djm 888: return NULL;
1.7 djm 889: strlcpy(retval, alg, rlen);
890: strlcat(retval, ":", rlen);
1.1 djm 891: for (i = 0; i < dgst_raw_len; i++) {
1.7 djm 892: snprintf(hex, sizeof(hex), "%s%02x",
893: i > 0 ? ":" : "", dgst_raw[i]);
894: strlcat(retval, hex, rlen);
1.1 djm 895: }
896: return retval;
897: }
898:
899: static char *
900: fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
901: {
902: char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
903: char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
904: 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
905: u_int i, j = 0, rounds, seed = 1;
906: char *retval;
907:
908: rounds = (dgst_raw_len / 2) + 1;
909: if ((retval = calloc(rounds, 6)) == NULL)
910: return NULL;
911: retval[j++] = 'x';
912: for (i = 0; i < rounds; i++) {
913: u_int idx0, idx1, idx2, idx3, idx4;
914: if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
915: idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
916: seed) % 6;
917: idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
918: idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
919: (seed / 6)) % 6;
920: retval[j++] = vowels[idx0];
921: retval[j++] = consonants[idx1];
922: retval[j++] = vowels[idx2];
923: if ((i + 1) < rounds) {
924: idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
925: idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
926: retval[j++] = consonants[idx3];
927: retval[j++] = '-';
928: retval[j++] = consonants[idx4];
929: seed = ((seed * 5) +
930: ((((u_int)(dgst_raw[2 * i])) * 7) +
931: ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
932: }
933: } else {
934: idx0 = seed % 6;
935: idx1 = 16;
936: idx2 = seed / 6;
937: retval[j++] = vowels[idx0];
938: retval[j++] = consonants[idx1];
939: retval[j++] = vowels[idx2];
940: }
941: }
942: retval[j++] = 'x';
943: retval[j++] = '\0';
944: return retval;
945: }
946:
947: /*
948: * Draw an ASCII-Art representing the fingerprint so human brain can
949: * profit from its built-in pattern recognition ability.
950: * This technique is called "random art" and can be found in some
951: * scientific publications like this original paper:
952: *
953: * "Hash Visualization: a New Technique to improve Real-World Security",
954: * Perrig A. and Song D., 1999, International Workshop on Cryptographic
955: * Techniques and E-Commerce (CrypTEC '99)
956: * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
957: *
958: * The subject came up in a talk by Dan Kaminsky, too.
959: *
960: * If you see the picture is different, the key is different.
961: * If the picture looks the same, you still know nothing.
962: *
963: * The algorithm used here is a worm crawling over a discrete plane,
964: * leaving a trace (augmenting the field) everywhere it goes.
965: * Movement is taken from dgst_raw 2bit-wise. Bumping into walls
966: * makes the respective movement vector be ignored for this turn.
967: * Graphs are not unambiguous, because circles in graphs can be
968: * walked in either direction.
969: */
970:
971: /*
972: * Field sizes for the random art. Have to be odd, so the starting point
973: * can be in the exact middle of the picture, and FLDBASE should be >=8 .
974: * Else pictures would be too dense, and drawing the frame would
975: * fail, too, because the key type would not fit in anymore.
976: */
977: #define FLDBASE 8
978: #define FLDSIZE_Y (FLDBASE + 1)
979: #define FLDSIZE_X (FLDBASE * 2 + 1)
980: static char *
1.7 djm 981: fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
1.1 djm 982: const struct sshkey *k)
983: {
984: /*
985: * Chars to be used after each other every time the worm
986: * intersects with itself. Matter of taste.
987: */
988: char *augmentation_string = " .o+=*BOX@%&#/^SE";
1.7 djm 989: char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
1.1 djm 990: u_char field[FLDSIZE_X][FLDSIZE_Y];
1.7 djm 991: size_t i, tlen, hlen;
1.1 djm 992: u_int b;
1.3 djm 993: int x, y, r;
1.1 djm 994: size_t len = strlen(augmentation_string) - 1;
995:
996: if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
997: return NULL;
998:
999: /* initialize field */
1000: memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
1001: x = FLDSIZE_X / 2;
1002: y = FLDSIZE_Y / 2;
1003:
1004: /* process raw key */
1005: for (i = 0; i < dgst_raw_len; i++) {
1006: int input;
1007: /* each byte conveys four 2-bit move commands */
1008: input = dgst_raw[i];
1009: for (b = 0; b < 4; b++) {
1010: /* evaluate 2 bit, rest is shifted later */
1011: x += (input & 0x1) ? 1 : -1;
1012: y += (input & 0x2) ? 1 : -1;
1013:
1014: /* assure we are still in bounds */
1.37 deraadt 1015: x = MAXIMUM(x, 0);
1016: y = MAXIMUM(y, 0);
1017: x = MINIMUM(x, FLDSIZE_X - 1);
1018: y = MINIMUM(y, FLDSIZE_Y - 1);
1.1 djm 1019:
1020: /* augment the field */
1021: if (field[x][y] < len - 2)
1022: field[x][y]++;
1023: input = input >> 2;
1024: }
1025: }
1026:
1027: /* mark starting point and end point*/
1028: field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
1029: field[x][y] = len;
1030:
1.3 djm 1031: /* assemble title */
1032: r = snprintf(title, sizeof(title), "[%s %u]",
1033: sshkey_type(k), sshkey_size(k));
1034: /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
1035: if (r < 0 || r > (int)sizeof(title))
1.7 djm 1036: r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
1037: tlen = (r <= 0) ? 0 : strlen(title);
1038:
1039: /* assemble hash ID. */
1040: r = snprintf(hash, sizeof(hash), "[%s]", alg);
1041: hlen = (r <= 0) ? 0 : strlen(hash);
1.1 djm 1042:
1043: /* output upper border */
1.3 djm 1044: p = retval;
1045: *p++ = '+';
1046: for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
1047: *p++ = '-';
1048: memcpy(p, title, tlen);
1049: p += tlen;
1.7 djm 1050: for (i += tlen; i < FLDSIZE_X; i++)
1.1 djm 1051: *p++ = '-';
1052: *p++ = '+';
1053: *p++ = '\n';
1054:
1055: /* output content */
1056: for (y = 0; y < FLDSIZE_Y; y++) {
1057: *p++ = '|';
1058: for (x = 0; x < FLDSIZE_X; x++)
1.37 deraadt 1059: *p++ = augmentation_string[MINIMUM(field[x][y], len)];
1.1 djm 1060: *p++ = '|';
1061: *p++ = '\n';
1062: }
1063:
1064: /* output lower border */
1065: *p++ = '+';
1.7 djm 1066: for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
1067: *p++ = '-';
1068: memcpy(p, hash, hlen);
1069: p += hlen;
1070: for (i += hlen; i < FLDSIZE_X; i++)
1.1 djm 1071: *p++ = '-';
1072: *p++ = '+';
1073:
1074: return retval;
1075: }
1076:
1077: char *
1.7 djm 1078: sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
1.1 djm 1079: enum sshkey_fp_rep dgst_rep)
1080: {
1081: char *retval = NULL;
1082: u_char *dgst_raw;
1083: size_t dgst_raw_len;
1084:
1.7 djm 1085: if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
1.1 djm 1086: return NULL;
1087: switch (dgst_rep) {
1.7 djm 1088: case SSH_FP_DEFAULT:
1089: if (dgst_alg == SSH_DIGEST_MD5) {
1090: retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1091: dgst_raw, dgst_raw_len);
1092: } else {
1093: retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1094: dgst_raw, dgst_raw_len);
1095: }
1096: break;
1.1 djm 1097: case SSH_FP_HEX:
1.7 djm 1098: retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1099: dgst_raw, dgst_raw_len);
1100: break;
1101: case SSH_FP_BASE64:
1102: retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1103: dgst_raw, dgst_raw_len);
1.1 djm 1104: break;
1105: case SSH_FP_BUBBLEBABBLE:
1106: retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
1107: break;
1108: case SSH_FP_RANDOMART:
1.7 djm 1109: retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
1110: dgst_raw, dgst_raw_len, k);
1.1 djm 1111: break;
1112: default:
1.100 jsg 1113: freezero(dgst_raw, dgst_raw_len);
1.1 djm 1114: return NULL;
1115: }
1.100 jsg 1116: freezero(dgst_raw, dgst_raw_len);
1.1 djm 1117: return retval;
1118: }
1119:
1.63 djm 1120: static int
1121: peek_type_nid(const char *s, size_t l, int *nid)
1122: {
1.123 djm 1123: const struct sshkey_impl *impl;
1124: int i;
1.63 djm 1125:
1.123 djm 1126: for (i = 0; keyimpls[i] != NULL; i++) {
1127: impl = keyimpls[i];
1128: if (impl->name == NULL || strlen(impl->name) != l)
1.63 djm 1129: continue;
1.123 djm 1130: if (memcmp(s, impl->name, l) == 0) {
1.63 djm 1131: *nid = -1;
1.123 djm 1132: if (key_type_is_ecdsa_variant(impl->type))
1133: *nid = impl->nid;
1134: return impl->type;
1.63 djm 1135: }
1136: }
1137: return KEY_UNSPEC;
1138: }
1.1 djm 1139:
1.63 djm 1140: /* XXX this can now be made const char * */
1.1 djm 1141: int
1142: sshkey_read(struct sshkey *ret, char **cpp)
1143: {
1144: struct sshkey *k;
1.63 djm 1145: char *cp, *blobcopy;
1146: size_t space;
1.1 djm 1147: int r, type, curve_nid = -1;
1148: struct sshbuf *blob;
1.44 dtucker 1149:
1150: if (ret == NULL)
1151: return SSH_ERR_INVALID_ARGUMENT;
1.126 djm 1152: if (ret->type != KEY_UNSPEC && sshkey_impl_from_type(ret->type) == NULL)
1.63 djm 1153: return SSH_ERR_INVALID_ARGUMENT;
1154:
1155: /* Decode type */
1156: cp = *cpp;
1157: space = strcspn(cp, " \t");
1158: if (space == strlen(cp))
1159: return SSH_ERR_INVALID_FORMAT;
1160: if ((type = peek_type_nid(cp, space, &curve_nid)) == KEY_UNSPEC)
1161: return SSH_ERR_INVALID_FORMAT;
1162:
1163: /* skip whitespace */
1164: for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
1165: ;
1166: if (*cp == '\0')
1167: return SSH_ERR_INVALID_FORMAT;
1168: if (ret->type != KEY_UNSPEC && ret->type != type)
1169: return SSH_ERR_KEY_TYPE_MISMATCH;
1170: if ((blob = sshbuf_new()) == NULL)
1171: return SSH_ERR_ALLOC_FAIL;
1172:
1173: /* find end of keyblob and decode */
1174: space = strcspn(cp, " \t");
1175: if ((blobcopy = strndup(cp, space)) == NULL) {
1176: sshbuf_free(blob);
1177: return SSH_ERR_ALLOC_FAIL;
1178: }
1179: if ((r = sshbuf_b64tod(blob, blobcopy)) != 0) {
1180: free(blobcopy);
1181: sshbuf_free(blob);
1182: return r;
1183: }
1184: free(blobcopy);
1185: if ((r = sshkey_fromb(blob, &k)) != 0) {
1.1 djm 1186: sshbuf_free(blob);
1.63 djm 1187: return r;
1188: }
1189: sshbuf_free(blob);
1190:
1191: /* skip whitespace and leave cp at start of comment */
1192: for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
1193: ;
1194:
1195: /* ensure type of blob matches type at start of line */
1196: if (k->type != type) {
1197: sshkey_free(k);
1198: return SSH_ERR_KEY_TYPE_MISMATCH;
1199: }
1.85 djm 1200: if (key_type_is_ecdsa_variant(type) && curve_nid != k->ecdsa_nid) {
1.63 djm 1201: sshkey_free(k);
1202: return SSH_ERR_EC_CURVE_MISMATCH;
1203: }
1204:
1205: /* Fill in ret from parsed key */
1.126 djm 1206: sshkey_free_contents(ret);
1207: *ret = *k;
1208: freezero(k, sizeof(*k));
1.63 djm 1209:
1210: /* success */
1211: *cpp = cp;
1212: return 0;
1.1 djm 1213: }
1214:
1215: int
1.19 djm 1216: sshkey_to_base64(const struct sshkey *key, char **b64p)
1.1 djm 1217: {
1.19 djm 1218: int r = SSH_ERR_INTERNAL_ERROR;
1219: struct sshbuf *b = NULL;
1.1 djm 1220: char *uu = NULL;
1.19 djm 1221:
1222: if (b64p != NULL)
1223: *b64p = NULL;
1224: if ((b = sshbuf_new()) == NULL)
1225: return SSH_ERR_ALLOC_FAIL;
1226: if ((r = sshkey_putb(key, b)) != 0)
1227: goto out;
1.81 djm 1228: if ((uu = sshbuf_dtob64_string(b, 0)) == NULL) {
1.19 djm 1229: r = SSH_ERR_ALLOC_FAIL;
1230: goto out;
1231: }
1232: /* Success */
1233: if (b64p != NULL) {
1234: *b64p = uu;
1235: uu = NULL;
1236: }
1237: r = 0;
1238: out:
1239: sshbuf_free(b);
1240: free(uu);
1241: return r;
1242: }
1243:
1.52 djm 1244: int
1.19 djm 1245: sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
1246: {
1247: int r = SSH_ERR_INTERNAL_ERROR;
1248: char *uu = NULL;
1249:
1.48 djm 1250: if ((r = sshkey_to_base64(key, &uu)) != 0)
1251: goto out;
1252: if ((r = sshbuf_putf(b, "%s %s",
1253: sshkey_ssh_name(key), uu)) != 0)
1254: goto out;
1.19 djm 1255: r = 0;
1256: out:
1257: free(uu);
1258: return r;
1259: }
1260:
1261: int
1262: sshkey_write(const struct sshkey *key, FILE *f)
1263: {
1264: struct sshbuf *b = NULL;
1265: int r = SSH_ERR_INTERNAL_ERROR;
1266:
1267: if ((b = sshbuf_new()) == NULL)
1268: return SSH_ERR_ALLOC_FAIL;
1269: if ((r = sshkey_format_text(key, b)) != 0)
1.1 djm 1270: goto out;
1271: if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1272: if (feof(f))
1273: errno = EPIPE;
1.19 djm 1274: r = SSH_ERR_SYSTEM_ERROR;
1.1 djm 1275: goto out;
1276: }
1.19 djm 1277: /* Success */
1278: r = 0;
1.1 djm 1279: out:
1.19 djm 1280: sshbuf_free(b);
1281: return r;
1.1 djm 1282: }
1283:
1284: const char *
1285: sshkey_cert_type(const struct sshkey *k)
1286: {
1287: switch (k->cert->type) {
1288: case SSH2_CERT_TYPE_USER:
1289: return "user";
1290: case SSH2_CERT_TYPE_HOST:
1291: return "host";
1292: default:
1293: return "unknown";
1294: }
1295: }
1296:
1.134 djm 1297: int
1298: sshkey_check_rsa_length(const struct sshkey *k, int min_size)
1299: {
1300: #ifdef WITH_OPENSSL
1301: const BIGNUM *rsa_n;
1302: int nbits;
1303:
1304: if (k == NULL || k->rsa == NULL ||
1305: (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
1306: return 0;
1307: RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
1308: nbits = BN_num_bits(rsa_n);
1309: if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
1310: (min_size > 0 && nbits < min_size))
1311: return SSH_ERR_KEY_LENGTH;
1312: #endif /* WITH_OPENSSL */
1313: return 0;
1314: }
1315:
1.1 djm 1316: #ifdef WITH_OPENSSL
1317: int
1318: sshkey_ecdsa_key_to_nid(EC_KEY *k)
1319: {
1320: EC_GROUP *eg;
1321: int nids[] = {
1322: NID_X9_62_prime256v1,
1323: NID_secp384r1,
1324: NID_secp521r1,
1325: -1
1326: };
1327: int nid;
1328: u_int i;
1329: const EC_GROUP *g = EC_KEY_get0_group(k);
1330:
1331: /*
1332: * The group may be stored in a ASN.1 encoded private key in one of two
1333: * ways: as a "named group", which is reconstituted by ASN.1 object ID
1334: * or explicit group parameters encoded into the key blob. Only the
1335: * "named group" case sets the group NID for us, but we can figure
1336: * it out for the other case by comparing against all the groups that
1337: * are supported.
1338: */
1339: if ((nid = EC_GROUP_get_curve_name(g)) > 0)
1340: return nid;
1341: for (i = 0; nids[i] != -1; i++) {
1.93 djm 1342: if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
1.1 djm 1343: return -1;
1.93 djm 1344: if (EC_GROUP_cmp(g, eg, NULL) == 0)
1.1 djm 1345: break;
1346: EC_GROUP_free(eg);
1347: }
1348: if (nids[i] != -1) {
1349: /* Use the group with the NID attached */
1350: EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
1351: if (EC_KEY_set_group(k, eg) != 1) {
1352: EC_GROUP_free(eg);
1353: return -1;
1354: }
1355: }
1356: return nids[i];
1357: }
1358: #endif /* WITH_OPENSSL */
1359:
1360: int
1361: sshkey_generate(int type, u_int bits, struct sshkey **keyp)
1362: {
1363: struct sshkey *k;
1364: int ret = SSH_ERR_INTERNAL_ERROR;
1.127 djm 1365: const struct sshkey_impl *impl;
1.1 djm 1366:
1.127 djm 1367: if (keyp == NULL || sshkey_type_is_cert(type))
1.1 djm 1368: return SSH_ERR_INVALID_ARGUMENT;
1369: *keyp = NULL;
1.127 djm 1370: if ((impl = sshkey_impl_from_type(type)) == NULL)
1371: return SSH_ERR_KEY_TYPE_UNKNOWN;
1372: if (impl->funcs->generate == NULL)
1373: return SSH_ERR_FEATURE_UNSUPPORTED;
1.1 djm 1374: if ((k = sshkey_new(KEY_UNSPEC)) == NULL)
1375: return SSH_ERR_ALLOC_FAIL;
1.127 djm 1376: k->type = type;
1377: if ((ret = impl->funcs->generate(k, bits)) != 0) {
1378: sshkey_free(k);
1379: return ret;
1.1 djm 1380: }
1.127 djm 1381: /* success */
1382: *keyp = k;
1383: return 0;
1.1 djm 1384: }
1385:
1386: int
1387: sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
1388: {
1389: u_int i;
1390: const struct sshkey_cert *from;
1391: struct sshkey_cert *to;
1.67 djm 1392: int r = SSH_ERR_INTERNAL_ERROR;
1.1 djm 1393:
1.67 djm 1394: if (to_key == NULL || (from = from_key->cert) == NULL)
1.1 djm 1395: return SSH_ERR_INVALID_ARGUMENT;
1396:
1.67 djm 1397: if ((to = cert_new()) == NULL)
1.1 djm 1398: return SSH_ERR_ALLOC_FAIL;
1399:
1.67 djm 1400: if ((r = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
1401: (r = sshbuf_putb(to->critical, from->critical)) != 0 ||
1402: (r = sshbuf_putb(to->extensions, from->extensions)) != 0)
1403: goto out;
1.1 djm 1404:
1405: to->serial = from->serial;
1406: to->type = from->type;
1407: if (from->key_id == NULL)
1408: to->key_id = NULL;
1.67 djm 1409: else if ((to->key_id = strdup(from->key_id)) == NULL) {
1410: r = SSH_ERR_ALLOC_FAIL;
1411: goto out;
1412: }
1.1 djm 1413: to->valid_after = from->valid_after;
1414: to->valid_before = from->valid_before;
1415: if (from->signature_key == NULL)
1416: to->signature_key = NULL;
1.67 djm 1417: else if ((r = sshkey_from_private(from->signature_key,
1.1 djm 1418: &to->signature_key)) != 0)
1.67 djm 1419: goto out;
1420: if (from->signature_type != NULL &&
1421: (to->signature_type = strdup(from->signature_type)) == NULL) {
1422: r = SSH_ERR_ALLOC_FAIL;
1423: goto out;
1424: }
1425: if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) {
1426: r = SSH_ERR_INVALID_ARGUMENT;
1427: goto out;
1428: }
1.1 djm 1429: if (from->nprincipals > 0) {
1430: if ((to->principals = calloc(from->nprincipals,
1.67 djm 1431: sizeof(*to->principals))) == NULL) {
1432: r = SSH_ERR_ALLOC_FAIL;
1433: goto out;
1434: }
1.1 djm 1435: for (i = 0; i < from->nprincipals; i++) {
1436: to->principals[i] = strdup(from->principals[i]);
1437: if (to->principals[i] == NULL) {
1438: to->nprincipals = i;
1.67 djm 1439: r = SSH_ERR_ALLOC_FAIL;
1440: goto out;
1.1 djm 1441: }
1442: }
1443: }
1444: to->nprincipals = from->nprincipals;
1.67 djm 1445:
1446: /* success */
1447: cert_free(to_key->cert);
1448: to_key->cert = to;
1449: to = NULL;
1450: r = 0;
1451: out:
1452: cert_free(to);
1453: return r;
1.1 djm 1454: }
1455:
1456: int
1.128 djm 1457: sshkey_copy_public_sk(const struct sshkey *from, struct sshkey *to)
1458: {
1459: /* Append security-key application string */
1460: if ((to->sk_application = strdup(from->sk_application)) == NULL)
1461: return SSH_ERR_ALLOC_FAIL;
1462: return 0;
1463: }
1464:
1465: int
1.1 djm 1466: sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
1467: {
1468: struct sshkey *n = NULL;
1.69 djm 1469: int r = SSH_ERR_INTERNAL_ERROR;
1.128 djm 1470: const struct sshkey_impl *impl;
1.1 djm 1471:
1.24 djm 1472: *pkp = NULL;
1.128 djm 1473: if ((impl = sshkey_impl_from_key(k)) == NULL)
1474: return SSH_ERR_KEY_TYPE_UNKNOWN;
1.85 djm 1475: if ((n = sshkey_new(k->type)) == NULL) {
1476: r = SSH_ERR_ALLOC_FAIL;
1477: goto out;
1478: }
1.128 djm 1479: if ((r = impl->funcs->copy_public(k, n)) != 0)
1.69 djm 1480: goto out;
1481: if (sshkey_is_cert(k) && (r = sshkey_cert_copy(k, n)) != 0)
1482: goto out;
1483: /* success */
1.1 djm 1484: *pkp = n;
1.69 djm 1485: n = NULL;
1486: r = 0;
1487: out:
1488: sshkey_free(n);
1489: return r;
1.1 djm 1490: }
1491:
1.76 djm 1492: int
1493: sshkey_is_shielded(struct sshkey *k)
1494: {
1495: return k != NULL && k->shielded_private != NULL;
1496: }
1497:
1498: int
1499: sshkey_shield_private(struct sshkey *k)
1500: {
1501: struct sshbuf *prvbuf = NULL;
1502: u_char *prekey = NULL, *enc = NULL, keyiv[SSH_DIGEST_MAX_LENGTH];
1503: struct sshcipher_ctx *cctx = NULL;
1504: const struct sshcipher *cipher;
1505: size_t i, enclen = 0;
1506: struct sshkey *kswap = NULL, tmp;
1507: int r = SSH_ERR_INTERNAL_ERROR;
1508:
1509: #ifdef DEBUG_PK
1510: fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k));
1511: #endif
1512: if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) {
1513: r = SSH_ERR_INVALID_ARGUMENT;
1514: goto out;
1515: }
1516: if (cipher_keylen(cipher) + cipher_ivlen(cipher) >
1517: ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) {
1518: r = SSH_ERR_INTERNAL_ERROR;
1519: goto out;
1520: }
1521:
1522: /* Prepare a random pre-key, and from it an ephemeral key */
1523: if ((prekey = malloc(SSHKEY_SHIELD_PREKEY_LEN)) == NULL) {
1524: r = SSH_ERR_ALLOC_FAIL;
1525: goto out;
1526: }
1527: arc4random_buf(prekey, SSHKEY_SHIELD_PREKEY_LEN);
1528: if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH,
1529: prekey, SSHKEY_SHIELD_PREKEY_LEN,
1530: keyiv, SSH_DIGEST_MAX_LENGTH)) != 0)
1531: goto out;
1532: #ifdef DEBUG_PK
1533: fprintf(stderr, "%s: key+iv\n", __func__);
1534: sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH),
1535: stderr);
1536: #endif
1537: if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher),
1538: keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 1)) != 0)
1539: goto out;
1540:
1541: /* Serialise and encrypt the private key using the ephemeral key */
1542: if ((prvbuf = sshbuf_new()) == NULL) {
1543: r = SSH_ERR_ALLOC_FAIL;
1544: goto out;
1545: }
1546: if (sshkey_is_shielded(k) && (r = sshkey_unshield_private(k)) != 0)
1547: goto out;
1548: if ((r = sshkey_private_serialize_opt(k, prvbuf,
1.116 djm 1549: SSHKEY_SERIALIZE_SHIELD)) != 0)
1.76 djm 1550: goto out;
1551: /* pad to cipher blocksize */
1552: i = 0;
1553: while (sshbuf_len(prvbuf) % cipher_blocksize(cipher)) {
1554: if ((r = sshbuf_put_u8(prvbuf, ++i & 0xff)) != 0)
1555: goto out;
1556: }
1557: #ifdef DEBUG_PK
1558: fprintf(stderr, "%s: serialised\n", __func__);
1559: sshbuf_dump(prvbuf, stderr);
1560: #endif
1561: /* encrypt */
1562: enclen = sshbuf_len(prvbuf);
1563: if ((enc = malloc(enclen)) == NULL) {
1564: r = SSH_ERR_ALLOC_FAIL;
1565: goto out;
1566: }
1567: if ((r = cipher_crypt(cctx, 0, enc,
1568: sshbuf_ptr(prvbuf), sshbuf_len(prvbuf), 0, 0)) != 0)
1569: goto out;
1570: #ifdef DEBUG_PK
1571: fprintf(stderr, "%s: encrypted\n", __func__);
1572: sshbuf_dump_data(enc, enclen, stderr);
1573: #endif
1574:
1575: /* Make a scrubbed, public-only copy of our private key argument */
1576: if ((r = sshkey_from_private(k, &kswap)) != 0)
1577: goto out;
1578:
1579: /* Swap the private key out (it will be destroyed below) */
1580: tmp = *kswap;
1581: *kswap = *k;
1582: *k = tmp;
1583:
1584: /* Insert the shielded key into our argument */
1585: k->shielded_private = enc;
1586: k->shielded_len = enclen;
1587: k->shield_prekey = prekey;
1588: k->shield_prekey_len = SSHKEY_SHIELD_PREKEY_LEN;
1589: enc = prekey = NULL; /* transferred */
1590: enclen = 0;
1.99 djm 1591:
1592: /* preserve key fields that are required for correct operation */
1593: k->sk_flags = kswap->sk_flags;
1.76 djm 1594:
1595: /* success */
1596: r = 0;
1597:
1598: out:
1599: /* XXX behaviour on error - invalidate original private key? */
1600: cipher_free(cctx);
1601: explicit_bzero(keyiv, sizeof(keyiv));
1602: explicit_bzero(&tmp, sizeof(tmp));
1.78 djm 1603: freezero(enc, enclen);
1.76 djm 1604: freezero(prekey, SSHKEY_SHIELD_PREKEY_LEN);
1605: sshkey_free(kswap);
1606: sshbuf_free(prvbuf);
1607: return r;
1608: }
1609:
1.121 djm 1610: /* Check deterministic padding after private key */
1611: static int
1612: private2_check_padding(struct sshbuf *decrypted)
1613: {
1614: u_char pad;
1615: size_t i;
1616: int r;
1617:
1618: i = 0;
1619: while (sshbuf_len(decrypted)) {
1620: if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
1621: goto out;
1622: if (pad != (++i & 0xff)) {
1623: r = SSH_ERR_INVALID_FORMAT;
1624: goto out;
1625: }
1626: }
1627: /* success */
1628: r = 0;
1629: out:
1630: explicit_bzero(&pad, sizeof(pad));
1631: explicit_bzero(&i, sizeof(i));
1632: return r;
1633: }
1634:
1.76 djm 1635: int
1636: sshkey_unshield_private(struct sshkey *k)
1637: {
1638: struct sshbuf *prvbuf = NULL;
1.121 djm 1639: u_char *cp, keyiv[SSH_DIGEST_MAX_LENGTH];
1.76 djm 1640: struct sshcipher_ctx *cctx = NULL;
1641: const struct sshcipher *cipher;
1642: struct sshkey *kswap = NULL, tmp;
1643: int r = SSH_ERR_INTERNAL_ERROR;
1644:
1645: #ifdef DEBUG_PK
1646: fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k));
1647: #endif
1648: if (!sshkey_is_shielded(k))
1649: return 0; /* nothing to do */
1650:
1651: if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) {
1652: r = SSH_ERR_INVALID_ARGUMENT;
1653: goto out;
1654: }
1655: if (cipher_keylen(cipher) + cipher_ivlen(cipher) >
1656: ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) {
1657: r = SSH_ERR_INTERNAL_ERROR;
1658: goto out;
1659: }
1660: /* check size of shielded key blob */
1661: if (k->shielded_len < cipher_blocksize(cipher) ||
1662: (k->shielded_len % cipher_blocksize(cipher)) != 0) {
1663: r = SSH_ERR_INVALID_FORMAT;
1664: goto out;
1665: }
1666:
1667: /* Calculate the ephemeral key from the prekey */
1668: if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH,
1669: k->shield_prekey, k->shield_prekey_len,
1670: keyiv, SSH_DIGEST_MAX_LENGTH)) != 0)
1671: goto out;
1672: if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher),
1673: keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0)) != 0)
1674: goto out;
1675: #ifdef DEBUG_PK
1676: fprintf(stderr, "%s: key+iv\n", __func__);
1677: sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH),
1678: stderr);
1679: #endif
1680:
1681: /* Decrypt and parse the shielded private key using the ephemeral key */
1682: if ((prvbuf = sshbuf_new()) == NULL) {
1683: r = SSH_ERR_ALLOC_FAIL;
1684: goto out;
1685: }
1686: if ((r = sshbuf_reserve(prvbuf, k->shielded_len, &cp)) != 0)
1687: goto out;
1688: /* decrypt */
1689: #ifdef DEBUG_PK
1690: fprintf(stderr, "%s: encrypted\n", __func__);
1691: sshbuf_dump_data(k->shielded_private, k->shielded_len, stderr);
1692: #endif
1693: if ((r = cipher_crypt(cctx, 0, cp,
1694: k->shielded_private, k->shielded_len, 0, 0)) != 0)
1695: goto out;
1696: #ifdef DEBUG_PK
1697: fprintf(stderr, "%s: serialised\n", __func__);
1698: sshbuf_dump(prvbuf, stderr);
1699: #endif
1700: /* Parse private key */
1701: if ((r = sshkey_private_deserialize(prvbuf, &kswap)) != 0)
1702: goto out;
1.121 djm 1703:
1704: if ((r = private2_check_padding(prvbuf)) != 0)
1705: goto out;
1.76 djm 1706:
1707: /* Swap the parsed key back into place */
1708: tmp = *kswap;
1709: *kswap = *k;
1710: *k = tmp;
1711:
1712: /* success */
1713: r = 0;
1714:
1715: out:
1716: cipher_free(cctx);
1717: explicit_bzero(keyiv, sizeof(keyiv));
1718: explicit_bzero(&tmp, sizeof(tmp));
1719: sshkey_free(kswap);
1720: sshbuf_free(prvbuf);
1721: return r;
1722: }
1723:
1.1 djm 1724: static int
1.14 djm 1725: cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
1.1 djm 1726: {
1.14 djm 1727: struct sshbuf *principals = NULL, *crit = NULL;
1728: struct sshbuf *exts = NULL, *ca = NULL;
1729: u_char *sig = NULL;
1730: size_t signed_len = 0, slen = 0, kidlen = 0;
1.1 djm 1731: int ret = SSH_ERR_INTERNAL_ERROR;
1732:
1733: /* Copy the entire key blob for verification and later serialisation */
1.14 djm 1734: if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0)
1.1 djm 1735: return ret;
1736:
1.20 djm 1737: /* Parse body of certificate up to signature */
1738: if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 ||
1.1 djm 1739: (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 ||
1740: (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 ||
1.4 djm 1741: (ret = sshbuf_froms(b, &principals)) != 0 ||
1.1 djm 1742: (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 ||
1743: (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 ||
1.4 djm 1744: (ret = sshbuf_froms(b, &crit)) != 0 ||
1.20 djm 1745: (ret = sshbuf_froms(b, &exts)) != 0 ||
1.1 djm 1746: (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 ||
1.14 djm 1747: (ret = sshbuf_froms(b, &ca)) != 0) {
1.1 djm 1748: /* XXX debug print error for ret */
1749: ret = SSH_ERR_INVALID_FORMAT;
1750: goto out;
1751: }
1752:
1753: /* Signature is left in the buffer so we can calculate this length */
1754: signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b);
1755:
1756: if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) {
1757: ret = SSH_ERR_INVALID_FORMAT;
1758: goto out;
1759: }
1760:
1761: if (key->cert->type != SSH2_CERT_TYPE_USER &&
1762: key->cert->type != SSH2_CERT_TYPE_HOST) {
1763: ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
1764: goto out;
1765: }
1766:
1.4 djm 1767: /* Parse principals section */
1768: while (sshbuf_len(principals) > 0) {
1769: char *principal = NULL;
1770: char **oprincipals = NULL;
1771:
1.1 djm 1772: if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) {
1773: ret = SSH_ERR_INVALID_FORMAT;
1774: goto out;
1775: }
1.4 djm 1776: if ((ret = sshbuf_get_cstring(principals, &principal,
1777: NULL)) != 0) {
1.1 djm 1778: ret = SSH_ERR_INVALID_FORMAT;
1779: goto out;
1780: }
1781: oprincipals = key->cert->principals;
1.51 deraadt 1782: key->cert->principals = recallocarray(key->cert->principals,
1783: key->cert->nprincipals, key->cert->nprincipals + 1,
1784: sizeof(*key->cert->principals));
1.1 djm 1785: if (key->cert->principals == NULL) {
1786: free(principal);
1787: key->cert->principals = oprincipals;
1788: ret = SSH_ERR_ALLOC_FAIL;
1789: goto out;
1790: }
1791: key->cert->principals[key->cert->nprincipals++] = principal;
1792: }
1793:
1.4 djm 1794: /*
1795: * Stash a copies of the critical options and extensions sections
1796: * for later use.
1797: */
1798: if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 ||
1799: (exts != NULL &&
1800: (ret = sshbuf_putb(key->cert->extensions, exts)) != 0))
1.1 djm 1801: goto out;
1802:
1.4 djm 1803: /*
1804: * Validate critical options and extensions sections format.
1805: */
1806: while (sshbuf_len(crit) != 0) {
1807: if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 ||
1808: (ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) {
1809: sshbuf_reset(key->cert->critical);
1.1 djm 1810: ret = SSH_ERR_INVALID_FORMAT;
1811: goto out;
1812: }
1813: }
1.4 djm 1814: while (exts != NULL && sshbuf_len(exts) != 0) {
1815: if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 ||
1816: (ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) {
1817: sshbuf_reset(key->cert->extensions);
1.1 djm 1818: ret = SSH_ERR_INVALID_FORMAT;
1819: goto out;
1820: }
1821: }
1822:
1.4 djm 1823: /* Parse CA key and check signature */
1.14 djm 1824: if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) {
1.1 djm 1825: ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1826: goto out;
1827: }
1828: if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
1829: ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1830: goto out;
1831: }
1832: if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
1.96 djm 1833: sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0, NULL)) != 0)
1.1 djm 1834: goto out;
1.82 djm 1835: if ((ret = sshkey_get_sigtype(sig, slen,
1836: &key->cert->signature_type)) != 0)
1.67 djm 1837: goto out;
1.4 djm 1838:
1839: /* Success */
1.1 djm 1840: ret = 0;
1841: out:
1.14 djm 1842: sshbuf_free(ca);
1.4 djm 1843: sshbuf_free(crit);
1844: sshbuf_free(exts);
1845: sshbuf_free(principals);
1.1 djm 1846: free(sig);
1847: return ret;
1848: }
1849:
1.122 djm 1850: int
1.129 djm 1851: sshkey_deserialize_sk(struct sshbuf *b, struct sshkey *key)
1.122 djm 1852: {
1.129 djm 1853: /* Parse additional security-key application string */
1854: if (sshbuf_get_cstring(b, &key->sk_application, NULL) != 0)
1855: return SSH_ERR_INVALID_FORMAT;
1.69 djm 1856: return 0;
1857: }
1858:
1859: static int
1.14 djm 1860: sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
1861: int allow_cert)
1.1 djm 1862: {
1.12 djm 1863: int type, ret = SSH_ERR_INTERNAL_ERROR;
1.129 djm 1864: char *ktype = NULL;
1.1 djm 1865: struct sshkey *key = NULL;
1.14 djm 1866: struct sshbuf *copy;
1.129 djm 1867: const struct sshkey_impl *impl;
1.1 djm 1868:
1869: #ifdef DEBUG_PK /* XXX */
1.14 djm 1870: sshbuf_dump(b, stderr);
1.1 djm 1871: #endif
1.32 djm 1872: if (keyp != NULL)
1873: *keyp = NULL;
1.14 djm 1874: if ((copy = sshbuf_fromb(b)) == NULL) {
1875: ret = SSH_ERR_ALLOC_FAIL;
1876: goto out;
1877: }
1.1 djm 1878: if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
1879: ret = SSH_ERR_INVALID_FORMAT;
1880: goto out;
1881: }
1882:
1883: type = sshkey_type_from_name(ktype);
1884: if (!allow_cert && sshkey_type_is_cert(type)) {
1885: ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1886: goto out;
1887: }
1.129 djm 1888: if ((impl = sshkey_impl_from_type(type)) == NULL) {
1889: ret = SSH_ERR_KEY_TYPE_UNKNOWN;
1890: goto out;
1891: }
1892: if ((key = sshkey_new(type)) == NULL) {
1893: ret = SSH_ERR_ALLOC_FAIL;
1894: goto out;
1895: }
1896: if (sshkey_type_is_cert(type)) {
1.141 ! jsg 1897: /* Skip nonce that precedes all certificates */
1.1 djm 1898: if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1899: ret = SSH_ERR_INVALID_FORMAT;
1900: goto out;
1901: }
1.129 djm 1902: }
1903: if ((ret = impl->funcs->deserialize_public(ktype, b, key)) != 0)
1.1 djm 1904: goto out;
1905:
1906: /* Parse certificate potion */
1.14 djm 1907: if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
1.1 djm 1908: goto out;
1909:
1910: if (key != NULL && sshbuf_len(b) != 0) {
1911: ret = SSH_ERR_INVALID_FORMAT;
1912: goto out;
1913: }
1914: ret = 0;
1.32 djm 1915: if (keyp != NULL) {
1916: *keyp = key;
1917: key = NULL;
1918: }
1.1 djm 1919: out:
1.14 djm 1920: sshbuf_free(copy);
1.1 djm 1921: sshkey_free(key);
1922: free(ktype);
1923: return ret;
1924: }
1925:
1926: int
1927: sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
1928: {
1.14 djm 1929: struct sshbuf *b;
1930: int r;
1931:
1932: if ((b = sshbuf_from(blob, blen)) == NULL)
1933: return SSH_ERR_ALLOC_FAIL;
1934: r = sshkey_from_blob_internal(b, keyp, 1);
1935: sshbuf_free(b);
1936: return r;
1937: }
1938:
1939: int
1940: sshkey_fromb(struct sshbuf *b, struct sshkey **keyp)
1941: {
1942: return sshkey_from_blob_internal(b, keyp, 1);
1943: }
1944:
1945: int
1946: sshkey_froms(struct sshbuf *buf, struct sshkey **keyp)
1947: {
1948: struct sshbuf *b;
1949: int r;
1950:
1951: if ((r = sshbuf_froms(buf, &b)) != 0)
1952: return r;
1953: r = sshkey_from_blob_internal(b, keyp, 1);
1.58 djm 1954: sshbuf_free(b);
1955: return r;
1956: }
1957:
1.82 djm 1958: int
1959: sshkey_get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
1.58 djm 1960: {
1961: int r;
1962: struct sshbuf *b = NULL;
1963: char *sigtype = NULL;
1964:
1965: if (sigtypep != NULL)
1966: *sigtypep = NULL;
1967: if ((b = sshbuf_from(sig, siglen)) == NULL)
1968: return SSH_ERR_ALLOC_FAIL;
1969: if ((r = sshbuf_get_cstring(b, &sigtype, NULL)) != 0)
1970: goto out;
1971: /* success */
1972: if (sigtypep != NULL) {
1973: *sigtypep = sigtype;
1974: sigtype = NULL;
1975: }
1976: r = 0;
1977: out:
1978: free(sigtype);
1.14 djm 1979: sshbuf_free(b);
1980: return r;
1.68 djm 1981: }
1982:
1983: /*
1984: *
1985: * Checks whether a certificate's signature type is allowed.
1986: * Returns 0 (success) if the certificate signature type appears in the
1987: * "allowed" pattern-list, or the key is not a certificate to begin with.
1988: * Otherwise returns a ssherr.h code.
1989: */
1990: int
1991: sshkey_check_cert_sigtype(const struct sshkey *key, const char *allowed)
1992: {
1993: if (key == NULL || allowed == NULL)
1994: return SSH_ERR_INVALID_ARGUMENT;
1995: if (!sshkey_type_is_cert(key->type))
1996: return 0;
1997: if (key->cert == NULL || key->cert->signature_type == NULL)
1998: return SSH_ERR_INVALID_ARGUMENT;
1999: if (match_pattern_list(key->cert->signature_type, allowed, 0) != 1)
2000: return SSH_ERR_SIGN_ALG_UNSUPPORTED;
2001: return 0;
1.65 djm 2002: }
2003:
2004: /*
2005: * Returns the expected signature algorithm for a given public key algorithm.
2006: */
1.66 djm 2007: const char *
2008: sshkey_sigalg_by_name(const char *name)
1.65 djm 2009: {
1.123 djm 2010: const struct sshkey_impl *impl;
2011: int i;
1.65 djm 2012:
1.123 djm 2013: for (i = 0; keyimpls[i] != NULL; i++) {
2014: impl = keyimpls[i];
2015: if (strcmp(impl->name, name) != 0)
1.65 djm 2016: continue;
1.123 djm 2017: if (impl->sigalg != NULL)
2018: return impl->sigalg;
2019: if (!impl->cert)
2020: return impl->name;
1.65 djm 2021: return sshkey_ssh_name_from_type_nid(
1.123 djm 2022: sshkey_type_plain(impl->type), impl->nid);
1.65 djm 2023: }
2024: return NULL;
2025: }
2026:
2027: /*
2028: * Verifies that the signature algorithm appearing inside the signature blob
2029: * matches that which was requested.
2030: */
2031: int
2032: sshkey_check_sigtype(const u_char *sig, size_t siglen,
2033: const char *requested_alg)
2034: {
2035: const char *expected_alg;
2036: char *sigtype = NULL;
2037: int r;
2038:
2039: if (requested_alg == NULL)
2040: return 0;
1.66 djm 2041: if ((expected_alg = sshkey_sigalg_by_name(requested_alg)) == NULL)
1.65 djm 2042: return SSH_ERR_INVALID_ARGUMENT;
1.82 djm 2043: if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0)
1.65 djm 2044: return r;
2045: r = strcmp(expected_alg, sigtype) == 0;
2046: free(sigtype);
2047: return r ? 0 : SSH_ERR_SIGN_ALG_UNSUPPORTED;
1.1 djm 2048: }
2049:
2050: int
1.76 djm 2051: sshkey_sign(struct sshkey *key,
1.1 djm 2052: u_char **sigp, size_t *lenp,
1.86 djm 2053: const u_char *data, size_t datalen,
1.111 djm 2054: const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
1.1 djm 2055: {
1.76 djm 2056: int was_shielded = sshkey_is_shielded(key);
2057: int r2, r = SSH_ERR_INTERNAL_ERROR;
1.130 djm 2058: const struct sshkey_impl *impl;
1.76 djm 2059:
1.1 djm 2060: if (sigp != NULL)
2061: *sigp = NULL;
2062: if (lenp != NULL)
2063: *lenp = 0;
2064: if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
2065: return SSH_ERR_INVALID_ARGUMENT;
1.130 djm 2066: if ((impl = sshkey_impl_from_key(key)) == NULL)
2067: return SSH_ERR_KEY_TYPE_UNKNOWN;
1.76 djm 2068: if ((r = sshkey_unshield_private(key)) != 0)
2069: return r;
1.130 djm 2070: if (sshkey_is_sk(key)) {
1.97 djm 2071: r = sshsk_sign(sk_provider, key, sigp, lenp, data,
1.111 djm 2072: datalen, compat, sk_pin);
1.130 djm 2073: } else {
2074: if (impl->funcs->sign == NULL)
2075: r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
2076: else {
2077: r = impl->funcs->sign(key, sigp, lenp, data, datalen,
2078: alg, sk_provider, sk_pin, compat);
2079: }
1.1 djm 2080: }
1.76 djm 2081: if (was_shielded && (r2 = sshkey_shield_private(key)) != 0)
2082: return r2;
2083: return r;
1.1 djm 2084: }
2085:
2086: /*
2087: * ssh_key_verify returns 0 for a correct signature and < 0 on error.
1.59 djm 2088: * If "alg" specified, then the signature must use that algorithm.
1.1 djm 2089: */
2090: int
2091: sshkey_verify(const struct sshkey *key,
2092: const u_char *sig, size_t siglen,
1.96 djm 2093: const u_char *data, size_t dlen, const char *alg, u_int compat,
2094: struct sshkey_sig_details **detailsp)
1.1 djm 2095: {
1.130 djm 2096: const struct sshkey_impl *impl;
2097:
1.96 djm 2098: if (detailsp != NULL)
2099: *detailsp = NULL;
1.6 djm 2100: if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
1.1 djm 2101: return SSH_ERR_INVALID_ARGUMENT;
1.130 djm 2102: if ((impl = sshkey_impl_from_key(key)) == NULL)
1.1 djm 2103: return SSH_ERR_KEY_TYPE_UNKNOWN;
1.130 djm 2104: return impl->funcs->verify(key, sig, siglen, data, dlen,
2105: alg, compat, detailsp);
1.1 djm 2106: }
2107:
2108: /* Convert a plain key to their _CERT equivalent */
2109: int
1.20 djm 2110: sshkey_to_certified(struct sshkey *k)
1.1 djm 2111: {
2112: int newtype;
2113:
1.131 djm 2114: if ((newtype = sshkey_type_certified(k->type)) == -1)
1.1 djm 2115: return SSH_ERR_INVALID_ARGUMENT;
2116: if ((k->cert = cert_new()) == NULL)
2117: return SSH_ERR_ALLOC_FAIL;
2118: k->type = newtype;
2119: return 0;
2120: }
2121:
2122: /* Convert a certificate to its raw key equivalent */
2123: int
2124: sshkey_drop_cert(struct sshkey *k)
2125: {
2126: if (!sshkey_type_is_cert(k->type))
2127: return SSH_ERR_KEY_TYPE_UNKNOWN;
2128: cert_free(k->cert);
2129: k->cert = NULL;
2130: k->type = sshkey_type_plain(k->type);
2131: return 0;
2132: }
2133:
2134: /* Sign a certified key, (re-)generating the signed certblob. */
2135: int
1.53 djm 2136: sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
1.111 djm 2137: const char *sk_provider, const char *sk_pin,
2138: sshkey_certify_signer *signer, void *signer_ctx)
1.1 djm 2139: {
1.131 djm 2140: const struct sshkey_impl *impl;
1.1 djm 2141: struct sshbuf *principals = NULL;
2142: u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
2143: size_t i, ca_len, sig_len;
2144: int ret = SSH_ERR_INTERNAL_ERROR;
1.67 djm 2145: struct sshbuf *cert = NULL;
2146: char *sigtype = NULL;
1.1 djm 2147:
2148: if (k == NULL || k->cert == NULL ||
2149: k->cert->certblob == NULL || ca == NULL)
2150: return SSH_ERR_INVALID_ARGUMENT;
2151: if (!sshkey_is_cert(k))
2152: return SSH_ERR_KEY_TYPE_UNKNOWN;
2153: if (!sshkey_type_is_valid_ca(ca->type))
2154: return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1.131 djm 2155: if ((impl = sshkey_impl_from_key(k)) == NULL)
2156: return SSH_ERR_INTERNAL_ERROR;
1.1 djm 2157:
1.67 djm 2158: /*
2159: * If no alg specified as argument but a signature_type was set,
2160: * then prefer that. If both were specified, then they must match.
2161: */
2162: if (alg == NULL)
2163: alg = k->cert->signature_type;
2164: else if (k->cert->signature_type != NULL &&
2165: strcmp(alg, k->cert->signature_type) != 0)
2166: return SSH_ERR_INVALID_ARGUMENT;
1.75 djm 2167:
2168: /*
2169: * If no signing algorithm or signature_type was specified and we're
2170: * using a RSA key, then default to a good signature algorithm.
2171: */
2172: if (alg == NULL && ca->type == KEY_RSA)
2173: alg = "rsa-sha2-512";
1.67 djm 2174:
1.1 djm 2175: if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0)
2176: return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2177:
2178: cert = k->cert->certblob; /* for readability */
2179: sshbuf_reset(cert);
2180: if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0)
2181: goto out;
2182:
2183: /* -v01 certs put nonce first */
2184: arc4random_buf(&nonce, sizeof(nonce));
1.20 djm 2185: if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
2186: goto out;
1.1 djm 2187:
1.131 djm 2188: /* Public key next */
2189: if ((ret = impl->funcs->serialize_public(k, cert,
2190: SSHKEY_SERIALIZE_DEFAULT)) != 0)
1.15 djm 2191: goto out;
1.1 djm 2192:
1.131 djm 2193: /* Then remaining cert fields */
1.20 djm 2194: if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 ||
2195: (ret = sshbuf_put_u32(cert, k->cert->type)) != 0 ||
1.1 djm 2196: (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0)
2197: goto out;
2198:
2199: if ((principals = sshbuf_new()) == NULL) {
2200: ret = SSH_ERR_ALLOC_FAIL;
2201: goto out;
2202: }
2203: for (i = 0; i < k->cert->nprincipals; i++) {
2204: if ((ret = sshbuf_put_cstring(principals,
2205: k->cert->principals[i])) != 0)
2206: goto out;
2207: }
2208: if ((ret = sshbuf_put_stringb(cert, principals)) != 0 ||
2209: (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 ||
2210: (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 ||
1.20 djm 2211: (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 ||
2212: (ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 ||
2213: (ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */
1.1 djm 2214: (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0)
2215: goto out;
2216:
2217: /* Sign the whole mess */
1.53 djm 2218: if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
1.111 djm 2219: sshbuf_len(cert), alg, sk_provider, sk_pin, 0, signer_ctx)) != 0)
1.1 djm 2220: goto out;
1.67 djm 2221: /* Check and update signature_type against what was actually used */
1.82 djm 2222: if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
1.67 djm 2223: goto out;
2224: if (alg != NULL && strcmp(alg, sigtype) != 0) {
2225: ret = SSH_ERR_SIGN_ALG_UNSUPPORTED;
2226: goto out;
2227: }
2228: if (k->cert->signature_type == NULL) {
2229: k->cert->signature_type = sigtype;
2230: sigtype = NULL;
2231: }
1.1 djm 2232: /* Append signature and we are done */
2233: if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
2234: goto out;
2235: ret = 0;
2236: out:
2237: if (ret != 0)
2238: sshbuf_reset(cert);
1.29 mmcc 2239: free(sig_blob);
2240: free(ca_blob);
1.67 djm 2241: free(sigtype);
1.31 mmcc 2242: sshbuf_free(principals);
1.1 djm 2243: return ret;
1.53 djm 2244: }
2245:
2246: static int
1.76 djm 2247: default_key_sign(struct sshkey *key, u_char **sigp, size_t *lenp,
1.53 djm 2248: const u_char *data, size_t datalen,
1.111 djm 2249: const char *alg, const char *sk_provider, const char *sk_pin,
2250: u_int compat, void *ctx)
1.53 djm 2251: {
2252: if (ctx != NULL)
2253: return SSH_ERR_INVALID_ARGUMENT;
1.86 djm 2254: return sshkey_sign(key, sigp, lenp, data, datalen, alg,
1.111 djm 2255: sk_provider, sk_pin, compat);
1.53 djm 2256: }
2257:
2258: int
1.86 djm 2259: sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg,
1.111 djm 2260: const char *sk_provider, const char *sk_pin)
1.53 djm 2261: {
1.111 djm 2262: return sshkey_certify_custom(k, ca, alg, sk_provider, sk_pin,
1.86 djm 2263: default_key_sign, NULL);
1.1 djm 2264: }
2265:
2266: int
2267: sshkey_cert_check_authority(const struct sshkey *k,
1.114 djm 2268: int want_host, int require_principal, int wildcard_pattern,
1.119 djm 2269: uint64_t verify_time, const char *name, const char **reason)
1.1 djm 2270: {
2271: u_int i, principal_matches;
2272:
1.102 markus 2273: if (reason == NULL)
2274: return SSH_ERR_INVALID_ARGUMENT;
1.114 djm 2275: if (!sshkey_is_cert(k)) {
2276: *reason = "Key is not a certificate";
2277: return SSH_ERR_KEY_CERT_INVALID;
2278: }
1.1 djm 2279: if (want_host) {
2280: if (k->cert->type != SSH2_CERT_TYPE_HOST) {
2281: *reason = "Certificate invalid: not a host certificate";
2282: return SSH_ERR_KEY_CERT_INVALID;
2283: }
2284: } else {
2285: if (k->cert->type != SSH2_CERT_TYPE_USER) {
2286: *reason = "Certificate invalid: not a user certificate";
2287: return SSH_ERR_KEY_CERT_INVALID;
2288: }
2289: }
1.119 djm 2290: if (verify_time < k->cert->valid_after) {
1.1 djm 2291: *reason = "Certificate invalid: not yet valid";
2292: return SSH_ERR_KEY_CERT_INVALID;
2293: }
1.119 djm 2294: if (verify_time >= k->cert->valid_before) {
1.1 djm 2295: *reason = "Certificate invalid: expired";
2296: return SSH_ERR_KEY_CERT_INVALID;
2297: }
2298: if (k->cert->nprincipals == 0) {
2299: if (require_principal) {
2300: *reason = "Certificate lacks principal list";
2301: return SSH_ERR_KEY_CERT_INVALID;
2302: }
2303: } else if (name != NULL) {
2304: principal_matches = 0;
2305: for (i = 0; i < k->cert->nprincipals; i++) {
1.114 djm 2306: if (wildcard_pattern) {
2307: if (match_pattern(k->cert->principals[i],
2308: name)) {
2309: principal_matches = 1;
2310: break;
2311: }
2312: } else if (strcmp(name, k->cert->principals[i]) == 0) {
1.1 djm 2313: principal_matches = 1;
2314: break;
2315: }
2316: }
2317: if (!principal_matches) {
2318: *reason = "Certificate invalid: name is not a listed "
2319: "principal";
2320: return SSH_ERR_KEY_CERT_INVALID;
2321: }
1.114 djm 2322: }
2323: return 0;
2324: }
2325:
2326: int
1.119 djm 2327: sshkey_cert_check_authority_now(const struct sshkey *k,
2328: int want_host, int require_principal, int wildcard_pattern,
2329: const char *name, const char **reason)
2330: {
2331: time_t now;
2332:
2333: if ((now = time(NULL)) < 0) {
2334: /* yikes - system clock before epoch! */
2335: *reason = "Certificate invalid: not yet valid";
2336: return SSH_ERR_KEY_CERT_INVALID;
2337: }
2338: return sshkey_cert_check_authority(k, want_host, require_principal,
2339: wildcard_pattern, (uint64_t)now, name, reason);
2340: }
2341:
2342: int
1.114 djm 2343: sshkey_cert_check_host(const struct sshkey *key, const char *host,
2344: int wildcard_principals, const char *ca_sign_algorithms,
2345: const char **reason)
2346: {
2347: int r;
2348:
1.119 djm 2349: if ((r = sshkey_cert_check_authority_now(key, 1, 0, wildcard_principals,
1.114 djm 2350: host, reason)) != 0)
2351: return r;
2352: if (sshbuf_len(key->cert->critical) != 0) {
2353: *reason = "Certificate contains unsupported critical options";
2354: return SSH_ERR_KEY_CERT_INVALID;
2355: }
2356: if (ca_sign_algorithms != NULL &&
2357: (r = sshkey_check_cert_sigtype(key, ca_sign_algorithms)) != 0) {
2358: *reason = "Certificate signed with disallowed algorithm";
2359: return SSH_ERR_KEY_CERT_INVALID;
1.1 djm 2360: }
2361: return 0;
1.27 djm 2362: }
2363:
2364: size_t
2365: sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
2366: {
1.113 dtucker 2367: char from[32], to[32], ret[128];
1.27 djm 2368:
2369: *from = *to = '\0';
2370: if (cert->valid_after == 0 &&
2371: cert->valid_before == 0xffffffffffffffffULL)
2372: return strlcpy(s, "forever", l);
2373:
1.118 dtucker 2374: if (cert->valid_after != 0)
2375: format_absolute_time(cert->valid_after, from, sizeof(from));
2376: if (cert->valid_before != 0xffffffffffffffffULL)
2377: format_absolute_time(cert->valid_before, to, sizeof(to));
1.27 djm 2378:
2379: if (cert->valid_after == 0)
2380: snprintf(ret, sizeof(ret), "before %s", to);
2381: else if (cert->valid_before == 0xffffffffffffffffULL)
2382: snprintf(ret, sizeof(ret), "after %s", from);
2383: else
2384: snprintf(ret, sizeof(ret), "from %s to %s", from, to);
2385:
2386: return strlcpy(s, ret, l);
1.1 djm 2387: }
2388:
1.132 djm 2389: /* Common serialization for FIDO private keys */
2390: int
2391: sshkey_serialize_private_sk(const struct sshkey *key, struct sshbuf *b)
2392: {
2393: int r;
2394:
2395: if ((r = sshbuf_put_cstring(b, key->sk_application)) != 0 ||
2396: (r = sshbuf_put_u8(b, key->sk_flags)) != 0 ||
2397: (r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 ||
2398: (r = sshbuf_put_stringb(b, key->sk_reserved)) != 0)
2399: return r;
2400:
2401: return 0;
2402: }
2403:
1.1 djm 2404: int
1.76 djm 2405: sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf,
1.62 markus 2406: enum sshkey_serialize_rep opts)
1.1 djm 2407: {
2408: int r = SSH_ERR_INTERNAL_ERROR;
1.76 djm 2409: int was_shielded = sshkey_is_shielded(key);
2410: struct sshbuf *b = NULL;
1.132 djm 2411: const struct sshkey_impl *impl;
1.1 djm 2412:
1.132 djm 2413: if ((impl = sshkey_impl_from_key(key)) == NULL)
2414: return SSH_ERR_INTERNAL_ERROR;
1.76 djm 2415: if ((r = sshkey_unshield_private(key)) != 0)
2416: return r;
2417: if ((b = sshbuf_new()) == NULL)
2418: return SSH_ERR_ALLOC_FAIL;
1.1 djm 2419: if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0)
2420: goto out;
1.132 djm 2421: if (sshkey_is_cert(key)) {
2422: if (key->cert == NULL ||
2423: sshbuf_len(key->cert->certblob) == 0) {
1.1 djm 2424: r = SSH_ERR_INVALID_ARGUMENT;
2425: goto out;
2426: }
1.132 djm 2427: if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0)
1.1 djm 2428: goto out;
1.132 djm 2429: }
2430: if ((r = impl->funcs->serialize_private(key, b, opts)) != 0)
1.1 djm 2431: goto out;
1.132 djm 2432:
1.76 djm 2433: /*
2434: * success (but we still need to append the output to buf after
2435: * possibly re-shielding the private key)
2436: */
1.1 djm 2437: r = 0;
2438: out:
1.76 djm 2439: if (was_shielded)
2440: r = sshkey_shield_private(key);
2441: if (r == 0)
2442: r = sshbuf_putb(buf, b);
2443: sshbuf_free(b);
2444:
1.1 djm 2445: return r;
2446: }
2447:
2448: int
1.76 djm 2449: sshkey_private_serialize(struct sshkey *key, struct sshbuf *b)
1.62 markus 2450: {
2451: return sshkey_private_serialize_opt(key, b,
2452: SSHKEY_SERIALIZE_DEFAULT);
2453: }
2454:
1.133 djm 2455: /* Shared deserialization of FIDO private key components */
2456: int
2457: sshkey_private_deserialize_sk(struct sshbuf *buf, struct sshkey *k)
2458: {
2459: int r;
2460:
2461: if ((k->sk_key_handle = sshbuf_new()) == NULL ||
2462: (k->sk_reserved = sshbuf_new()) == NULL)
2463: return SSH_ERR_ALLOC_FAIL;
2464: if ((r = sshbuf_get_cstring(buf, &k->sk_application, NULL)) != 0 ||
2465: (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
2466: (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
2467: (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
2468: return r;
2469:
2470: return 0;
2471: }
2472:
1.62 markus 2473: int
1.1 djm 2474: sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2475: {
1.133 djm 2476: const struct sshkey_impl *impl;
2477: char *tname = NULL;
1.115 djm 2478: char *expect_sk_application = NULL;
1.133 djm 2479: u_char *expect_ed25519_pk = NULL;
1.1 djm 2480: struct sshkey *k = NULL;
2481: int type, r = SSH_ERR_INTERNAL_ERROR;
2482:
2483: if (kp != NULL)
2484: *kp = NULL;
2485: if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0)
2486: goto out;
2487: type = sshkey_type_from_name(tname);
1.108 djm 2488: if (sshkey_type_is_cert(type)) {
2489: /*
2490: * Certificate key private keys begin with the certificate
2491: * itself. Make sure this matches the type of the enclosing
2492: * private key.
2493: */
2494: if ((r = sshkey_froms(buf, &k)) != 0)
2495: goto out;
2496: if (k->type != type) {
2497: r = SSH_ERR_KEY_CERT_MISMATCH;
2498: goto out;
2499: }
2500: /* For ECDSA keys, the group must match too */
2501: if (k->type == KEY_ECDSA &&
2502: k->ecdsa_nid != sshkey_ecdsa_nid_from_name(tname)) {
2503: r = SSH_ERR_KEY_CERT_MISMATCH;
2504: goto out;
2505: }
1.115 djm 2506: /*
2507: * Several fields are redundant between certificate and
2508: * private key body, we require these to match.
2509: */
2510: expect_sk_application = k->sk_application;
2511: expect_ed25519_pk = k->ed25519_pk;
2512: k->sk_application = NULL;
2513: k->ed25519_pk = NULL;
1.133 djm 2514: /* XXX xmss too or refactor */
1.108 djm 2515: } else {
1.70 djm 2516: if ((k = sshkey_new(type)) == NULL) {
1.1 djm 2517: r = SSH_ERR_ALLOC_FAIL;
2518: goto out;
2519: }
1.108 djm 2520: }
1.133 djm 2521: if ((impl = sshkey_impl_from_type(type)) == NULL) {
2522: r = SSH_ERR_INTERNAL_ERROR;
1.1 djm 2523: goto out;
2524: }
1.133 djm 2525: if ((r = impl->funcs->deserialize_private(tname, buf, k)) != 0)
2526: goto out;
2527:
2528: /* XXX xmss too or refactor */
1.115 djm 2529: if ((expect_sk_application != NULL && (k->sk_application == NULL ||
2530: strcmp(expect_sk_application, k->sk_application) != 0)) ||
2531: (expect_ed25519_pk != NULL && (k->ed25519_pk == NULL ||
1.116 djm 2532: memcmp(expect_ed25519_pk, k->ed25519_pk, ED25519_PK_SZ) != 0))) {
1.115 djm 2533: r = SSH_ERR_KEY_CERT_MISMATCH;
2534: goto out;
2535: }
1.1 djm 2536: /* success */
2537: r = 0;
2538: if (kp != NULL) {
2539: *kp = k;
2540: k = NULL;
2541: }
2542: out:
2543: free(tname);
2544: sshkey_free(k);
1.115 djm 2545: free(expect_sk_application);
2546: free(expect_ed25519_pk);
1.1 djm 2547: return r;
2548: }
2549:
2550: #ifdef WITH_OPENSSL
2551: int
2552: sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
2553: {
2554: EC_POINT *nq = NULL;
1.93 djm 2555: BIGNUM *order = NULL, *x = NULL, *y = NULL, *tmp = NULL;
1.1 djm 2556: int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
1.40 djm 2557:
2558: /*
2559: * NB. This assumes OpenSSL has already verified that the public
2560: * point lies on the curve. This is done by EC_POINT_oct2point()
2561: * implicitly calling EC_POINT_is_on_curve(). If this code is ever
2562: * reachable with public points not unmarshalled using
2563: * EC_POINT_oct2point then the caller will need to explicitly check.
2564: */
1.1 djm 2565:
2566: /*
2567: * We shouldn't ever hit this case because bignum_get_ecpoint()
2568: * refuses to load GF2m points.
2569: */
2570: if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2571: NID_X9_62_prime_field)
2572: goto out;
2573:
2574: /* Q != infinity */
2575: if (EC_POINT_is_at_infinity(group, public))
2576: goto out;
2577:
1.93 djm 2578: if ((x = BN_new()) == NULL ||
2579: (y = BN_new()) == NULL ||
2580: (order = BN_new()) == NULL ||
2581: (tmp = BN_new()) == NULL) {
1.1 djm 2582: ret = SSH_ERR_ALLOC_FAIL;
2583: goto out;
2584: }
2585:
2586: /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
1.93 djm 2587: if (EC_GROUP_get_order(group, order, NULL) != 1 ||
1.1 djm 2588: EC_POINT_get_affine_coordinates_GFp(group, public,
1.93 djm 2589: x, y, NULL) != 1) {
1.1 djm 2590: ret = SSH_ERR_LIBCRYPTO_ERROR;
2591: goto out;
2592: }
2593: if (BN_num_bits(x) <= BN_num_bits(order) / 2 ||
2594: BN_num_bits(y) <= BN_num_bits(order) / 2)
2595: goto out;
2596:
2597: /* nQ == infinity (n == order of subgroup) */
2598: if ((nq = EC_POINT_new(group)) == NULL) {
2599: ret = SSH_ERR_ALLOC_FAIL;
2600: goto out;
2601: }
1.93 djm 2602: if (EC_POINT_mul(group, nq, NULL, public, order, NULL) != 1) {
1.1 djm 2603: ret = SSH_ERR_LIBCRYPTO_ERROR;
2604: goto out;
2605: }
2606: if (EC_POINT_is_at_infinity(group, nq) != 1)
2607: goto out;
2608:
2609: /* x < order - 1, y < order - 1 */
2610: if (!BN_sub(tmp, order, BN_value_one())) {
2611: ret = SSH_ERR_LIBCRYPTO_ERROR;
2612: goto out;
2613: }
2614: if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0)
2615: goto out;
2616: ret = 0;
2617: out:
1.93 djm 2618: BN_clear_free(x);
2619: BN_clear_free(y);
2620: BN_clear_free(order);
2621: BN_clear_free(tmp);
1.60 jsing 2622: EC_POINT_free(nq);
1.1 djm 2623: return ret;
2624: }
2625:
2626: int
2627: sshkey_ec_validate_private(const EC_KEY *key)
2628: {
1.93 djm 2629: BIGNUM *order = NULL, *tmp = NULL;
1.1 djm 2630: int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2631:
1.93 djm 2632: if ((order = BN_new()) == NULL || (tmp = BN_new()) == NULL) {
1.1 djm 2633: ret = SSH_ERR_ALLOC_FAIL;
2634: goto out;
2635: }
2636:
2637: /* log2(private) > log2(order)/2 */
1.93 djm 2638: if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, NULL) != 1) {
1.1 djm 2639: ret = SSH_ERR_LIBCRYPTO_ERROR;
2640: goto out;
2641: }
2642: if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
2643: BN_num_bits(order) / 2)
2644: goto out;
2645:
2646: /* private < order - 1 */
2647: if (!BN_sub(tmp, order, BN_value_one())) {
2648: ret = SSH_ERR_LIBCRYPTO_ERROR;
2649: goto out;
2650: }
2651: if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0)
2652: goto out;
2653: ret = 0;
2654: out:
1.93 djm 2655: BN_clear_free(order);
2656: BN_clear_free(tmp);
1.1 djm 2657: return ret;
2658: }
2659:
2660: void
2661: sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
2662: {
1.93 djm 2663: BIGNUM *x = NULL, *y = NULL;
1.1 djm 2664:
2665: if (point == NULL) {
2666: fputs("point=(NULL)\n", stderr);
2667: return;
2668: }
1.93 djm 2669: if ((x = BN_new()) == NULL || (y = BN_new()) == NULL) {
2670: fprintf(stderr, "%s: BN_new failed\n", __func__);
2671: goto out;
1.1 djm 2672: }
2673: if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2674: NID_X9_62_prime_field) {
2675: fprintf(stderr, "%s: group is not a prime field\n", __func__);
1.93 djm 2676: goto out;
1.1 djm 2677: }
1.93 djm 2678: if (EC_POINT_get_affine_coordinates_GFp(group, point,
2679: x, y, NULL) != 1) {
1.1 djm 2680: fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n",
2681: __func__);
1.93 djm 2682: goto out;
1.1 djm 2683: }
2684: fputs("x=", stderr);
2685: BN_print_fp(stderr, x);
2686: fputs("\ny=", stderr);
2687: BN_print_fp(stderr, y);
2688: fputs("\n", stderr);
1.93 djm 2689: out:
2690: BN_clear_free(x);
2691: BN_clear_free(y);
1.1 djm 2692: }
2693:
2694: void
2695: sshkey_dump_ec_key(const EC_KEY *key)
2696: {
2697: const BIGNUM *exponent;
2698:
2699: sshkey_dump_ec_point(EC_KEY_get0_group(key),
2700: EC_KEY_get0_public_key(key));
2701: fputs("exponent=", stderr);
2702: if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
2703: fputs("(NULL)", stderr);
2704: else
2705: BN_print_fp(stderr, EC_KEY_get0_private_key(key));
2706: fputs("\n", stderr);
2707: }
2708: #endif /* WITH_OPENSSL */
2709:
2710: static int
1.76 djm 2711: sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob,
1.1 djm 2712: const char *passphrase, const char *comment, const char *ciphername,
2713: int rounds)
2714: {
1.4 djm 2715: u_char *cp, *key = NULL, *pubkeyblob = NULL;
1.1 djm 2716: u_char salt[SALT_LEN];
2717: size_t i, pubkeylen, keylen, ivlen, blocksize, authlen;
2718: u_int check;
2719: int r = SSH_ERR_INTERNAL_ERROR;
1.36 djm 2720: struct sshcipher_ctx *ciphercontext = NULL;
1.1 djm 2721: const struct sshcipher *cipher;
2722: const char *kdfname = KDFNAME;
2723: struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL;
2724:
2725: if (rounds <= 0)
2726: rounds = DEFAULT_ROUNDS;
2727: if (passphrase == NULL || !strlen(passphrase)) {
2728: ciphername = "none";
2729: kdfname = "none";
2730: } else if (ciphername == NULL)
2731: ciphername = DEFAULT_CIPHERNAME;
1.47 djm 2732: if ((cipher = cipher_by_name(ciphername)) == NULL) {
1.1 djm 2733: r = SSH_ERR_INVALID_ARGUMENT;
2734: goto out;
2735: }
2736:
2737: if ((kdf = sshbuf_new()) == NULL ||
2738: (encoded = sshbuf_new()) == NULL ||
2739: (encrypted = sshbuf_new()) == NULL) {
2740: r = SSH_ERR_ALLOC_FAIL;
2741: goto out;
2742: }
2743: blocksize = cipher_blocksize(cipher);
2744: keylen = cipher_keylen(cipher);
2745: ivlen = cipher_ivlen(cipher);
2746: authlen = cipher_authlen(cipher);
2747: if ((key = calloc(1, keylen + ivlen)) == NULL) {
2748: r = SSH_ERR_ALLOC_FAIL;
2749: goto out;
2750: }
2751: if (strcmp(kdfname, "bcrypt") == 0) {
2752: arc4random_buf(salt, SALT_LEN);
2753: if (bcrypt_pbkdf(passphrase, strlen(passphrase),
2754: salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) {
2755: r = SSH_ERR_INVALID_ARGUMENT;
2756: goto out;
2757: }
2758: if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 ||
2759: (r = sshbuf_put_u32(kdf, rounds)) != 0)
2760: goto out;
2761: } else if (strcmp(kdfname, "none") != 0) {
2762: /* Unsupported KDF type */
2763: r = SSH_ERR_KEY_UNKNOWN_CIPHER;
2764: goto out;
2765: }
2766: if ((r = cipher_init(&ciphercontext, cipher, key, keylen,
2767: key + keylen, ivlen, 1)) != 0)
2768: goto out;
2769:
2770: if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 ||
2771: (r = sshbuf_put_cstring(encoded, ciphername)) != 0 ||
2772: (r = sshbuf_put_cstring(encoded, kdfname)) != 0 ||
2773: (r = sshbuf_put_stringb(encoded, kdf)) != 0 ||
2774: (r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */
2775: (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 ||
2776: (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0)
2777: goto out;
2778:
2779: /* set up the buffer that will be encrypted */
2780:
2781: /* Random check bytes */
2782: check = arc4random();
2783: if ((r = sshbuf_put_u32(encrypted, check)) != 0 ||
2784: (r = sshbuf_put_u32(encrypted, check)) != 0)
2785: goto out;
2786:
2787: /* append private key and comment*/
1.62 markus 2788: if ((r = sshkey_private_serialize_opt(prv, encrypted,
1.116 djm 2789: SSHKEY_SERIALIZE_FULL)) != 0 ||
1.1 djm 2790: (r = sshbuf_put_cstring(encrypted, comment)) != 0)
2791: goto out;
2792:
2793: /* padding */
2794: i = 0;
2795: while (sshbuf_len(encrypted) % blocksize) {
2796: if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0)
2797: goto out;
2798: }
2799:
2800: /* length in destination buffer */
2801: if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0)
2802: goto out;
2803:
2804: /* encrypt */
2805: if ((r = sshbuf_reserve(encoded,
2806: sshbuf_len(encrypted) + authlen, &cp)) != 0)
2807: goto out;
1.36 djm 2808: if ((r = cipher_crypt(ciphercontext, 0, cp,
1.1 djm 2809: sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0)
2810: goto out;
2811:
1.81 djm 2812: sshbuf_reset(blob);
1.1 djm 2813:
1.81 djm 2814: /* assemble uuencoded key */
2815: if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0 ||
2816: (r = sshbuf_dtob64(encoded, blob, 1)) != 0 ||
2817: (r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0)
1.1 djm 2818: goto out;
2819:
2820: /* success */
2821: r = 0;
2822:
2823: out:
2824: sshbuf_free(kdf);
2825: sshbuf_free(encoded);
2826: sshbuf_free(encrypted);
1.36 djm 2827: cipher_free(ciphercontext);
1.1 djm 2828: explicit_bzero(salt, sizeof(salt));
1.100 jsg 2829: if (key != NULL)
2830: freezero(key, keylen + ivlen);
1.121 djm 2831: if (pubkeyblob != NULL)
1.100 jsg 2832: freezero(pubkeyblob, pubkeylen);
1.1 djm 2833: return r;
2834: }
2835:
2836: static int
1.103 djm 2837: private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp)
1.1 djm 2838: {
2839: const u_char *cp;
2840: size_t encoded_len;
1.103 djm 2841: int r;
2842: u_char last;
1.1 djm 2843: struct sshbuf *encoded = NULL, *decoded = NULL;
2844:
1.103 djm 2845: if (blob == NULL || decodedp == NULL)
2846: return SSH_ERR_INVALID_ARGUMENT;
2847:
2848: *decodedp = NULL;
1.1 djm 2849:
2850: if ((encoded = sshbuf_new()) == NULL ||
1.103 djm 2851: (decoded = sshbuf_new()) == NULL) {
1.1 djm 2852: r = SSH_ERR_ALLOC_FAIL;
2853: goto out;
2854: }
2855:
2856: /* check preamble */
2857: cp = sshbuf_ptr(blob);
2858: encoded_len = sshbuf_len(blob);
2859: if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) ||
2860: memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) {
2861: r = SSH_ERR_INVALID_FORMAT;
2862: goto out;
2863: }
2864: cp += MARK_BEGIN_LEN;
2865: encoded_len -= MARK_BEGIN_LEN;
2866:
2867: /* Look for end marker, removing whitespace as we go */
2868: while (encoded_len > 0) {
2869: if (*cp != '\n' && *cp != '\r') {
2870: if ((r = sshbuf_put_u8(encoded, *cp)) != 0)
2871: goto out;
2872: }
2873: last = *cp;
2874: encoded_len--;
2875: cp++;
2876: if (last == '\n') {
2877: if (encoded_len >= MARK_END_LEN &&
2878: memcmp(cp, MARK_END, MARK_END_LEN) == 0) {
2879: /* \0 terminate */
2880: if ((r = sshbuf_put_u8(encoded, 0)) != 0)
2881: goto out;
2882: break;
2883: }
2884: }
2885: }
2886: if (encoded_len == 0) {
2887: r = SSH_ERR_INVALID_FORMAT;
2888: goto out;
2889: }
2890:
2891: /* decode base64 */
1.4 djm 2892: if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0)
1.1 djm 2893: goto out;
2894:
2895: /* check magic */
2896: if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) ||
2897: memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
2898: r = SSH_ERR_INVALID_FORMAT;
2899: goto out;
2900: }
1.103 djm 2901: /* success */
2902: *decodedp = decoded;
2903: decoded = NULL;
2904: r = 0;
2905: out:
2906: sshbuf_free(encoded);
2907: sshbuf_free(decoded);
2908: return r;
2909: }
2910:
2911: static int
1.104 djm 2912: private2_decrypt(struct sshbuf *decoded, const char *passphrase,
2913: struct sshbuf **decryptedp, struct sshkey **pubkeyp)
1.103 djm 2914: {
2915: char *ciphername = NULL, *kdfname = NULL;
2916: const struct sshcipher *cipher = NULL;
2917: int r = SSH_ERR_INTERNAL_ERROR;
2918: size_t keylen = 0, ivlen = 0, authlen = 0, slen = 0;
2919: struct sshbuf *kdf = NULL, *decrypted = NULL;
2920: struct sshcipher_ctx *ciphercontext = NULL;
1.104 djm 2921: struct sshkey *pubkey = NULL;
1.103 djm 2922: u_char *key = NULL, *salt = NULL, *dp;
2923: u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
2924:
1.104 djm 2925: if (decoded == NULL || decryptedp == NULL || pubkeyp == NULL)
1.103 djm 2926: return SSH_ERR_INVALID_ARGUMENT;
2927:
2928: *decryptedp = NULL;
1.104 djm 2929: *pubkeyp = NULL;
1.103 djm 2930:
2931: if ((decrypted = sshbuf_new()) == NULL) {
2932: r = SSH_ERR_ALLOC_FAIL;
2933: goto out;
2934: }
2935:
1.1 djm 2936: /* parse public portion of key */
2937: if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
2938: (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
2939: (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
2940: (r = sshbuf_froms(decoded, &kdf)) != 0 ||
1.103 djm 2941: (r = sshbuf_get_u32(decoded, &nkeys)) != 0)
2942: goto out;
2943:
2944: if (nkeys != 1) {
2945: /* XXX only one key supported at present */
2946: r = SSH_ERR_INVALID_FORMAT;
2947: goto out;
2948: }
2949:
1.104 djm 2950: if ((r = sshkey_froms(decoded, &pubkey)) != 0 ||
1.1 djm 2951: (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
2952: goto out;
2953:
2954: if ((cipher = cipher_by_name(ciphername)) == NULL) {
2955: r = SSH_ERR_KEY_UNKNOWN_CIPHER;
2956: goto out;
2957: }
2958: if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
2959: r = SSH_ERR_KEY_UNKNOWN_CIPHER;
2960: goto out;
2961: }
1.101 markus 2962: if (strcmp(kdfname, "none") == 0 && strcmp(ciphername, "none") != 0) {
1.1 djm 2963: r = SSH_ERR_INVALID_FORMAT;
1.101 markus 2964: goto out;
2965: }
2966: if ((passphrase == NULL || strlen(passphrase) == 0) &&
2967: strcmp(kdfname, "none") != 0) {
2968: /* passphrase required */
2969: r = SSH_ERR_KEY_WRONG_PASSPHRASE;
1.1 djm 2970: goto out;
2971: }
2972:
2973: /* check size of encrypted key blob */
2974: blocksize = cipher_blocksize(cipher);
2975: if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
2976: r = SSH_ERR_INVALID_FORMAT;
2977: goto out;
2978: }
2979:
2980: /* setup key */
2981: keylen = cipher_keylen(cipher);
2982: ivlen = cipher_ivlen(cipher);
1.18 djm 2983: authlen = cipher_authlen(cipher);
1.1 djm 2984: if ((key = calloc(1, keylen + ivlen)) == NULL) {
2985: r = SSH_ERR_ALLOC_FAIL;
2986: goto out;
2987: }
2988: if (strcmp(kdfname, "bcrypt") == 0) {
2989: if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
2990: (r = sshbuf_get_u32(kdf, &rounds)) != 0)
2991: goto out;
2992: if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
2993: key, keylen + ivlen, rounds) < 0) {
2994: r = SSH_ERR_INVALID_FORMAT;
2995: goto out;
2996: }
2997: }
2998:
1.18 djm 2999: /* check that an appropriate amount of auth data is present */
1.84 djm 3000: if (sshbuf_len(decoded) < authlen ||
3001: sshbuf_len(decoded) - authlen < encrypted_len) {
1.18 djm 3002: r = SSH_ERR_INVALID_FORMAT;
3003: goto out;
3004: }
3005:
1.1 djm 3006: /* decrypt private portion of key */
3007: if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 ||
3008: (r = cipher_init(&ciphercontext, cipher, key, keylen,
3009: key + keylen, ivlen, 0)) != 0)
3010: goto out;
1.36 djm 3011: if ((r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(decoded),
1.18 djm 3012: encrypted_len, 0, authlen)) != 0) {
1.1 djm 3013: /* an integrity error here indicates an incorrect passphrase */
3014: if (r == SSH_ERR_MAC_INVALID)
3015: r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3016: goto out;
3017: }
1.18 djm 3018: if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0)
1.1 djm 3019: goto out;
3020: /* there should be no trailing data */
3021: if (sshbuf_len(decoded) != 0) {
3022: r = SSH_ERR_INVALID_FORMAT;
3023: goto out;
3024: }
3025:
3026: /* check check bytes */
3027: if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 ||
3028: (r = sshbuf_get_u32(decrypted, &check2)) != 0)
3029: goto out;
3030: if (check1 != check2) {
3031: r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3032: goto out;
3033: }
1.103 djm 3034: /* success */
3035: *decryptedp = decrypted;
3036: decrypted = NULL;
1.104 djm 3037: *pubkeyp = pubkey;
3038: pubkey = NULL;
1.103 djm 3039: r = 0;
3040: out:
3041: cipher_free(ciphercontext);
3042: free(ciphername);
3043: free(kdfname);
1.104 djm 3044: sshkey_free(pubkey);
1.103 djm 3045: if (salt != NULL) {
3046: explicit_bzero(salt, slen);
3047: free(salt);
3048: }
3049: if (key != NULL) {
3050: explicit_bzero(key, keylen + ivlen);
3051: free(key);
3052: }
3053: sshbuf_free(kdf);
3054: sshbuf_free(decrypted);
3055: return r;
3056: }
3057:
3058: static int
3059: sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
3060: struct sshkey **keyp, char **commentp)
3061: {
3062: char *comment = NULL;
3063: int r = SSH_ERR_INTERNAL_ERROR;
3064: struct sshbuf *decoded = NULL, *decrypted = NULL;
1.104 djm 3065: struct sshkey *k = NULL, *pubkey = NULL;
1.103 djm 3066:
3067: if (keyp != NULL)
3068: *keyp = NULL;
3069: if (commentp != NULL)
3070: *commentp = NULL;
3071:
3072: /* Undo base64 encoding and decrypt the private section */
3073: if ((r = private2_uudecode(blob, &decoded)) != 0 ||
1.104 djm 3074: (r = private2_decrypt(decoded, passphrase,
3075: &decrypted, &pubkey)) != 0)
1.103 djm 3076: goto out;
1.105 djm 3077:
3078: if (type != KEY_UNSPEC &&
3079: sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) {
3080: r = SSH_ERR_KEY_TYPE_MISMATCH;
3081: goto out;
3082: }
1.103 djm 3083:
3084: /* Load the private key and comment */
3085: if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
3086: (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
3087: goto out;
3088:
3089: /* Check deterministic padding after private section */
3090: if ((r = private2_check_padding(decrypted)) != 0)
3091: goto out;
1.1 djm 3092:
1.104 djm 3093: /* Check that the public key in the envelope matches the private key */
3094: if (!sshkey_equal(pubkey, k)) {
3095: r = SSH_ERR_INVALID_FORMAT;
3096: goto out;
3097: }
1.1 djm 3098:
3099: /* success */
3100: r = 0;
3101: if (keyp != NULL) {
3102: *keyp = k;
3103: k = NULL;
3104: }
3105: if (commentp != NULL) {
3106: *commentp = comment;
3107: comment = NULL;
3108: }
3109: out:
3110: free(comment);
3111: sshbuf_free(decoded);
3112: sshbuf_free(decrypted);
3113: sshkey_free(k);
1.104 djm 3114: sshkey_free(pubkey);
1.1 djm 3115: return r;
3116: }
3117:
1.107 djm 3118: static int
3119: sshkey_parse_private2_pubkey(struct sshbuf *blob, int type,
3120: struct sshkey **keyp)
3121: {
3122: int r = SSH_ERR_INTERNAL_ERROR;
3123: struct sshbuf *decoded = NULL;
3124: struct sshkey *pubkey = NULL;
3125: u_int nkeys = 0;
3126:
3127: if (keyp != NULL)
3128: *keyp = NULL;
3129:
3130: if ((r = private2_uudecode(blob, &decoded)) != 0)
3131: goto out;
3132: /* parse public key from unencrypted envelope */
3133: if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
3134: (r = sshbuf_skip_string(decoded)) != 0 || /* cipher */
3135: (r = sshbuf_skip_string(decoded)) != 0 || /* KDF alg */
3136: (r = sshbuf_skip_string(decoded)) != 0 || /* KDF hint */
3137: (r = sshbuf_get_u32(decoded, &nkeys)) != 0)
3138: goto out;
3139:
3140: if (nkeys != 1) {
3141: /* XXX only one key supported at present */
3142: r = SSH_ERR_INVALID_FORMAT;
3143: goto out;
3144: }
3145:
3146: /* Parse the public key */
3147: if ((r = sshkey_froms(decoded, &pubkey)) != 0)
3148: goto out;
3149:
3150: if (type != KEY_UNSPEC &&
3151: sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) {
3152: r = SSH_ERR_KEY_TYPE_MISMATCH;
3153: goto out;
3154: }
3155:
3156: /* success */
3157: r = 0;
3158: if (keyp != NULL) {
3159: *keyp = pubkey;
3160: pubkey = NULL;
3161: }
3162: out:
3163: sshbuf_free(decoded);
3164: sshkey_free(pubkey);
3165: return r;
3166: }
3167:
1.1 djm 3168: #ifdef WITH_OPENSSL
1.80 djm 3169: /* convert SSH v2 key to PEM or PKCS#8 format */
1.1 djm 3170: static int
1.80 djm 3171: sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf,
3172: int format, const char *_passphrase, const char *comment)
1.1 djm 3173: {
1.76 djm 3174: int was_shielded = sshkey_is_shielded(key);
1.1 djm 3175: int success, r;
3176: int blen, len = strlen(_passphrase);
3177: u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
3178: const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
1.57 djm 3179: char *bptr;
1.1 djm 3180: BIO *bio = NULL;
1.76 djm 3181: struct sshbuf *blob;
1.80 djm 3182: EVP_PKEY *pkey = NULL;
1.1 djm 3183:
3184: if (len > 0 && len <= 4)
3185: return SSH_ERR_PASSPHRASE_TOO_SHORT;
1.76 djm 3186: if ((blob = sshbuf_new()) == NULL)
1.1 djm 3187: return SSH_ERR_ALLOC_FAIL;
1.76 djm 3188: if ((bio = BIO_new(BIO_s_mem())) == NULL) {
1.80 djm 3189: r = SSH_ERR_ALLOC_FAIL;
3190: goto out;
3191: }
3192: if (format == SSHKEY_PRIVATE_PKCS8 && (pkey = EVP_PKEY_new()) == NULL) {
3193: r = SSH_ERR_ALLOC_FAIL;
3194: goto out;
1.76 djm 3195: }
3196: if ((r = sshkey_unshield_private(key)) != 0)
3197: goto out;
1.1 djm 3198:
3199: switch (key->type) {
3200: case KEY_DSA:
1.80 djm 3201: if (format == SSHKEY_PRIVATE_PEM) {
3202: success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
3203: cipher, passphrase, len, NULL, NULL);
3204: } else {
3205: success = EVP_PKEY_set1_DSA(pkey, key->dsa);
3206: }
1.1 djm 3207: break;
3208: case KEY_ECDSA:
1.80 djm 3209: if (format == SSHKEY_PRIVATE_PEM) {
3210: success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
3211: cipher, passphrase, len, NULL, NULL);
3212: } else {
3213: success = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
3214: }
1.1 djm 3215: break;
3216: case KEY_RSA:
1.80 djm 3217: if (format == SSHKEY_PRIVATE_PEM) {
3218: success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
3219: cipher, passphrase, len, NULL, NULL);
3220: } else {
3221: success = EVP_PKEY_set1_RSA(pkey, key->rsa);
3222: }
1.1 djm 3223: break;
3224: default:
3225: success = 0;
3226: break;
3227: }
3228: if (success == 0) {
3229: r = SSH_ERR_LIBCRYPTO_ERROR;
3230: goto out;
3231: }
1.80 djm 3232: if (format == SSHKEY_PRIVATE_PKCS8) {
3233: if ((success = PEM_write_bio_PrivateKey(bio, pkey, cipher,
3234: passphrase, len, NULL, NULL)) == 0) {
3235: r = SSH_ERR_LIBCRYPTO_ERROR;
3236: goto out;
3237: }
3238: }
1.1 djm 3239: if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) {
3240: r = SSH_ERR_INTERNAL_ERROR;
3241: goto out;
3242: }
3243: if ((r = sshbuf_put(blob, bptr, blen)) != 0)
3244: goto out;
3245: r = 0;
3246: out:
1.76 djm 3247: if (was_shielded)
3248: r = sshkey_shield_private(key);
3249: if (r == 0)
3250: r = sshbuf_putb(buf, blob);
1.80 djm 3251:
3252: EVP_PKEY_free(pkey);
1.76 djm 3253: sshbuf_free(blob);
1.1 djm 3254: BIO_free(bio);
3255: return r;
3256: }
3257: #endif /* WITH_OPENSSL */
3258:
3259: /* Serialise "key" to buffer "blob" */
3260: int
3261: sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
3262: const char *passphrase, const char *comment,
1.80 djm 3263: int format, const char *openssh_format_cipher, int openssh_format_rounds)
1.1 djm 3264: {
3265: switch (key->type) {
1.9 markus 3266: #ifdef WITH_OPENSSL
1.1 djm 3267: case KEY_DSA:
3268: case KEY_ECDSA:
3269: case KEY_RSA:
1.80 djm 3270: break; /* see below */
1.1 djm 3271: #endif /* WITH_OPENSSL */
3272: case KEY_ED25519:
1.90 markus 3273: case KEY_ED25519_SK:
1.62 markus 3274: #ifdef WITH_XMSS
3275: case KEY_XMSS:
3276: #endif /* WITH_XMSS */
1.85 djm 3277: #ifdef WITH_OPENSSL
3278: case KEY_ECDSA_SK:
3279: #endif /* WITH_OPENSSL */
1.1 djm 3280: return sshkey_private_to_blob2(key, blob, passphrase,
1.80 djm 3281: comment, openssh_format_cipher, openssh_format_rounds);
1.1 djm 3282: default:
3283: return SSH_ERR_KEY_TYPE_UNKNOWN;
3284: }
1.80 djm 3285:
3286: #ifdef WITH_OPENSSL
3287: switch (format) {
3288: case SSHKEY_PRIVATE_OPENSSH:
3289: return sshkey_private_to_blob2(key, blob, passphrase,
3290: comment, openssh_format_cipher, openssh_format_rounds);
3291: case SSHKEY_PRIVATE_PEM:
3292: case SSHKEY_PRIVATE_PKCS8:
3293: return sshkey_private_to_blob_pem_pkcs8(key, blob,
3294: format, passphrase, comment);
3295: default:
3296: return SSH_ERR_INVALID_ARGUMENT;
3297: }
3298: #endif /* WITH_OPENSSL */
1.1 djm 3299: }
3300:
3301: #ifdef WITH_OPENSSL
1.8 djm 3302: static int
1.52 djm 3303: translate_libcrypto_error(unsigned long pem_err)
3304: {
3305: int pem_reason = ERR_GET_REASON(pem_err);
3306:
3307: switch (ERR_GET_LIB(pem_err)) {
3308: case ERR_LIB_PEM:
3309: switch (pem_reason) {
3310: case PEM_R_BAD_PASSWORD_READ:
3311: case PEM_R_PROBLEMS_GETTING_PASSWORD:
3312: case PEM_R_BAD_DECRYPT:
3313: return SSH_ERR_KEY_WRONG_PASSPHRASE;
3314: default:
3315: return SSH_ERR_INVALID_FORMAT;
3316: }
3317: case ERR_LIB_EVP:
3318: switch (pem_reason) {
3319: case EVP_R_BAD_DECRYPT:
3320: return SSH_ERR_KEY_WRONG_PASSPHRASE;
1.69 djm 3321: #ifdef EVP_R_BN_DECODE_ERROR
1.52 djm 3322: case EVP_R_BN_DECODE_ERROR:
1.69 djm 3323: #endif
1.52 djm 3324: case EVP_R_DECODE_ERROR:
3325: #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
3326: case EVP_R_PRIVATE_KEY_DECODE_ERROR:
3327: #endif
3328: return SSH_ERR_INVALID_FORMAT;
3329: default:
3330: return SSH_ERR_LIBCRYPTO_ERROR;
3331: }
3332: case ERR_LIB_ASN1:
3333: return SSH_ERR_INVALID_FORMAT;
3334: }
3335: return SSH_ERR_LIBCRYPTO_ERROR;
3336: }
3337:
3338: static void
3339: clear_libcrypto_errors(void)
3340: {
3341: while (ERR_get_error() != 0)
3342: ;
3343: }
3344:
3345: /*
3346: * Translate OpenSSL error codes to determine whether
3347: * passphrase is required/incorrect.
3348: */
3349: static int
3350: convert_libcrypto_error(void)
3351: {
3352: /*
3353: * Some password errors are reported at the beginning
3354: * of the error queue.
3355: */
3356: if (translate_libcrypto_error(ERR_peek_error()) ==
3357: SSH_ERR_KEY_WRONG_PASSPHRASE)
3358: return SSH_ERR_KEY_WRONG_PASSPHRASE;
3359: return translate_libcrypto_error(ERR_peek_last_error());
3360: }
3361:
3362: static int
1.1 djm 3363: sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
1.8 djm 3364: const char *passphrase, struct sshkey **keyp)
1.1 djm 3365: {
3366: EVP_PKEY *pk = NULL;
3367: struct sshkey *prv = NULL;
3368: BIO *bio = NULL;
3369: int r;
3370:
1.32 djm 3371: if (keyp != NULL)
3372: *keyp = NULL;
1.1 djm 3373:
3374: if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
3375: return SSH_ERR_ALLOC_FAIL;
3376: if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) !=
3377: (int)sshbuf_len(blob)) {
3378: r = SSH_ERR_ALLOC_FAIL;
3379: goto out;
3380: }
3381:
1.52 djm 3382: clear_libcrypto_errors();
1.1 djm 3383: if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL,
3384: (char *)passphrase)) == NULL) {
1.116 djm 3385: /*
3386: * libcrypto may return various ASN.1 errors when attempting
3387: * to parse a key with an incorrect passphrase.
3388: * Treat all format errors as "incorrect passphrase" if a
3389: * passphrase was supplied.
3390: */
1.71 djm 3391: if (passphrase != NULL && *passphrase != '\0')
3392: r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3393: else
3394: r = convert_libcrypto_error();
1.1 djm 3395: goto out;
3396: }
1.69 djm 3397: if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA &&
1.1 djm 3398: (type == KEY_UNSPEC || type == KEY_RSA)) {
3399: if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3400: r = SSH_ERR_ALLOC_FAIL;
3401: goto out;
3402: }
3403: prv->rsa = EVP_PKEY_get1_RSA(pk);
3404: prv->type = KEY_RSA;
3405: #ifdef DEBUG_PK
3406: RSA_print_fp(stderr, prv->rsa, 8);
3407: #endif
3408: if (RSA_blinding_on(prv->rsa, NULL) != 1) {
3409: r = SSH_ERR_LIBCRYPTO_ERROR;
1.49 djm 3410: goto out;
3411: }
1.122 djm 3412: if ((r = sshkey_check_rsa_length(prv, 0)) != 0)
1.1 djm 3413: goto out;
1.69 djm 3414: } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA &&
1.1 djm 3415: (type == KEY_UNSPEC || type == KEY_DSA)) {
3416: if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3417: r = SSH_ERR_ALLOC_FAIL;
3418: goto out;
3419: }
3420: prv->dsa = EVP_PKEY_get1_DSA(pk);
3421: prv->type = KEY_DSA;
3422: #ifdef DEBUG_PK
3423: DSA_print_fp(stderr, prv->dsa, 8);
3424: #endif
1.69 djm 3425: } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_EC &&
1.1 djm 3426: (type == KEY_UNSPEC || type == KEY_ECDSA)) {
3427: if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3428: r = SSH_ERR_ALLOC_FAIL;
3429: goto out;
3430: }
3431: prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
3432: prv->type = KEY_ECDSA;
3433: prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
3434: if (prv->ecdsa_nid == -1 ||
3435: sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
3436: sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
3437: EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
3438: sshkey_ec_validate_private(prv->ecdsa) != 0) {
3439: r = SSH_ERR_INVALID_FORMAT;
3440: goto out;
3441: }
3442: #ifdef DEBUG_PK
3443: if (prv != NULL && prv->ecdsa != NULL)
3444: sshkey_dump_ec_key(prv->ecdsa);
3445: #endif
1.139 djm 3446: } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_ED25519 &&
3447: (type == KEY_UNSPEC || type == KEY_ED25519)) {
1.140 dtucker 3448: size_t len;
3449:
1.139 djm 3450: if ((prv = sshkey_new(KEY_UNSPEC)) == NULL ||
3451: (prv->ed25519_sk = calloc(1, ED25519_SK_SZ)) == NULL ||
3452: (prv->ed25519_pk = calloc(1, ED25519_PK_SZ)) == NULL) {
3453: r = SSH_ERR_ALLOC_FAIL;
3454: goto out;
3455: }
3456: prv->type = KEY_ED25519;
3457: len = ED25519_PK_SZ;
3458: if (!EVP_PKEY_get_raw_public_key(pk, prv->ed25519_pk, &len)) {
3459: r = SSH_ERR_LIBCRYPTO_ERROR;
3460: goto out;
3461: }
3462: if (len != ED25519_PK_SZ) {
3463: r = SSH_ERR_INVALID_FORMAT;
3464: goto out;
3465: }
3466: len = ED25519_SK_SZ - ED25519_PK_SZ;
3467: if (!EVP_PKEY_get_raw_private_key(pk, prv->ed25519_sk, &len)) {
3468: r = SSH_ERR_LIBCRYPTO_ERROR;
3469: goto out;
3470: }
3471: if (len != ED25519_SK_SZ - ED25519_PK_SZ) {
3472: r = SSH_ERR_INVALID_FORMAT;
3473: goto out;
3474: }
3475: /* Append the public key to our private key */
3476: memcpy(prv->ed25519_sk + (ED25519_SK_SZ - ED25519_PK_SZ),
3477: prv->ed25519_pk, ED25519_PK_SZ);
3478: #ifdef DEBUG_PK
3479: sshbuf_dump_data(prv->ed25519_sk, ED25519_SK_SZ, stderr);
3480: #endif
1.1 djm 3481: } else {
3482: r = SSH_ERR_INVALID_FORMAT;
3483: goto out;
3484: }
3485: r = 0;
1.32 djm 3486: if (keyp != NULL) {
3487: *keyp = prv;
3488: prv = NULL;
3489: }
1.1 djm 3490: out:
3491: BIO_free(bio);
1.60 jsing 3492: EVP_PKEY_free(pk);
1.30 mmcc 3493: sshkey_free(prv);
1.1 djm 3494: return r;
3495: }
3496: #endif /* WITH_OPENSSL */
3497:
3498: int
3499: sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
3500: const char *passphrase, struct sshkey **keyp, char **commentp)
3501: {
1.42 djm 3502: int r = SSH_ERR_INTERNAL_ERROR;
3503:
1.32 djm 3504: if (keyp != NULL)
3505: *keyp = NULL;
1.1 djm 3506: if (commentp != NULL)
3507: *commentp = NULL;
3508:
3509: switch (type) {
1.62 markus 3510: case KEY_XMSS:
1.106 djm 3511: /* No fallback for new-format-only keys */
1.1 djm 3512: return sshkey_parse_private2(blob, type, passphrase,
3513: keyp, commentp);
1.106 djm 3514: default:
1.42 djm 3515: r = sshkey_parse_private2(blob, type, passphrase, keyp,
3516: commentp);
1.106 djm 3517: /* Only fallback to PEM parser if a format error occurred. */
3518: if (r != SSH_ERR_INVALID_FORMAT)
1.42 djm 3519: return r;
1.1 djm 3520: #ifdef WITH_OPENSSL
1.8 djm 3521: return sshkey_parse_private_pem_fileblob(blob, type,
3522: passphrase, keyp);
1.1 djm 3523: #else
3524: return SSH_ERR_INVALID_FORMAT;
3525: #endif /* WITH_OPENSSL */
3526: }
3527: }
3528:
3529: int
3530: sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
1.23 tim 3531: struct sshkey **keyp, char **commentp)
1.1 djm 3532: {
3533: if (keyp != NULL)
3534: *keyp = NULL;
3535: if (commentp != NULL)
3536: *commentp = NULL;
3537:
1.23 tim 3538: return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
3539: passphrase, keyp, commentp);
1.96 djm 3540: }
3541:
3542: void
3543: sshkey_sig_details_free(struct sshkey_sig_details *details)
3544: {
3545: freezero(details, sizeof(*details));
1.107 djm 3546: }
3547:
3548: int
3549: sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type,
3550: struct sshkey **pubkeyp)
3551: {
3552: int r = SSH_ERR_INTERNAL_ERROR;
3553:
3554: if (pubkeyp != NULL)
3555: *pubkeyp = NULL;
3556: /* only new-format private keys bundle a public key inside */
3557: if ((r = sshkey_parse_private2_pubkey(blob, type, pubkeyp)) != 0)
3558: return r;
3559: return 0;
1.1 djm 3560: }
1.62 markus 3561:
3562: #ifdef WITH_XMSS
3563: /*
3564: * serialize the key with the current state and forward the state
3565: * maxsign times.
3566: */
3567: int
1.77 djm 3568: sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b,
1.112 dtucker 3569: u_int32_t maxsign, int printerror)
1.62 markus 3570: {
3571: int r, rupdate;
3572:
3573: if (maxsign == 0 ||
3574: sshkey_type_plain(k->type) != KEY_XMSS)
3575: return sshkey_private_serialize_opt(k, b,
3576: SSHKEY_SERIALIZE_DEFAULT);
1.112 dtucker 3577: if ((r = sshkey_xmss_get_state(k, printerror)) != 0 ||
1.62 markus 3578: (r = sshkey_private_serialize_opt(k, b,
3579: SSHKEY_SERIALIZE_STATE)) != 0 ||
3580: (r = sshkey_xmss_forward_state(k, maxsign)) != 0)
3581: goto out;
3582: r = 0;
3583: out:
1.112 dtucker 3584: if ((rupdate = sshkey_xmss_update_state(k, printerror)) != 0) {
1.62 markus 3585: if (r == 0)
3586: r = rupdate;
3587: }
3588: return r;
3589: }
3590:
3591: u_int32_t
3592: sshkey_signatures_left(const struct sshkey *k)
3593: {
3594: if (sshkey_type_plain(k->type) == KEY_XMSS)
3595: return sshkey_xmss_signatures_left(k);
3596: return 0;
3597: }
3598:
3599: int
3600: sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
3601: {
3602: if (sshkey_type_plain(k->type) != KEY_XMSS)
3603: return SSH_ERR_INVALID_ARGUMENT;
3604: return sshkey_xmss_enable_maxsign(k, maxsign);
3605: }
3606:
3607: int
3608: sshkey_set_filename(struct sshkey *k, const char *filename)
3609: {
3610: if (k == NULL)
3611: return SSH_ERR_INVALID_ARGUMENT;
3612: if (sshkey_type_plain(k->type) != KEY_XMSS)
3613: return 0;
3614: if (filename == NULL)
3615: return SSH_ERR_INVALID_ARGUMENT;
3616: if ((k->xmss_filename = strdup(filename)) == NULL)
3617: return SSH_ERR_ALLOC_FAIL;
3618: return 0;
3619: }
3620: #else
3621: int
1.76 djm 3622: sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b,
1.112 dtucker 3623: u_int32_t maxsign, int printerror)
1.62 markus 3624: {
3625: return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT);
3626: }
3627:
3628: u_int32_t
3629: sshkey_signatures_left(const struct sshkey *k)
3630: {
3631: return 0;
3632: }
3633:
3634: int
3635: sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
3636: {
3637: return SSH_ERR_INVALID_ARGUMENT;
3638: }
3639:
3640: int
3641: sshkey_set_filename(struct sshkey *k, const char *filename)
3642: {
3643: if (k == NULL)
3644: return SSH_ERR_INVALID_ARGUMENT;
3645: return 0;
3646: }
3647: #endif /* WITH_XMSS */