xref: /freebsd/crypto/openssl/apps/pkcs8.c (revision 1f4bcc459a76b7aa664f3fd557684cd0ba6da352)
1 /* pkcs8.c */
2 /*
3  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4  * 1999-2004.
5  */
6 /* ====================================================================
7  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. All advertising materials mentioning features or use of this
22  *    software must display the following acknowledgment:
23  *    "This product includes software developed by the OpenSSL Project
24  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25  *
26  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27  *    endorse or promote products derived from this software without
28  *    prior written permission. For written permission, please contact
29  *    licensing@OpenSSL.org.
30  *
31  * 5. Products derived from this software may not be called "OpenSSL"
32  *    nor may "OpenSSL" appear in their names without prior written
33  *    permission of the OpenSSL Project.
34  *
35  * 6. Redistributions of any form whatsoever must retain the following
36  *    acknowledgment:
37  *    "This product includes software developed by the OpenSSL Project
38  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51  * OF THE POSSIBILITY OF SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This product includes cryptographic software written by Eric Young
55  * (eay@cryptsoft.com).  This product includes software written by Tim
56  * Hudson (tjh@cryptsoft.com).
57  *
58  */
59 #include <stdio.h>
60 #include <string.h>
61 #include "apps.h"
62 #include <openssl/pem.h>
63 #include <openssl/err.h>
64 #include <openssl/evp.h>
65 #include <openssl/pkcs12.h>
66 
67 #define PROG pkcs8_main
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 = NULL;
85     PKCS8_PRIV_KEY_INFO *p8inf = NULL;
86     EVP_PKEY *pkey = NULL;
87     char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL;
88     int badarg = 0;
89     int ret = 1;
90 #ifndef OPENSSL_NO_ENGINE
91     char *engine = NULL;
92 #endif
93 
94     if (bio_err == NULL)
95         bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
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         if (!strcmp(*args, "-v2")) {
108             if (args[1]) {
109                 args++;
110                 cipher = EVP_get_cipherbyname(*args);
111                 if (!cipher) {
112                     BIO_printf(bio_err, "Unknown cipher %s\n", *args);
113                     badarg = 1;
114                 }
115             } else
116                 badarg = 1;
117         } else if (!strcmp(*args, "-v1")) {
118             if (args[1]) {
119                 args++;
120                 pbe_nid = OBJ_txt2nid(*args);
121                 if (pbe_nid == NID_undef) {
122                     BIO_printf(bio_err, "Unknown PBE algorithm %s\n", *args);
123                     badarg = 1;
124                 }
125             } else
126                 badarg = 1;
127         } else if (!strcmp(*args, "-v2prf")) {
128             if (args[1]) {
129                 args++;
130                 pbe_nid = OBJ_txt2nid(*args);
131                 if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, pbe_nid, NULL, NULL, 0)) {
132                     BIO_printf(bio_err, "Unknown PRF algorithm %s\n", *args);
133                     badarg = 1;
134                 }
135             } else
136                 badarg = 1;
137         } else if (!strcmp(*args, "-inform")) {
138             if (args[1]) {
139                 args++;
140                 informat = str2fmt(*args);
141             } else
142                 badarg = 1;
143         } else if (!strcmp(*args, "-outform")) {
144             if (args[1]) {
145                 args++;
146                 outformat = str2fmt(*args);
147             } else
148                 badarg = 1;
149         } else if (!strcmp(*args, "-topk8"))
150             topk8 = 1;
151         else if (!strcmp(*args, "-noiter"))
152             iter = 1;
153         else if (!strcmp(*args, "-nocrypt"))
154             nocrypt = 1;
155         else if (!strcmp(*args, "-nooct"))
156             p8_broken = PKCS8_NO_OCTET;
157         else if (!strcmp(*args, "-nsdb"))
158             p8_broken = PKCS8_NS_DB;
159         else if (!strcmp(*args, "-embed"))
160             p8_broken = PKCS8_EMBEDDED_PARAM;
161         else if (!strcmp(*args, "-passin")) {
162             if (!args[1])
163                 goto bad;
164             passargin = *(++args);
165         } else if (!strcmp(*args, "-passout")) {
166             if (!args[1])
167                 goto bad;
168             passargout = *(++args);
169         }
170 #ifndef OPENSSL_NO_ENGINE
171         else if (strcmp(*args, "-engine") == 0) {
172             if (!args[1])
173                 goto bad;
174             engine = *(++args);
175         }
176 #endif
177         else if (!strcmp(*args, "-in")) {
178             if (args[1]) {
179                 args++;
180                 infile = *args;
181             } else
182                 badarg = 1;
183         } else if (!strcmp(*args, "-out")) {
184             if (args[1]) {
185                 args++;
186                 outfile = *args;
187             } else
188                 badarg = 1;
189         } else
190             badarg = 1;
191         args++;
192     }
193 
194     if (badarg) {
195  bad:
196         BIO_printf(bio_err, "Usage pkcs8 [options]\n");
197         BIO_printf(bio_err, "where options are\n");
198         BIO_printf(bio_err, "-in file        input file\n");
199         BIO_printf(bio_err, "-inform X       input format (DER or PEM)\n");
200         BIO_printf(bio_err,
201                    "-passin arg     input file pass phrase source\n");
202         BIO_printf(bio_err, "-outform X      output format (DER or PEM)\n");
203         BIO_printf(bio_err, "-out file       output file\n");
204         BIO_printf(bio_err,
205                    "-passout arg    output file pass phrase source\n");
206         BIO_printf(bio_err, "-topk8          output PKCS8 file\n");
207         BIO_printf(bio_err,
208                    "-nooct          use (nonstandard) no octet format\n");
209         BIO_printf(bio_err,
210                    "-embed          use (nonstandard) embedded DSA parameters format\n");
211         BIO_printf(bio_err,
212                    "-nsdb           use (nonstandard) DSA Netscape DB format\n");
213         BIO_printf(bio_err, "-noiter         use 1 as iteration count\n");
214         BIO_printf(bio_err,
215                    "-nocrypt        use or expect unencrypted private key\n");
216         BIO_printf(bio_err,
217                    "-v2 alg         use PKCS#5 v2.0 and cipher \"alg\"\n");
218         BIO_printf(bio_err,
219                    "-v1 obj         use PKCS#5 v1.5 and cipher \"alg\"\n");
220 #ifndef OPENSSL_NO_ENGINE
221         BIO_printf(bio_err,
222                    " -engine e       use engine e, possibly a hardware device.\n");
223 #endif
224         goto end;
225     }
226 #ifndef OPENSSL_NO_ENGINE
227     e = setup_engine(bio_err, engine, 0);
228 #endif
229 
230     if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) {
231         BIO_printf(bio_err, "Error getting passwords\n");
232         goto end;
233     }
234 
235     if ((pbe_nid == -1) && !cipher)
236         pbe_nid = NID_pbeWithMD5AndDES_CBC;
237 
238     if (infile) {
239         if (!(in = BIO_new_file(infile, "rb"))) {
240             BIO_printf(bio_err, "Can't open input file %s\n", infile);
241             goto end;
242         }
243     } else
244         in = BIO_new_fp(stdin, BIO_NOCLOSE);
245 
246     if (outfile) {
247         if (!(out = BIO_new_file(outfile, "wb"))) {
248             BIO_printf(bio_err, "Can't open output file %s\n", outfile);
249             goto end;
250         }
251     } else {
252         out = BIO_new_fp(stdout, BIO_NOCLOSE);
253 #ifdef OPENSSL_SYS_VMS
254         {
255             BIO *tmpbio = BIO_new(BIO_f_linebuffer());
256             out = BIO_push(tmpbio, out);
257         }
258 #endif
259     }
260     if (topk8) {
261         pkey = load_key(bio_err, infile, informat, 1, passin, e, "key");
262         if (!pkey)
263             goto end;
264         if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, p8_broken))) {
265             BIO_printf(bio_err, "Error converting key\n");
266             ERR_print_errors(bio_err);
267             goto end;
268         }
269         if (nocrypt) {
270             if (outformat == FORMAT_PEM)
271                 PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf);
272             else if (outformat == FORMAT_ASN1)
273                 i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf);
274             else {
275                 BIO_printf(bio_err, "Bad format specified for key\n");
276                 goto end;
277             }
278         } else {
279             if (passout)
280                 p8pass = passout;
281             else {
282                 p8pass = pass;
283                 if (EVP_read_pw_string
284                     (pass, sizeof pass, "Enter Encryption Password:", 1))
285                     goto end;
286             }
287             app_RAND_load_file(NULL, bio_err, 0);
288             if (!(p8 = PKCS8_encrypt(pbe_nid, cipher,
289                                      p8pass, strlen(p8pass),
290                                      NULL, 0, iter, p8inf))) {
291                 BIO_printf(bio_err, "Error encrypting key\n");
292                 ERR_print_errors(bio_err);
293                 goto end;
294             }
295             app_RAND_write_file(NULL, bio_err);
296             if (outformat == FORMAT_PEM)
297                 PEM_write_bio_PKCS8(out, p8);
298             else if (outformat == FORMAT_ASN1)
299                 i2d_PKCS8_bio(out, p8);
300             else {
301                 BIO_printf(bio_err, "Bad format specified for key\n");
302                 goto end;
303             }
304         }
305 
306         ret = 0;
307         goto end;
308     }
309 
310     if (nocrypt) {
311         if (informat == FORMAT_PEM)
312             p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL);
313         else if (informat == FORMAT_ASN1)
314             p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL);
315         else {
316             BIO_printf(bio_err, "Bad format specified for key\n");
317             goto end;
318         }
319     } else {
320         if (informat == FORMAT_PEM)
321             p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL);
322         else if (informat == FORMAT_ASN1)
323             p8 = d2i_PKCS8_bio(in, NULL);
324         else {
325             BIO_printf(bio_err, "Bad format specified for key\n");
326             goto end;
327         }
328 
329         if (!p8) {
330             BIO_printf(bio_err, "Error reading key\n");
331             ERR_print_errors(bio_err);
332             goto end;
333         }
334         if (passin)
335             p8pass = passin;
336         else {
337             p8pass = pass;
338             EVP_read_pw_string(pass, sizeof pass, "Enter Password:", 0);
339         }
340         p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass));
341     }
342 
343     if (!p8inf) {
344         BIO_printf(bio_err, "Error decrypting key\n");
345         ERR_print_errors(bio_err);
346         goto end;
347     }
348 
349     if (!(pkey = EVP_PKCS82PKEY(p8inf))) {
350         BIO_printf(bio_err, "Error converting key\n");
351         ERR_print_errors(bio_err);
352         goto end;
353     }
354 
355     if (p8inf->broken) {
356         BIO_printf(bio_err, "Warning: broken key encoding: ");
357         switch (p8inf->broken) {
358         case PKCS8_NO_OCTET:
359             BIO_printf(bio_err, "No Octet String in PrivateKey\n");
360             break;
361 
362         case PKCS8_EMBEDDED_PARAM:
363             BIO_printf(bio_err, "DSA parameters included in PrivateKey\n");
364             break;
365 
366         case PKCS8_NS_DB:
367             BIO_printf(bio_err, "DSA public key include in PrivateKey\n");
368             break;
369 
370         case PKCS8_NEG_PRIVKEY:
371             BIO_printf(bio_err, "DSA private key value is negative\n");
372             break;
373 
374         default:
375             BIO_printf(bio_err, "Unknown broken type\n");
376             break;
377         }
378     }
379 
380     if (outformat == FORMAT_PEM)
381         PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout);
382     else if (outformat == FORMAT_ASN1)
383         i2d_PrivateKey_bio(out, pkey);
384     else {
385         BIO_printf(bio_err, "Bad format specified for key\n");
386         goto end;
387     }
388     ret = 0;
389 
390  end:
391     X509_SIG_free(p8);
392     PKCS8_PRIV_KEY_INFO_free(p8inf);
393     EVP_PKEY_free(pkey);
394     BIO_free_all(out);
395     BIO_free(in);
396     if (passin)
397         OPENSSL_free(passin);
398     if (passout)
399         OPENSSL_free(passout);
400 
401     return ret;
402 }
403