|
1 /* pkcs8.c */ |
|
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL |
|
3 * project 1999-2004. |
|
4 */ |
|
5 /* ==================================================================== |
|
6 * Copyright (c) 1999 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 #include <stdio.h> |
|
59 #include <string.h> |
|
60 #include "apps.h" |
|
61 #include <openssl/pem.h> |
|
62 #include <openssl/err.h> |
|
63 #include <openssl/evp.h> |
|
64 #include <openssl/pkcs12.h> |
|
65 |
|
66 #define PROG pkcs8_main |
|
67 |
|
68 |
|
69 int MAIN(int, char **); |
|
70 |
|
71 int MAIN(int argc, char **argv) |
|
72 { |
|
73 ENGINE *e = NULL; |
|
74 char **args, *infile = NULL, *outfile = NULL; |
|
75 char *passargin = NULL, *passargout = NULL; |
|
76 BIO *in = NULL, *out = NULL; |
|
77 int topk8 = 0; |
|
78 int pbe_nid = -1; |
|
79 const EVP_CIPHER *cipher = NULL; |
|
80 int iter = PKCS12_DEFAULT_ITER; |
|
81 int informat, outformat; |
|
82 int p8_broken = PKCS8_OK; |
|
83 int nocrypt = 0; |
|
84 X509_SIG *p8; |
|
85 PKCS8_PRIV_KEY_INFO *p8inf; |
|
86 EVP_PKEY *pkey=NULL; |
|
87 char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL; |
|
88 int badarg = 0; |
|
89 #ifndef OPENSSL_NO_ENGINE |
|
90 char *engine=NULL; |
|
91 #endif |
|
92 |
|
93 if (bio_err == NULL) |
|
94 bio_err = BIO_new_fp (stderr, BIO_NOCLOSE); |
|
95 |
|
96 |
|
97 if (!load_config(bio_err, NULL)) |
|
98 goto end; |
|
99 |
|
100 informat=FORMAT_PEM; |
|
101 outformat=FORMAT_PEM; |
|
102 |
|
103 ERR_load_crypto_strings(); |
|
104 OpenSSL_add_all_algorithms(); |
|
105 args = argv + 1; |
|
106 while (!badarg && *args && *args[0] == '-') |
|
107 { |
|
108 if (!strcmp(*args,"-v2")) |
|
109 { |
|
110 if (args[1]) |
|
111 { |
|
112 args++; |
|
113 cipher=EVP_get_cipherbyname(*args); |
|
114 if (!cipher) |
|
115 { |
|
116 BIO_printf(bio_err, |
|
117 "Unknown cipher %s\n", *args); |
|
118 badarg = 1; |
|
119 } |
|
120 } |
|
121 else |
|
122 badarg = 1; |
|
123 } |
|
124 else if (!strcmp(*args,"-v1")) |
|
125 { |
|
126 if (args[1]) |
|
127 { |
|
128 args++; |
|
129 pbe_nid=OBJ_txt2nid(*args); |
|
130 if (pbe_nid == NID_undef) |
|
131 { |
|
132 BIO_printf(bio_err, |
|
133 "Unknown PBE algorithm %s\n", *args); |
|
134 badarg = 1; |
|
135 } |
|
136 } |
|
137 else |
|
138 badarg = 1; |
|
139 } |
|
140 else if (!strcmp(*args,"-inform")) |
|
141 { |
|
142 if (args[1]) |
|
143 { |
|
144 args++; |
|
145 informat=str2fmt(*args); |
|
146 } |
|
147 else badarg = 1; |
|
148 } |
|
149 else if (!strcmp(*args,"-outform")) |
|
150 { |
|
151 if (args[1]) |
|
152 { |
|
153 args++; |
|
154 outformat=str2fmt(*args); |
|
155 } |
|
156 else badarg = 1; |
|
157 } |
|
158 else if (!strcmp (*args, "-topk8")) |
|
159 topk8 = 1; |
|
160 else if (!strcmp (*args, "-noiter")) |
|
161 iter = 1; |
|
162 else if (!strcmp (*args, "-nocrypt")) |
|
163 nocrypt = 1; |
|
164 else if (!strcmp (*args, "-nooct")) |
|
165 p8_broken = PKCS8_NO_OCTET; |
|
166 else if (!strcmp (*args, "-nsdb")) |
|
167 p8_broken = PKCS8_NS_DB; |
|
168 else if (!strcmp (*args, "-embed")) |
|
169 p8_broken = PKCS8_EMBEDDED_PARAM; |
|
170 else if (!strcmp(*args,"-passin")) |
|
171 { |
|
172 if (!args[1]) goto bad; |
|
173 passargin= *(++args); |
|
174 } |
|
175 else if (!strcmp(*args,"-passout")) |
|
176 { |
|
177 if (!args[1]) goto bad; |
|
178 passargout= *(++args); |
|
179 } |
|
180 #ifndef OPENSSL_NO_ENGINE |
|
181 else if (strcmp(*args,"-engine") == 0) |
|
182 { |
|
183 if (!args[1]) goto bad; |
|
184 engine= *(++args); |
|
185 } |
|
186 #endif |
|
187 else if (!strcmp (*args, "-in")) |
|
188 { |
|
189 if (args[1]) |
|
190 { |
|
191 args++; |
|
192 infile = *args; |
|
193 } |
|
194 else badarg = 1; |
|
195 } |
|
196 else if (!strcmp (*args, "-out")) |
|
197 { |
|
198 if (args[1]) |
|
199 { |
|
200 args++; |
|
201 outfile = *args; |
|
202 } |
|
203 else badarg = 1; |
|
204 } |
|
205 else badarg = 1; |
|
206 args++; |
|
207 } |
|
208 |
|
209 if (badarg) |
|
210 { |
|
211 bad: |
|
212 BIO_printf(bio_err, "Usage pkcs8 [options]\n"); |
|
213 BIO_printf(bio_err, "where options are\n"); |
|
214 BIO_printf(bio_err, "-in file input file\n"); |
|
215 BIO_printf(bio_err, "-inform X input format (DER or PEM)\n"); |
|
216 BIO_printf(bio_err, "-passin arg input file pass phrase source\n"); |
|
217 BIO_printf(bio_err, "-outform X output format (DER or PEM)\n"); |
|
218 BIO_printf(bio_err, "-out file output file\n"); |
|
219 BIO_printf(bio_err, "-passout arg output file pass phrase source\n"); |
|
220 BIO_printf(bio_err, "-topk8 output PKCS8 file\n"); |
|
221 BIO_printf(bio_err, "-nooct use (nonstandard) no octet format\n"); |
|
222 BIO_printf(bio_err, "-embed use (nonstandard) embedded DSA parameters format\n"); |
|
223 BIO_printf(bio_err, "-nsdb use (nonstandard) DSA Netscape DB format\n"); |
|
224 BIO_printf(bio_err, "-noiter use 1 as iteration count\n"); |
|
225 BIO_printf(bio_err, "-nocrypt use or expect unencrypted private key\n"); |
|
226 BIO_printf(bio_err, "-v2 alg use PKCS#5 v2.0 and cipher \"alg\"\n"); |
|
227 BIO_printf(bio_err, "-v1 obj use PKCS#5 v1.5 and cipher \"alg\"\n"); |
|
228 #ifndef OPENSSL_NO_ENGINE |
|
229 BIO_printf(bio_err," -engine e use engine e, possibly a hardware device.\n"); |
|
230 #endif |
|
231 return 1; |
|
232 } |
|
233 |
|
234 #ifndef OPENSSL_NO_ENGINE |
|
235 e = setup_engine(bio_err, engine, 0); |
|
236 #endif |
|
237 |
|
238 if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) |
|
239 { |
|
240 BIO_printf(bio_err, "Error getting passwords\n"); |
|
241 return 1; |
|
242 } |
|
243 |
|
244 if ((pbe_nid == -1) && !cipher) |
|
245 pbe_nid = NID_pbeWithMD5AndDES_CBC; |
|
246 |
|
247 if (infile) |
|
248 { |
|
249 if (!(in = BIO_new_file(infile, "rb"))) |
|
250 { |
|
251 BIO_printf(bio_err, |
|
252 "Can't open input file %s\n", infile); |
|
253 return (1); |
|
254 } |
|
255 } |
|
256 else |
|
257 in = BIO_new_fp (stdin, BIO_NOCLOSE); |
|
258 if (outfile) |
|
259 { |
|
260 if (!(out = BIO_new_file (outfile, "wb"))) |
|
261 { |
|
262 BIO_printf(bio_err, |
|
263 "Can't open output file %s\n", outfile); |
|
264 return (1); |
|
265 } |
|
266 } |
|
267 else |
|
268 { |
|
269 out = BIO_new_fp (stdout, BIO_NOCLOSE); |
|
270 #ifdef OPENSSL_SYS_VMS |
|
271 { |
|
272 BIO *tmpbio = BIO_new(BIO_f_linebuffer()); |
|
273 out = BIO_push(tmpbio, out); |
|
274 } |
|
275 #endif |
|
276 } |
|
277 if (topk8) |
|
278 { |
|
279 BIO_free(in); /* Not needed in this section */ |
|
280 pkey = load_key(bio_err, infile, informat, 1, |
|
281 passin, e, "key"); |
|
282 if (!pkey) |
|
283 { |
|
284 BIO_free_all(out); |
|
285 return 1; |
|
286 } |
|
287 if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, p8_broken))) |
|
288 { |
|
289 BIO_printf(bio_err, "Error converting key\n"); |
|
290 ERR_print_errors(bio_err); |
|
291 EVP_PKEY_free(pkey); |
|
292 BIO_free_all(out); |
|
293 return 1; |
|
294 } |
|
295 if (nocrypt) |
|
296 { |
|
297 if (outformat == FORMAT_PEM) |
|
298 PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); |
|
299 else if (outformat == FORMAT_ASN1) |
|
300 i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf); |
|
301 else |
|
302 { |
|
303 BIO_printf(bio_err, "Bad format specified for key\n"); |
|
304 PKCS8_PRIV_KEY_INFO_free(p8inf); |
|
305 EVP_PKEY_free(pkey); |
|
306 BIO_free_all(out); |
|
307 return (1); |
|
308 } |
|
309 } |
|
310 else |
|
311 { |
|
312 if (passout) |
|
313 p8pass = passout; |
|
314 else |
|
315 { |
|
316 p8pass = pass; |
|
317 if (EVP_read_pw_string(pass, sizeof pass, "Enter Encryption Password:", 1)) |
|
318 { |
|
319 PKCS8_PRIV_KEY_INFO_free(p8inf); |
|
320 EVP_PKEY_free(pkey); |
|
321 BIO_free_all(out); |
|
322 return (1); |
|
323 } |
|
324 } |
|
325 app_RAND_load_file(NULL, bio_err, 0); |
|
326 if (!(p8 = PKCS8_encrypt(pbe_nid, cipher, |
|
327 p8pass, strlen(p8pass), |
|
328 NULL, 0, iter, p8inf))) |
|
329 { |
|
330 BIO_printf(bio_err, "Error encrypting key\n"); |
|
331 ERR_print_errors(bio_err); |
|
332 PKCS8_PRIV_KEY_INFO_free(p8inf); |
|
333 EVP_PKEY_free(pkey); |
|
334 BIO_free_all(out); |
|
335 return (1); |
|
336 } |
|
337 app_RAND_write_file(NULL, bio_err); |
|
338 if (outformat == FORMAT_PEM) |
|
339 PEM_write_bio_PKCS8(out, p8); |
|
340 else if (outformat == FORMAT_ASN1) |
|
341 i2d_PKCS8_bio(out, p8); |
|
342 else |
|
343 { |
|
344 BIO_printf(bio_err, "Bad format specified for key\n"); |
|
345 PKCS8_PRIV_KEY_INFO_free(p8inf); |
|
346 EVP_PKEY_free(pkey); |
|
347 BIO_free_all(out); |
|
348 return (1); |
|
349 } |
|
350 X509_SIG_free(p8); |
|
351 } |
|
352 |
|
353 PKCS8_PRIV_KEY_INFO_free (p8inf); |
|
354 EVP_PKEY_free(pkey); |
|
355 BIO_free_all(out); |
|
356 if (passin) |
|
357 OPENSSL_free(passin); |
|
358 if (passout) |
|
359 OPENSSL_free(passout); |
|
360 return (0); |
|
361 } |
|
362 |
|
363 if (nocrypt) |
|
364 { |
|
365 if (informat == FORMAT_PEM) |
|
366 p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in,NULL,NULL, NULL); |
|
367 else if (informat == FORMAT_ASN1) |
|
368 p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL); |
|
369 else |
|
370 { |
|
371 BIO_printf(bio_err, "Bad format specified for key\n"); |
|
372 return (1); |
|
373 } |
|
374 } |
|
375 else |
|
376 { |
|
377 if (informat == FORMAT_PEM) |
|
378 p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); |
|
379 else if (informat == FORMAT_ASN1) |
|
380 p8 = d2i_PKCS8_bio(in, NULL); |
|
381 else |
|
382 { |
|
383 BIO_printf(bio_err, "Bad format specified for key\n"); |
|
384 return (1); |
|
385 } |
|
386 |
|
387 if (!p8) |
|
388 { |
|
389 BIO_printf (bio_err, "Error reading key\n"); |
|
390 ERR_print_errors(bio_err); |
|
391 return (1); |
|
392 } |
|
393 if (passin) |
|
394 p8pass = passin; |
|
395 else |
|
396 { |
|
397 p8pass = pass; |
|
398 EVP_read_pw_string(pass, sizeof pass, "Enter Password:", 0); |
|
399 } |
|
400 p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass)); |
|
401 X509_SIG_free(p8); |
|
402 } |
|
403 |
|
404 if (!p8inf) |
|
405 { |
|
406 BIO_printf(bio_err, "Error decrypting key\n"); |
|
407 ERR_print_errors(bio_err); |
|
408 return (1); |
|
409 } |
|
410 |
|
411 if (!(pkey = EVP_PKCS82PKEY(p8inf))) |
|
412 { |
|
413 BIO_printf(bio_err, "Error converting key\n"); |
|
414 ERR_print_errors(bio_err); |
|
415 return (1); |
|
416 } |
|
417 |
|
418 if (p8inf->broken) |
|
419 { |
|
420 BIO_printf(bio_err, "Warning: broken key encoding: "); |
|
421 switch (p8inf->broken) |
|
422 { |
|
423 case PKCS8_NO_OCTET: |
|
424 BIO_printf(bio_err, "No Octet String in PrivateKey\n"); |
|
425 break; |
|
426 |
|
427 case PKCS8_EMBEDDED_PARAM: |
|
428 BIO_printf(bio_err, "DSA parameters included in PrivateKey\n"); |
|
429 break; |
|
430 |
|
431 case PKCS8_NS_DB: |
|
432 BIO_printf(bio_err, "DSA public key include in PrivateKey\n"); |
|
433 break; |
|
434 |
|
435 default: |
|
436 BIO_printf(bio_err, "Unknown broken type\n"); |
|
437 break; |
|
438 } |
|
439 } |
|
440 |
|
441 PKCS8_PRIV_KEY_INFO_free(p8inf); |
|
442 if (outformat == FORMAT_PEM) |
|
443 PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout); |
|
444 else if (outformat == FORMAT_ASN1) |
|
445 i2d_PrivateKey_bio(out, pkey); |
|
446 else |
|
447 { |
|
448 BIO_printf(bio_err, "Bad format specified for key\n"); |
|
449 return (1); |
|
450 } |
|
451 |
|
452 end: |
|
453 EVP_PKEY_free(pkey); |
|
454 BIO_free_all(out); |
|
455 BIO_free(in); |
|
456 if (passin) |
|
457 OPENSSL_free(passin); |
|
458 if (passout) |
|
459 OPENSSL_free(passout); |
|
460 |
|
461 return (0); |
|
462 } |