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