Initial keygen support.
[openssl.git] / apps / genpkey.c
1 /* apps/genpkey.c */
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) 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 #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
65 static int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
66                                 const char *file, ENGINE *e);
67 static int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
68                                 const char *algname, ENGINE *e, int do_param);
69 static int genpkey_cb(EVP_PKEY_CTX *ctx);
70
71 #define PROG genpkey_main
72
73 int MAIN(int, char **);
74
75 int MAIN(int argc, char **argv)
76         {
77         ENGINE *e = NULL;
78         char **args, *outfile = NULL;
79         char *passarg = NULL;
80         BIO *in = NULL, *out = NULL;
81         const EVP_CIPHER *cipher = NULL;
82         int outformat;
83         int text = 0;
84         EVP_PKEY *pkey=NULL;
85         EVP_PKEY_CTX *ctx = NULL;
86         char *pass = NULL;
87         int badarg = 0;
88         int ret = 1;
89
90         if (bio_err == NULL)
91                 bio_err = BIO_new_fp (stderr, BIO_NOCLOSE);
92
93         if (!load_config(bio_err, NULL))
94                 goto end;
95
96         outformat=FORMAT_PEM;
97
98         ERR_load_crypto_strings();
99         OpenSSL_add_all_algorithms();
100         args = argv + 1;
101         while (!badarg && *args && *args[0] == '-')
102                 {
103                 if (!strcmp(*args,"-outform"))
104                         {
105                         if (args[1])
106                                 {
107                                 args++;
108                                 outformat=str2fmt(*args);
109                                 }
110                         else badarg = 1;
111                         }
112                 else if (!strcmp(*args,"-pass"))
113                         {
114                         if (!args[1]) goto bad;
115                         passarg= *(++args);
116                         }
117 #ifndef OPENSSL_NO_ENGINE
118                 else if (strcmp(*args,"-engine") == 0)
119                         {
120                         if (!args[1])
121                                 goto bad;
122                         e = setup_engine(bio_err, *(++args), 0);
123                         }
124 #endif
125                 else if (!strcmp (*args, "-paramfile"))
126                         {
127                         if (!args[1])
128                                 goto bad;
129                         args++;
130                         if (!init_keygen_file(bio_err, &ctx, *args, e))
131                                 goto end;
132                         }
133                 else if (!strcmp (*args, "-out"))
134                         {
135                         if (args[1])
136                                 {
137                                 args++;
138                                 outfile = *args;
139                                 }
140                         else badarg = 1;
141                         }
142                 else if (strcmp(*args,"-algorithm") == 0)
143                         {
144                         if (!args[1])
145                                 goto bad;
146                         if (!init_gen_str(bio_err, &ctx, *(++args), e, 0))
147                                 goto end;
148                         }
149                 else if (strcmp(*args,"-param") == 0)
150                         {
151                         if (!args[1])
152                                 goto bad;
153                         if (!ctx)
154                                 {
155                                 BIO_puts(bio_err, "No keytype specified\n");
156                                 goto bad;
157                                 }
158                         else if (pkey_ctrl_string(ctx, *(++args)) <= 0)
159                                 {
160                                 BIO_puts(bio_err, "parameter setting error\n");
161                                 ERR_print_errors(bio_err);
162                                 goto end;
163                                 }
164                         }
165                 else if (strcmp(*args,"-text") == 0)
166                         text=1;
167                 else
168                         {
169                         cipher = EVP_get_cipherbyname(*args + 1);
170                         if (!cipher)
171                                 {
172                                 BIO_printf(bio_err, "Unknown cipher %s\n",
173                                                                 *args + 1);
174                                 badarg = 1;
175                                 }
176                         }
177                 args++;
178                 }
179
180         if (!ctx)
181                 badarg = 1;
182
183         if (badarg)
184                 {
185                 bad:
186                 BIO_printf(bio_err, "Usage genpkey [options]\n");
187                 BIO_printf(bio_err, "where options are\n");
188                 BIO_printf(bio_err, "-paramfile file parameter file\n");
189                 BIO_printf(bio_err, "-pass arg       output file pass phrase source\n");
190                 BIO_printf(bio_err, "-outform X      output format (DER or PEM)\n");
191                 BIO_printf(bio_err, "-out file       output file\n");
192 #ifndef OPENSSL_NO_ENGINE
193                 BIO_printf(bio_err, "-engine e       use engine e, possibly a hardware device.\n");
194 #endif
195                 return 1;
196                 }
197
198         if (!app_passwd(bio_err, passarg, NULL, &pass, NULL))
199                 {
200                 BIO_puts(bio_err, "Error getting password\n");
201                 goto end;
202                 }
203
204         if (outfile)
205                 {
206                 if (!(out = BIO_new_file (outfile, "wb")))
207                         {
208                         BIO_printf(bio_err,
209                                  "Can't open output file %s\n", outfile);
210                         goto end;
211                         }
212                 }
213         else
214                 {
215                 out = BIO_new_fp (stdout, BIO_NOCLOSE);
216 #ifdef OPENSSL_SYS_VMS
217                         {
218                         BIO *tmpbio = BIO_new(BIO_f_linebuffer());
219                         out = BIO_push(tmpbio, out);
220                         }
221 #endif
222                 }
223
224         EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
225         EVP_PKEY_CTX_set_app_data(ctx, bio_err);
226
227         if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
228                 {
229                 BIO_puts(bio_err, "Error generating key\n");
230                 goto end;
231                 }
232
233         if (outformat == FORMAT_PEM) 
234                 PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0,
235                                                                 NULL, pass);
236         else if (outformat == FORMAT_ASN1)
237                 i2d_PrivateKey_bio(out, pkey);
238         else
239                 {
240                 BIO_printf(bio_err, "Bad format specified for key\n");
241                 goto end;
242                 }
243
244
245         if (text)
246                 EVP_PKEY_print_private(out, pkey, 0, NULL);
247
248         ret = 0;
249
250         end:
251         if (pkey)
252                 EVP_PKEY_free(pkey);
253         if (ctx)
254                 EVP_PKEY_CTX_free(ctx);
255         if (out)
256                 BIO_free_all(out);
257         BIO_free(in);
258         if (pass)
259                 OPENSSL_free(pass);
260
261         return ret;
262         }
263
264 static int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
265                                 const char *file, ENGINE *e)
266         {
267         BIO *pbio;
268         EVP_PKEY *pkey = NULL;
269         EVP_PKEY_CTX *ctx = NULL;
270         if (*pctx)
271                 {
272                 BIO_puts(err, "Parameters already set!\n");
273                 return 0;
274                 }
275
276         pbio = BIO_new_file(file, "r");
277         if (!pbio)
278                 {
279                 BIO_printf(err, "Can't open parameter file %s\n", file);
280                 return 0;
281                 }
282
283         pkey = PEM_read_bio_Parameters(pbio, NULL);
284         BIO_free(pbio);
285
286         if (!pkey)
287                 {
288                 BIO_printf(bio_err, "Error reading parameter file %s\n", file);
289                 return 0;
290                 }
291
292         ctx = EVP_PKEY_CTX_new(pkey, e);
293         if (!ctx)
294                 goto err;
295         if (EVP_PKEY_keygen_init(ctx) <= 0)
296                 goto err;
297         EVP_PKEY_free(pkey);
298         *pctx = ctx;
299         return 1;
300
301         err:
302         BIO_puts(err, "Error initializing context\n");
303         ERR_print_errors(err);
304         if (ctx)
305                 EVP_PKEY_CTX_free(ctx);
306         if (pkey)
307                 EVP_PKEY_free(pkey);
308         return 0;
309
310         }
311
312 static int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
313                                 const char *algname, ENGINE *e, int do_param)
314         {
315         EVP_PKEY_CTX *ctx = NULL;
316         const EVP_PKEY_ASN1_METHOD *ameth;
317         int pkey_id;
318         if (*pctx)
319                 {
320                 BIO_puts(err, "Algorithm already set!\n");
321                 return 0;
322                 }
323
324         ameth = EVP_PKEY_asn1_find_str(algname, -1);
325         if (!ameth)
326                 {
327                 BIO_printf(bio_err, "Algorithm %s not found\n", algname);
328                 return 0;
329                 }
330
331         EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
332         ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
333
334         if (!ctx)
335                 goto err;
336         if (do_param)
337                 {
338                 if (EVP_PKEY_paramgen_init(ctx) <= 0)
339                         goto err;
340                 }
341         else
342                 {
343                 if (EVP_PKEY_keygen_init(ctx) <= 0)
344                         goto err;
345                 }
346
347         *pctx = ctx;
348         return 1;
349
350         err:
351         BIO_printf(err, "Error initializing %s context\n", algname);
352         ERR_print_errors(err);
353         if (ctx)
354                 EVP_PKEY_CTX_free(ctx);
355         return 0;
356
357         }
358
359 static int genpkey_cb(EVP_PKEY_CTX *ctx)
360         {
361         char c='*';
362         BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
363         int p;
364         p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
365         if (p == 0) c='.';
366         if (p == 1) c='+';
367         if (p == 2) c='*';
368         if (p == 3) c='\n';
369         BIO_write(b,&c,1);
370         (void)BIO_flush(b);
371 #ifdef LINT
372         p=n;
373 #endif
374         return 1;
375         }