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