1238384Sjkim/* apps/genpkey.c */
2280304Sjkim/*
3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4280304Sjkim * 2006
5238384Sjkim */
6238384Sjkim/* ====================================================================
7238384Sjkim * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
8238384Sjkim *
9238384Sjkim * Redistribution and use in source and binary forms, with or without
10238384Sjkim * modification, are permitted provided that the following conditions
11238384Sjkim * are met:
12238384Sjkim *
13238384Sjkim * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15238384Sjkim *
16238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright
17238384Sjkim *    notice, this list of conditions and the following disclaimer in
18238384Sjkim *    the documentation and/or other materials provided with the
19238384Sjkim *    distribution.
20238384Sjkim *
21238384Sjkim * 3. All advertising materials mentioning features or use of this
22238384Sjkim *    software must display the following acknowledgment:
23238384Sjkim *    "This product includes software developed by the OpenSSL Project
24238384Sjkim *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25238384Sjkim *
26238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27238384Sjkim *    endorse or promote products derived from this software without
28238384Sjkim *    prior written permission. For written permission, please contact
29238384Sjkim *    licensing@OpenSSL.org.
30238384Sjkim *
31238384Sjkim * 5. Products derived from this software may not be called "OpenSSL"
32238384Sjkim *    nor may "OpenSSL" appear in their names without prior written
33238384Sjkim *    permission of the OpenSSL Project.
34238384Sjkim *
35238384Sjkim * 6. Redistributions of any form whatsoever must retain the following
36238384Sjkim *    acknowledgment:
37238384Sjkim *    "This product includes software developed by the OpenSSL Project
38238384Sjkim *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39238384Sjkim *
40238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43238384Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE.
52238384Sjkim * ====================================================================
53238384Sjkim *
54238384Sjkim * This product includes cryptographic software written by Eric Young
55238384Sjkim * (eay@cryptsoft.com).  This product includes software written by Tim
56238384Sjkim * Hudson (tjh@cryptsoft.com).
57238384Sjkim *
58238384Sjkim */
59238384Sjkim#include <stdio.h>
60238384Sjkim#include <string.h>
61238384Sjkim#include "apps.h"
62238384Sjkim#include <openssl/pem.h>
63238384Sjkim#include <openssl/err.h>
64238384Sjkim#include <openssl/evp.h>
65238384Sjkim#ifndef OPENSSL_NO_ENGINE
66280304Sjkim# include <openssl/engine.h>
67238384Sjkim#endif
68238384Sjkim
69238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
70280304Sjkim                            const char *file, ENGINE *e);
71238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx);
72238384Sjkim
73238384Sjkim#define PROG genpkey_main
74238384Sjkim
75238384Sjkimint MAIN(int, char **);
76238384Sjkim
77238384Sjkimint MAIN(int argc, char **argv)
78280304Sjkim{
79280304Sjkim    ENGINE *e = NULL;
80280304Sjkim    char **args, *outfile = NULL;
81280304Sjkim    char *passarg = NULL;
82280304Sjkim    BIO *in = NULL, *out = NULL;
83280304Sjkim    const EVP_CIPHER *cipher = NULL;
84280304Sjkim    int outformat;
85280304Sjkim    int text = 0;
86280304Sjkim    EVP_PKEY *pkey = NULL;
87280304Sjkim    EVP_PKEY_CTX *ctx = NULL;
88280304Sjkim    char *pass = NULL;
89280304Sjkim    int badarg = 0;
90280304Sjkim    int ret = 1, rv;
91238384Sjkim
92280304Sjkim    int do_param = 0;
93238384Sjkim
94280304Sjkim    if (bio_err == NULL)
95280304Sjkim        bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
96238384Sjkim
97280304Sjkim    if (!load_config(bio_err, NULL))
98280304Sjkim        goto end;
99238384Sjkim
100280304Sjkim    outformat = FORMAT_PEM;
101238384Sjkim
102280304Sjkim    ERR_load_crypto_strings();
103280304Sjkim    OpenSSL_add_all_algorithms();
104280304Sjkim    args = argv + 1;
105280304Sjkim    while (!badarg && *args && *args[0] == '-') {
106280304Sjkim        if (!strcmp(*args, "-outform")) {
107280304Sjkim            if (args[1]) {
108280304Sjkim                args++;
109280304Sjkim                outformat = str2fmt(*args);
110280304Sjkim            } else
111280304Sjkim                badarg = 1;
112280304Sjkim        } else if (!strcmp(*args, "-pass")) {
113280304Sjkim            if (!args[1])
114280304Sjkim                goto bad;
115280304Sjkim            passarg = *(++args);
116280304Sjkim        }
117238384Sjkim#ifndef OPENSSL_NO_ENGINE
118280304Sjkim        else if (strcmp(*args, "-engine") == 0) {
119280304Sjkim            if (!args[1])
120280304Sjkim                goto bad;
121280304Sjkim            e = setup_engine(bio_err, *(++args), 0);
122280304Sjkim        }
123238384Sjkim#endif
124280304Sjkim        else if (!strcmp(*args, "-paramfile")) {
125280304Sjkim            if (!args[1])
126280304Sjkim                goto bad;
127280304Sjkim            args++;
128280304Sjkim            if (do_param == 1)
129280304Sjkim                goto bad;
130280304Sjkim            if (!init_keygen_file(bio_err, &ctx, *args, e))
131280304Sjkim                goto end;
132280304Sjkim        } else if (!strcmp(*args, "-out")) {
133280304Sjkim            if (args[1]) {
134280304Sjkim                args++;
135280304Sjkim                outfile = *args;
136280304Sjkim            } else
137280304Sjkim                badarg = 1;
138280304Sjkim        } else if (strcmp(*args, "-algorithm") == 0) {
139280304Sjkim            if (!args[1])
140280304Sjkim                goto bad;
141280304Sjkim            if (!init_gen_str(bio_err, &ctx, *(++args), e, do_param))
142280304Sjkim                goto end;
143280304Sjkim        } else if (strcmp(*args, "-pkeyopt") == 0) {
144280304Sjkim            if (!args[1])
145280304Sjkim                goto bad;
146280304Sjkim            if (!ctx) {
147280304Sjkim                BIO_puts(bio_err, "No keytype specified\n");
148280304Sjkim                goto bad;
149280304Sjkim            } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) {
150280304Sjkim                BIO_puts(bio_err, "parameter setting error\n");
151280304Sjkim                ERR_print_errors(bio_err);
152280304Sjkim                goto end;
153280304Sjkim            }
154280304Sjkim        } else if (strcmp(*args, "-genparam") == 0) {
155280304Sjkim            if (ctx)
156280304Sjkim                goto bad;
157280304Sjkim            do_param = 1;
158280304Sjkim        } else if (strcmp(*args, "-text") == 0)
159280304Sjkim            text = 1;
160280304Sjkim        else {
161280304Sjkim            cipher = EVP_get_cipherbyname(*args + 1);
162280304Sjkim            if (!cipher) {
163280304Sjkim                BIO_printf(bio_err, "Unknown cipher %s\n", *args + 1);
164280304Sjkim                badarg = 1;
165280304Sjkim            }
166280304Sjkim            if (do_param == 1)
167280304Sjkim                badarg = 1;
168280304Sjkim        }
169280304Sjkim        args++;
170280304Sjkim    }
171238384Sjkim
172280304Sjkim    if (!ctx)
173280304Sjkim        badarg = 1;
174238384Sjkim
175280304Sjkim    if (badarg) {
176280304Sjkim bad:
177280304Sjkim        BIO_printf(bio_err, "Usage: genpkey [options]\n");
178280304Sjkim        BIO_printf(bio_err, "where options may be\n");
179280304Sjkim        BIO_printf(bio_err, "-out file          output file\n");
180280304Sjkim        BIO_printf(bio_err,
181280304Sjkim                   "-outform X         output format (DER or PEM)\n");
182280304Sjkim        BIO_printf(bio_err,
183280304Sjkim                   "-pass arg          output file pass phrase source\n");
184280304Sjkim        BIO_printf(bio_err,
185280304Sjkim                   "-<cipher>          use cipher <cipher> to encrypt the key\n");
186238384Sjkim#ifndef OPENSSL_NO_ENGINE
187280304Sjkim        BIO_printf(bio_err,
188280304Sjkim                   "-engine e          use engine e, possibly a hardware device.\n");
189238384Sjkim#endif
190280304Sjkim        BIO_printf(bio_err, "-paramfile file    parameters file\n");
191280304Sjkim        BIO_printf(bio_err, "-algorithm alg     the public key algorithm\n");
192280304Sjkim        BIO_printf(bio_err,
193280304Sjkim                   "-pkeyopt opt:value set the public key algorithm option <opt>\n"
194280304Sjkim                   "                   to value <value>\n");
195280304Sjkim        BIO_printf(bio_err,
196280304Sjkim                   "-genparam          generate parameters, not key\n");
197280304Sjkim        BIO_printf(bio_err, "-text              print the in text\n");
198280304Sjkim        BIO_printf(bio_err,
199280304Sjkim                   "NB: options order may be important!  See the manual page.\n");
200280304Sjkim        goto end;
201280304Sjkim    }
202238384Sjkim
203280304Sjkim    if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) {
204280304Sjkim        BIO_puts(bio_err, "Error getting password\n");
205280304Sjkim        goto end;
206280304Sjkim    }
207238384Sjkim
208280304Sjkim    if (outfile) {
209280304Sjkim        if (!(out = BIO_new_file(outfile, "wb"))) {
210280304Sjkim            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
211280304Sjkim            goto end;
212280304Sjkim        }
213280304Sjkim    } else {
214280304Sjkim        out = BIO_new_fp(stdout, BIO_NOCLOSE);
215238384Sjkim#ifdef OPENSSL_SYS_VMS
216280304Sjkim        {
217280304Sjkim            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
218280304Sjkim            out = BIO_push(tmpbio, out);
219280304Sjkim        }
220238384Sjkim#endif
221280304Sjkim    }
222238384Sjkim
223280304Sjkim    EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
224280304Sjkim    EVP_PKEY_CTX_set_app_data(ctx, bio_err);
225238384Sjkim
226280304Sjkim    if (do_param) {
227280304Sjkim        if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) {
228280304Sjkim            BIO_puts(bio_err, "Error generating parameters\n");
229280304Sjkim            ERR_print_errors(bio_err);
230280304Sjkim            goto end;
231280304Sjkim        }
232280304Sjkim    } else {
233280304Sjkim        if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
234280304Sjkim            BIO_puts(bio_err, "Error generating key\n");
235280304Sjkim            ERR_print_errors(bio_err);
236280304Sjkim            goto end;
237280304Sjkim        }
238280304Sjkim    }
239238384Sjkim
240280304Sjkim    if (do_param)
241280304Sjkim        rv = PEM_write_bio_Parameters(out, pkey);
242280304Sjkim    else if (outformat == FORMAT_PEM)
243280304Sjkim        rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
244280304Sjkim    else if (outformat == FORMAT_ASN1)
245280304Sjkim        rv = i2d_PrivateKey_bio(out, pkey);
246280304Sjkim    else {
247280304Sjkim        BIO_printf(bio_err, "Bad format specified for key\n");
248280304Sjkim        goto end;
249280304Sjkim    }
250238384Sjkim
251280304Sjkim    if (rv <= 0) {
252280304Sjkim        BIO_puts(bio_err, "Error writing key\n");
253280304Sjkim        ERR_print_errors(bio_err);
254280304Sjkim    }
255238384Sjkim
256280304Sjkim    if (text) {
257280304Sjkim        if (do_param)
258280304Sjkim            rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
259280304Sjkim        else
260280304Sjkim            rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
261238384Sjkim
262280304Sjkim        if (rv <= 0) {
263280304Sjkim            BIO_puts(bio_err, "Error printing key\n");
264280304Sjkim            ERR_print_errors(bio_err);
265280304Sjkim        }
266280304Sjkim    }
267238384Sjkim
268280304Sjkim    ret = 0;
269238384Sjkim
270280304Sjkim end:
271280304Sjkim    if (pkey)
272280304Sjkim        EVP_PKEY_free(pkey);
273280304Sjkim    if (ctx)
274280304Sjkim        EVP_PKEY_CTX_free(ctx);
275280304Sjkim    if (out)
276280304Sjkim        BIO_free_all(out);
277280304Sjkim    BIO_free(in);
278280304Sjkim    if (pass)
279280304Sjkim        OPENSSL_free(pass);
280238384Sjkim
281280304Sjkim    return ret;
282280304Sjkim}
283238384Sjkim
284238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
285280304Sjkim                            const char *file, ENGINE *e)
286280304Sjkim{
287280304Sjkim    BIO *pbio;
288280304Sjkim    EVP_PKEY *pkey = NULL;
289280304Sjkim    EVP_PKEY_CTX *ctx = NULL;
290280304Sjkim    if (*pctx) {
291280304Sjkim        BIO_puts(err, "Parameters already set!\n");
292280304Sjkim        return 0;
293280304Sjkim    }
294238384Sjkim
295280304Sjkim    pbio = BIO_new_file(file, "r");
296280304Sjkim    if (!pbio) {
297280304Sjkim        BIO_printf(err, "Can't open parameter file %s\n", file);
298280304Sjkim        return 0;
299280304Sjkim    }
300238384Sjkim
301280304Sjkim    pkey = PEM_read_bio_Parameters(pbio, NULL);
302280304Sjkim    BIO_free(pbio);
303238384Sjkim
304280304Sjkim    if (!pkey) {
305280304Sjkim        BIO_printf(bio_err, "Error reading parameter file %s\n", file);
306280304Sjkim        return 0;
307280304Sjkim    }
308238384Sjkim
309280304Sjkim    ctx = EVP_PKEY_CTX_new(pkey, e);
310280304Sjkim    if (!ctx)
311280304Sjkim        goto err;
312280304Sjkim    if (EVP_PKEY_keygen_init(ctx) <= 0)
313280304Sjkim        goto err;
314280304Sjkim    EVP_PKEY_free(pkey);
315280304Sjkim    *pctx = ctx;
316280304Sjkim    return 1;
317238384Sjkim
318280304Sjkim err:
319280304Sjkim    BIO_puts(err, "Error initializing context\n");
320280304Sjkim    ERR_print_errors(err);
321280304Sjkim    if (ctx)
322280304Sjkim        EVP_PKEY_CTX_free(ctx);
323280304Sjkim    if (pkey)
324280304Sjkim        EVP_PKEY_free(pkey);
325280304Sjkim    return 0;
326238384Sjkim
327280304Sjkim}
328238384Sjkim
329238384Sjkimint init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
330280304Sjkim                 const char *algname, ENGINE *e, int do_param)
331280304Sjkim{
332280304Sjkim    EVP_PKEY_CTX *ctx = NULL;
333280304Sjkim    const EVP_PKEY_ASN1_METHOD *ameth;
334280304Sjkim    ENGINE *tmpeng = NULL;
335280304Sjkim    int pkey_id;
336238384Sjkim
337280304Sjkim    if (*pctx) {
338280304Sjkim        BIO_puts(err, "Algorithm already set!\n");
339280304Sjkim        return 0;
340280304Sjkim    }
341238384Sjkim
342280304Sjkim    ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
343238384Sjkim
344238384Sjkim#ifndef OPENSSL_NO_ENGINE
345280304Sjkim    if (!ameth && e)
346280304Sjkim        ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
347238384Sjkim#endif
348238384Sjkim
349280304Sjkim    if (!ameth) {
350280304Sjkim        BIO_printf(bio_err, "Algorithm %s not found\n", algname);
351280304Sjkim        return 0;
352280304Sjkim    }
353238384Sjkim
354280304Sjkim    ERR_clear_error();
355238384Sjkim
356280304Sjkim    EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
357238384Sjkim#ifndef OPENSSL_NO_ENGINE
358280304Sjkim    if (tmpeng)
359280304Sjkim        ENGINE_finish(tmpeng);
360238384Sjkim#endif
361280304Sjkim    ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
362238384Sjkim
363280304Sjkim    if (!ctx)
364280304Sjkim        goto err;
365280304Sjkim    if (do_param) {
366280304Sjkim        if (EVP_PKEY_paramgen_init(ctx) <= 0)
367280304Sjkim            goto err;
368280304Sjkim    } else {
369280304Sjkim        if (EVP_PKEY_keygen_init(ctx) <= 0)
370280304Sjkim            goto err;
371280304Sjkim    }
372238384Sjkim
373280304Sjkim    *pctx = ctx;
374280304Sjkim    return 1;
375238384Sjkim
376280304Sjkim err:
377280304Sjkim    BIO_printf(err, "Error initializing %s context\n", algname);
378280304Sjkim    ERR_print_errors(err);
379280304Sjkim    if (ctx)
380280304Sjkim        EVP_PKEY_CTX_free(ctx);
381280304Sjkim    return 0;
382238384Sjkim
383280304Sjkim}
384238384Sjkim
385238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx)
386280304Sjkim{
387280304Sjkim    char c = '*';
388280304Sjkim    BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
389280304Sjkim    int p;
390280304Sjkim    p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
391280304Sjkim    if (p == 0)
392280304Sjkim        c = '.';
393280304Sjkim    if (p == 1)
394280304Sjkim        c = '+';
395280304Sjkim    if (p == 2)
396280304Sjkim        c = '*';
397280304Sjkim    if (p == 3)
398280304Sjkim        c = '\n';
399280304Sjkim    BIO_write(b, &c, 1);
400280304Sjkim    (void)BIO_flush(b);
401238384Sjkim#ifdef LINT
402280304Sjkim    p = n;
403238384Sjkim#endif
404280304Sjkim    return 1;
405280304Sjkim}
406