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