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