Annotation of src/usr.bin/openssl/pkcs12.c, Revision 1.17
1.17 ! inoguchi 1: /* $OpenBSD: pkcs12.c,v 1.16 2021/10/31 16:47:27 tb Exp $ */
1.1 jsing 2: /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3: * project.
4: */
5: /* ====================================================================
6: * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: *
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: *
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in
17: * the documentation and/or other materials provided with the
18: * distribution.
19: *
20: * 3. All advertising materials mentioning features or use of this
21: * software must display the following acknowledgment:
22: * "This product includes software developed by the OpenSSL Project
23: * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24: *
25: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26: * endorse or promote products derived from this software without
27: * prior written permission. For written permission, please contact
28: * licensing@OpenSSL.org.
29: *
30: * 5. Products derived from this software may not be called "OpenSSL"
31: * nor may "OpenSSL" appear in their names without prior written
32: * permission of the OpenSSL Project.
33: *
34: * 6. Redistributions of any form whatsoever must retain the following
35: * acknowledgment:
36: * "This product includes software developed by the OpenSSL Project
37: * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38: *
39: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50: * OF THE POSSIBILITY OF SUCH DAMAGE.
51: * ====================================================================
52: *
53: * This product includes cryptographic software written by Eric Young
54: * (eay@cryptsoft.com). This product includes software written by Tim
55: * Hudson (tjh@cryptsoft.com).
56: *
57: */
58:
59: #include <openssl/opensslconf.h>
60:
61: #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_SHA1)
62:
63: #include <stdio.h>
64: #include <stdlib.h>
65: #include <string.h>
66:
67: #include "apps.h"
68:
69: #include <openssl/crypto.h>
70: #include <openssl/err.h>
71: #include <openssl/pem.h>
72: #include <openssl/pkcs12.h>
73:
74: #define NOKEYS 0x1
75: #define NOCERTS 0x2
76: #define INFO 0x4
77: #define CLCERTS 0x8
78: #define CACERTS 0x10
79:
1.14 inoguchi 80: int get_cert_chain(X509 *cert, X509_STORE *store, STACK_OF(X509) **chain);
81: int dump_certs_keys_p12(BIO *out, PKCS12 *p12, char *pass, int passlen,
1.1 jsing 82: int options, char *pempass);
1.14 inoguchi 83: int dump_certs_pkeys_bags(BIO *out, STACK_OF(PKCS12_SAFEBAG) *bags, char *pass,
1.1 jsing 84: int passlen, int options, char *pempass);
1.14 inoguchi 85: int dump_certs_pkeys_bag(BIO *out, PKCS12_SAFEBAG *bags, char *pass,
86: int passlen, int options, char *pempass);
1.15 tb 87: int print_attribs(BIO *out, const STACK_OF(X509_ATTRIBUTE) *attrlst,
1.14 inoguchi 88: const char *name);
89: void hex_prin(BIO *out, unsigned char *buf, int len);
1.15 tb 90: int alg_print(BIO *x, const X509_ALGOR *alg);
1.14 inoguchi 91: static int set_pbe(BIO *err, int *ppbe, const char *str);
1.1 jsing 92:
1.11 inoguchi 93: static struct {
94: int add_lmk;
95: char *CAfile;
96: STACK_OF(OPENSSL_STRING) *canames;
97: char *CApath;
98: int cert_pbe;
99: char *certfile;
100: int chain;
101: char *csp_name;
102: const EVP_CIPHER *enc;
103: int export_cert;
104: int key_pbe;
105: char *keyname;
106: int keytype;
107: char *infile;
108: int iter;
109: char *macalg;
110: int maciter;
111: int macver;
112: char *name;
113: int noprompt;
114: int options;
115: char *outfile;
116: char *passarg;
117: char *passargin;
118: char *passargout;
119: int twopass;
120: } pkcs12_config;
121:
1.12 inoguchi 122: static int
123: pkcs12_opt_canames(char *arg)
124: {
125: if (pkcs12_config.canames == NULL &&
126: (pkcs12_config.canames = sk_OPENSSL_STRING_new_null()) == NULL)
127: return (1);
128:
129: if (!sk_OPENSSL_STRING_push(pkcs12_config.canames, arg))
130: return (1);
131:
132: return (0);
133: }
134:
135: static int
136: pkcs12_opt_cert_pbe(char *arg)
137: {
138: return (!set_pbe(bio_err, &pkcs12_config.cert_pbe, arg));
139: }
140:
141: static int
142: pkcs12_opt_key_pbe(char *arg)
143: {
144: return (!set_pbe(bio_err, &pkcs12_config.key_pbe, arg));
145: }
146:
147: static int
148: pkcs12_opt_passarg(char *arg)
149: {
150: pkcs12_config.passarg = arg;
151: pkcs12_config.noprompt = 1;
152: return (0);
153: }
154:
155: static const EVP_CIPHER *get_cipher_by_name(char *name)
156: {
157: if (name == NULL || strcmp(name, "") == 0)
158: return (NULL);
159: #ifndef OPENSSL_NO_AES
160: else if (strcmp(name, "aes128") == 0)
161: return EVP_aes_128_cbc();
162: else if (strcmp(name, "aes192") == 0)
163: return EVP_aes_192_cbc();
164: else if (strcmp(name, "aes256") == 0)
165: return EVP_aes_256_cbc();
166: #endif
167: #ifndef OPENSSL_NO_CAMELLIA
168: else if (strcmp(name, "camellia128") == 0)
169: return EVP_camellia_128_cbc();
170: else if (strcmp(name, "camellia192") == 0)
171: return EVP_camellia_192_cbc();
172: else if (strcmp(name, "camellia256") == 0)
173: return EVP_camellia_256_cbc();
174: #endif
175: #ifndef OPENSSL_NO_DES
176: else if (strcmp(name, "des") == 0)
177: return EVP_des_cbc();
178: else if (strcmp(name, "des3") == 0)
179: return EVP_des_ede3_cbc();
180: #endif
181: #ifndef OPENSSL_NO_IDEA
182: else if (strcmp(name, "idea") == 0)
183: return EVP_idea_cbc();
184: #endif
185: else
186: return (NULL);
187: }
188:
189: static int
190: pkcs12_opt_enc(int argc, char **argv, int *argsused)
191: {
192: char *name = argv[0];
193:
194: if (*name++ != '-')
195: return (1);
196:
197: if (strcmp(name, "nodes") == 0)
198: pkcs12_config.enc = NULL;
199: else if ((pkcs12_config.enc = get_cipher_by_name(name)) == NULL)
200: return (1);
201:
202: *argsused = 1;
203: return (0);
204: }
205:
206: static const struct option pkcs12_options[] = {
207: #ifndef OPENSSL_NO_AES
208: {
209: .name = "aes128",
210: .desc = "Encrypt PEM output with CBC AES",
211: .type = OPTION_ARGV_FUNC,
212: .opt.argvfunc = pkcs12_opt_enc,
213: },
214: {
215: .name = "aes192",
216: .desc = "Encrypt PEM output with CBC AES",
217: .type = OPTION_ARGV_FUNC,
218: .opt.argvfunc = pkcs12_opt_enc,
219: },
220: {
221: .name = "aes256",
222: .desc = "Encrypt PEM output with CBC AES",
223: .type = OPTION_ARGV_FUNC,
224: .opt.argvfunc = pkcs12_opt_enc,
225: },
226: #endif
227: #ifndef OPENSSL_NO_CAMELLIA
228: {
229: .name = "camellia128",
230: .desc = "Encrypt PEM output with CBC Camellia",
231: .type = OPTION_ARGV_FUNC,
232: .opt.argvfunc = pkcs12_opt_enc,
233: },
234: {
235: .name = "camellia192",
236: .desc = "Encrypt PEM output with CBC Camellia",
237: .type = OPTION_ARGV_FUNC,
238: .opt.argvfunc = pkcs12_opt_enc,
239: },
240: {
241: .name = "camellia256",
242: .desc = "Encrypt PEM output with CBC Camellia",
243: .type = OPTION_ARGV_FUNC,
244: .opt.argvfunc = pkcs12_opt_enc,
245: },
246: #endif
247: {
248: .name = "des",
249: .desc = "Encrypt private keys with DES",
250: .type = OPTION_ARGV_FUNC,
251: .opt.argvfunc = pkcs12_opt_enc,
252: },
253: {
254: .name = "des3",
255: .desc = "Encrypt private keys with triple DES (default)",
256: .type = OPTION_ARGV_FUNC,
257: .opt.argvfunc = pkcs12_opt_enc,
258: },
259: #ifndef OPENSSL_NO_IDEA
260: {
261: .name = "idea",
262: .desc = "Encrypt private keys with IDEA",
263: .type = OPTION_ARGV_FUNC,
264: .opt.argvfunc = pkcs12_opt_enc,
265: },
266: #endif
267: {
268: .name = "cacerts",
269: .desc = "Only output CA certificates",
270: .type = OPTION_VALUE_OR,
271: .opt.value = &pkcs12_config.options,
272: .value = CACERTS,
273: },
274: {
275: .name = "CAfile",
276: .argname = "file",
277: .desc = "PEM format file of CA certificates",
278: .type = OPTION_ARG,
279: .opt.arg = &pkcs12_config.CAfile,
280: },
281: {
282: .name = "caname",
283: .argname = "name",
284: .desc = "Use name as CA friendly name (can be used more than once)",
285: .type = OPTION_ARG_FUNC,
286: .opt.argfunc = pkcs12_opt_canames,
287: },
288: {
289: .name = "CApath",
290: .argname = "directory",
291: .desc = "PEM format directory of CA certificates",
292: .type = OPTION_ARG,
293: .opt.arg = &pkcs12_config.CApath,
294: },
295: {
296: .name = "certfile",
297: .argname = "file",
298: .desc = "Add all certs in file",
299: .type = OPTION_ARG,
300: .opt.arg = &pkcs12_config.certfile,
301: },
302: {
303: .name = "certpbe",
304: .argname = "alg",
305: .desc = "Specify certificate PBE algorithm (default RC2-40)",
306: .type = OPTION_ARG_FUNC,
307: .opt.argfunc = pkcs12_opt_cert_pbe,
308: },
309: {
310: .name = "chain",
311: .desc = "Add certificate chain",
312: .type = OPTION_FLAG,
313: .opt.flag = &pkcs12_config.chain,
314: },
315: {
316: .name = "clcerts",
317: .desc = "Only output client certificates",
318: .type = OPTION_VALUE_OR,
319: .opt.value = &pkcs12_config.options,
320: .value = CLCERTS,
321: },
322: {
323: .name = "CSP",
324: .argname = "name",
325: .desc = "Microsoft CSP name",
326: .type = OPTION_ARG,
327: .opt.arg = &pkcs12_config.csp_name,
328: },
329: {
330: .name = "descert",
331: .desc = "Encrypt PKCS#12 certificates with triple DES (default RC2-40)",
332: .type = OPTION_VALUE,
333: .opt.value = &pkcs12_config.cert_pbe,
334: .value = NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
335: },
336: {
337: .name = "export",
338: .desc = "Output PKCS#12 file",
339: .type = OPTION_FLAG,
340: .opt.flag = &pkcs12_config.export_cert,
341: },
342: {
343: .name = "in",
344: .argname = "file",
345: .desc = "Input filename",
346: .type = OPTION_ARG,
347: .opt.arg = &pkcs12_config.infile,
348: },
349: {
350: .name = "info",
351: .desc = "Give info about PKCS#12 structure",
352: .type = OPTION_VALUE_OR,
353: .opt.value = &pkcs12_config.options,
354: .value = INFO,
355: },
356: {
357: .name = "inkey",
358: .argname = "file",
359: .desc = "Private key if not infile",
360: .type = OPTION_ARG,
361: .opt.arg = &pkcs12_config.keyname,
362: },
363: {
364: .name = "keyex",
365: .desc = "Set MS key exchange type",
366: .type = OPTION_VALUE,
367: .opt.value = &pkcs12_config.keytype,
368: .value = KEY_EX,
369: },
370: {
371: .name = "keypbe",
372: .argname = "alg",
373: .desc = "Specify private key PBE algorithm (default 3DES)",
374: .type = OPTION_ARG_FUNC,
375: .opt.argfunc = pkcs12_opt_key_pbe,
376: },
377: {
378: .name = "keysig",
379: .desc = "Set MS key signature type",
380: .type = OPTION_VALUE,
381: .opt.value = &pkcs12_config.keytype,
382: .value = KEY_SIG,
383: },
384: {
385: .name = "LMK",
386: .desc = "Add local machine keyset attribute to private key",
387: .type = OPTION_FLAG,
388: .opt.flag = &pkcs12_config.add_lmk,
389: },
390: {
391: .name = "macalg",
392: .argname = "alg",
393: .desc = "Digest algorithm used in MAC (default SHA1)",
394: .type = OPTION_ARG,
395: .opt.arg = &pkcs12_config.macalg,
396: },
397: {
398: .name = "maciter",
399: .desc = "Use MAC iteration",
400: .type = OPTION_VALUE,
401: .opt.value = &pkcs12_config.maciter,
402: .value = PKCS12_DEFAULT_ITER,
403: },
404: {
405: .name = "name",
406: .argname = "name",
407: .desc = "Use name as friendly name",
408: .type = OPTION_ARG,
409: .opt.arg = &pkcs12_config.name,
410: },
411: {
412: .name = "nocerts",
413: .desc = "Don't output certificates",
414: .type = OPTION_VALUE_OR,
415: .opt.value = &pkcs12_config.options,
416: .value = NOCERTS,
417: },
418: {
419: .name = "nodes",
420: .desc = "Don't encrypt private keys",
421: .type = OPTION_ARGV_FUNC,
422: .opt.argvfunc = pkcs12_opt_enc,
423: },
424: {
425: .name = "noiter",
426: .desc = "Don't use encryption iteration",
427: .type = OPTION_VALUE,
428: .opt.value = &pkcs12_config.iter,
429: .value = 1,
430: },
431: {
432: .name = "nokeys",
433: .desc = "Don't output private keys",
434: .type = OPTION_VALUE_OR,
435: .opt.value = &pkcs12_config.options,
436: .value = NOKEYS,
437: },
438: {
439: .name = "nomac",
440: .desc = "Don't generate MAC",
441: .type = OPTION_VALUE,
442: .opt.value = &pkcs12_config.maciter,
443: .value = -1,
444: },
445: {
446: .name = "nomaciter",
447: .desc = "Don't use MAC iteration",
448: .type = OPTION_VALUE,
449: .opt.value = &pkcs12_config.maciter,
450: .value = 1,
451: },
452: {
453: .name = "nomacver",
454: .desc = "Don't verify MAC",
455: .type = OPTION_VALUE,
456: .opt.value = &pkcs12_config.macver,
457: .value = 0,
458: },
459: {
460: .name = "noout",
461: .desc = "Don't output anything, just verify",
462: .type = OPTION_VALUE_OR,
463: .opt.value = &pkcs12_config.options,
464: .value = (NOKEYS | NOCERTS),
465: },
466: {
467: .name = "out",
468: .argname = "file",
469: .desc = "Output filename",
470: .type = OPTION_ARG,
471: .opt.arg = &pkcs12_config.outfile,
472: },
473: {
474: .name = "passin",
475: .argname = "arg",
476: .desc = "Input file passphrase source",
477: .type = OPTION_ARG,
478: .opt.arg = &pkcs12_config.passargin,
479: },
480: {
481: .name = "passout",
482: .argname = "arg",
483: .desc = "Output file passphrase source",
484: .type = OPTION_ARG,
485: .opt.arg = &pkcs12_config.passargout,
486: },
487: {
488: .name = "password",
489: .argname = "arg",
490: .desc = "Set import/export password source",
491: .type = OPTION_ARG_FUNC,
492: .opt.argfunc = pkcs12_opt_passarg,
493: },
494: {
495: .name = "twopass",
496: .desc = "Separate MAC, encryption passwords",
497: .type = OPTION_FLAG,
498: .opt.flag = &pkcs12_config.twopass,
499: },
500: { NULL },
501: };
502:
503: static void
504: pkcs12_usage(void)
505: {
506: fprintf(stderr, "usage: pkcs12 [-aes128 | -aes192 | -aes256 |");
507: fprintf(stderr, " -camellia128 |\n");
508: fprintf(stderr, " -camellia192 | -camellia256 | -des | -des3 |");
509: fprintf(stderr, " -idea]\n");
510: fprintf(stderr, " [-cacerts] [-CAfile file] [-caname name]\n");
511: fprintf(stderr, " [-CApath directory] [-certfile file]");
512: fprintf(stderr, " [-certpbe alg]\n");
513: fprintf(stderr, " [-chain] [-clcerts] [-CSP name] [-descert]");
514: fprintf(stderr, " [-export]\n");
515: fprintf(stderr, " [-in file] [-info] [-inkey file] [-keyex]");
516: fprintf(stderr, " [-keypbe alg]\n");
517: fprintf(stderr, " [-keysig] [-LMK] [-macalg alg] [-maciter]");
518: fprintf(stderr, " [-name name]\n");
519: fprintf(stderr, " [-nocerts] [-nodes] [-noiter] [-nokeys]");
520: fprintf(stderr, " [-nomac]\n");
521: fprintf(stderr, " [-nomaciter] [-nomacver] [-noout] [-out file]\n");
522: fprintf(stderr, " [-passin arg] [-passout arg] [-password arg]");
523: fprintf(stderr, " [-twopass]\n\n");
524: options_usage(pkcs12_options);
525: fprintf(stderr, "\n");
526: }
527:
1.1 jsing 528: int
529: pkcs12_main(int argc, char **argv)
530: {
531: BIO *in = NULL, *out = NULL;
532: PKCS12 *p12 = NULL;
533: char pass[50], macpass[50];
534: int ret = 1;
535: char *cpass = NULL, *mpass = NULL;
536: char *passin = NULL, *passout = NULL;
1.5 doug 537:
538: if (single_execution) {
1.9 deraadt 539: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.5 doug 540: perror("pledge");
1.7 doug 541: exit(1);
542: }
1.5 doug 543: }
1.1 jsing 544:
1.11 inoguchi 545: memset(&pkcs12_config, 0, sizeof(pkcs12_config));
546: pkcs12_config.cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC;
547: pkcs12_config.enc = EVP_des_ede3_cbc();
548: pkcs12_config.iter = PKCS12_DEFAULT_ITER;
549: pkcs12_config.key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
550: pkcs12_config.maciter = PKCS12_DEFAULT_ITER;
551: pkcs12_config.macver = 1;
1.1 jsing 552:
1.12 inoguchi 553: if (options_parse(argc, argv, pkcs12_options, NULL, NULL) != 0) {
554: pkcs12_usage();
1.1 jsing 555: goto end;
556: }
557:
1.11 inoguchi 558: if (pkcs12_config.passarg) {
559: if (pkcs12_config.export_cert)
560: pkcs12_config.passargout = pkcs12_config.passarg;
1.1 jsing 561: else
1.11 inoguchi 562: pkcs12_config.passargin = pkcs12_config.passarg;
1.1 jsing 563: }
1.14 inoguchi 564: if (!app_passwd(bio_err, pkcs12_config.passargin,
565: pkcs12_config.passargout, &passin, &passout)) {
1.1 jsing 566: BIO_printf(bio_err, "Error getting passwords\n");
567: goto end;
568: }
569: if (!cpass) {
1.11 inoguchi 570: if (pkcs12_config.export_cert)
1.1 jsing 571: cpass = passout;
572: else
573: cpass = passin;
574: }
575: if (cpass) {
576: mpass = cpass;
1.11 inoguchi 577: pkcs12_config.noprompt = 1;
1.1 jsing 578: } else {
579: cpass = pass;
580: mpass = macpass;
581: }
582:
1.11 inoguchi 583: if (!pkcs12_config.infile)
1.1 jsing 584: in = BIO_new_fp(stdin, BIO_NOCLOSE);
585: else
1.11 inoguchi 586: in = BIO_new_file(pkcs12_config.infile, "rb");
1.1 jsing 587: if (!in) {
588: BIO_printf(bio_err, "Error opening input file %s\n",
1.11 inoguchi 589: pkcs12_config.infile ? pkcs12_config.infile : "<stdin>");
590: perror(pkcs12_config.infile);
1.1 jsing 591: goto end;
592: }
593:
1.11 inoguchi 594: if (!pkcs12_config.outfile) {
1.1 jsing 595: out = BIO_new_fp(stdout, BIO_NOCLOSE);
596: } else
1.11 inoguchi 597: out = BIO_new_file(pkcs12_config.outfile, "wb");
1.1 jsing 598: if (!out) {
599: BIO_printf(bio_err, "Error opening output file %s\n",
1.11 inoguchi 600: pkcs12_config.outfile ? pkcs12_config.outfile : "<stdout>");
601: perror(pkcs12_config.outfile);
1.1 jsing 602: goto end;
603: }
1.11 inoguchi 604: if (pkcs12_config.twopass) {
1.14 inoguchi 605: if (EVP_read_pw_string(macpass, sizeof macpass,
606: "Enter MAC Password:", pkcs12_config.export_cert)) {
1.1 jsing 607: BIO_printf(bio_err, "Can't read Password\n");
608: goto end;
609: }
610: }
1.11 inoguchi 611: if (pkcs12_config.export_cert) {
1.1 jsing 612: EVP_PKEY *key = NULL;
613: X509 *ucert = NULL, *x = NULL;
1.14 inoguchi 614: STACK_OF(X509) *certs = NULL;
1.1 jsing 615: const EVP_MD *macmd = NULL;
616: unsigned char *catmp = NULL;
617: int i;
618:
1.14 inoguchi 619: if ((pkcs12_config.options & (NOCERTS | NOKEYS)) ==
620: (NOCERTS | NOKEYS)) {
1.1 jsing 621: BIO_printf(bio_err, "Nothing to do!\n");
622: goto export_end;
623: }
1.11 inoguchi 624: if (pkcs12_config.options & NOCERTS)
625: pkcs12_config.chain = 0;
1.1 jsing 626:
1.11 inoguchi 627: if (!(pkcs12_config.options & NOKEYS)) {
1.14 inoguchi 628: key = load_key(bio_err, pkcs12_config.keyname ?
629: pkcs12_config.keyname : pkcs12_config.infile,
1.4 bcook 630: FORMAT_PEM, 1, passin, "private key");
1.1 jsing 631: if (!key)
632: goto export_end;
633: }
634:
635: /* Load in all certs in input file */
1.11 inoguchi 636: if (!(pkcs12_config.options & NOCERTS)) {
1.14 inoguchi 637: certs = load_certs(bio_err, pkcs12_config.infile,
638: FORMAT_PEM, NULL, "certificates");
1.1 jsing 639: if (!certs)
640: goto export_end;
641:
642: if (key) {
643: /* Look for matching private key */
644: for (i = 0; i < sk_X509_num(certs); i++) {
645: x = sk_X509_value(certs, i);
646: if (X509_check_private_key(x, key)) {
647: ucert = x;
648: /* Zero keyid and alias */
649: X509_keyid_set1(ucert, NULL, 0);
650: X509_alias_set1(ucert, NULL, 0);
651: /* Remove from list */
652: (void) sk_X509_delete(certs, i);
653: break;
654: }
655: }
656: if (!ucert) {
1.14 inoguchi 657: BIO_printf(bio_err,
658: "No certificate matches private key\n");
1.1 jsing 659: goto export_end;
660: }
661: }
662: }
663:
664: /* Add any more certificates asked for */
1.11 inoguchi 665: if (pkcs12_config.certfile) {
1.14 inoguchi 666: STACK_OF(X509) *morecerts = NULL;
667: if (!(morecerts = load_certs(bio_err,
668: pkcs12_config.certfile, FORMAT_PEM, NULL,
669: "certificates from certfile")))
1.1 jsing 670: goto export_end;
671: while (sk_X509_num(morecerts) > 0)
672: sk_X509_push(certs, sk_X509_shift(morecerts));
673: sk_X509_free(morecerts);
674: }
675:
676:
677: /* If chaining get chain from user cert */
1.11 inoguchi 678: if (pkcs12_config.chain) {
1.1 jsing 679: int vret;
1.14 inoguchi 680: STACK_OF(X509) *chain2;
1.1 jsing 681: X509_STORE *store = X509_STORE_new();
682: if (!store) {
1.14 inoguchi 683: BIO_printf(bio_err,
684: "Memory allocation error\n");
1.1 jsing 685: goto export_end;
686: }
1.14 inoguchi 687: if (!X509_STORE_load_locations(store,
688: pkcs12_config.CAfile, pkcs12_config.CApath))
1.1 jsing 689: X509_STORE_set_default_paths(store);
690:
691: vret = get_cert_chain(ucert, store, &chain2);
692: X509_STORE_free(store);
693:
1.15 tb 694: if (vret == X509_V_OK) {
1.1 jsing 695: /* Exclude verified certificate */
696: for (i = 1; i < sk_X509_num(chain2); i++)
1.14 inoguchi 697: sk_X509_push(certs, sk_X509_value(
698: chain2, i));
1.1 jsing 699: /* Free first certificate */
700: X509_free(sk_X509_value(chain2, 0));
701: sk_X509_free(chain2);
702: } else {
1.15 tb 703: if (vret != X509_V_ERR_UNSPECIFIED)
1.14 inoguchi 704: BIO_printf(bio_err,
705: "Error %s getting chain.\n",
706: X509_verify_cert_error_string(
707: vret));
1.1 jsing 708: else
709: ERR_print_errors(bio_err);
710: goto export_end;
711: }
712: }
713: /* Add any CA names */
714:
1.14 inoguchi 715: for (i = 0; i < sk_OPENSSL_STRING_num(pkcs12_config.canames);
716: i++) {
717: catmp = (unsigned char *) sk_OPENSSL_STRING_value(
718: pkcs12_config.canames, i);
1.1 jsing 719: X509_alias_set1(sk_X509_value(certs, i), catmp, -1);
720: }
721:
1.11 inoguchi 722: if (pkcs12_config.csp_name && key)
1.1 jsing 723: EVP_PKEY_add1_attr_by_NID(key, NID_ms_csp_name,
1.14 inoguchi 724: MBSTRING_ASC,
725: (unsigned char *) pkcs12_config.csp_name, -1);
1.1 jsing 726:
1.11 inoguchi 727: if (pkcs12_config.add_lmk && key)
1.14 inoguchi 728: EVP_PKEY_add1_attr_by_NID(key, NID_LocalKeySet, 0, NULL,
729: -1);
1.1 jsing 730:
1.11 inoguchi 731: if (!pkcs12_config.noprompt &&
1.14 inoguchi 732: EVP_read_pw_string(pass, sizeof pass,
733: "Enter Export Password:", 1)) {
1.1 jsing 734: BIO_printf(bio_err, "Can't read Password\n");
735: goto export_end;
736: }
1.11 inoguchi 737: if (!pkcs12_config.twopass)
1.1 jsing 738: strlcpy(macpass, pass, sizeof macpass);
739:
740:
1.14 inoguchi 741: p12 = PKCS12_create(cpass, pkcs12_config.name, key, ucert,
742: certs, pkcs12_config.key_pbe, pkcs12_config.cert_pbe,
743: pkcs12_config.iter, -1, pkcs12_config.keytype);
1.1 jsing 744:
745: if (!p12) {
746: ERR_print_errors(bio_err);
747: goto export_end;
748: }
1.11 inoguchi 749: if (pkcs12_config.macalg) {
750: macmd = EVP_get_digestbyname(pkcs12_config.macalg);
1.1 jsing 751: if (!macmd) {
1.14 inoguchi 752: BIO_printf(bio_err,
753: "Unknown digest algorithm %s\n",
1.11 inoguchi 754: pkcs12_config.macalg);
1.1 jsing 755: }
756: }
1.11 inoguchi 757: if (pkcs12_config.maciter != -1)
1.14 inoguchi 758: PKCS12_set_mac(p12, mpass, -1, NULL, 0,
759: pkcs12_config.maciter, macmd);
1.1 jsing 760:
761: i2d_PKCS12_bio(out, p12);
762:
763: ret = 0;
764:
1.14 inoguchi 765: export_end:
1.13 inoguchi 766: EVP_PKEY_free(key);
767: sk_X509_pop_free(certs, X509_free);
768: X509_free(ucert);
1.1 jsing 769:
770: goto end;
771:
772: }
773: if (!(p12 = d2i_PKCS12_bio(in, NULL))) {
774: ERR_print_errors(bio_err);
775: goto end;
776: }
1.14 inoguchi 777: if (!pkcs12_config.noprompt && EVP_read_pw_string(pass, sizeof pass,
778: "Enter Import Password:", 0)) {
1.1 jsing 779: BIO_printf(bio_err, "Can't read Password\n");
780: goto end;
781: }
782:
1.11 inoguchi 783: if (!pkcs12_config.twopass)
1.1 jsing 784: strlcpy(macpass, pass, sizeof macpass);
785:
1.11 inoguchi 786: if ((pkcs12_config.options & INFO) && p12->mac)
1.14 inoguchi 787: BIO_printf(bio_err, "MAC Iteration %ld\n",
788: p12->mac->iter ? ASN1_INTEGER_get(p12->mac->iter) : 1);
1.11 inoguchi 789: if (pkcs12_config.macver) {
1.1 jsing 790: /* If we enter empty password try no password first */
791: if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) {
792: /* If mac and crypto pass the same set it to NULL too */
1.11 inoguchi 793: if (!pkcs12_config.twopass)
1.1 jsing 794: cpass = NULL;
795: } else if (!PKCS12_verify_mac(p12, mpass, -1)) {
1.14 inoguchi 796: BIO_printf(bio_err,
797: "Mac verify error: invalid password?\n");
1.1 jsing 798: ERR_print_errors(bio_err);
799: goto end;
800: }
801: BIO_printf(bio_err, "MAC verified OK\n");
802: }
1.14 inoguchi 803: if (!dump_certs_keys_p12(out, p12, cpass, -1, pkcs12_config.options,
804: passout)) {
1.1 jsing 805: BIO_printf(bio_err, "Error outputting keys and certificates\n");
806: ERR_print_errors(bio_err);
807: goto end;
808: }
809: ret = 0;
1.10 jsing 810: end:
1.13 inoguchi 811: PKCS12_free(p12);
1.1 jsing 812: BIO_free(in);
813: BIO_free_all(out);
1.13 inoguchi 814: sk_OPENSSL_STRING_free(pkcs12_config.canames);
1.1 jsing 815: free(passin);
816: free(passout);
817:
818: return (ret);
819: }
820:
821: int
1.14 inoguchi 822: dump_certs_keys_p12(BIO *out, PKCS12 *p12, char *pass,
1.1 jsing 823: int passlen, int options, char *pempass)
824: {
1.14 inoguchi 825: STACK_OF(PKCS7) *asafes = NULL;
826: STACK_OF(PKCS12_SAFEBAG) *bags;
1.1 jsing 827: int i, bagnid;
828: int ret = 0;
829: PKCS7 *p7;
830:
831: if (!(asafes = PKCS12_unpack_authsafes(p12)))
832: return 0;
833: for (i = 0; i < sk_PKCS7_num(asafes); i++) {
834: p7 = sk_PKCS7_value(asafes, i);
835: bagnid = OBJ_obj2nid(p7->type);
836: if (bagnid == NID_pkcs7_data) {
837: bags = PKCS12_unpack_p7data(p7);
838: if (options & INFO)
839: BIO_printf(bio_err, "PKCS7 Data\n");
840: } else if (bagnid == NID_pkcs7_encrypted) {
841: if (options & INFO) {
842: BIO_printf(bio_err, "PKCS7 Encrypted data: ");
843: alg_print(bio_err,
844: p7->d.encrypted->enc_data->algorithm);
845: }
846: bags = PKCS12_unpack_p7encdata(p7, pass, passlen);
847: } else
848: continue;
849: if (!bags)
850: goto err;
851: if (!dump_certs_pkeys_bags(out, bags, pass, passlen,
852: options, pempass)) {
853: sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
854: goto err;
855: }
856: sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
857: bags = NULL;
858: }
859: ret = 1;
860:
1.10 jsing 861: err:
1.13 inoguchi 862: sk_PKCS7_pop_free(asafes, PKCS7_free);
1.1 jsing 863: return ret;
864: }
865:
866: int
1.14 inoguchi 867: dump_certs_pkeys_bags(BIO *out, STACK_OF(PKCS12_SAFEBAG) *bags,
1.1 jsing 868: char *pass, int passlen, int options, char *pempass)
869: {
870: int i;
871: for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
872: if (!dump_certs_pkeys_bag(out,
873: sk_PKCS12_SAFEBAG_value(bags, i),
874: pass, passlen,
875: options, pempass))
876: return 0;
877: }
878: return 1;
879: }
880:
881: int
1.14 inoguchi 882: dump_certs_pkeys_bag(BIO *out, PKCS12_SAFEBAG *bag, char *pass,
1.1 jsing 883: int passlen, int options, char *pempass)
884: {
885: EVP_PKEY *pkey;
886: PKCS8_PRIV_KEY_INFO *p8;
887: X509 *x509;
888:
1.8 jsing 889: switch (OBJ_obj2nid(bag->type)) {
1.1 jsing 890: case NID_keyBag:
891: if (options & INFO)
892: BIO_printf(bio_err, "Key bag\n");
893: if (options & NOKEYS)
894: return 1;
895: print_attribs(out, bag->attrib, "Bag Attributes");
896: p8 = bag->value.keybag;
1.15 tb 897: if ((pkey = EVP_PKCS82PKEY(p8)) == NULL)
1.1 jsing 898: return 0;
1.15 tb 899: print_attribs(out, PKCS8_pkey_get0_attrs(p8), "Key Attributes");
1.14 inoguchi 900: PEM_write_bio_PrivateKey(out, pkey, pkcs12_config.enc, NULL, 0,
901: NULL, pempass);
1.1 jsing 902: EVP_PKEY_free(pkey);
903: break;
904:
905: case NID_pkcs8ShroudedKeyBag:
906: if (options & INFO) {
1.16 tb 907: const X509_ALGOR *tp8alg;
908:
1.1 jsing 909: BIO_printf(bio_err, "Shrouded Keybag: ");
1.16 tb 910: X509_SIG_get0(bag->value.shkeybag, &tp8alg, NULL);
911: alg_print(bio_err, tp8alg);
1.1 jsing 912: }
913: if (options & NOKEYS)
914: return 1;
915: print_attribs(out, bag->attrib, "Bag Attributes");
916: if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen)))
917: return 0;
918: if (!(pkey = EVP_PKCS82PKEY(p8))) {
919: PKCS8_PRIV_KEY_INFO_free(p8);
920: return 0;
921: }
1.15 tb 922: print_attribs(out, PKCS8_pkey_get0_attrs(p8), "Key Attributes");
1.1 jsing 923: PKCS8_PRIV_KEY_INFO_free(p8);
1.14 inoguchi 924: PEM_write_bio_PrivateKey(out, pkey, pkcs12_config.enc, NULL, 0,
925: NULL, pempass);
1.1 jsing 926: EVP_PKEY_free(pkey);
927: break;
928:
929: case NID_certBag:
930: if (options & INFO)
931: BIO_printf(bio_err, "Certificate bag\n");
932: if (options & NOCERTS)
933: return 1;
934: if (PKCS12_get_attr(bag, NID_localKeyID)) {
935: if (options & CACERTS)
936: return 1;
937: } else if (options & CLCERTS)
938: return 1;
939: print_attribs(out, bag->attrib, "Bag Attributes");
1.8 jsing 940: if (OBJ_obj2nid(bag->value.bag->type) != NID_x509Certificate)
1.1 jsing 941: return 1;
942: if (!(x509 = PKCS12_certbag2x509(bag)))
943: return 0;
944: dump_cert_text(out, x509);
945: PEM_write_bio_X509(out, x509);
946: X509_free(x509);
947: break;
948:
949: case NID_safeContentsBag:
950: if (options & INFO)
951: BIO_printf(bio_err, "Safe Contents bag\n");
952: print_attribs(out, bag->attrib, "Bag Attributes");
953: return dump_certs_pkeys_bags(out, bag->value.safes, pass,
954: passlen, options, pempass);
955:
956: default:
957: BIO_printf(bio_err, "Warning unsupported bag type: ");
958: i2a_ASN1_OBJECT(bio_err, bag->type);
959: BIO_printf(bio_err, "\n");
960: return 1;
961: break;
962: }
963: return 1;
964: }
965:
966: /* Given a single certificate return a verified chain or NULL if error */
967: int
1.15 tb 968: get_cert_chain(X509 *cert, X509_STORE *store, STACK_OF(X509) **out_chain)
1.1 jsing 969: {
1.15 tb 970: X509_STORE_CTX *store_ctx = NULL;
971: STACK_OF(X509) *chain = NULL;
972: int ret = X509_V_ERR_UNSPECIFIED;
973:
974: if ((store_ctx = X509_STORE_CTX_new()) == NULL)
975: goto err;
976: if (!X509_STORE_CTX_init(store_ctx, store, cert, NULL))
1.1 jsing 977: goto err;
1.15 tb 978:
979: if (X509_verify_cert(store_ctx) > 0) {
980: if ((chain = X509_STORE_CTX_get1_chain(store_ctx)) == NULL)
981: goto err;
982: }
983: ret = X509_STORE_CTX_get_error(store_ctx);
984:
1.10 jsing 985: err:
1.15 tb 986: X509_STORE_CTX_free(store_ctx);
987: *out_chain = chain;
1.1 jsing 988:
1.15 tb 989: return ret;
1.1 jsing 990: }
991:
992: int
1.15 tb 993: alg_print(BIO *x, const X509_ALGOR *alg)
1.1 jsing 994: {
995: PBEPARAM *pbe;
996: const unsigned char *p;
997: p = alg->parameter->value.sequence->data;
998: pbe = d2i_PBEPARAM(NULL, &p, alg->parameter->value.sequence->length);
999: if (!pbe)
1000: return 1;
1001: BIO_printf(bio_err, "%s, Iteration %ld\n",
1002: OBJ_nid2ln(OBJ_obj2nid(alg->algorithm)),
1003: ASN1_INTEGER_get(pbe->iter));
1004: PBEPARAM_free(pbe);
1005: return 1;
1006: }
1007:
1008: /* Generalised attribute print: handle PKCS#8 and bag attributes */
1.15 tb 1009: void
1010: print_attribute(BIO *out, const ASN1_TYPE *av)
1011: {
1012: char *value;
1013:
1014: switch (av->type) {
1015: case V_ASN1_BMPSTRING:
1016: value = OPENSSL_uni2asc(
1017: av->value.bmpstring->data,
1018: av->value.bmpstring->length);
1019: BIO_printf(out, "%s\n", value);
1020: free(value);
1021: break;
1022:
1023: case V_ASN1_OCTET_STRING:
1024: hex_prin(out, av->value.octet_string->data,
1025: av->value.octet_string->length);
1026: BIO_printf(out, "\n");
1027: break;
1028:
1029: case V_ASN1_BIT_STRING:
1030: hex_prin(out, av->value.bit_string->data,
1031: av->value.bit_string->length);
1032: BIO_printf(out, "\n");
1033: break;
1034:
1035: default:
1036: BIO_printf(out, "<Unsupported tag %d>\n",
1037: av->type);
1038: break;
1039: }
1040: }
1.1 jsing 1041:
1042: int
1.15 tb 1043: print_attribs(BIO *out, const STACK_OF(X509_ATTRIBUTE) *attrlst, const char *name)
1.1 jsing 1044: {
1045: X509_ATTRIBUTE *attr;
1046: ASN1_TYPE *av;
1.15 tb 1047: int i, j, attr_nid;
1.1 jsing 1048: if (!attrlst) {
1049: BIO_printf(out, "%s: <No Attributes>\n", name);
1050: return 1;
1051: }
1052: if (!sk_X509_ATTRIBUTE_num(attrlst)) {
1053: BIO_printf(out, "%s: <Empty Attributes>\n", name);
1054: return 1;
1055: }
1056: BIO_printf(out, "%s\n", name);
1057: for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) {
1.15 tb 1058: ASN1_OBJECT *obj;
1059:
1.1 jsing 1060: attr = sk_X509_ATTRIBUTE_value(attrlst, i);
1.15 tb 1061: obj = X509_ATTRIBUTE_get0_object(attr);
1062: attr_nid = OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr));
1.1 jsing 1063: BIO_printf(out, " ");
1064: if (attr_nid == NID_undef) {
1.15 tb 1065: i2a_ASN1_OBJECT(out, obj);
1.1 jsing 1066: BIO_printf(out, ": ");
1067: } else
1068: BIO_printf(out, "%s: ", OBJ_nid2ln(attr_nid));
1069:
1.15 tb 1070: if (X509_ATTRIBUTE_count(attr)) {
1071: for (j = 0; j < X509_ATTRIBUTE_count(attr); j++) {
1072: av = X509_ATTRIBUTE_get0_type(attr, j);
1073: print_attribute(out, av);
1.1 jsing 1074: }
1075: } else
1076: BIO_printf(out, "<No Values>\n");
1077: }
1078: return 1;
1079: }
1080:
1081: void
1.14 inoguchi 1082: hex_prin(BIO *out, unsigned char *buf, int len)
1.1 jsing 1083: {
1084: int i;
1085: for (i = 0; i < len; i++)
1086: BIO_printf(out, "%02X ", buf[i]);
1087: }
1088:
1089: static int
1.14 inoguchi 1090: set_pbe(BIO *err, int *ppbe, const char *str)
1.1 jsing 1091: {
1092: if (!str)
1093: return 0;
1094: if (!strcmp(str, "NONE")) {
1095: *ppbe = -1;
1096: return 1;
1097: }
1098: *ppbe = OBJ_txt2nid(str);
1099: if (*ppbe == NID_undef) {
1100: BIO_printf(bio_err, "Unknown PBE algorithm %s\n", str);
1101: return 0;
1102: }
1103: return 1;
1104: }
1105:
1106: #endif