1 |
|
|
/* $OpenBSD: pkcs12.c,v 1.7 2015/10/17 15:00:11 doug 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 |
96 |
|
|
pkcs12_main(int argc, char **argv) |
97 |
|
|
{ |
98 |
|
|
char *infile = NULL, *outfile = NULL, *keyname = NULL; |
99 |
|
|
char *certfile = NULL; |
100 |
|
|
BIO *in = NULL, *out = NULL; |
101 |
|
|
char **args; |
102 |
|
|
char *name = NULL; |
103 |
|
|
char *csp_name = NULL; |
104 |
|
|
int add_lmk = 0; |
105 |
|
|
PKCS12 *p12 = NULL; |
106 |
|
|
char pass[50], macpass[50]; |
107 |
|
|
int export_cert = 0; |
108 |
|
|
int options = 0; |
109 |
|
|
int chain = 0; |
110 |
|
|
int badarg = 0; |
111 |
|
|
int iter = PKCS12_DEFAULT_ITER; |
112 |
|
|
int maciter = PKCS12_DEFAULT_ITER; |
113 |
|
|
int twopass = 0; |
114 |
|
|
int keytype = 0; |
115 |
|
|
int cert_pbe; |
116 |
|
|
int key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; |
117 |
|
|
int ret = 1; |
118 |
|
|
int macver = 1; |
119 |
|
|
int noprompt = 0; |
120 |
|
|
STACK_OF(OPENSSL_STRING) * canames = NULL; |
121 |
|
|
char *cpass = NULL, *mpass = NULL; |
122 |
|
|
char *passargin = NULL, *passargout = NULL, *passarg = NULL; |
123 |
|
|
char *passin = NULL, *passout = NULL; |
124 |
|
|
char *macalg = NULL; |
125 |
|
|
char *CApath = NULL, *CAfile = NULL; |
126 |
|
|
|
127 |
|
|
if (single_execution) { |
128 |
|
|
if (pledge("stdio rpath wpath cpath tty", NULL) == -1) { |
129 |
|
|
perror("pledge"); |
130 |
|
|
exit(1); |
131 |
|
|
} |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; |
135 |
|
|
|
136 |
|
|
enc = EVP_des_ede3_cbc(); |
137 |
|
|
|
138 |
|
|
args = argv + 1; |
139 |
|
|
|
140 |
|
|
while (*args) { |
141 |
|
|
if (*args[0] == '-') { |
142 |
|
|
if (!strcmp(*args, "-nokeys")) |
143 |
|
|
options |= NOKEYS; |
144 |
|
|
else if (!strcmp(*args, "-keyex")) |
145 |
|
|
keytype = KEY_EX; |
146 |
|
|
else if (!strcmp(*args, "-keysig")) |
147 |
|
|
keytype = KEY_SIG; |
148 |
|
|
else if (!strcmp(*args, "-nocerts")) |
149 |
|
|
options |= NOCERTS; |
150 |
|
|
else if (!strcmp(*args, "-clcerts")) |
151 |
|
|
options |= CLCERTS; |
152 |
|
|
else if (!strcmp(*args, "-cacerts")) |
153 |
|
|
options |= CACERTS; |
154 |
|
|
else if (!strcmp(*args, "-noout")) |
155 |
|
|
options |= (NOKEYS | NOCERTS); |
156 |
|
|
else if (!strcmp(*args, "-info")) |
157 |
|
|
options |= INFO; |
158 |
|
|
else if (!strcmp(*args, "-chain")) |
159 |
|
|
chain = 1; |
160 |
|
|
else if (!strcmp(*args, "-twopass")) |
161 |
|
|
twopass = 1; |
162 |
|
|
else if (!strcmp(*args, "-nomacver")) |
163 |
|
|
macver = 0; |
164 |
|
|
else if (!strcmp(*args, "-descert")) |
165 |
|
|
cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; |
166 |
|
|
else if (!strcmp(*args, "-export")) |
167 |
|
|
export_cert = 1; |
168 |
|
|
else if (!strcmp(*args, "-des")) |
169 |
|
|
enc = EVP_des_cbc(); |
170 |
|
|
else if (!strcmp(*args, "-des3")) |
171 |
|
|
enc = EVP_des_ede3_cbc(); |
172 |
|
|
#ifndef OPENSSL_NO_IDEA |
173 |
|
|
else if (!strcmp(*args, "-idea")) |
174 |
|
|
enc = EVP_idea_cbc(); |
175 |
|
|
#endif |
176 |
|
|
#ifndef OPENSSL_NO_AES |
177 |
|
|
else if (!strcmp(*args, "-aes128")) |
178 |
|
|
enc = EVP_aes_128_cbc(); |
179 |
|
|
else if (!strcmp(*args, "-aes192")) |
180 |
|
|
enc = EVP_aes_192_cbc(); |
181 |
|
|
else if (!strcmp(*args, "-aes256")) |
182 |
|
|
enc = EVP_aes_256_cbc(); |
183 |
|
|
#endif |
184 |
|
|
#ifndef OPENSSL_NO_CAMELLIA |
185 |
|
|
else if (!strcmp(*args, "-camellia128")) |
186 |
|
|
enc = EVP_camellia_128_cbc(); |
187 |
|
|
else if (!strcmp(*args, "-camellia192")) |
188 |
|
|
enc = EVP_camellia_192_cbc(); |
189 |
|
|
else if (!strcmp(*args, "-camellia256")) |
190 |
|
|
enc = EVP_camellia_256_cbc(); |
191 |
|
|
#endif |
192 |
|
|
else if (!strcmp(*args, "-noiter")) |
193 |
|
|
iter = 1; |
194 |
|
|
else if (!strcmp(*args, "-maciter")) |
195 |
|
|
maciter = PKCS12_DEFAULT_ITER; |
196 |
|
|
else if (!strcmp(*args, "-nomaciter")) |
197 |
|
|
maciter = 1; |
198 |
|
|
else if (!strcmp(*args, "-nomac")) |
199 |
|
|
maciter = -1; |
200 |
|
|
else if (!strcmp(*args, "-macalg")) |
201 |
|
|
if (args[1]) { |
202 |
|
|
args++; |
203 |
|
|
macalg = *args; |
204 |
|
|
} else |
205 |
|
|
badarg = 1; |
206 |
|
|
else if (!strcmp(*args, "-nodes")) |
207 |
|
|
enc = NULL; |
208 |
|
|
else if (!strcmp(*args, "-certpbe")) { |
209 |
|
|
if (!set_pbe(bio_err, &cert_pbe, *++args)) |
210 |
|
|
badarg = 1; |
211 |
|
|
} else if (!strcmp(*args, "-keypbe")) { |
212 |
|
|
if (!set_pbe(bio_err, &key_pbe, *++args)) |
213 |
|
|
badarg = 1; |
214 |
|
|
} else if (!strcmp(*args, "-inkey")) { |
215 |
|
|
if (args[1]) { |
216 |
|
|
args++; |
217 |
|
|
keyname = *args; |
218 |
|
|
} else |
219 |
|
|
badarg = 1; |
220 |
|
|
} else if (!strcmp(*args, "-certfile")) { |
221 |
|
|
if (args[1]) { |
222 |
|
|
args++; |
223 |
|
|
certfile = *args; |
224 |
|
|
} else |
225 |
|
|
badarg = 1; |
226 |
|
|
} else if (!strcmp(*args, "-name")) { |
227 |
|
|
if (args[1]) { |
228 |
|
|
args++; |
229 |
|
|
name = *args; |
230 |
|
|
} else |
231 |
|
|
badarg = 1; |
232 |
|
|
} else if (!strcmp(*args, "-LMK")) |
233 |
|
|
add_lmk = 1; |
234 |
|
|
else if (!strcmp(*args, "-CSP")) { |
235 |
|
|
if (args[1]) { |
236 |
|
|
args++; |
237 |
|
|
csp_name = *args; |
238 |
|
|
} else |
239 |
|
|
badarg = 1; |
240 |
|
|
} else if (!strcmp(*args, "-caname")) { |
241 |
|
|
if (args[1]) { |
242 |
|
|
args++; |
243 |
|
|
if (!canames) |
244 |
|
|
canames = sk_OPENSSL_STRING_new_null(); |
245 |
|
|
sk_OPENSSL_STRING_push(canames, *args); |
246 |
|
|
} else |
247 |
|
|
badarg = 1; |
248 |
|
|
} else if (!strcmp(*args, "-in")) { |
249 |
|
|
if (args[1]) { |
250 |
|
|
args++; |
251 |
|
|
infile = *args; |
252 |
|
|
} else |
253 |
|
|
badarg = 1; |
254 |
|
|
} else if (!strcmp(*args, "-out")) { |
255 |
|
|
if (args[1]) { |
256 |
|
|
args++; |
257 |
|
|
outfile = *args; |
258 |
|
|
} else |
259 |
|
|
badarg = 1; |
260 |
|
|
} else if (!strcmp(*args, "-passin")) { |
261 |
|
|
if (args[1]) { |
262 |
|
|
args++; |
263 |
|
|
passargin = *args; |
264 |
|
|
} else |
265 |
|
|
badarg = 1; |
266 |
|
|
} else if (!strcmp(*args, "-passout")) { |
267 |
|
|
if (args[1]) { |
268 |
|
|
args++; |
269 |
|
|
passargout = *args; |
270 |
|
|
} else |
271 |
|
|
badarg = 1; |
272 |
|
|
} else if (!strcmp(*args, "-password")) { |
273 |
|
|
if (args[1]) { |
274 |
|
|
args++; |
275 |
|
|
passarg = *args; |
276 |
|
|
noprompt = 1; |
277 |
|
|
} else |
278 |
|
|
badarg = 1; |
279 |
|
|
} else if (!strcmp(*args, "-CApath")) { |
280 |
|
|
if (args[1]) { |
281 |
|
|
args++; |
282 |
|
|
CApath = *args; |
283 |
|
|
} else |
284 |
|
|
badarg = 1; |
285 |
|
|
} else if (!strcmp(*args, "-CAfile")) { |
286 |
|
|
if (args[1]) { |
287 |
|
|
args++; |
288 |
|
|
CAfile = *args; |
289 |
|
|
} else |
290 |
|
|
badarg = 1; |
291 |
|
|
} else |
292 |
|
|
badarg = 1; |
293 |
|
|
|
294 |
|
|
} else |
295 |
|
|
badarg = 1; |
296 |
|
|
args++; |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
if (badarg) { |
300 |
|
|
BIO_printf(bio_err, "Usage: pkcs12 [options]\n"); |
301 |
|
|
BIO_printf(bio_err, "where options are\n"); |
302 |
|
|
BIO_printf(bio_err, "-export output PKCS12 file\n"); |
303 |
|
|
BIO_printf(bio_err, "-chain add certificate chain\n"); |
304 |
|
|
BIO_printf(bio_err, "-inkey file private key if not infile\n"); |
305 |
|
|
BIO_printf(bio_err, "-certfile f add all certs in f\n"); |
306 |
|
|
BIO_printf(bio_err, "-CApath arg - PEM format directory of CA's\n"); |
307 |
|
|
BIO_printf(bio_err, "-CAfile arg - PEM format file of CA's\n"); |
308 |
|
|
BIO_printf(bio_err, "-name \"name\" use name as friendly name\n"); |
309 |
|
|
BIO_printf(bio_err, "-caname \"nm\" use nm as CA friendly name (can be used more than once).\n"); |
310 |
|
|
BIO_printf(bio_err, "-in infile input filename\n"); |
311 |
|
|
BIO_printf(bio_err, "-out outfile output filename\n"); |
312 |
|
|
BIO_printf(bio_err, "-noout don't output anything, just verify.\n"); |
313 |
|
|
BIO_printf(bio_err, "-nomacver don't verify MAC.\n"); |
314 |
|
|
BIO_printf(bio_err, "-nocerts don't output certificates.\n"); |
315 |
|
|
BIO_printf(bio_err, "-clcerts only output client certificates.\n"); |
316 |
|
|
BIO_printf(bio_err, "-cacerts only output CA certificates.\n"); |
317 |
|
|
BIO_printf(bio_err, "-nokeys don't output private keys.\n"); |
318 |
|
|
BIO_printf(bio_err, "-info give info about PKCS#12 structure.\n"); |
319 |
|
|
BIO_printf(bio_err, "-des encrypt private keys with DES\n"); |
320 |
|
|
BIO_printf(bio_err, "-des3 encrypt private keys with triple DES (default)\n"); |
321 |
|
|
#ifndef OPENSSL_NO_IDEA |
322 |
|
|
BIO_printf(bio_err, "-idea encrypt private keys with idea\n"); |
323 |
|
|
#endif |
324 |
|
|
#ifndef OPENSSL_NO_AES |
325 |
|
|
BIO_printf(bio_err, "-aes128, -aes192, -aes256\n"); |
326 |
|
|
BIO_printf(bio_err, " encrypt PEM output with cbc aes\n"); |
327 |
|
|
#endif |
328 |
|
|
#ifndef OPENSSL_NO_CAMELLIA |
329 |
|
|
BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n"); |
330 |
|
|
BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n"); |
331 |
|
|
#endif |
332 |
|
|
BIO_printf(bio_err, "-nodes don't encrypt private keys\n"); |
333 |
|
|
BIO_printf(bio_err, "-noiter don't use encryption iteration\n"); |
334 |
|
|
BIO_printf(bio_err, "-nomaciter don't use MAC iteration\n"); |
335 |
|
|
BIO_printf(bio_err, "-maciter use MAC iteration\n"); |
336 |
|
|
BIO_printf(bio_err, "-nomac don't generate MAC\n"); |
337 |
|
|
BIO_printf(bio_err, "-twopass separate MAC, encryption passwords\n"); |
338 |
|
|
BIO_printf(bio_err, "-descert encrypt PKCS#12 certificates with triple DES (default RC2-40)\n"); |
339 |
|
|
BIO_printf(bio_err, "-certpbe alg specify certificate PBE algorithm (default RC2-40)\n"); |
340 |
|
|
BIO_printf(bio_err, "-keypbe alg specify private key PBE algorithm (default 3DES)\n"); |
341 |
|
|
BIO_printf(bio_err, "-macalg alg digest algorithm used in MAC (default SHA1)\n"); |
342 |
|
|
BIO_printf(bio_err, "-keyex set MS key exchange type\n"); |
343 |
|
|
BIO_printf(bio_err, "-keysig set MS key signature type\n"); |
344 |
|
|
BIO_printf(bio_err, "-password p set import/export password source\n"); |
345 |
|
|
BIO_printf(bio_err, "-passin p input file pass phrase source\n"); |
346 |
|
|
BIO_printf(bio_err, "-passout p output file pass phrase source\n"); |
347 |
|
|
BIO_printf(bio_err, "-CSP name Microsoft CSP name\n"); |
348 |
|
|
BIO_printf(bio_err, "-LMK Add local machine keyset attribute to private key\n"); |
349 |
|
|
goto end; |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
if (passarg) { |
353 |
|
|
if (export_cert) |
354 |
|
|
passargout = passarg; |
355 |
|
|
else |
356 |
|
|
passargin = passarg; |
357 |
|
|
} |
358 |
|
|
if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { |
359 |
|
|
BIO_printf(bio_err, "Error getting passwords\n"); |
360 |
|
|
goto end; |
361 |
|
|
} |
362 |
|
|
if (!cpass) { |
363 |
|
|
if (export_cert) |
364 |
|
|
cpass = passout; |
365 |
|
|
else |
366 |
|
|
cpass = passin; |
367 |
|
|
} |
368 |
|
|
if (cpass) { |
369 |
|
|
mpass = cpass; |
370 |
|
|
noprompt = 1; |
371 |
|
|
} else { |
372 |
|
|
cpass = pass; |
373 |
|
|
mpass = macpass; |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
if (!infile) |
377 |
|
|
in = BIO_new_fp(stdin, BIO_NOCLOSE); |
378 |
|
|
else |
379 |
|
|
in = BIO_new_file(infile, "rb"); |
380 |
|
|
if (!in) { |
381 |
|
|
BIO_printf(bio_err, "Error opening input file %s\n", |
382 |
|
|
infile ? infile : "<stdin>"); |
383 |
|
|
perror(infile); |
384 |
|
|
goto end; |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
if (!outfile) { |
388 |
|
|
out = BIO_new_fp(stdout, BIO_NOCLOSE); |
389 |
|
|
} else |
390 |
|
|
out = BIO_new_file(outfile, "wb"); |
391 |
|
|
if (!out) { |
392 |
|
|
BIO_printf(bio_err, "Error opening output file %s\n", |
393 |
|
|
outfile ? outfile : "<stdout>"); |
394 |
|
|
perror(outfile); |
395 |
|
|
goto end; |
396 |
|
|
} |
397 |
|
|
if (twopass) { |
398 |
|
|
if (EVP_read_pw_string(macpass, sizeof macpass, "Enter MAC Password:", export_cert)) { |
399 |
|
|
BIO_printf(bio_err, "Can't read Password\n"); |
400 |
|
|
goto end; |
401 |
|
|
} |
402 |
|
|
} |
403 |
|
|
if (export_cert) { |
404 |
|
|
EVP_PKEY *key = NULL; |
405 |
|
|
X509 *ucert = NULL, *x = NULL; |
406 |
|
|
STACK_OF(X509) * certs = NULL; |
407 |
|
|
const EVP_MD *macmd = NULL; |
408 |
|
|
unsigned char *catmp = NULL; |
409 |
|
|
int i; |
410 |
|
|
|
411 |
|
|
if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { |
412 |
|
|
BIO_printf(bio_err, "Nothing to do!\n"); |
413 |
|
|
goto export_end; |
414 |
|
|
} |
415 |
|
|
if (options & NOCERTS) |
416 |
|
|
chain = 0; |
417 |
|
|
|
418 |
|
|
if (!(options & NOKEYS)) { |
419 |
|
|
key = load_key(bio_err, keyname ? keyname : infile, |
420 |
|
|
FORMAT_PEM, 1, passin, "private key"); |
421 |
|
|
if (!key) |
422 |
|
|
goto export_end; |
423 |
|
|
} |
424 |
|
|
|
425 |
|
|
/* Load in all certs in input file */ |
426 |
|
|
if (!(options & NOCERTS)) { |
427 |
|
|
certs = load_certs(bio_err, infile, FORMAT_PEM, NULL, |
428 |
|
|
"certificates"); |
429 |
|
|
if (!certs) |
430 |
|
|
goto export_end; |
431 |
|
|
|
432 |
|
|
if (key) { |
433 |
|
|
/* Look for matching private key */ |
434 |
|
|
for (i = 0; i < sk_X509_num(certs); i++) { |
435 |
|
|
x = sk_X509_value(certs, i); |
436 |
|
|
if (X509_check_private_key(x, key)) { |
437 |
|
|
ucert = x; |
438 |
|
|
/* Zero keyid and alias */ |
439 |
|
|
X509_keyid_set1(ucert, NULL, 0); |
440 |
|
|
X509_alias_set1(ucert, NULL, 0); |
441 |
|
|
/* Remove from list */ |
442 |
|
|
(void) sk_X509_delete(certs, i); |
443 |
|
|
break; |
444 |
|
|
} |
445 |
|
|
} |
446 |
|
|
if (!ucert) { |
447 |
|
|
BIO_printf(bio_err, "No certificate matches private key\n"); |
448 |
|
|
goto export_end; |
449 |
|
|
} |
450 |
|
|
} |
451 |
|
|
} |
452 |
|
|
|
453 |
|
|
/* Add any more certificates asked for */ |
454 |
|
|
if (certfile) { |
455 |
|
|
STACK_OF(X509) * morecerts = NULL; |
456 |
|
|
if (!(morecerts = load_certs(bio_err, certfile, FORMAT_PEM, |
457 |
|
|
NULL, "certificates from certfile"))) |
458 |
|
|
goto export_end; |
459 |
|
|
while (sk_X509_num(morecerts) > 0) |
460 |
|
|
sk_X509_push(certs, sk_X509_shift(morecerts)); |
461 |
|
|
sk_X509_free(morecerts); |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
|
465 |
|
|
/* If chaining get chain from user cert */ |
466 |
|
|
if (chain) { |
467 |
|
|
int vret; |
468 |
|
|
STACK_OF(X509) * chain2; |
469 |
|
|
X509_STORE *store = X509_STORE_new(); |
470 |
|
|
if (!store) { |
471 |
|
|
BIO_printf(bio_err, "Memory allocation error\n"); |
472 |
|
|
goto export_end; |
473 |
|
|
} |
474 |
|
|
if (!X509_STORE_load_locations(store, CAfile, CApath)) |
475 |
|
|
X509_STORE_set_default_paths(store); |
476 |
|
|
|
477 |
|
|
vret = get_cert_chain(ucert, store, &chain2); |
478 |
|
|
X509_STORE_free(store); |
479 |
|
|
|
480 |
|
|
if (!vret) { |
481 |
|
|
/* Exclude verified certificate */ |
482 |
|
|
for (i = 1; i < sk_X509_num(chain2); i++) |
483 |
|
|
sk_X509_push(certs, sk_X509_value(chain2, i)); |
484 |
|
|
/* Free first certificate */ |
485 |
|
|
X509_free(sk_X509_value(chain2, 0)); |
486 |
|
|
sk_X509_free(chain2); |
487 |
|
|
} else { |
488 |
|
|
if (vret >= 0) |
489 |
|
|
BIO_printf(bio_err, "Error %s getting chain.\n", |
490 |
|
|
X509_verify_cert_error_string(vret)); |
491 |
|
|
else |
492 |
|
|
ERR_print_errors(bio_err); |
493 |
|
|
goto export_end; |
494 |
|
|
} |
495 |
|
|
} |
496 |
|
|
/* Add any CA names */ |
497 |
|
|
|
498 |
|
|
for (i = 0; i < sk_OPENSSL_STRING_num(canames); i++) { |
499 |
|
|
catmp = (unsigned char *) sk_OPENSSL_STRING_value(canames, i); |
500 |
|
|
X509_alias_set1(sk_X509_value(certs, i), catmp, -1); |
501 |
|
|
} |
502 |
|
|
|
503 |
|
|
if (csp_name && key) |
504 |
|
|
EVP_PKEY_add1_attr_by_NID(key, NID_ms_csp_name, |
505 |
|
|
MBSTRING_ASC, (unsigned char *) csp_name, -1); |
506 |
|
|
|
507 |
|
|
if (add_lmk && key) |
508 |
|
|
EVP_PKEY_add1_attr_by_NID(key, NID_LocalKeySet, 0, NULL, -1); |
509 |
|
|
|
510 |
|
|
|
511 |
|
|
if (!noprompt && |
512 |
|
|
EVP_read_pw_string(pass, sizeof pass, "Enter Export Password:", 1)) { |
513 |
|
|
BIO_printf(bio_err, "Can't read Password\n"); |
514 |
|
|
goto export_end; |
515 |
|
|
} |
516 |
|
|
if (!twopass) |
517 |
|
|
strlcpy(macpass, pass, sizeof macpass); |
518 |
|
|
|
519 |
|
|
|
520 |
|
|
p12 = PKCS12_create(cpass, name, key, ucert, certs, |
521 |
|
|
key_pbe, cert_pbe, iter, -1, keytype); |
522 |
|
|
|
523 |
|
|
if (!p12) { |
524 |
|
|
ERR_print_errors(bio_err); |
525 |
|
|
goto export_end; |
526 |
|
|
} |
527 |
|
|
if (macalg) { |
528 |
|
|
macmd = EVP_get_digestbyname(macalg); |
529 |
|
|
if (!macmd) { |
530 |
|
|
BIO_printf(bio_err, "Unknown digest algorithm %s\n", |
531 |
|
|
macalg); |
532 |
|
|
} |
533 |
|
|
} |
534 |
|
|
if (maciter != -1) |
535 |
|
|
PKCS12_set_mac(p12, mpass, -1, NULL, 0, maciter, macmd); |
536 |
|
|
|
537 |
|
|
|
538 |
|
|
i2d_PKCS12_bio(out, p12); |
539 |
|
|
|
540 |
|
|
ret = 0; |
541 |
|
|
|
542 |
|
|
export_end: |
543 |
|
|
|
544 |
|
|
if (key) |
545 |
|
|
EVP_PKEY_free(key); |
546 |
|
|
if (certs) |
547 |
|
|
sk_X509_pop_free(certs, X509_free); |
548 |
|
|
if (ucert) |
549 |
|
|
X509_free(ucert); |
550 |
|
|
|
551 |
|
|
goto end; |
552 |
|
|
|
553 |
|
|
} |
554 |
|
|
if (!(p12 = d2i_PKCS12_bio(in, NULL))) { |
555 |
|
|
ERR_print_errors(bio_err); |
556 |
|
|
goto end; |
557 |
|
|
} |
558 |
|
|
if (!noprompt && EVP_read_pw_string(pass, sizeof pass, "Enter Import Password:", 0)) { |
559 |
|
|
BIO_printf(bio_err, "Can't read Password\n"); |
560 |
|
|
goto end; |
561 |
|
|
} |
562 |
|
|
|
563 |
|
|
if (!twopass) |
564 |
|
|
strlcpy(macpass, pass, sizeof macpass); |
565 |
|
|
|
566 |
|
|
if ((options & INFO) && p12->mac) |
567 |
|
|
BIO_printf(bio_err, "MAC Iteration %ld\n", p12->mac->iter ? ASN1_INTEGER_get(p12->mac->iter) : 1); |
568 |
|
|
if (macver) { |
569 |
|
|
/* If we enter empty password try no password first */ |
570 |
|
|
if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) { |
571 |
|
|
/* If mac and crypto pass the same set it to NULL too */ |
572 |
|
|
if (!twopass) |
573 |
|
|
cpass = NULL; |
574 |
|
|
} else if (!PKCS12_verify_mac(p12, mpass, -1)) { |
575 |
|
|
BIO_printf(bio_err, "Mac verify error: invalid password?\n"); |
576 |
|
|
ERR_print_errors(bio_err); |
577 |
|
|
goto end; |
578 |
|
|
} |
579 |
|
|
BIO_printf(bio_err, "MAC verified OK\n"); |
580 |
|
|
} |
581 |
|
|
if (!dump_certs_keys_p12(out, p12, cpass, -1, options, passout)) { |
582 |
|
|
BIO_printf(bio_err, "Error outputting keys and certificates\n"); |
583 |
|
|
ERR_print_errors(bio_err); |
584 |
|
|
goto end; |
585 |
|
|
} |
586 |
|
|
ret = 0; |
587 |
|
|
end: |
588 |
|
|
if (p12) |
589 |
|
|
PKCS12_free(p12); |
590 |
|
|
BIO_free(in); |
591 |
|
|
BIO_free_all(out); |
592 |
|
|
if (canames) |
593 |
|
|
sk_OPENSSL_STRING_free(canames); |
594 |
|
|
free(passin); |
595 |
|
|
free(passout); |
596 |
|
|
|
597 |
|
|
return (ret); |
598 |
|
|
} |
599 |
|
|
|
600 |
|
|
int |
601 |
|
|
dump_certs_keys_p12(BIO * out, PKCS12 * p12, char *pass, |
602 |
|
|
int passlen, int options, char *pempass) |
603 |
|
|
{ |
604 |
|
|
STACK_OF(PKCS7) * asafes = NULL; |
605 |
|
|
STACK_OF(PKCS12_SAFEBAG) * bags; |
606 |
|
|
int i, bagnid; |
607 |
|
|
int ret = 0; |
608 |
|
|
PKCS7 *p7; |
609 |
|
|
|
610 |
|
|
if (!(asafes = PKCS12_unpack_authsafes(p12))) |
611 |
|
|
return 0; |
612 |
|
|
for (i = 0; i < sk_PKCS7_num(asafes); i++) { |
613 |
|
|
p7 = sk_PKCS7_value(asafes, i); |
614 |
|
|
bagnid = OBJ_obj2nid(p7->type); |
615 |
|
|
if (bagnid == NID_pkcs7_data) { |
616 |
|
|
bags = PKCS12_unpack_p7data(p7); |
617 |
|
|
if (options & INFO) |
618 |
|
|
BIO_printf(bio_err, "PKCS7 Data\n"); |
619 |
|
|
} else if (bagnid == NID_pkcs7_encrypted) { |
620 |
|
|
if (options & INFO) { |
621 |
|
|
BIO_printf(bio_err, "PKCS7 Encrypted data: "); |
622 |
|
|
alg_print(bio_err, |
623 |
|
|
p7->d.encrypted->enc_data->algorithm); |
624 |
|
|
} |
625 |
|
|
bags = PKCS12_unpack_p7encdata(p7, pass, passlen); |
626 |
|
|
} else |
627 |
|
|
continue; |
628 |
|
|
if (!bags) |
629 |
|
|
goto err; |
630 |
|
|
if (!dump_certs_pkeys_bags(out, bags, pass, passlen, |
631 |
|
|
options, pempass)) { |
632 |
|
|
sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); |
633 |
|
|
goto err; |
634 |
|
|
} |
635 |
|
|
sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); |
636 |
|
|
bags = NULL; |
637 |
|
|
} |
638 |
|
|
ret = 1; |
639 |
|
|
|
640 |
|
|
err: |
641 |
|
|
|
642 |
|
|
if (asafes) |
643 |
|
|
sk_PKCS7_pop_free(asafes, PKCS7_free); |
644 |
|
|
return ret; |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
int |
648 |
|
|
dump_certs_pkeys_bags(BIO * out, STACK_OF(PKCS12_SAFEBAG) * bags, |
649 |
|
|
char *pass, int passlen, int options, char *pempass) |
650 |
|
|
{ |
651 |
|
|
int i; |
652 |
|
|
for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { |
653 |
|
|
if (!dump_certs_pkeys_bag(out, |
654 |
|
|
sk_PKCS12_SAFEBAG_value(bags, i), |
655 |
|
|
pass, passlen, |
656 |
|
|
options, pempass)) |
657 |
|
|
return 0; |
658 |
|
|
} |
659 |
|
|
return 1; |
660 |
|
|
} |
661 |
|
|
|
662 |
|
|
int |
663 |
|
|
dump_certs_pkeys_bag(BIO * out, PKCS12_SAFEBAG * bag, char *pass, |
664 |
|
|
int passlen, int options, char *pempass) |
665 |
|
|
{ |
666 |
|
|
EVP_PKEY *pkey; |
667 |
|
|
PKCS8_PRIV_KEY_INFO *p8; |
668 |
|
|
X509 *x509; |
669 |
|
|
|
670 |
|
|
switch (M_PKCS12_bag_type(bag)) { |
671 |
|
|
case NID_keyBag: |
672 |
|
|
if (options & INFO) |
673 |
|
|
BIO_printf(bio_err, "Key bag\n"); |
674 |
|
|
if (options & NOKEYS) |
675 |
|
|
return 1; |
676 |
|
|
print_attribs(out, bag->attrib, "Bag Attributes"); |
677 |
|
|
p8 = bag->value.keybag; |
678 |
|
|
if (!(pkey = EVP_PKCS82PKEY(p8))) |
679 |
|
|
return 0; |
680 |
|
|
print_attribs(out, p8->attributes, "Key Attributes"); |
681 |
|
|
PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); |
682 |
|
|
EVP_PKEY_free(pkey); |
683 |
|
|
break; |
684 |
|
|
|
685 |
|
|
case NID_pkcs8ShroudedKeyBag: |
686 |
|
|
if (options & INFO) { |
687 |
|
|
BIO_printf(bio_err, "Shrouded Keybag: "); |
688 |
|
|
alg_print(bio_err, bag->value.shkeybag->algor); |
689 |
|
|
} |
690 |
|
|
if (options & NOKEYS) |
691 |
|
|
return 1; |
692 |
|
|
print_attribs(out, bag->attrib, "Bag Attributes"); |
693 |
|
|
if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen))) |
694 |
|
|
return 0; |
695 |
|
|
if (!(pkey = EVP_PKCS82PKEY(p8))) { |
696 |
|
|
PKCS8_PRIV_KEY_INFO_free(p8); |
697 |
|
|
return 0; |
698 |
|
|
} |
699 |
|
|
print_attribs(out, p8->attributes, "Key Attributes"); |
700 |
|
|
PKCS8_PRIV_KEY_INFO_free(p8); |
701 |
|
|
PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); |
702 |
|
|
EVP_PKEY_free(pkey); |
703 |
|
|
break; |
704 |
|
|
|
705 |
|
|
case NID_certBag: |
706 |
|
|
if (options & INFO) |
707 |
|
|
BIO_printf(bio_err, "Certificate bag\n"); |
708 |
|
|
if (options & NOCERTS) |
709 |
|
|
return 1; |
710 |
|
|
if (PKCS12_get_attr(bag, NID_localKeyID)) { |
711 |
|
|
if (options & CACERTS) |
712 |
|
|
return 1; |
713 |
|
|
} else if (options & CLCERTS) |
714 |
|
|
return 1; |
715 |
|
|
print_attribs(out, bag->attrib, "Bag Attributes"); |
716 |
|
|
if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) |
717 |
|
|
return 1; |
718 |
|
|
if (!(x509 = PKCS12_certbag2x509(bag))) |
719 |
|
|
return 0; |
720 |
|
|
dump_cert_text(out, x509); |
721 |
|
|
PEM_write_bio_X509(out, x509); |
722 |
|
|
X509_free(x509); |
723 |
|
|
break; |
724 |
|
|
|
725 |
|
|
case NID_safeContentsBag: |
726 |
|
|
if (options & INFO) |
727 |
|
|
BIO_printf(bio_err, "Safe Contents bag\n"); |
728 |
|
|
print_attribs(out, bag->attrib, "Bag Attributes"); |
729 |
|
|
return dump_certs_pkeys_bags(out, bag->value.safes, pass, |
730 |
|
|
passlen, options, pempass); |
731 |
|
|
|
732 |
|
|
default: |
733 |
|
|
BIO_printf(bio_err, "Warning unsupported bag type: "); |
734 |
|
|
i2a_ASN1_OBJECT(bio_err, bag->type); |
735 |
|
|
BIO_printf(bio_err, "\n"); |
736 |
|
|
return 1; |
737 |
|
|
break; |
738 |
|
|
} |
739 |
|
|
return 1; |
740 |
|
|
} |
741 |
|
|
|
742 |
|
|
/* Given a single certificate return a verified chain or NULL if error */ |
743 |
|
|
|
744 |
|
|
/* Hope this is OK .... */ |
745 |
|
|
|
746 |
|
|
int |
747 |
|
|
get_cert_chain(X509 * cert, X509_STORE * store, STACK_OF(X509) ** chain) |
748 |
|
|
{ |
749 |
|
|
X509_STORE_CTX store_ctx; |
750 |
|
|
STACK_OF(X509) * chn; |
751 |
|
|
int i = 0; |
752 |
|
|
|
753 |
|
|
/* |
754 |
|
|
* FIXME: Should really check the return status of |
755 |
|
|
* X509_STORE_CTX_init for an error, but how that fits into the |
756 |
|
|
* return value of this function is less obvious. |
757 |
|
|
*/ |
758 |
|
|
X509_STORE_CTX_init(&store_ctx, store, cert, NULL); |
759 |
|
|
if (X509_verify_cert(&store_ctx) <= 0) { |
760 |
|
|
i = X509_STORE_CTX_get_error(&store_ctx); |
761 |
|
|
if (i == 0) |
762 |
|
|
/* |
763 |
|
|
* avoid returning 0 if X509_verify_cert() did not |
764 |
|
|
* set an appropriate error value in the context |
765 |
|
|
*/ |
766 |
|
|
i = -1; |
767 |
|
|
chn = NULL; |
768 |
|
|
goto err; |
769 |
|
|
} else |
770 |
|
|
chn = X509_STORE_CTX_get1_chain(&store_ctx); |
771 |
|
|
err: |
772 |
|
|
X509_STORE_CTX_cleanup(&store_ctx); |
773 |
|
|
*chain = chn; |
774 |
|
|
|
775 |
|
|
return i; |
776 |
|
|
} |
777 |
|
|
|
778 |
|
|
int |
779 |
|
|
alg_print(BIO * x, X509_ALGOR * alg) |
780 |
|
|
{ |
781 |
|
|
PBEPARAM *pbe; |
782 |
|
|
const unsigned char *p; |
783 |
|
|
p = alg->parameter->value.sequence->data; |
784 |
|
|
pbe = d2i_PBEPARAM(NULL, &p, alg->parameter->value.sequence->length); |
785 |
|
|
if (!pbe) |
786 |
|
|
return 1; |
787 |
|
|
BIO_printf(bio_err, "%s, Iteration %ld\n", |
788 |
|
|
OBJ_nid2ln(OBJ_obj2nid(alg->algorithm)), |
789 |
|
|
ASN1_INTEGER_get(pbe->iter)); |
790 |
|
|
PBEPARAM_free(pbe); |
791 |
|
|
return 1; |
792 |
|
|
} |
793 |
|
|
|
794 |
|
|
/* Load all certificates from a given file */ |
795 |
|
|
|
796 |
|
|
int |
797 |
|
|
cert_load(BIO * in, STACK_OF(X509) * sk) |
798 |
|
|
{ |
799 |
|
|
int ret; |
800 |
|
|
X509 *cert; |
801 |
|
|
ret = 0; |
802 |
|
|
while ((cert = PEM_read_bio_X509(in, NULL, NULL, NULL))) { |
803 |
|
|
ret = 1; |
804 |
|
|
sk_X509_push(sk, cert); |
805 |
|
|
} |
806 |
|
|
if (ret) |
807 |
|
|
ERR_clear_error(); |
808 |
|
|
return ret; |
809 |
|
|
} |
810 |
|
|
|
811 |
|
|
/* Generalised attribute print: handle PKCS#8 and bag attributes */ |
812 |
|
|
|
813 |
|
|
int |
814 |
|
|
print_attribs(BIO * out, STACK_OF(X509_ATTRIBUTE) * attrlst, const char *name) |
815 |
|
|
{ |
816 |
|
|
X509_ATTRIBUTE *attr; |
817 |
|
|
ASN1_TYPE *av; |
818 |
|
|
char *value; |
819 |
|
|
int i, attr_nid; |
820 |
|
|
if (!attrlst) { |
821 |
|
|
BIO_printf(out, "%s: <No Attributes>\n", name); |
822 |
|
|
return 1; |
823 |
|
|
} |
824 |
|
|
if (!sk_X509_ATTRIBUTE_num(attrlst)) { |
825 |
|
|
BIO_printf(out, "%s: <Empty Attributes>\n", name); |
826 |
|
|
return 1; |
827 |
|
|
} |
828 |
|
|
BIO_printf(out, "%s\n", name); |
829 |
|
|
for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) { |
830 |
|
|
attr = sk_X509_ATTRIBUTE_value(attrlst, i); |
831 |
|
|
attr_nid = OBJ_obj2nid(attr->object); |
832 |
|
|
BIO_printf(out, " "); |
833 |
|
|
if (attr_nid == NID_undef) { |
834 |
|
|
i2a_ASN1_OBJECT(out, attr->object); |
835 |
|
|
BIO_printf(out, ": "); |
836 |
|
|
} else |
837 |
|
|
BIO_printf(out, "%s: ", OBJ_nid2ln(attr_nid)); |
838 |
|
|
|
839 |
|
|
if (sk_ASN1_TYPE_num(attr->value.set)) { |
840 |
|
|
av = sk_ASN1_TYPE_value(attr->value.set, 0); |
841 |
|
|
switch (av->type) { |
842 |
|
|
case V_ASN1_BMPSTRING: |
843 |
|
|
value = OPENSSL_uni2asc(av->value.bmpstring->data, |
844 |
|
|
av->value.bmpstring->length); |
845 |
|
|
BIO_printf(out, "%s\n", value); |
846 |
|
|
free(value); |
847 |
|
|
break; |
848 |
|
|
|
849 |
|
|
case V_ASN1_OCTET_STRING: |
850 |
|
|
hex_prin(out, av->value.octet_string->data, |
851 |
|
|
av->value.octet_string->length); |
852 |
|
|
BIO_printf(out, "\n"); |
853 |
|
|
break; |
854 |
|
|
|
855 |
|
|
case V_ASN1_BIT_STRING: |
856 |
|
|
hex_prin(out, av->value.bit_string->data, |
857 |
|
|
av->value.bit_string->length); |
858 |
|
|
BIO_printf(out, "\n"); |
859 |
|
|
break; |
860 |
|
|
|
861 |
|
|
default: |
862 |
|
|
BIO_printf(out, "<Unsupported tag %d>\n", av->type); |
863 |
|
|
break; |
864 |
|
|
} |
865 |
|
|
} else |
866 |
|
|
BIO_printf(out, "<No Values>\n"); |
867 |
|
|
} |
868 |
|
|
return 1; |
869 |
|
|
} |
870 |
|
|
|
871 |
|
|
void |
872 |
|
|
hex_prin(BIO * out, unsigned char *buf, int len) |
873 |
|
|
{ |
874 |
|
|
int i; |
875 |
|
|
for (i = 0; i < len; i++) |
876 |
|
|
BIO_printf(out, "%02X ", buf[i]); |
877 |
|
|
} |
878 |
|
|
|
879 |
|
|
static int |
880 |
|
|
set_pbe(BIO * err, int *ppbe, const char *str) |
881 |
|
|
{ |
882 |
|
|
if (!str) |
883 |
|
|
return 0; |
884 |
|
|
if (!strcmp(str, "NONE")) { |
885 |
|
|
*ppbe = -1; |
886 |
|
|
return 1; |
887 |
|
|
} |
888 |
|
|
*ppbe = OBJ_txt2nid(str); |
889 |
|
|
if (*ppbe == NID_undef) { |
890 |
|
|
BIO_printf(bio_err, "Unknown PBE algorithm %s\n", str); |
891 |
|
|
return 0; |
892 |
|
|
} |
893 |
|
|
return 1; |
894 |
|
|
} |
895 |
|
|
|
896 |
|
|
#endif |