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