diff options
author | jsing <> | 2014-08-26 17:47:25 +0000 |
---|---|---|
committer | jsing <> | 2014-08-26 17:47:25 +0000 |
commit | f3755acd5513f85ff734de6a822b6f804d3776ce (patch) | |
tree | 1f859a78eae941040f58599de8c0e1e56d61fdad /src/usr.bin/openssl/pkcs12.c | |
parent | 0779b9f30aa9875c290af18a4362799668829707 (diff) | |
download | openbsd-f3755acd5513f85ff734de6a822b6f804d3776ce.tar.gz openbsd-f3755acd5513f85ff734de6a822b6f804d3776ce.tar.bz2 openbsd-f3755acd5513f85ff734de6a822b6f804d3776ce.zip |
Move openssl(1) from /usr/sbin/openssl to /usr/bin/openssl, since it is not
a system/superuser binary. At the same time, move the source code from its
current lib/libssl/src/apps location to a more appropriate home under
usr.bin/openssl.
ok deraadt@ miod@
Diffstat (limited to 'src/usr.bin/openssl/pkcs12.c')
-rw-r--r-- | src/usr.bin/openssl/pkcs12.c | 913 |
1 files changed, 913 insertions, 0 deletions
diff --git a/src/usr.bin/openssl/pkcs12.c b/src/usr.bin/openssl/pkcs12.c new file mode 100644 index 0000000000..77b7c31d01 --- /dev/null +++ b/src/usr.bin/openssl/pkcs12.c | |||
@@ -0,0 +1,913 @@ | |||
1 | /* $OpenBSD: pkcs12.c,v 1.1 2014/08/26 17:47:25 jsing Exp $ */ | ||
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | ||
3 | * project. | ||
4 | */ | ||
5 | /* ==================================================================== | ||
6 | * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * 1. Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer. | ||
14 | * | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in | ||
17 | * the documentation and/or other materials provided with the | ||
18 | * distribution. | ||
19 | * | ||
20 | * 3. All advertising materials mentioning features or use of this | ||
21 | * software must display the following acknowledgment: | ||
22 | * "This product includes software developed by the OpenSSL Project | ||
23 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | ||
24 | * | ||
25 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | ||
26 | * endorse or promote products derived from this software without | ||
27 | * prior written permission. For written permission, please contact | ||
28 | * licensing@OpenSSL.org. | ||
29 | * | ||
30 | * 5. Products derived from this software may not be called "OpenSSL" | ||
31 | * nor may "OpenSSL" appear in their names without prior written | ||
32 | * permission of the OpenSSL Project. | ||
33 | * | ||
34 | * 6. Redistributions of any form whatsoever must retain the following | ||
35 | * acknowledgment: | ||
36 | * "This product includes software developed by the OpenSSL Project | ||
37 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | ||
40 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | ||
43 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
48 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
49 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
50 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
51 | * ==================================================================== | ||
52 | * | ||
53 | * This product includes cryptographic software written by Eric Young | ||
54 | * (eay@cryptsoft.com). This product includes software written by Tim | ||
55 | * Hudson (tjh@cryptsoft.com). | ||
56 | * | ||
57 | */ | ||
58 | |||
59 | #include <openssl/opensslconf.h> | ||
60 | |||
61 | #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_SHA1) | ||
62 | |||
63 | #include <stdio.h> | ||
64 | #include <stdlib.h> | ||
65 | #include <string.h> | ||
66 | |||
67 | #include "apps.h" | ||
68 | |||
69 | #include <openssl/crypto.h> | ||
70 | #include <openssl/err.h> | ||
71 | #include <openssl/pem.h> | ||
72 | #include <openssl/pkcs12.h> | ||
73 | |||
74 | const EVP_CIPHER *enc; | ||
75 | |||
76 | #define NOKEYS 0x1 | ||
77 | #define NOCERTS 0x2 | ||
78 | #define INFO 0x4 | ||
79 | #define CLCERTS 0x8 | ||
80 | #define CACERTS 0x10 | ||
81 | |||
82 | int get_cert_chain(X509 * cert, X509_STORE * store, STACK_OF(X509) ** chain); | ||
83 | int dump_certs_keys_p12(BIO * out, PKCS12 * p12, char *pass, int passlen, | ||
84 | int options, char *pempass); | ||
85 | int dump_certs_pkeys_bags(BIO * out, STACK_OF(PKCS12_SAFEBAG) * bags, char *pass, | ||
86 | int passlen, int options, char *pempass); | ||
87 | int dump_certs_pkeys_bag(BIO * out, PKCS12_SAFEBAG * bags, char *pass, int passlen, | ||
88 | int options, char *pempass); | ||
89 | int print_attribs(BIO * out, STACK_OF(X509_ATTRIBUTE) * attrlst, const char *name); | ||
90 | void hex_prin(BIO * out, unsigned char *buf, int len); | ||
91 | int alg_print(BIO * x, X509_ALGOR * alg); | ||
92 | int cert_load(BIO * in, STACK_OF(X509) * sk); | ||
93 | static int set_pbe(BIO * err, int *ppbe, const char *str); | ||
94 | |||
95 | int pkcs12_main(int, char **); | ||
96 | |||
97 | int | ||
98 | pkcs12_main(int argc, char **argv) | ||
99 | { | ||
100 | ENGINE *e = NULL; | ||
101 | char *infile = NULL, *outfile = NULL, *keyname = NULL; | ||
102 | char *certfile = NULL; | ||
103 | BIO *in = NULL, *out = NULL; | ||
104 | char **args; | ||
105 | char *name = NULL; | ||
106 | char *csp_name = NULL; | ||
107 | int add_lmk = 0; | ||
108 | PKCS12 *p12 = NULL; | ||
109 | char pass[50], macpass[50]; | ||
110 | int export_cert = 0; | ||
111 | int options = 0; | ||
112 | int chain = 0; | ||
113 | int badarg = 0; | ||
114 | int iter = PKCS12_DEFAULT_ITER; | ||
115 | int maciter = PKCS12_DEFAULT_ITER; | ||
116 | int twopass = 0; | ||
117 | int keytype = 0; | ||
118 | int cert_pbe; | ||
119 | int key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; | ||
120 | int ret = 1; | ||
121 | int macver = 1; | ||
122 | int noprompt = 0; | ||
123 | STACK_OF(OPENSSL_STRING) * canames = NULL; | ||
124 | char *cpass = NULL, *mpass = NULL; | ||
125 | char *passargin = NULL, *passargout = NULL, *passarg = NULL; | ||
126 | char *passin = NULL, *passout = NULL; | ||
127 | char *macalg = NULL; | ||
128 | char *CApath = NULL, *CAfile = NULL; | ||
129 | #ifndef OPENSSL_NO_ENGINE | ||
130 | char *engine = NULL; | ||
131 | #endif | ||
132 | |||
133 | cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; | ||
134 | |||
135 | enc = EVP_des_ede3_cbc(); | ||
136 | |||
137 | args = argv + 1; | ||
138 | |||
139 | while (*args) { | ||
140 | if (*args[0] == '-') { | ||
141 | if (!strcmp(*args, "-nokeys")) | ||
142 | options |= NOKEYS; | ||
143 | else if (!strcmp(*args, "-keyex")) | ||
144 | keytype = KEY_EX; | ||
145 | else if (!strcmp(*args, "-keysig")) | ||
146 | keytype = KEY_SIG; | ||
147 | else if (!strcmp(*args, "-nocerts")) | ||
148 | options |= NOCERTS; | ||
149 | else if (!strcmp(*args, "-clcerts")) | ||
150 | options |= CLCERTS; | ||
151 | else if (!strcmp(*args, "-cacerts")) | ||
152 | options |= CACERTS; | ||
153 | else if (!strcmp(*args, "-noout")) | ||
154 | options |= (NOKEYS | NOCERTS); | ||
155 | else if (!strcmp(*args, "-info")) | ||
156 | options |= INFO; | ||
157 | else if (!strcmp(*args, "-chain")) | ||
158 | chain = 1; | ||
159 | else if (!strcmp(*args, "-twopass")) | ||
160 | twopass = 1; | ||
161 | else if (!strcmp(*args, "-nomacver")) | ||
162 | macver = 0; | ||
163 | else if (!strcmp(*args, "-descert")) | ||
164 | cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; | ||
165 | else if (!strcmp(*args, "-export")) | ||
166 | export_cert = 1; | ||
167 | else if (!strcmp(*args, "-des")) | ||
168 | enc = EVP_des_cbc(); | ||
169 | else if (!strcmp(*args, "-des3")) | ||
170 | enc = EVP_des_ede3_cbc(); | ||
171 | #ifndef OPENSSL_NO_IDEA | ||
172 | else if (!strcmp(*args, "-idea")) | ||
173 | enc = EVP_idea_cbc(); | ||
174 | #endif | ||
175 | #ifndef OPENSSL_NO_AES | ||
176 | else if (!strcmp(*args, "-aes128")) | ||
177 | enc = EVP_aes_128_cbc(); | ||
178 | else if (!strcmp(*args, "-aes192")) | ||
179 | enc = EVP_aes_192_cbc(); | ||
180 | else if (!strcmp(*args, "-aes256")) | ||
181 | enc = EVP_aes_256_cbc(); | ||
182 | #endif | ||
183 | #ifndef OPENSSL_NO_CAMELLIA | ||
184 | else if (!strcmp(*args, "-camellia128")) | ||
185 | enc = EVP_camellia_128_cbc(); | ||
186 | else if (!strcmp(*args, "-camellia192")) | ||
187 | enc = EVP_camellia_192_cbc(); | ||
188 | else if (!strcmp(*args, "-camellia256")) | ||
189 | enc = EVP_camellia_256_cbc(); | ||
190 | #endif | ||
191 | else if (!strcmp(*args, "-noiter")) | ||
192 | iter = 1; | ||
193 | else if (!strcmp(*args, "-maciter")) | ||
194 | maciter = PKCS12_DEFAULT_ITER; | ||
195 | else if (!strcmp(*args, "-nomaciter")) | ||
196 | maciter = 1; | ||
197 | else if (!strcmp(*args, "-nomac")) | ||
198 | maciter = -1; | ||
199 | else if (!strcmp(*args, "-macalg")) | ||
200 | if (args[1]) { | ||
201 | args++; | ||
202 | macalg = *args; | ||
203 | } else | ||
204 | badarg = 1; | ||
205 | else if (!strcmp(*args, "-nodes")) | ||
206 | enc = NULL; | ||
207 | else if (!strcmp(*args, "-certpbe")) { | ||
208 | if (!set_pbe(bio_err, &cert_pbe, *++args)) | ||
209 | badarg = 1; | ||
210 | } else if (!strcmp(*args, "-keypbe")) { | ||
211 | if (!set_pbe(bio_err, &key_pbe, *++args)) | ||
212 | badarg = 1; | ||
213 | } else if (!strcmp(*args, "-inkey")) { | ||
214 | if (args[1]) { | ||
215 | args++; | ||
216 | keyname = *args; | ||
217 | } else | ||
218 | badarg = 1; | ||
219 | } else if (!strcmp(*args, "-certfile")) { | ||
220 | if (args[1]) { | ||
221 | args++; | ||
222 | certfile = *args; | ||
223 | } else | ||
224 | badarg = 1; | ||
225 | } else if (!strcmp(*args, "-name")) { | ||
226 | if (args[1]) { | ||
227 | args++; | ||
228 | name = *args; | ||
229 | } else | ||
230 | badarg = 1; | ||
231 | } else if (!strcmp(*args, "-LMK")) | ||
232 | add_lmk = 1; | ||
233 | else if (!strcmp(*args, "-CSP")) { | ||
234 | if (args[1]) { | ||
235 | args++; | ||
236 | csp_name = *args; | ||
237 | } else | ||
238 | badarg = 1; | ||
239 | } else if (!strcmp(*args, "-caname")) { | ||
240 | if (args[1]) { | ||
241 | args++; | ||
242 | if (!canames) | ||
243 | canames = sk_OPENSSL_STRING_new_null(); | ||
244 | sk_OPENSSL_STRING_push(canames, *args); | ||
245 | } else | ||
246 | badarg = 1; | ||
247 | } else if (!strcmp(*args, "-in")) { | ||
248 | if (args[1]) { | ||
249 | args++; | ||
250 | infile = *args; | ||
251 | } else | ||
252 | badarg = 1; | ||
253 | } else if (!strcmp(*args, "-out")) { | ||
254 | if (args[1]) { | ||
255 | args++; | ||
256 | outfile = *args; | ||
257 | } else | ||
258 | badarg = 1; | ||
259 | } else if (!strcmp(*args, "-passin")) { | ||
260 | if (args[1]) { | ||
261 | args++; | ||
262 | passargin = *args; | ||
263 | } else | ||
264 | badarg = 1; | ||
265 | } else if (!strcmp(*args, "-passout")) { | ||
266 | if (args[1]) { | ||
267 | args++; | ||
268 | passargout = *args; | ||
269 | } else | ||
270 | badarg = 1; | ||
271 | } else if (!strcmp(*args, "-password")) { | ||
272 | if (args[1]) { | ||
273 | args++; | ||
274 | passarg = *args; | ||
275 | noprompt = 1; | ||
276 | } else | ||
277 | badarg = 1; | ||
278 | } else if (!strcmp(*args, "-CApath")) { | ||
279 | if (args[1]) { | ||
280 | args++; | ||
281 | CApath = *args; | ||
282 | } else | ||
283 | badarg = 1; | ||
284 | } else if (!strcmp(*args, "-CAfile")) { | ||
285 | if (args[1]) { | ||
286 | args++; | ||
287 | CAfile = *args; | ||
288 | } else | ||
289 | badarg = 1; | ||
290 | #ifndef OPENSSL_NO_ENGINE | ||
291 | } else if (!strcmp(*args, "-engine")) { | ||
292 | if (args[1]) { | ||
293 | args++; | ||
294 | engine = *args; | ||
295 | } else | ||
296 | badarg = 1; | ||
297 | #endif | ||
298 | } else | ||
299 | badarg = 1; | ||
300 | |||
301 | } else | ||
302 | badarg = 1; | ||
303 | args++; | ||
304 | } | ||
305 | |||
306 | if (badarg) { | ||
307 | BIO_printf(bio_err, "Usage: pkcs12 [options]\n"); | ||
308 | BIO_printf(bio_err, "where options are\n"); | ||
309 | BIO_printf(bio_err, "-export output PKCS12 file\n"); | ||
310 | BIO_printf(bio_err, "-chain add certificate chain\n"); | ||
311 | BIO_printf(bio_err, "-inkey file private key if not infile\n"); | ||
312 | BIO_printf(bio_err, "-certfile f add all certs in f\n"); | ||
313 | BIO_printf(bio_err, "-CApath arg - PEM format directory of CA's\n"); | ||
314 | BIO_printf(bio_err, "-CAfile arg - PEM format file of CA's\n"); | ||
315 | BIO_printf(bio_err, "-name \"name\" use name as friendly name\n"); | ||
316 | BIO_printf(bio_err, "-caname \"nm\" use nm as CA friendly name (can be used more than once).\n"); | ||
317 | BIO_printf(bio_err, "-in infile input filename\n"); | ||
318 | BIO_printf(bio_err, "-out outfile output filename\n"); | ||
319 | BIO_printf(bio_err, "-noout don't output anything, just verify.\n"); | ||
320 | BIO_printf(bio_err, "-nomacver don't verify MAC.\n"); | ||
321 | BIO_printf(bio_err, "-nocerts don't output certificates.\n"); | ||
322 | BIO_printf(bio_err, "-clcerts only output client certificates.\n"); | ||
323 | BIO_printf(bio_err, "-cacerts only output CA certificates.\n"); | ||
324 | BIO_printf(bio_err, "-nokeys don't output private keys.\n"); | ||
325 | BIO_printf(bio_err, "-info give info about PKCS#12 structure.\n"); | ||
326 | BIO_printf(bio_err, "-des encrypt private keys with DES\n"); | ||
327 | BIO_printf(bio_err, "-des3 encrypt private keys with triple DES (default)\n"); | ||
328 | #ifndef OPENSSL_NO_IDEA | ||
329 | BIO_printf(bio_err, "-idea encrypt private keys with idea\n"); | ||
330 | #endif | ||
331 | #ifndef OPENSSL_NO_AES | ||
332 | BIO_printf(bio_err, "-aes128, -aes192, -aes256\n"); | ||
333 | BIO_printf(bio_err, " encrypt PEM output with cbc aes\n"); | ||
334 | #endif | ||
335 | #ifndef OPENSSL_NO_CAMELLIA | ||
336 | BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n"); | ||
337 | BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n"); | ||
338 | #endif | ||
339 | BIO_printf(bio_err, "-nodes don't encrypt private keys\n"); | ||
340 | BIO_printf(bio_err, "-noiter don't use encryption iteration\n"); | ||
341 | BIO_printf(bio_err, "-nomaciter don't use MAC iteration\n"); | ||
342 | BIO_printf(bio_err, "-maciter use MAC iteration\n"); | ||
343 | BIO_printf(bio_err, "-nomac don't generate MAC\n"); | ||
344 | BIO_printf(bio_err, "-twopass separate MAC, encryption passwords\n"); | ||
345 | BIO_printf(bio_err, "-descert encrypt PKCS#12 certificates with triple DES (default RC2-40)\n"); | ||
346 | BIO_printf(bio_err, "-certpbe alg specify certificate PBE algorithm (default RC2-40)\n"); | ||
347 | BIO_printf(bio_err, "-keypbe alg specify private key PBE algorithm (default 3DES)\n"); | ||
348 | BIO_printf(bio_err, "-macalg alg digest algorithm used in MAC (default SHA1)\n"); | ||
349 | BIO_printf(bio_err, "-keyex set MS key exchange type\n"); | ||
350 | BIO_printf(bio_err, "-keysig set MS key signature type\n"); | ||
351 | BIO_printf(bio_err, "-password p set import/export password source\n"); | ||
352 | BIO_printf(bio_err, "-passin p input file pass phrase source\n"); | ||
353 | BIO_printf(bio_err, "-passout p output file pass phrase source\n"); | ||
354 | #ifndef OPENSSL_NO_ENGINE | ||
355 | BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); | ||
356 | #endif | ||
357 | BIO_printf(bio_err, "-CSP name Microsoft CSP name\n"); | ||
358 | BIO_printf(bio_err, "-LMK Add local machine keyset attribute to private key\n"); | ||
359 | goto end; | ||
360 | } | ||
361 | #ifndef OPENSSL_NO_ENGINE | ||
362 | e = setup_engine(bio_err, engine, 0); | ||
363 | #endif | ||
364 | |||
365 | if (passarg) { | ||
366 | if (export_cert) | ||
367 | passargout = passarg; | ||
368 | else | ||
369 | passargin = passarg; | ||
370 | } | ||
371 | if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { | ||
372 | BIO_printf(bio_err, "Error getting passwords\n"); | ||
373 | goto end; | ||
374 | } | ||
375 | if (!cpass) { | ||
376 | if (export_cert) | ||
377 | cpass = passout; | ||
378 | else | ||
379 | cpass = passin; | ||
380 | } | ||
381 | if (cpass) { | ||
382 | mpass = cpass; | ||
383 | noprompt = 1; | ||
384 | } else { | ||
385 | cpass = pass; | ||
386 | mpass = macpass; | ||
387 | } | ||
388 | |||
389 | ERR_load_crypto_strings(); | ||
390 | |||
391 | |||
392 | if (!infile) | ||
393 | in = BIO_new_fp(stdin, BIO_NOCLOSE); | ||
394 | else | ||
395 | in = BIO_new_file(infile, "rb"); | ||
396 | if (!in) { | ||
397 | BIO_printf(bio_err, "Error opening input file %s\n", | ||
398 | infile ? infile : "<stdin>"); | ||
399 | perror(infile); | ||
400 | goto end; | ||
401 | } | ||
402 | |||
403 | if (!outfile) { | ||
404 | out = BIO_new_fp(stdout, BIO_NOCLOSE); | ||
405 | } else | ||
406 | out = BIO_new_file(outfile, "wb"); | ||
407 | if (!out) { | ||
408 | BIO_printf(bio_err, "Error opening output file %s\n", | ||
409 | outfile ? outfile : "<stdout>"); | ||
410 | perror(outfile); | ||
411 | goto end; | ||
412 | } | ||
413 | if (twopass) { | ||
414 | if (EVP_read_pw_string(macpass, sizeof macpass, "Enter MAC Password:", export_cert)) { | ||
415 | BIO_printf(bio_err, "Can't read Password\n"); | ||
416 | goto end; | ||
417 | } | ||
418 | } | ||
419 | if (export_cert) { | ||
420 | EVP_PKEY *key = NULL; | ||
421 | X509 *ucert = NULL, *x = NULL; | ||
422 | STACK_OF(X509) * certs = NULL; | ||
423 | const EVP_MD *macmd = NULL; | ||
424 | unsigned char *catmp = NULL; | ||
425 | int i; | ||
426 | |||
427 | if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { | ||
428 | BIO_printf(bio_err, "Nothing to do!\n"); | ||
429 | goto export_end; | ||
430 | } | ||
431 | if (options & NOCERTS) | ||
432 | chain = 0; | ||
433 | |||
434 | if (!(options & NOKEYS)) { | ||
435 | key = load_key(bio_err, keyname ? keyname : infile, | ||
436 | FORMAT_PEM, 1, passin, e, "private key"); | ||
437 | if (!key) | ||
438 | goto export_end; | ||
439 | } | ||
440 | |||
441 | /* Load in all certs in input file */ | ||
442 | if (!(options & NOCERTS)) { | ||
443 | certs = load_certs(bio_err, infile, FORMAT_PEM, NULL, e, | ||
444 | "certificates"); | ||
445 | if (!certs) | ||
446 | goto export_end; | ||
447 | |||
448 | if (key) { | ||
449 | /* Look for matching private key */ | ||
450 | for (i = 0; i < sk_X509_num(certs); i++) { | ||
451 | x = sk_X509_value(certs, i); | ||
452 | if (X509_check_private_key(x, key)) { | ||
453 | ucert = x; | ||
454 | /* Zero keyid and alias */ | ||
455 | X509_keyid_set1(ucert, NULL, 0); | ||
456 | X509_alias_set1(ucert, NULL, 0); | ||
457 | /* Remove from list */ | ||
458 | (void) sk_X509_delete(certs, i); | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | if (!ucert) { | ||
463 | BIO_printf(bio_err, "No certificate matches private key\n"); | ||
464 | goto export_end; | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | |||
469 | /* Add any more certificates asked for */ | ||
470 | if (certfile) { | ||
471 | STACK_OF(X509) * morecerts = NULL; | ||
472 | if (!(morecerts = load_certs(bio_err, certfile, FORMAT_PEM, | ||
473 | NULL, e, | ||
474 | "certificates from certfile"))) | ||
475 | goto export_end; | ||
476 | while (sk_X509_num(morecerts) > 0) | ||
477 | sk_X509_push(certs, sk_X509_shift(morecerts)); | ||
478 | sk_X509_free(morecerts); | ||
479 | } | ||
480 | |||
481 | |||
482 | /* If chaining get chain from user cert */ | ||
483 | if (chain) { | ||
484 | int vret; | ||
485 | STACK_OF(X509) * chain2; | ||
486 | X509_STORE *store = X509_STORE_new(); | ||
487 | if (!store) { | ||
488 | BIO_printf(bio_err, "Memory allocation error\n"); | ||
489 | goto export_end; | ||
490 | } | ||
491 | if (!X509_STORE_load_locations(store, CAfile, CApath)) | ||
492 | X509_STORE_set_default_paths(store); | ||
493 | |||
494 | vret = get_cert_chain(ucert, store, &chain2); | ||
495 | X509_STORE_free(store); | ||
496 | |||
497 | if (!vret) { | ||
498 | /* Exclude verified certificate */ | ||
499 | for (i = 1; i < sk_X509_num(chain2); i++) | ||
500 | sk_X509_push(certs, sk_X509_value(chain2, i)); | ||
501 | /* Free first certificate */ | ||
502 | X509_free(sk_X509_value(chain2, 0)); | ||
503 | sk_X509_free(chain2); | ||
504 | } else { | ||
505 | if (vret >= 0) | ||
506 | BIO_printf(bio_err, "Error %s getting chain.\n", | ||
507 | X509_verify_cert_error_string(vret)); | ||
508 | else | ||
509 | ERR_print_errors(bio_err); | ||
510 | goto export_end; | ||
511 | } | ||
512 | } | ||
513 | /* Add any CA names */ | ||
514 | |||
515 | for (i = 0; i < sk_OPENSSL_STRING_num(canames); i++) { | ||
516 | catmp = (unsigned char *) sk_OPENSSL_STRING_value(canames, i); | ||
517 | X509_alias_set1(sk_X509_value(certs, i), catmp, -1); | ||
518 | } | ||
519 | |||
520 | if (csp_name && key) | ||
521 | EVP_PKEY_add1_attr_by_NID(key, NID_ms_csp_name, | ||
522 | MBSTRING_ASC, (unsigned char *) csp_name, -1); | ||
523 | |||
524 | if (add_lmk && key) | ||
525 | EVP_PKEY_add1_attr_by_NID(key, NID_LocalKeySet, 0, NULL, -1); | ||
526 | |||
527 | |||
528 | if (!noprompt && | ||
529 | EVP_read_pw_string(pass, sizeof pass, "Enter Export Password:", 1)) { | ||
530 | BIO_printf(bio_err, "Can't read Password\n"); | ||
531 | goto export_end; | ||
532 | } | ||
533 | if (!twopass) | ||
534 | strlcpy(macpass, pass, sizeof macpass); | ||
535 | |||
536 | |||
537 | p12 = PKCS12_create(cpass, name, key, ucert, certs, | ||
538 | key_pbe, cert_pbe, iter, -1, keytype); | ||
539 | |||
540 | if (!p12) { | ||
541 | ERR_print_errors(bio_err); | ||
542 | goto export_end; | ||
543 | } | ||
544 | if (macalg) { | ||
545 | macmd = EVP_get_digestbyname(macalg); | ||
546 | if (!macmd) { | ||
547 | BIO_printf(bio_err, "Unknown digest algorithm %s\n", | ||
548 | macalg); | ||
549 | } | ||
550 | } | ||
551 | if (maciter != -1) | ||
552 | PKCS12_set_mac(p12, mpass, -1, NULL, 0, maciter, macmd); | ||
553 | |||
554 | |||
555 | i2d_PKCS12_bio(out, p12); | ||
556 | |||
557 | ret = 0; | ||
558 | |||
559 | export_end: | ||
560 | |||
561 | if (key) | ||
562 | EVP_PKEY_free(key); | ||
563 | if (certs) | ||
564 | sk_X509_pop_free(certs, X509_free); | ||
565 | if (ucert) | ||
566 | X509_free(ucert); | ||
567 | |||
568 | goto end; | ||
569 | |||
570 | } | ||
571 | if (!(p12 = d2i_PKCS12_bio(in, NULL))) { | ||
572 | ERR_print_errors(bio_err); | ||
573 | goto end; | ||
574 | } | ||
575 | if (!noprompt && EVP_read_pw_string(pass, sizeof pass, "Enter Import Password:", 0)) { | ||
576 | BIO_printf(bio_err, "Can't read Password\n"); | ||
577 | goto end; | ||
578 | } | ||
579 | |||
580 | if (!twopass) | ||
581 | strlcpy(macpass, pass, sizeof macpass); | ||
582 | |||
583 | if ((options & INFO) && p12->mac) | ||
584 | BIO_printf(bio_err, "MAC Iteration %ld\n", p12->mac->iter ? ASN1_INTEGER_get(p12->mac->iter) : 1); | ||
585 | if (macver) { | ||
586 | /* If we enter empty password try no password first */ | ||
587 | if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) { | ||
588 | /* If mac and crypto pass the same set it to NULL too */ | ||
589 | if (!twopass) | ||
590 | cpass = NULL; | ||
591 | } else if (!PKCS12_verify_mac(p12, mpass, -1)) { | ||
592 | BIO_printf(bio_err, "Mac verify error: invalid password?\n"); | ||
593 | ERR_print_errors(bio_err); | ||
594 | goto end; | ||
595 | } | ||
596 | BIO_printf(bio_err, "MAC verified OK\n"); | ||
597 | } | ||
598 | if (!dump_certs_keys_p12(out, p12, cpass, -1, options, passout)) { | ||
599 | BIO_printf(bio_err, "Error outputting keys and certificates\n"); | ||
600 | ERR_print_errors(bio_err); | ||
601 | goto end; | ||
602 | } | ||
603 | ret = 0; | ||
604 | end: | ||
605 | if (p12) | ||
606 | PKCS12_free(p12); | ||
607 | BIO_free(in); | ||
608 | BIO_free_all(out); | ||
609 | if (canames) | ||
610 | sk_OPENSSL_STRING_free(canames); | ||
611 | free(passin); | ||
612 | free(passout); | ||
613 | |||
614 | return (ret); | ||
615 | } | ||
616 | |||
617 | int | ||
618 | dump_certs_keys_p12(BIO * out, PKCS12 * p12, char *pass, | ||
619 | int passlen, int options, char *pempass) | ||
620 | { | ||
621 | STACK_OF(PKCS7) * asafes = NULL; | ||
622 | STACK_OF(PKCS12_SAFEBAG) * bags; | ||
623 | int i, bagnid; | ||
624 | int ret = 0; | ||
625 | PKCS7 *p7; | ||
626 | |||
627 | if (!(asafes = PKCS12_unpack_authsafes(p12))) | ||
628 | return 0; | ||
629 | for (i = 0; i < sk_PKCS7_num(asafes); i++) { | ||
630 | p7 = sk_PKCS7_value(asafes, i); | ||
631 | bagnid = OBJ_obj2nid(p7->type); | ||
632 | if (bagnid == NID_pkcs7_data) { | ||
633 | bags = PKCS12_unpack_p7data(p7); | ||
634 | if (options & INFO) | ||
635 | BIO_printf(bio_err, "PKCS7 Data\n"); | ||
636 | } else if (bagnid == NID_pkcs7_encrypted) { | ||
637 | if (options & INFO) { | ||
638 | BIO_printf(bio_err, "PKCS7 Encrypted data: "); | ||
639 | alg_print(bio_err, | ||
640 | p7->d.encrypted->enc_data->algorithm); | ||
641 | } | ||
642 | bags = PKCS12_unpack_p7encdata(p7, pass, passlen); | ||
643 | } else | ||
644 | continue; | ||
645 | if (!bags) | ||
646 | goto err; | ||
647 | if (!dump_certs_pkeys_bags(out, bags, pass, passlen, | ||
648 | options, pempass)) { | ||
649 | sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); | ||
650 | goto err; | ||
651 | } | ||
652 | sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); | ||
653 | bags = NULL; | ||
654 | } | ||
655 | ret = 1; | ||
656 | |||
657 | err: | ||
658 | |||
659 | if (asafes) | ||
660 | sk_PKCS7_pop_free(asafes, PKCS7_free); | ||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | int | ||
665 | dump_certs_pkeys_bags(BIO * out, STACK_OF(PKCS12_SAFEBAG) * bags, | ||
666 | char *pass, int passlen, int options, char *pempass) | ||
667 | { | ||
668 | int i; | ||
669 | for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { | ||
670 | if (!dump_certs_pkeys_bag(out, | ||
671 | sk_PKCS12_SAFEBAG_value(bags, i), | ||
672 | pass, passlen, | ||
673 | options, pempass)) | ||
674 | return 0; | ||
675 | } | ||
676 | return 1; | ||
677 | } | ||
678 | |||
679 | int | ||
680 | dump_certs_pkeys_bag(BIO * out, PKCS12_SAFEBAG * bag, char *pass, | ||
681 | int passlen, int options, char *pempass) | ||
682 | { | ||
683 | EVP_PKEY *pkey; | ||
684 | PKCS8_PRIV_KEY_INFO *p8; | ||
685 | X509 *x509; | ||
686 | |||
687 | switch (M_PKCS12_bag_type(bag)) { | ||
688 | case NID_keyBag: | ||
689 | if (options & INFO) | ||
690 | BIO_printf(bio_err, "Key bag\n"); | ||
691 | if (options & NOKEYS) | ||
692 | return 1; | ||
693 | print_attribs(out, bag->attrib, "Bag Attributes"); | ||
694 | p8 = bag->value.keybag; | ||
695 | if (!(pkey = EVP_PKCS82PKEY(p8))) | ||
696 | return 0; | ||
697 | print_attribs(out, p8->attributes, "Key Attributes"); | ||
698 | PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); | ||
699 | EVP_PKEY_free(pkey); | ||
700 | break; | ||
701 | |||
702 | case NID_pkcs8ShroudedKeyBag: | ||
703 | if (options & INFO) { | ||
704 | BIO_printf(bio_err, "Shrouded Keybag: "); | ||
705 | alg_print(bio_err, bag->value.shkeybag->algor); | ||
706 | } | ||
707 | if (options & NOKEYS) | ||
708 | return 1; | ||
709 | print_attribs(out, bag->attrib, "Bag Attributes"); | ||
710 | if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen))) | ||
711 | return 0; | ||
712 | if (!(pkey = EVP_PKCS82PKEY(p8))) { | ||
713 | PKCS8_PRIV_KEY_INFO_free(p8); | ||
714 | return 0; | ||
715 | } | ||
716 | print_attribs(out, p8->attributes, "Key Attributes"); | ||
717 | PKCS8_PRIV_KEY_INFO_free(p8); | ||
718 | PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); | ||
719 | EVP_PKEY_free(pkey); | ||
720 | break; | ||
721 | |||
722 | case NID_certBag: | ||
723 | if (options & INFO) | ||
724 | BIO_printf(bio_err, "Certificate bag\n"); | ||
725 | if (options & NOCERTS) | ||
726 | return 1; | ||
727 | if (PKCS12_get_attr(bag, NID_localKeyID)) { | ||
728 | if (options & CACERTS) | ||
729 | return 1; | ||
730 | } else if (options & CLCERTS) | ||
731 | return 1; | ||
732 | print_attribs(out, bag->attrib, "Bag Attributes"); | ||
733 | if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) | ||
734 | return 1; | ||
735 | if (!(x509 = PKCS12_certbag2x509(bag))) | ||
736 | return 0; | ||
737 | dump_cert_text(out, x509); | ||
738 | PEM_write_bio_X509(out, x509); | ||
739 | X509_free(x509); | ||
740 | break; | ||
741 | |||
742 | case NID_safeContentsBag: | ||
743 | if (options & INFO) | ||
744 | BIO_printf(bio_err, "Safe Contents bag\n"); | ||
745 | print_attribs(out, bag->attrib, "Bag Attributes"); | ||
746 | return dump_certs_pkeys_bags(out, bag->value.safes, pass, | ||
747 | passlen, options, pempass); | ||
748 | |||
749 | default: | ||
750 | BIO_printf(bio_err, "Warning unsupported bag type: "); | ||
751 | i2a_ASN1_OBJECT(bio_err, bag->type); | ||
752 | BIO_printf(bio_err, "\n"); | ||
753 | return 1; | ||
754 | break; | ||
755 | } | ||
756 | return 1; | ||
757 | } | ||
758 | |||
759 | /* Given a single certificate return a verified chain or NULL if error */ | ||
760 | |||
761 | /* Hope this is OK .... */ | ||
762 | |||
763 | int | ||
764 | get_cert_chain(X509 * cert, X509_STORE * store, STACK_OF(X509) ** chain) | ||
765 | { | ||
766 | X509_STORE_CTX store_ctx; | ||
767 | STACK_OF(X509) * chn; | ||
768 | int i = 0; | ||
769 | |||
770 | /* | ||
771 | * FIXME: Should really check the return status of | ||
772 | * X509_STORE_CTX_init for an error, but how that fits into the | ||
773 | * return value of this function is less obvious. | ||
774 | */ | ||
775 | X509_STORE_CTX_init(&store_ctx, store, cert, NULL); | ||
776 | if (X509_verify_cert(&store_ctx) <= 0) { | ||
777 | i = X509_STORE_CTX_get_error(&store_ctx); | ||
778 | if (i == 0) | ||
779 | /* | ||
780 | * avoid returning 0 if X509_verify_cert() did not | ||
781 | * set an appropriate error value in the context | ||
782 | */ | ||
783 | i = -1; | ||
784 | chn = NULL; | ||
785 | goto err; | ||
786 | } else | ||
787 | chn = X509_STORE_CTX_get1_chain(&store_ctx); | ||
788 | err: | ||
789 | X509_STORE_CTX_cleanup(&store_ctx); | ||
790 | *chain = chn; | ||
791 | |||
792 | return i; | ||
793 | } | ||
794 | |||
795 | int | ||
796 | alg_print(BIO * x, X509_ALGOR * alg) | ||
797 | { | ||
798 | PBEPARAM *pbe; | ||
799 | const unsigned char *p; | ||
800 | p = alg->parameter->value.sequence->data; | ||
801 | pbe = d2i_PBEPARAM(NULL, &p, alg->parameter->value.sequence->length); | ||
802 | if (!pbe) | ||
803 | return 1; | ||
804 | BIO_printf(bio_err, "%s, Iteration %ld\n", | ||
805 | OBJ_nid2ln(OBJ_obj2nid(alg->algorithm)), | ||
806 | ASN1_INTEGER_get(pbe->iter)); | ||
807 | PBEPARAM_free(pbe); | ||
808 | return 1; | ||
809 | } | ||
810 | |||
811 | /* Load all certificates from a given file */ | ||
812 | |||
813 | int | ||
814 | cert_load(BIO * in, STACK_OF(X509) * sk) | ||
815 | { | ||
816 | int ret; | ||
817 | X509 *cert; | ||
818 | ret = 0; | ||
819 | while ((cert = PEM_read_bio_X509(in, NULL, NULL, NULL))) { | ||
820 | ret = 1; | ||
821 | sk_X509_push(sk, cert); | ||
822 | } | ||
823 | if (ret) | ||
824 | ERR_clear_error(); | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | /* Generalised attribute print: handle PKCS#8 and bag attributes */ | ||
829 | |||
830 | int | ||
831 | print_attribs(BIO * out, STACK_OF(X509_ATTRIBUTE) * attrlst, const char *name) | ||
832 | { | ||
833 | X509_ATTRIBUTE *attr; | ||
834 | ASN1_TYPE *av; | ||
835 | char *value; | ||
836 | int i, attr_nid; | ||
837 | if (!attrlst) { | ||
838 | BIO_printf(out, "%s: <No Attributes>\n", name); | ||
839 | return 1; | ||
840 | } | ||
841 | if (!sk_X509_ATTRIBUTE_num(attrlst)) { | ||
842 | BIO_printf(out, "%s: <Empty Attributes>\n", name); | ||
843 | return 1; | ||
844 | } | ||
845 | BIO_printf(out, "%s\n", name); | ||
846 | for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) { | ||
847 | attr = sk_X509_ATTRIBUTE_value(attrlst, i); | ||
848 | attr_nid = OBJ_obj2nid(attr->object); | ||
849 | BIO_printf(out, " "); | ||
850 | if (attr_nid == NID_undef) { | ||
851 | i2a_ASN1_OBJECT(out, attr->object); | ||
852 | BIO_printf(out, ": "); | ||
853 | } else | ||
854 | BIO_printf(out, "%s: ", OBJ_nid2ln(attr_nid)); | ||
855 | |||
856 | if (sk_ASN1_TYPE_num(attr->value.set)) { | ||
857 | av = sk_ASN1_TYPE_value(attr->value.set, 0); | ||
858 | switch (av->type) { | ||
859 | case V_ASN1_BMPSTRING: | ||
860 | value = OPENSSL_uni2asc(av->value.bmpstring->data, | ||
861 | av->value.bmpstring->length); | ||
862 | BIO_printf(out, "%s\n", value); | ||
863 | free(value); | ||
864 | break; | ||
865 | |||
866 | case V_ASN1_OCTET_STRING: | ||
867 | hex_prin(out, av->value.octet_string->data, | ||
868 | av->value.octet_string->length); | ||
869 | BIO_printf(out, "\n"); | ||
870 | break; | ||
871 | |||
872 | case V_ASN1_BIT_STRING: | ||
873 | hex_prin(out, av->value.bit_string->data, | ||
874 | av->value.bit_string->length); | ||
875 | BIO_printf(out, "\n"); | ||
876 | break; | ||
877 | |||
878 | default: | ||
879 | BIO_printf(out, "<Unsupported tag %d>\n", av->type); | ||
880 | break; | ||
881 | } | ||
882 | } else | ||
883 | BIO_printf(out, "<No Values>\n"); | ||
884 | } | ||
885 | return 1; | ||
886 | } | ||
887 | |||
888 | void | ||
889 | hex_prin(BIO * out, unsigned char *buf, int len) | ||
890 | { | ||
891 | int i; | ||
892 | for (i = 0; i < len; i++) | ||
893 | BIO_printf(out, "%02X ", buf[i]); | ||
894 | } | ||
895 | |||
896 | static int | ||
897 | set_pbe(BIO * err, int *ppbe, const char *str) | ||
898 | { | ||
899 | if (!str) | ||
900 | return 0; | ||
901 | if (!strcmp(str, "NONE")) { | ||
902 | *ppbe = -1; | ||
903 | return 1; | ||
904 | } | ||
905 | *ppbe = OBJ_txt2nid(str); | ||
906 | if (*ppbe == NID_undef) { | ||
907 | BIO_printf(bio_err, "Unknown PBE algorithm %s\n", str); | ||
908 | return 0; | ||
909 | } | ||
910 | return 1; | ||
911 | } | ||
912 | |||
913 | #endif | ||