Import LibreSSL v2.4.2 to vendor branch
[dragonfly.git] / crypto / libressl / apps / openssl / genpkey.c
1 /* $OpenBSD: genpkey.c,v 1.7 2015/10/17 07:51:10 semarie Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 2006
4  */
5 /* ====================================================================
6  * Copyright (c) 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 <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
68 static int
69 init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx, const char *file);
70 static int genpkey_cb(EVP_PKEY_CTX * ctx);
71
72 int
73 genpkey_main(int argc, char **argv)
74 {
75         char **args, *outfile = NULL;
76         char *passarg = NULL;
77         BIO *in = NULL, *out = NULL;
78         const EVP_CIPHER *cipher = NULL;
79         int outformat;
80         int text = 0;
81         EVP_PKEY *pkey = NULL;
82         EVP_PKEY_CTX *ctx = NULL;
83         char *pass = NULL;
84         int badarg = 0;
85         int ret = 1, rv;
86
87         int do_param = 0;
88
89         if (single_execution) {
90                 if (pledge("stdio rpath wpath cpath tty", NULL) == -1) {
91                         perror("pledge");
92                         exit(1);
93                 }
94         }
95
96         outformat = FORMAT_PEM;
97
98         args = argv + 1;
99         while (!badarg && *args && *args[0] == '-') {
100                 if (!strcmp(*args, "-outform")) {
101                         if (args[1]) {
102                                 args++;
103                                 outformat = str2fmt(*args);
104                         } else
105                                 badarg = 1;
106                 } else if (!strcmp(*args, "-pass")) {
107                         if (!args[1])
108                                 goto bad;
109                         passarg = *(++args);
110                 }
111                 else if (!strcmp(*args, "-paramfile")) {
112                         if (!args[1])
113                                 goto bad;
114                         args++;
115                         if (do_param == 1)
116                                 goto bad;
117                         if (!init_keygen_file(bio_err, &ctx, *args))
118                                 goto end;
119                 } else if (!strcmp(*args, "-out")) {
120                         if (args[1]) {
121                                 args++;
122                                 outfile = *args;
123                         } else
124                                 badarg = 1;
125                 } else if (strcmp(*args, "-algorithm") == 0) {
126                         if (!args[1])
127                                 goto bad;
128                         if (!init_gen_str(bio_err, &ctx, *(++args), do_param))
129                                 goto end;
130                 } else if (strcmp(*args, "-pkeyopt") == 0) {
131                         if (!args[1])
132                                 goto bad;
133                         if (!ctx) {
134                                 BIO_puts(bio_err, "No keytype specified\n");
135                                 goto bad;
136                         } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) {
137                                 BIO_puts(bio_err, "parameter setting error\n");
138                                 ERR_print_errors(bio_err);
139                                 goto end;
140                         }
141                 } else if (strcmp(*args, "-genparam") == 0) {
142                         if (ctx)
143                                 goto bad;
144                         do_param = 1;
145                 } else if (strcmp(*args, "-text") == 0)
146                         text = 1;
147                 else {
148                         cipher = EVP_get_cipherbyname(*args + 1);
149                         if (!cipher) {
150                                 BIO_printf(bio_err, "Unknown cipher %s\n",
151                                     *args + 1);
152                                 badarg = 1;
153                         }
154                         if (do_param == 1)
155                                 badarg = 1;
156                 }
157                 args++;
158         }
159
160         if (!ctx)
161                 badarg = 1;
162
163         if (badarg) {
164 bad:
165                 BIO_printf(bio_err, "Usage: genpkey [options]\n");
166                 BIO_printf(bio_err, "where options may be\n");
167                 BIO_printf(bio_err, "-out file          output file\n");
168                 BIO_printf(bio_err, "-outform X         output format (DER or PEM)\n");
169                 BIO_printf(bio_err, "-pass arg          output file pass phrase source\n");
170                 BIO_printf(bio_err, "-<cipher>          use cipher <cipher> to encrypt the key\n");
171                 BIO_printf(bio_err, "-paramfile file    parameters file\n");
172                 BIO_printf(bio_err, "-algorithm alg     the public key algorithm\n");
173                 BIO_printf(bio_err, "-pkeyopt opt:value set the public key algorithm option <opt>\n"
174                     "                   to value <value>\n");
175                 BIO_printf(bio_err, "-genparam          generate parameters, not key\n");
176                 BIO_printf(bio_err, "-text              print the in text\n");
177                 BIO_printf(bio_err, "NB: options order may be important!  See the manual page.\n");
178                 goto end;
179         }
180         if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) {
181                 BIO_puts(bio_err, "Error getting password\n");
182                 goto end;
183         }
184         if (outfile) {
185                 if (!(out = BIO_new_file(outfile, "wb"))) {
186                         BIO_printf(bio_err,
187                             "Can't open output file %s\n", outfile);
188                         goto end;
189                 }
190         } else {
191                 out = BIO_new_fp(stdout, BIO_NOCLOSE);
192         }
193
194         EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
195         EVP_PKEY_CTX_set_app_data(ctx, bio_err);
196
197         if (do_param) {
198                 if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) {
199                         BIO_puts(bio_err, "Error generating parameters\n");
200                         ERR_print_errors(bio_err);
201                         goto end;
202                 }
203         } else {
204                 if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
205                         BIO_puts(bio_err, "Error generating key\n");
206                         ERR_print_errors(bio_err);
207                         goto end;
208                 }
209         }
210
211         if (do_param)
212                 rv = PEM_write_bio_Parameters(out, pkey);
213         else if (outformat == FORMAT_PEM)
214                 rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0,
215                     NULL, pass);
216         else if (outformat == FORMAT_ASN1)
217                 rv = i2d_PrivateKey_bio(out, pkey);
218         else {
219                 BIO_printf(bio_err, "Bad format specified for key\n");
220                 goto end;
221         }
222
223         if (rv <= 0) {
224                 BIO_puts(bio_err, "Error writing key\n");
225                 ERR_print_errors(bio_err);
226         }
227         if (text) {
228                 if (do_param)
229                         rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
230                 else
231                         rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
232
233                 if (rv <= 0) {
234                         BIO_puts(bio_err, "Error printing key\n");
235                         ERR_print_errors(bio_err);
236                 }
237         }
238         ret = 0;
239
240 end:
241         if (pkey)
242                 EVP_PKEY_free(pkey);
243         if (ctx)
244                 EVP_PKEY_CTX_free(ctx);
245         if (out)
246                 BIO_free_all(out);
247         BIO_free(in);
248         free(pass);
249
250         return ret;
251 }
252
253 static int
254 init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx,
255     const char *file)
256 {
257         BIO *pbio;
258         EVP_PKEY *pkey = NULL;
259         EVP_PKEY_CTX *ctx = NULL;
260         if (*pctx) {
261                 BIO_puts(err, "Parameters already set!\n");
262                 return 0;
263         }
264         pbio = BIO_new_file(file, "r");
265         if (!pbio) {
266                 BIO_printf(err, "Can't open parameter file %s\n", file);
267                 return 0;
268         }
269         pkey = PEM_read_bio_Parameters(pbio, NULL);
270         BIO_free(pbio);
271
272         if (!pkey) {
273                 BIO_printf(bio_err, "Error reading parameter file %s\n", file);
274                 return 0;
275         }
276         ctx = EVP_PKEY_CTX_new(pkey, NULL);
277         if (!ctx)
278                 goto err;
279         if (EVP_PKEY_keygen_init(ctx) <= 0)
280                 goto err;
281         EVP_PKEY_free(pkey);
282         *pctx = ctx;
283         return 1;
284
285 err:
286         BIO_puts(err, "Error initializing context\n");
287         ERR_print_errors(err);
288         if (ctx)
289                 EVP_PKEY_CTX_free(ctx);
290         if (pkey)
291                 EVP_PKEY_free(pkey);
292         return 0;
293
294 }
295
296 int
297 init_gen_str(BIO * err, EVP_PKEY_CTX ** pctx,
298     const char *algname, int do_param)
299 {
300         EVP_PKEY_CTX *ctx = NULL;
301         const EVP_PKEY_ASN1_METHOD *ameth;
302         int pkey_id;
303
304         if (*pctx) {
305                 BIO_puts(err, "Algorithm already set!\n");
306                 return 0;
307         }
308         ameth = EVP_PKEY_asn1_find_str(NULL, algname, -1);
309
310         if (!ameth) {
311                 BIO_printf(bio_err, "Algorithm %s not found\n", algname);
312                 return 0;
313         }
314         ERR_clear_error();
315
316         EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
317         ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL);
318
319         if (!ctx)
320                 goto err;
321         if (do_param) {
322                 if (EVP_PKEY_paramgen_init(ctx) <= 0)
323                         goto err;
324         } else {
325                 if (EVP_PKEY_keygen_init(ctx) <= 0)
326                         goto err;
327         }
328
329         *pctx = ctx;
330         return 1;
331
332 err:
333         BIO_printf(err, "Error initializing %s context\n", algname);
334         ERR_print_errors(err);
335         if (ctx)
336                 EVP_PKEY_CTX_free(ctx);
337         return 0;
338
339 }
340
341 static int
342 genpkey_cb(EVP_PKEY_CTX * ctx)
343 {
344         char c = '*';
345         BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
346         int p;
347         p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
348         if (p == 0)
349                 c = '.';
350         if (p == 1)
351                 c = '+';
352         if (p == 2)
353                 c = '*';
354         if (p == 3)
355                 c = '\n';
356         BIO_write(b, &c, 1);
357         (void) BIO_flush(b);
358         return 1;
359 }