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