1238384Sjkim/* apps/genpkey.c */
2280297Sjkim/*
3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4280297Sjkim * 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
14280297Sjkim *    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
66280297Sjkim# include <openssl/engine.h>
67238384Sjkim#endif
68238384Sjkim
69238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
70280297Sjkim                            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)
78280297Sjkim{
79280297Sjkim    ENGINE *e = NULL;
80280297Sjkim    char **args, *outfile = NULL;
81280297Sjkim    char *passarg = NULL;
82280297Sjkim    BIO *in = NULL, *out = NULL;
83280297Sjkim    const EVP_CIPHER *cipher = NULL;
84280297Sjkim    int outformat;
85280297Sjkim    int text = 0;
86280297Sjkim    EVP_PKEY *pkey = NULL;
87280297Sjkim    EVP_PKEY_CTX *ctx = NULL;
88280297Sjkim    char *pass = NULL;
89280297Sjkim    int badarg = 0;
90280297Sjkim    int ret = 1, rv;
91238384Sjkim
92280297Sjkim    int do_param = 0;
93238384Sjkim
94280297Sjkim    if (bio_err == NULL)
95280297Sjkim        bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
96238384Sjkim
97280297Sjkim    if (!load_config(bio_err, NULL))
98280297Sjkim        goto end;
99238384Sjkim
100280297Sjkim    outformat = FORMAT_PEM;
101238384Sjkim
102280297Sjkim    ERR_load_crypto_strings();
103280297Sjkim    OpenSSL_add_all_algorithms();
104280297Sjkim    args = argv + 1;
105280297Sjkim    while (!badarg && *args && *args[0] == '-') {
106280297Sjkim        if (!strcmp(*args, "-outform")) {
107280297Sjkim            if (args[1]) {
108280297Sjkim                args++;
109280297Sjkim                outformat = str2fmt(*args);
110280297Sjkim            } else
111280297Sjkim                badarg = 1;
112280297Sjkim        } else if (!strcmp(*args, "-pass")) {
113280297Sjkim            if (!args[1])
114280297Sjkim                goto bad;
115280297Sjkim            passarg = *(++args);
116280297Sjkim        }
117238384Sjkim#ifndef OPENSSL_NO_ENGINE
118280297Sjkim        else if (strcmp(*args, "-engine") == 0) {
119280297Sjkim            if (!args[1])
120280297Sjkim                goto bad;
121280297Sjkim            e = setup_engine(bio_err, *(++args), 0);
122280297Sjkim        }
123238384Sjkim#endif
124280297Sjkim        else if (!strcmp(*args, "-paramfile")) {
125280297Sjkim            if (!args[1])
126280297Sjkim                goto bad;
127280297Sjkim            args++;
128280297Sjkim            if (do_param == 1)
129280297Sjkim                goto bad;
130280297Sjkim            if (!init_keygen_file(bio_err, &ctx, *args, e))
131280297Sjkim                goto end;
132280297Sjkim        } else if (!strcmp(*args, "-out")) {
133280297Sjkim            if (args[1]) {
134280297Sjkim                args++;
135280297Sjkim                outfile = *args;
136280297Sjkim            } else
137280297Sjkim                badarg = 1;
138280297Sjkim        } else if (strcmp(*args, "-algorithm") == 0) {
139280297Sjkim            if (!args[1])
140280297Sjkim                goto bad;
141280297Sjkim            if (!init_gen_str(bio_err, &ctx, *(++args), e, do_param))
142280297Sjkim                goto end;
143280297Sjkim        } else if (strcmp(*args, "-pkeyopt") == 0) {
144280297Sjkim            if (!args[1])
145280297Sjkim                goto bad;
146280297Sjkim            if (!ctx) {
147280297Sjkim                BIO_puts(bio_err, "No keytype specified\n");
148280297Sjkim                goto bad;
149280297Sjkim            } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) {
150280297Sjkim                BIO_puts(bio_err, "parameter setting error\n");
151280297Sjkim                ERR_print_errors(bio_err);
152280297Sjkim                goto end;
153280297Sjkim            }
154280297Sjkim        } else if (strcmp(*args, "-genparam") == 0) {
155280297Sjkim            if (ctx)
156280297Sjkim                goto bad;
157280297Sjkim            do_param = 1;
158280297Sjkim        } else if (strcmp(*args, "-text") == 0)
159280297Sjkim            text = 1;
160280297Sjkim        else {
161280297Sjkim            cipher = EVP_get_cipherbyname(*args + 1);
162280297Sjkim            if (!cipher) {
163280297Sjkim                BIO_printf(bio_err, "Unknown cipher %s\n", *args + 1);
164280297Sjkim                badarg = 1;
165280297Sjkim            }
166280297Sjkim            if (do_param == 1)
167280297Sjkim                badarg = 1;
168280297Sjkim        }
169280297Sjkim        args++;
170280297Sjkim    }
171238384Sjkim
172280297Sjkim    if (!ctx)
173280297Sjkim        badarg = 1;
174238384Sjkim
175280297Sjkim    if (badarg) {
176280297Sjkim bad:
177280297Sjkim        BIO_printf(bio_err, "Usage: genpkey [options]\n");
178280297Sjkim        BIO_printf(bio_err, "where options may be\n");
179280297Sjkim        BIO_printf(bio_err, "-out file          output file\n");
180280297Sjkim        BIO_printf(bio_err,
181280297Sjkim                   "-outform X         output format (DER or PEM)\n");
182280297Sjkim        BIO_printf(bio_err,
183280297Sjkim                   "-pass arg          output file pass phrase source\n");
184280297Sjkim        BIO_printf(bio_err,
185280297Sjkim                   "-<cipher>          use cipher <cipher> to encrypt the key\n");
186238384Sjkim#ifndef OPENSSL_NO_ENGINE
187280297Sjkim        BIO_printf(bio_err,
188280297Sjkim                   "-engine e          use engine e, possibly a hardware device.\n");
189238384Sjkim#endif
190280297Sjkim        BIO_printf(bio_err, "-paramfile file    parameters file\n");
191280297Sjkim        BIO_printf(bio_err, "-algorithm alg     the public key algorithm\n");
192280297Sjkim        BIO_printf(bio_err,
193280297Sjkim                   "-pkeyopt opt:value set the public key algorithm option <opt>\n"
194280297Sjkim                   "                   to value <value>\n");
195280297Sjkim        BIO_printf(bio_err,
196280297Sjkim                   "-genparam          generate parameters, not key\n");
197280297Sjkim        BIO_printf(bio_err, "-text              print the in text\n");
198280297Sjkim        BIO_printf(bio_err,
199280297Sjkim                   "NB: options order may be important!  See the manual page.\n");
200280297Sjkim        goto end;
201280297Sjkim    }
202238384Sjkim
203280297Sjkim    if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) {
204280297Sjkim        BIO_puts(bio_err, "Error getting password\n");
205280297Sjkim        goto end;
206280297Sjkim    }
207238384Sjkim
208280297Sjkim    if (outfile) {
209280297Sjkim        if (!(out = BIO_new_file(outfile, "wb"))) {
210280297Sjkim            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
211280297Sjkim            goto end;
212280297Sjkim        }
213280297Sjkim    } else {
214280297Sjkim        out = BIO_new_fp(stdout, BIO_NOCLOSE);
215238384Sjkim#ifdef OPENSSL_SYS_VMS
216280297Sjkim        {
217280297Sjkim            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
218280297Sjkim            out = BIO_push(tmpbio, out);
219280297Sjkim        }
220238384Sjkim#endif
221280297Sjkim    }
222238384Sjkim
223280297Sjkim    EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
224280297Sjkim    EVP_PKEY_CTX_set_app_data(ctx, bio_err);
225238384Sjkim
226280297Sjkim    if (do_param) {
227280297Sjkim        if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) {
228280297Sjkim            BIO_puts(bio_err, "Error generating parameters\n");
229280297Sjkim            ERR_print_errors(bio_err);
230280297Sjkim            goto end;
231280297Sjkim        }
232280297Sjkim    } else {
233280297Sjkim        if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
234280297Sjkim            BIO_puts(bio_err, "Error generating key\n");
235280297Sjkim            ERR_print_errors(bio_err);
236280297Sjkim            goto end;
237280297Sjkim        }
238280297Sjkim    }
239238384Sjkim
240280297Sjkim    if (do_param)
241280297Sjkim        rv = PEM_write_bio_Parameters(out, pkey);
242280297Sjkim    else if (outformat == FORMAT_PEM)
243280297Sjkim        rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
244280297Sjkim    else if (outformat == FORMAT_ASN1)
245280297Sjkim        rv = i2d_PrivateKey_bio(out, pkey);
246280297Sjkim    else {
247280297Sjkim        BIO_printf(bio_err, "Bad format specified for key\n");
248280297Sjkim        goto end;
249280297Sjkim    }
250238384Sjkim
251280297Sjkim    if (rv <= 0) {
252280297Sjkim        BIO_puts(bio_err, "Error writing key\n");
253280297Sjkim        ERR_print_errors(bio_err);
254280297Sjkim    }
255238384Sjkim
256280297Sjkim    if (text) {
257280297Sjkim        if (do_param)
258280297Sjkim            rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
259280297Sjkim        else
260280297Sjkim            rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
261238384Sjkim
262280297Sjkim        if (rv <= 0) {
263280297Sjkim            BIO_puts(bio_err, "Error printing key\n");
264280297Sjkim            ERR_print_errors(bio_err);
265280297Sjkim        }
266280297Sjkim    }
267238384Sjkim
268280297Sjkim    ret = 0;
269238384Sjkim
270280297Sjkim end:
271280297Sjkim    if (pkey)
272280297Sjkim        EVP_PKEY_free(pkey);
273280297Sjkim    if (ctx)
274280297Sjkim        EVP_PKEY_CTX_free(ctx);
275280297Sjkim    if (out)
276280297Sjkim        BIO_free_all(out);
277280297Sjkim    BIO_free(in);
278312826Sjkim    release_engine(e);
279280297Sjkim    if (pass)
280280297Sjkim        OPENSSL_free(pass);
281280297Sjkim    return ret;
282280297Sjkim}
283238384Sjkim
284238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
285280297Sjkim                            const char *file, ENGINE *e)
286280297Sjkim{
287280297Sjkim    BIO *pbio;
288280297Sjkim    EVP_PKEY *pkey = NULL;
289280297Sjkim    EVP_PKEY_CTX *ctx = NULL;
290280297Sjkim    if (*pctx) {
291280297Sjkim        BIO_puts(err, "Parameters already set!\n");
292280297Sjkim        return 0;
293280297Sjkim    }
294238384Sjkim
295280297Sjkim    pbio = BIO_new_file(file, "r");
296280297Sjkim    if (!pbio) {
297280297Sjkim        BIO_printf(err, "Can't open parameter file %s\n", file);
298280297Sjkim        return 0;
299280297Sjkim    }
300238384Sjkim
301280297Sjkim    pkey = PEM_read_bio_Parameters(pbio, NULL);
302280297Sjkim    BIO_free(pbio);
303238384Sjkim
304280297Sjkim    if (!pkey) {
305280297Sjkim        BIO_printf(bio_err, "Error reading parameter file %s\n", file);
306280297Sjkim        return 0;
307280297Sjkim    }
308238384Sjkim
309280297Sjkim    ctx = EVP_PKEY_CTX_new(pkey, e);
310280297Sjkim    if (!ctx)
311280297Sjkim        goto err;
312280297Sjkim    if (EVP_PKEY_keygen_init(ctx) <= 0)
313280297Sjkim        goto err;
314280297Sjkim    EVP_PKEY_free(pkey);
315280297Sjkim    *pctx = ctx;
316280297Sjkim    return 1;
317238384Sjkim
318280297Sjkim err:
319280297Sjkim    BIO_puts(err, "Error initializing context\n");
320280297Sjkim    ERR_print_errors(err);
321280297Sjkim    if (ctx)
322280297Sjkim        EVP_PKEY_CTX_free(ctx);
323280297Sjkim    if (pkey)
324280297Sjkim        EVP_PKEY_free(pkey);
325280297Sjkim    return 0;
326238384Sjkim
327280297Sjkim}
328238384Sjkim
329238384Sjkimint init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
330280297Sjkim                 const char *algname, ENGINE *e, int do_param)
331280297Sjkim{
332280297Sjkim    EVP_PKEY_CTX *ctx = NULL;
333280297Sjkim    const EVP_PKEY_ASN1_METHOD *ameth;
334280297Sjkim    ENGINE *tmpeng = NULL;
335280297Sjkim    int pkey_id;
336238384Sjkim
337280297Sjkim    if (*pctx) {
338280297Sjkim        BIO_puts(err, "Algorithm already set!\n");
339280297Sjkim        return 0;
340280297Sjkim    }
341238384Sjkim
342280297Sjkim    ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
343238384Sjkim
344238384Sjkim#ifndef OPENSSL_NO_ENGINE
345280297Sjkim    if (!ameth && e)
346280297Sjkim        ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
347238384Sjkim#endif
348238384Sjkim
349280297Sjkim    if (!ameth) {
350280297Sjkim        BIO_printf(bio_err, "Algorithm %s not found\n", algname);
351280297Sjkim        return 0;
352280297Sjkim    }
353238384Sjkim
354280297Sjkim    ERR_clear_error();
355238384Sjkim
356280297Sjkim    EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
357238384Sjkim#ifndef OPENSSL_NO_ENGINE
358280297Sjkim    if (tmpeng)
359280297Sjkim        ENGINE_finish(tmpeng);
360238384Sjkim#endif
361280297Sjkim    ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
362238384Sjkim
363280297Sjkim    if (!ctx)
364280297Sjkim        goto err;
365280297Sjkim    if (do_param) {
366280297Sjkim        if (EVP_PKEY_paramgen_init(ctx) <= 0)
367280297Sjkim            goto err;
368280297Sjkim    } else {
369280297Sjkim        if (EVP_PKEY_keygen_init(ctx) <= 0)
370280297Sjkim            goto err;
371280297Sjkim    }
372238384Sjkim
373280297Sjkim    *pctx = ctx;
374280297Sjkim    return 1;
375238384Sjkim
376280297Sjkim err:
377280297Sjkim    BIO_printf(err, "Error initializing %s context\n", algname);
378280297Sjkim    ERR_print_errors(err);
379280297Sjkim    if (ctx)
380280297Sjkim        EVP_PKEY_CTX_free(ctx);
381280297Sjkim    return 0;
382238384Sjkim
383280297Sjkim}
384238384Sjkim
385238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx)
386280297Sjkim{
387280297Sjkim    char c = '*';
388280297Sjkim    BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
389280297Sjkim    int p;
390280297Sjkim    p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
391280297Sjkim    if (p == 0)
392280297Sjkim        c = '.';
393280297Sjkim    if (p == 1)
394280297Sjkim        c = '+';
395280297Sjkim    if (p == 2)
396280297Sjkim        c = '*';
397280297Sjkim    if (p == 3)
398280297Sjkim        c = '\n';
399280297Sjkim    BIO_write(b, &c, 1);
400280297Sjkim    (void)BIO_flush(b);
401238384Sjkim#ifdef LINT
402280297Sjkim    p = n;
403238384Sjkim#endif
404280297Sjkim    return 1;
405280297Sjkim}
406