1238384Sjkim/* apps/genpkey.c */
2238384Sjkim/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3238384Sjkim * project 2006
4238384Sjkim */
5238384Sjkim/* ====================================================================
6238384Sjkim * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7238384Sjkim *
8238384Sjkim * Redistribution and use in source and binary forms, with or without
9238384Sjkim * modification, are permitted provided that the following conditions
10238384Sjkim * are met:
11238384Sjkim *
12238384Sjkim * 1. Redistributions of source code must retain the above copyright
13238384Sjkim *    notice, this list of conditions and the following disclaimer.
14238384Sjkim *
15238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright
16238384Sjkim *    notice, this list of conditions and the following disclaimer in
17238384Sjkim *    the documentation and/or other materials provided with the
18238384Sjkim *    distribution.
19238384Sjkim *
20238384Sjkim * 3. All advertising materials mentioning features or use of this
21238384Sjkim *    software must display the following acknowledgment:
22238384Sjkim *    "This product includes software developed by the OpenSSL Project
23238384Sjkim *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24238384Sjkim *
25238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26238384Sjkim *    endorse or promote products derived from this software without
27238384Sjkim *    prior written permission. For written permission, please contact
28238384Sjkim *    licensing@OpenSSL.org.
29238384Sjkim *
30238384Sjkim * 5. Products derived from this software may not be called "OpenSSL"
31238384Sjkim *    nor may "OpenSSL" appear in their names without prior written
32238384Sjkim *    permission of the OpenSSL Project.
33238384Sjkim *
34238384Sjkim * 6. Redistributions of any form whatsoever must retain the following
35238384Sjkim *    acknowledgment:
36238384Sjkim *    "This product includes software developed by the OpenSSL Project
37238384Sjkim *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38238384Sjkim *
39238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42238384Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE.
51238384Sjkim * ====================================================================
52238384Sjkim *
53238384Sjkim * This product includes cryptographic software written by Eric Young
54238384Sjkim * (eay@cryptsoft.com).  This product includes software written by Tim
55238384Sjkim * Hudson (tjh@cryptsoft.com).
56238384Sjkim *
57238384Sjkim */
58238384Sjkim#include <stdio.h>
59238384Sjkim#include <string.h>
60238384Sjkim#include "apps.h"
61238384Sjkim#include <openssl/pem.h>
62238384Sjkim#include <openssl/err.h>
63238384Sjkim#include <openssl/evp.h>
64238384Sjkim#ifndef OPENSSL_NO_ENGINE
65238384Sjkim#include <openssl/engine.h>
66238384Sjkim#endif
67238384Sjkim
68238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
69238384Sjkim				const char *file, ENGINE *e);
70238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx);
71238384Sjkim
72238384Sjkim#define PROG genpkey_main
73238384Sjkim
74238384Sjkimint MAIN(int, char **);
75238384Sjkim
76238384Sjkimint MAIN(int argc, char **argv)
77238384Sjkim	{
78238384Sjkim	ENGINE *e = NULL;
79238384Sjkim	char **args, *outfile = NULL;
80238384Sjkim	char *passarg = NULL;
81238384Sjkim	BIO *in = NULL, *out = NULL;
82238384Sjkim	const EVP_CIPHER *cipher = NULL;
83238384Sjkim	int outformat;
84238384Sjkim	int text = 0;
85238384Sjkim	EVP_PKEY *pkey=NULL;
86238384Sjkim	EVP_PKEY_CTX *ctx = NULL;
87238384Sjkim	char *pass = NULL;
88238384Sjkim	int badarg = 0;
89238384Sjkim	int ret = 1, rv;
90238384Sjkim
91238384Sjkim	int do_param = 0;
92238384Sjkim
93238384Sjkim	if (bio_err == NULL)
94238384Sjkim		bio_err = BIO_new_fp (stderr, BIO_NOCLOSE);
95238384Sjkim
96238384Sjkim	if (!load_config(bio_err, NULL))
97238384Sjkim		goto end;
98238384Sjkim
99238384Sjkim	outformat=FORMAT_PEM;
100238384Sjkim
101238384Sjkim	ERR_load_crypto_strings();
102238384Sjkim	OpenSSL_add_all_algorithms();
103238384Sjkim	args = argv + 1;
104238384Sjkim	while (!badarg && *args && *args[0] == '-')
105238384Sjkim		{
106238384Sjkim		if (!strcmp(*args,"-outform"))
107238384Sjkim			{
108238384Sjkim			if (args[1])
109238384Sjkim				{
110238384Sjkim				args++;
111238384Sjkim				outformat=str2fmt(*args);
112238384Sjkim				}
113238384Sjkim			else badarg = 1;
114238384Sjkim			}
115238384Sjkim		else if (!strcmp(*args,"-pass"))
116238384Sjkim			{
117238384Sjkim			if (!args[1]) goto bad;
118238384Sjkim			passarg= *(++args);
119238384Sjkim			}
120238384Sjkim#ifndef OPENSSL_NO_ENGINE
121238384Sjkim		else if (strcmp(*args,"-engine") == 0)
122238384Sjkim			{
123238384Sjkim			if (!args[1])
124238384Sjkim				goto bad;
125238384Sjkim        		e = setup_engine(bio_err, *(++args), 0);
126238384Sjkim			}
127238384Sjkim#endif
128238384Sjkim		else if (!strcmp (*args, "-paramfile"))
129238384Sjkim			{
130238384Sjkim			if (!args[1])
131238384Sjkim				goto bad;
132238384Sjkim			args++;
133238384Sjkim			if (do_param == 1)
134238384Sjkim				goto bad;
135238384Sjkim			if (!init_keygen_file(bio_err, &ctx, *args, e))
136238384Sjkim				goto end;
137238384Sjkim			}
138238384Sjkim		else if (!strcmp (*args, "-out"))
139238384Sjkim			{
140238384Sjkim			if (args[1])
141238384Sjkim				{
142238384Sjkim				args++;
143238384Sjkim				outfile = *args;
144238384Sjkim				}
145238384Sjkim			else badarg = 1;
146238384Sjkim			}
147238384Sjkim		else if (strcmp(*args,"-algorithm") == 0)
148238384Sjkim			{
149238384Sjkim			if (!args[1])
150238384Sjkim				goto bad;
151238384Sjkim			if (!init_gen_str(bio_err, &ctx, *(++args),e, do_param))
152238384Sjkim				goto end;
153238384Sjkim			}
154238384Sjkim		else if (strcmp(*args,"-pkeyopt") == 0)
155238384Sjkim			{
156238384Sjkim			if (!args[1])
157238384Sjkim				goto bad;
158238384Sjkim			if (!ctx)
159238384Sjkim				{
160238384Sjkim				BIO_puts(bio_err, "No keytype specified\n");
161238384Sjkim				goto bad;
162238384Sjkim				}
163238384Sjkim			else if (pkey_ctrl_string(ctx, *(++args)) <= 0)
164238384Sjkim				{
165238384Sjkim				BIO_puts(bio_err, "parameter setting error\n");
166238384Sjkim				ERR_print_errors(bio_err);
167238384Sjkim				goto end;
168238384Sjkim				}
169238384Sjkim			}
170238384Sjkim		else if (strcmp(*args,"-genparam") == 0)
171238384Sjkim			{
172238384Sjkim			if (ctx)
173238384Sjkim				goto bad;
174238384Sjkim			do_param = 1;
175238384Sjkim			}
176238384Sjkim		else if (strcmp(*args,"-text") == 0)
177238384Sjkim			text=1;
178238384Sjkim		else
179238384Sjkim			{
180238384Sjkim			cipher = EVP_get_cipherbyname(*args + 1);
181238384Sjkim			if (!cipher)
182238384Sjkim				{
183238384Sjkim				BIO_printf(bio_err, "Unknown cipher %s\n",
184238384Sjkim								*args + 1);
185238384Sjkim				badarg = 1;
186238384Sjkim				}
187238384Sjkim			if (do_param == 1)
188238384Sjkim				badarg = 1;
189238384Sjkim			}
190238384Sjkim		args++;
191238384Sjkim		}
192238384Sjkim
193238384Sjkim	if (!ctx)
194238384Sjkim		badarg = 1;
195238384Sjkim
196238384Sjkim	if (badarg)
197238384Sjkim		{
198238384Sjkim		bad:
199238384Sjkim		BIO_printf(bio_err, "Usage: genpkey [options]\n");
200238384Sjkim		BIO_printf(bio_err, "where options may be\n");
201238384Sjkim		BIO_printf(bio_err, "-out file          output file\n");
202238384Sjkim		BIO_printf(bio_err, "-outform X         output format (DER or PEM)\n");
203238384Sjkim		BIO_printf(bio_err, "-pass arg          output file pass phrase source\n");
204238384Sjkim		BIO_printf(bio_err, "-<cipher>          use cipher <cipher> to encrypt the key\n");
205238384Sjkim#ifndef OPENSSL_NO_ENGINE
206238384Sjkim		BIO_printf(bio_err, "-engine e          use engine e, possibly a hardware device.\n");
207238384Sjkim#endif
208238384Sjkim		BIO_printf(bio_err, "-paramfile file    parameters file\n");
209238384Sjkim		BIO_printf(bio_err, "-algorithm alg     the public key algorithm\n");
210238384Sjkim		BIO_printf(bio_err, "-pkeyopt opt:value set the public key algorithm option <opt>\n"
211238384Sjkim				            "                   to value <value>\n");
212238384Sjkim		BIO_printf(bio_err, "-genparam          generate parameters, not key\n");
213238384Sjkim		BIO_printf(bio_err, "-text              print the in text\n");
214238384Sjkim		BIO_printf(bio_err, "NB: options order may be important!  See the manual page.\n");
215238384Sjkim		goto end;
216238384Sjkim		}
217238384Sjkim
218238384Sjkim	if (!app_passwd(bio_err, passarg, NULL, &pass, NULL))
219238384Sjkim		{
220238384Sjkim		BIO_puts(bio_err, "Error getting password\n");
221238384Sjkim		goto end;
222238384Sjkim		}
223238384Sjkim
224238384Sjkim	if (outfile)
225238384Sjkim		{
226238384Sjkim		if (!(out = BIO_new_file (outfile, "wb")))
227238384Sjkim			{
228238384Sjkim			BIO_printf(bio_err,
229238384Sjkim				 "Can't open output file %s\n", outfile);
230238384Sjkim			goto end;
231238384Sjkim			}
232238384Sjkim		}
233238384Sjkim	else
234238384Sjkim		{
235238384Sjkim		out = BIO_new_fp (stdout, BIO_NOCLOSE);
236238384Sjkim#ifdef OPENSSL_SYS_VMS
237238384Sjkim			{
238238384Sjkim			BIO *tmpbio = BIO_new(BIO_f_linebuffer());
239238384Sjkim			out = BIO_push(tmpbio, out);
240238384Sjkim			}
241238384Sjkim#endif
242238384Sjkim		}
243238384Sjkim
244238384Sjkim	EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
245238384Sjkim	EVP_PKEY_CTX_set_app_data(ctx, bio_err);
246238384Sjkim
247238384Sjkim	if (do_param)
248238384Sjkim		{
249238384Sjkim		if (EVP_PKEY_paramgen(ctx, &pkey) <= 0)
250238384Sjkim			{
251238384Sjkim			BIO_puts(bio_err, "Error generating parameters\n");
252238384Sjkim			ERR_print_errors(bio_err);
253238384Sjkim			goto end;
254238384Sjkim			}
255238384Sjkim		}
256238384Sjkim	else
257238384Sjkim		{
258238384Sjkim		if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
259238384Sjkim			{
260238384Sjkim			BIO_puts(bio_err, "Error generating key\n");
261238384Sjkim			ERR_print_errors(bio_err);
262238384Sjkim			goto end;
263238384Sjkim			}
264238384Sjkim		}
265238384Sjkim
266238384Sjkim	if (do_param)
267238384Sjkim		rv = PEM_write_bio_Parameters(out, pkey);
268238384Sjkim	else if (outformat == FORMAT_PEM)
269238384Sjkim		rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0,
270238384Sjkim								NULL, pass);
271238384Sjkim	else if (outformat == FORMAT_ASN1)
272238384Sjkim		rv = i2d_PrivateKey_bio(out, pkey);
273238384Sjkim	else
274238384Sjkim		{
275238384Sjkim		BIO_printf(bio_err, "Bad format specified for key\n");
276238384Sjkim		goto end;
277238384Sjkim		}
278238384Sjkim
279238384Sjkim	if (rv <= 0)
280238384Sjkim		{
281238384Sjkim		BIO_puts(bio_err, "Error writing key\n");
282238384Sjkim		ERR_print_errors(bio_err);
283238384Sjkim		}
284238384Sjkim
285238384Sjkim	if (text)
286238384Sjkim		{
287238384Sjkim		if (do_param)
288238384Sjkim			rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
289238384Sjkim		else
290238384Sjkim			rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
291238384Sjkim
292238384Sjkim		if (rv <= 0)
293238384Sjkim			{
294238384Sjkim			BIO_puts(bio_err, "Error printing key\n");
295238384Sjkim			ERR_print_errors(bio_err);
296238384Sjkim			}
297238384Sjkim		}
298238384Sjkim
299238384Sjkim	ret = 0;
300238384Sjkim
301238384Sjkim	end:
302238384Sjkim	if (pkey)
303238384Sjkim		EVP_PKEY_free(pkey);
304238384Sjkim	if (ctx)
305238384Sjkim		EVP_PKEY_CTX_free(ctx);
306238384Sjkim	if (out)
307238384Sjkim		BIO_free_all(out);
308238384Sjkim	BIO_free(in);
309238384Sjkim	if (pass)
310238384Sjkim		OPENSSL_free(pass);
311238384Sjkim
312238384Sjkim	return ret;
313238384Sjkim	}
314238384Sjkim
315238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
316238384Sjkim				const char *file, ENGINE *e)
317238384Sjkim	{
318238384Sjkim	BIO *pbio;
319238384Sjkim	EVP_PKEY *pkey = NULL;
320238384Sjkim	EVP_PKEY_CTX *ctx = NULL;
321238384Sjkim	if (*pctx)
322238384Sjkim		{
323238384Sjkim		BIO_puts(err, "Parameters already set!\n");
324238384Sjkim		return 0;
325238384Sjkim		}
326238384Sjkim
327238384Sjkim	pbio = BIO_new_file(file, "r");
328238384Sjkim	if (!pbio)
329238384Sjkim		{
330238384Sjkim		BIO_printf(err, "Can't open parameter file %s\n", file);
331238384Sjkim		return 0;
332238384Sjkim		}
333238384Sjkim
334238384Sjkim	pkey = PEM_read_bio_Parameters(pbio, NULL);
335238384Sjkim	BIO_free(pbio);
336238384Sjkim
337238384Sjkim	if (!pkey)
338238384Sjkim		{
339238384Sjkim		BIO_printf(bio_err, "Error reading parameter file %s\n", file);
340238384Sjkim		return 0;
341238384Sjkim		}
342238384Sjkim
343238384Sjkim	ctx = EVP_PKEY_CTX_new(pkey, e);
344238384Sjkim	if (!ctx)
345238384Sjkim		goto err;
346238384Sjkim	if (EVP_PKEY_keygen_init(ctx) <= 0)
347238384Sjkim		goto err;
348238384Sjkim	EVP_PKEY_free(pkey);
349238384Sjkim	*pctx = ctx;
350238384Sjkim	return 1;
351238384Sjkim
352238384Sjkim	err:
353238384Sjkim	BIO_puts(err, "Error initializing context\n");
354238384Sjkim	ERR_print_errors(err);
355238384Sjkim	if (ctx)
356238384Sjkim		EVP_PKEY_CTX_free(ctx);
357238384Sjkim	if (pkey)
358238384Sjkim		EVP_PKEY_free(pkey);
359238384Sjkim	return 0;
360238384Sjkim
361238384Sjkim	}
362238384Sjkim
363238384Sjkimint init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
364238384Sjkim			const char *algname, ENGINE *e, int do_param)
365238384Sjkim	{
366238384Sjkim	EVP_PKEY_CTX *ctx = NULL;
367238384Sjkim	const EVP_PKEY_ASN1_METHOD *ameth;
368238384Sjkim	ENGINE *tmpeng = NULL;
369238384Sjkim	int pkey_id;
370238384Sjkim
371238384Sjkim	if (*pctx)
372238384Sjkim		{
373238384Sjkim		BIO_puts(err, "Algorithm already set!\n");
374238384Sjkim		return 0;
375238384Sjkim		}
376238384Sjkim
377238384Sjkim	ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
378238384Sjkim
379238384Sjkim#ifndef OPENSSL_NO_ENGINE
380238384Sjkim	if (!ameth && e)
381238384Sjkim		ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
382238384Sjkim#endif
383238384Sjkim
384238384Sjkim	if (!ameth)
385238384Sjkim		{
386238384Sjkim		BIO_printf(bio_err, "Algorithm %s not found\n", algname);
387238384Sjkim		return 0;
388238384Sjkim		}
389238384Sjkim
390238384Sjkim	ERR_clear_error();
391238384Sjkim
392238384Sjkim	EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
393238384Sjkim#ifndef OPENSSL_NO_ENGINE
394238384Sjkim	if (tmpeng)
395238384Sjkim		ENGINE_finish(tmpeng);
396238384Sjkim#endif
397238384Sjkim	ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
398238384Sjkim
399238384Sjkim	if (!ctx)
400238384Sjkim		goto err;
401238384Sjkim	if (do_param)
402238384Sjkim		{
403238384Sjkim		if (EVP_PKEY_paramgen_init(ctx) <= 0)
404238384Sjkim			goto err;
405238384Sjkim		}
406238384Sjkim	else
407238384Sjkim		{
408238384Sjkim		if (EVP_PKEY_keygen_init(ctx) <= 0)
409238384Sjkim			goto err;
410238384Sjkim		}
411238384Sjkim
412238384Sjkim	*pctx = ctx;
413238384Sjkim	return 1;
414238384Sjkim
415238384Sjkim	err:
416238384Sjkim	BIO_printf(err, "Error initializing %s context\n", algname);
417238384Sjkim	ERR_print_errors(err);
418238384Sjkim	if (ctx)
419238384Sjkim		EVP_PKEY_CTX_free(ctx);
420238384Sjkim	return 0;
421238384Sjkim
422238384Sjkim	}
423238384Sjkim
424238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx)
425238384Sjkim	{
426238384Sjkim	char c='*';
427238384Sjkim	BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
428238384Sjkim	int p;
429238384Sjkim	p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
430238384Sjkim	if (p == 0) c='.';
431238384Sjkim	if (p == 1) c='+';
432238384Sjkim	if (p == 2) c='*';
433238384Sjkim	if (p == 3) c='\n';
434238384Sjkim	BIO_write(b,&c,1);
435238384Sjkim	(void)BIO_flush(b);
436238384Sjkim#ifdef LINT
437238384Sjkim	p=n;
438238384Sjkim#endif
439238384Sjkim	return 1;
440238384Sjkim	}
441