xref: /openbsd/usr.bin/openssl/pkcs8.c (revision a6445c1d)
1 /* $OpenBSD: pkcs8.c,v 1.3 2014/08/28 14:25:48 jsing Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) 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 
59 #include <stdio.h>
60 #include <string.h>
61 
62 #include "apps.h"
63 
64 #include <openssl/err.h>
65 #include <openssl/evp.h>
66 #include <openssl/pem.h>
67 #include <openssl/pkcs12.h>
68 
69 int pkcs8_main(int, char **);
70 
71 int
72 pkcs8_main(int argc, char **argv)
73 {
74 	ENGINE *e = NULL;
75 	char **args, *infile = NULL, *outfile = NULL;
76 	char *passargin = NULL, *passargout = NULL;
77 	BIO *in = NULL, *out = NULL;
78 	int topk8 = 0;
79 	int pbe_nid = -1;
80 	const EVP_CIPHER *cipher = NULL;
81 	int iter = PKCS12_DEFAULT_ITER;
82 	int informat, outformat;
83 	int p8_broken = PKCS8_OK;
84 	int nocrypt = 0;
85 	X509_SIG *p8 = NULL;
86 	PKCS8_PRIV_KEY_INFO *p8inf = NULL;
87 	EVP_PKEY *pkey = NULL;
88 	char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL;
89 	int badarg = 0;
90 	int ret = 1;
91 #ifndef OPENSSL_NO_ENGINE
92 	char *engine = NULL;
93 #endif
94 
95 	informat = FORMAT_PEM;
96 	outformat = FORMAT_PEM;
97 
98 	args = argv + 1;
99 	while (!badarg && *args && *args[0] == '-') {
100 		if (!strcmp(*args, "-v2")) {
101 			if (args[1]) {
102 				args++;
103 				cipher = EVP_get_cipherbyname(*args);
104 				if (!cipher) {
105 					BIO_printf(bio_err,
106 					    "Unknown cipher %s\n", *args);
107 					badarg = 1;
108 				}
109 			} else
110 				badarg = 1;
111 		} else if (!strcmp(*args, "-v1")) {
112 			if (args[1]) {
113 				args++;
114 				pbe_nid = OBJ_txt2nid(*args);
115 				if (pbe_nid == NID_undef) {
116 					BIO_printf(bio_err,
117 					    "Unknown PBE algorithm %s\n", *args);
118 					badarg = 1;
119 				}
120 			} else
121 				badarg = 1;
122 		} else if (!strcmp(*args, "-inform")) {
123 			if (args[1]) {
124 				args++;
125 				informat = str2fmt(*args);
126 			} else
127 				badarg = 1;
128 		} else if (!strcmp(*args, "-outform")) {
129 			if (args[1]) {
130 				args++;
131 				outformat = str2fmt(*args);
132 			} else
133 				badarg = 1;
134 		} else if (!strcmp(*args, "-topk8"))
135 			topk8 = 1;
136 		else if (!strcmp(*args, "-noiter"))
137 			iter = 1;
138 		else if (!strcmp(*args, "-nocrypt"))
139 			nocrypt = 1;
140 		else if (!strcmp(*args, "-nooct"))
141 			p8_broken = PKCS8_NO_OCTET;
142 		else if (!strcmp(*args, "-nsdb"))
143 			p8_broken = PKCS8_NS_DB;
144 		else if (!strcmp(*args, "-embed"))
145 			p8_broken = PKCS8_EMBEDDED_PARAM;
146 		else if (!strcmp(*args, "-passin")) {
147 			if (!args[1])
148 				goto bad;
149 			passargin = *(++args);
150 		} else if (!strcmp(*args, "-passout")) {
151 			if (!args[1])
152 				goto bad;
153 			passargout = *(++args);
154 		}
155 #ifndef OPENSSL_NO_ENGINE
156 		else if (strcmp(*args, "-engine") == 0) {
157 			if (!args[1])
158 				goto bad;
159 			engine = *(++args);
160 		}
161 #endif
162 		else if (!strcmp(*args, "-in")) {
163 			if (args[1]) {
164 				args++;
165 				infile = *args;
166 			} else
167 				badarg = 1;
168 		} else if (!strcmp(*args, "-out")) {
169 			if (args[1]) {
170 				args++;
171 				outfile = *args;
172 			} else
173 				badarg = 1;
174 		} else
175 			badarg = 1;
176 		args++;
177 	}
178 
179 	if (badarg) {
180 bad:
181 		BIO_printf(bio_err, "Usage pkcs8 [options]\n");
182 		BIO_printf(bio_err, "where options are\n");
183 		BIO_printf(bio_err, "-in file        input file\n");
184 		BIO_printf(bio_err, "-inform X       input format (DER or PEM)\n");
185 		BIO_printf(bio_err, "-passin arg     input file pass phrase source\n");
186 		BIO_printf(bio_err, "-outform X      output format (DER or PEM)\n");
187 		BIO_printf(bio_err, "-out file       output file\n");
188 		BIO_printf(bio_err, "-passout arg    output file pass phrase source\n");
189 		BIO_printf(bio_err, "-topk8          output PKCS8 file\n");
190 		BIO_printf(bio_err, "-nooct          use (nonstandard) no octet format\n");
191 		BIO_printf(bio_err, "-embed          use (nonstandard) embedded DSA parameters format\n");
192 		BIO_printf(bio_err, "-nsdb           use (nonstandard) DSA Netscape DB format\n");
193 		BIO_printf(bio_err, "-noiter         use 1 as iteration count\n");
194 		BIO_printf(bio_err, "-nocrypt        use or expect unencrypted private key\n");
195 		BIO_printf(bio_err, "-v2 alg         use PKCS#5 v2.0 and cipher \"alg\"\n");
196 		BIO_printf(bio_err, "-v1 obj         use PKCS#5 v1.5 and cipher \"alg\"\n");
197 #ifndef OPENSSL_NO_ENGINE
198 		BIO_printf(bio_err, " -engine e       use engine e, possibly a hardware device.\n");
199 #endif
200 		goto end;
201 	}
202 #ifndef OPENSSL_NO_ENGINE
203 	e = setup_engine(bio_err, engine, 0);
204 #endif
205 
206 	if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) {
207 		BIO_printf(bio_err, "Error getting passwords\n");
208 		goto end;
209 	}
210 	if ((pbe_nid == -1) && !cipher)
211 		pbe_nid = NID_pbeWithMD5AndDES_CBC;
212 
213 	if (infile) {
214 		if (!(in = BIO_new_file(infile, "rb"))) {
215 			BIO_printf(bio_err,
216 			    "Can't open input file %s\n", infile);
217 			goto end;
218 		}
219 	} else
220 		in = BIO_new_fp(stdin, BIO_NOCLOSE);
221 
222 	if (outfile) {
223 		if (!(out = BIO_new_file(outfile, "wb"))) {
224 			BIO_printf(bio_err,
225 			    "Can't open output file %s\n", outfile);
226 			goto end;
227 		}
228 	} else {
229 		out = BIO_new_fp(stdout, BIO_NOCLOSE);
230 	}
231 	if (topk8) {
232 		pkey = load_key(bio_err, infile, informat, 1,
233 		    passin, e, "key");
234 		if (!pkey)
235 			goto end;
236 		if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, p8_broken))) {
237 			BIO_printf(bio_err, "Error converting key\n");
238 			ERR_print_errors(bio_err);
239 			goto end;
240 		}
241 		if (nocrypt) {
242 			if (outformat == FORMAT_PEM)
243 				PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf);
244 			else if (outformat == FORMAT_ASN1)
245 				i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf);
246 			else {
247 				BIO_printf(bio_err, "Bad format specified for key\n");
248 				goto end;
249 			}
250 		} else {
251 			if (passout)
252 				p8pass = passout;
253 			else {
254 				p8pass = pass;
255 				if (EVP_read_pw_string(pass, sizeof pass, "Enter Encryption Password:", 1))
256 					goto end;
257 			}
258 			if (!(p8 = PKCS8_encrypt(pbe_nid, cipher,
259 				    p8pass, strlen(p8pass),
260 				    NULL, 0, iter, p8inf))) {
261 				BIO_printf(bio_err, "Error encrypting key\n");
262 				ERR_print_errors(bio_err);
263 				goto end;
264 			}
265 			if (outformat == FORMAT_PEM)
266 				PEM_write_bio_PKCS8(out, p8);
267 			else if (outformat == FORMAT_ASN1)
268 				i2d_PKCS8_bio(out, p8);
269 			else {
270 				BIO_printf(bio_err, "Bad format specified for key\n");
271 				goto end;
272 			}
273 		}
274 
275 		ret = 0;
276 		goto end;
277 	}
278 	if (nocrypt) {
279 		if (informat == FORMAT_PEM)
280 			p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL);
281 		else if (informat == FORMAT_ASN1)
282 			p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL);
283 		else {
284 			BIO_printf(bio_err, "Bad format specified for key\n");
285 			goto end;
286 		}
287 	} else {
288 		if (informat == FORMAT_PEM)
289 			p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL);
290 		else if (informat == FORMAT_ASN1)
291 			p8 = d2i_PKCS8_bio(in, NULL);
292 		else {
293 			BIO_printf(bio_err, "Bad format specified for key\n");
294 			goto end;
295 		}
296 
297 		if (!p8) {
298 			BIO_printf(bio_err, "Error reading key\n");
299 			ERR_print_errors(bio_err);
300 			goto end;
301 		}
302 		if (passin)
303 			p8pass = passin;
304 		else {
305 			p8pass = pass;
306 			EVP_read_pw_string(pass, sizeof pass, "Enter Password:", 0);
307 		}
308 		p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass));
309 	}
310 
311 	if (!p8inf) {
312 		BIO_printf(bio_err, "Error decrypting key\n");
313 		ERR_print_errors(bio_err);
314 		goto end;
315 	}
316 	if (!(pkey = EVP_PKCS82PKEY(p8inf))) {
317 		BIO_printf(bio_err, "Error converting key\n");
318 		ERR_print_errors(bio_err);
319 		goto end;
320 	}
321 	if (p8inf->broken) {
322 		BIO_printf(bio_err, "Warning: broken key encoding: ");
323 		switch (p8inf->broken) {
324 		case PKCS8_NO_OCTET:
325 			BIO_printf(bio_err, "No Octet String in PrivateKey\n");
326 			break;
327 
328 		case PKCS8_EMBEDDED_PARAM:
329 			BIO_printf(bio_err, "DSA parameters included in PrivateKey\n");
330 			break;
331 
332 		case PKCS8_NS_DB:
333 			BIO_printf(bio_err, "DSA public key include in PrivateKey\n");
334 			break;
335 
336 		case PKCS8_NEG_PRIVKEY:
337 			BIO_printf(bio_err, "DSA private key value is negative\n");
338 			break;
339 
340 		default:
341 			BIO_printf(bio_err, "Unknown broken type\n");
342 			break;
343 		}
344 	}
345 	if (outformat == FORMAT_PEM)
346 		PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout);
347 	else if (outformat == FORMAT_ASN1)
348 		i2d_PrivateKey_bio(out, pkey);
349 	else {
350 		BIO_printf(bio_err, "Bad format specified for key\n");
351 		goto end;
352 	}
353 	ret = 0;
354 
355 end:
356 	X509_SIG_free(p8);
357 	PKCS8_PRIV_KEY_INFO_free(p8inf);
358 	EVP_PKEY_free(pkey);
359 	BIO_free_all(out);
360 	BIO_free(in);
361 	free(passin);
362 	free(passout);
363 
364 	return ret;
365 }
366