xref: /freebsd/crypto/openssl/apps/genpkey.c (revision ad991e4c142ebabad7aef488ad97b189ecabb270)
16f9291ceSJung-uk Kim /*
2*ad991e4cSEd Maste  * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
81f13597dSJung-uk Kim  */
9e71b7053SJung-uk Kim 
101f13597dSJung-uk Kim #include <stdio.h>
111f13597dSJung-uk Kim #include <string.h>
121f13597dSJung-uk Kim #include "apps.h"
13e71b7053SJung-uk Kim #include "progs.h"
141f13597dSJung-uk Kim #include <openssl/pem.h>
151f13597dSJung-uk Kim #include <openssl/err.h>
161f13597dSJung-uk Kim #include <openssl/evp.h>
171f13597dSJung-uk Kim 
18b077aed3SPierre Pronchery static int quiet;
19b077aed3SPierre Pronchery 
20b077aed3SPierre Pronchery static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
21b077aed3SPierre Pronchery                             OSSL_LIB_CTX *libctx, const char *propq);
221f13597dSJung-uk Kim static int genpkey_cb(EVP_PKEY_CTX *ctx);
231f13597dSJung-uk Kim 
24e71b7053SJung-uk Kim typedef enum OPTION_choice {
25b077aed3SPierre Pronchery     OPT_COMMON,
26e71b7053SJung-uk Kim     OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE,
27b077aed3SPierre Pronchery     OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER,
28b077aed3SPierre Pronchery     OPT_QUIET, OPT_CONFIG,
29b077aed3SPierre Pronchery     OPT_PROV_ENUM
30e71b7053SJung-uk Kim } OPTION_CHOICE;
311f13597dSJung-uk Kim 
32e71b7053SJung-uk Kim const OPTIONS genpkey_options[] = {
33b077aed3SPierre Pronchery     OPT_SECTION("General"),
34e71b7053SJung-uk Kim     {"help", OPT_HELP, '-', "Display this summary"},
35e71b7053SJung-uk Kim #ifndef OPENSSL_NO_ENGINE
36e71b7053SJung-uk Kim     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
37e71b7053SJung-uk Kim #endif
38b077aed3SPierre Pronchery     {"paramfile", OPT_PARAMFILE, '<', "Parameters file"},
39b077aed3SPierre Pronchery     {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"},
40b077aed3SPierre Pronchery     {"quiet", OPT_QUIET, '-', "Do not output status while generating keys"},
41b077aed3SPierre Pronchery     {"pkeyopt", OPT_PKEYOPT, 's',
42b077aed3SPierre Pronchery      "Set the public key algorithm option as opt:value"},
43b077aed3SPierre Pronchery      OPT_CONFIG_OPTION,
44b077aed3SPierre Pronchery 
45b077aed3SPierre Pronchery     OPT_SECTION("Output"),
46b077aed3SPierre Pronchery     {"out", OPT_OUT, '>', "Output file"},
47b077aed3SPierre Pronchery     {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"},
48b077aed3SPierre Pronchery     {"pass", OPT_PASS, 's', "Output file pass phrase source"},
49b077aed3SPierre Pronchery     {"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"},
50b077aed3SPierre Pronchery     {"text", OPT_TEXT, '-', "Print the in text"},
51b077aed3SPierre Pronchery     {"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"},
52b077aed3SPierre Pronchery 
53b077aed3SPierre Pronchery     OPT_PROV_OPTIONS,
54b077aed3SPierre Pronchery 
55e71b7053SJung-uk Kim     /* This is deliberately last. */
56e71b7053SJung-uk Kim     {OPT_HELP_STR, 1, 1,
57e71b7053SJung-uk Kim      "Order of options may be important!  See the documentation.\n"},
58e71b7053SJung-uk Kim     {NULL}
59e71b7053SJung-uk Kim };
601f13597dSJung-uk Kim 
genpkey_main(int argc,char ** argv)61e71b7053SJung-uk Kim int genpkey_main(int argc, char **argv)
621f13597dSJung-uk Kim {
63b077aed3SPierre Pronchery     CONF *conf = NULL;
641f13597dSJung-uk Kim     BIO *in = NULL, *out = NULL;
65e71b7053SJung-uk Kim     ENGINE *e = NULL;
661f13597dSJung-uk Kim     EVP_PKEY *pkey = NULL;
671f13597dSJung-uk Kim     EVP_PKEY_CTX *ctx = NULL;
68b077aed3SPierre Pronchery     char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p;
69b077aed3SPierre Pronchery     const char *ciphername = NULL, *paramfile = NULL, *algname = NULL;
70b077aed3SPierre Pronchery     EVP_CIPHER *cipher = NULL;
71e71b7053SJung-uk Kim     OPTION_CHOICE o;
72e71b7053SJung-uk Kim     int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
73b077aed3SPierre Pronchery     int private = 0, i;
74b077aed3SPierre Pronchery     OSSL_LIB_CTX *libctx = app_get0_libctx();
75b077aed3SPierre Pronchery     STACK_OF(OPENSSL_STRING) *keyopt = NULL;
761f13597dSJung-uk Kim 
77e71b7053SJung-uk Kim     prog = opt_init(argc, argv, genpkey_options);
78b077aed3SPierre Pronchery     keyopt = sk_OPENSSL_STRING_new_null();
79b077aed3SPierre Pronchery     if (keyopt == NULL)
80b077aed3SPierre Pronchery         goto end;
81e71b7053SJung-uk Kim     while ((o = opt_next()) != OPT_EOF) {
82e71b7053SJung-uk Kim         switch (o) {
83e71b7053SJung-uk Kim         case OPT_EOF:
84e71b7053SJung-uk Kim         case OPT_ERR:
85e71b7053SJung-uk Kim  opthelp:
86e71b7053SJung-uk Kim             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
871f13597dSJung-uk Kim             goto end;
88e71b7053SJung-uk Kim         case OPT_HELP:
89e71b7053SJung-uk Kim             ret = 0;
90e71b7053SJung-uk Kim             opt_help(genpkey_options);
91e71b7053SJung-uk Kim             goto end;
92e71b7053SJung-uk Kim         case OPT_OUTFORM:
93e71b7053SJung-uk Kim             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
94e71b7053SJung-uk Kim                 goto opthelp;
95e71b7053SJung-uk Kim             break;
96e71b7053SJung-uk Kim         case OPT_OUT:
97e71b7053SJung-uk Kim             outfile = opt_arg();
98e71b7053SJung-uk Kim             break;
99e71b7053SJung-uk Kim         case OPT_PASS:
100e71b7053SJung-uk Kim             passarg = opt_arg();
101e71b7053SJung-uk Kim             break;
102e71b7053SJung-uk Kim         case OPT_ENGINE:
103e71b7053SJung-uk Kim             e = setup_engine(opt_arg(), 0);
104e71b7053SJung-uk Kim             break;
105e71b7053SJung-uk Kim         case OPT_PARAMFILE:
1061f13597dSJung-uk Kim             if (do_param == 1)
107e71b7053SJung-uk Kim                 goto opthelp;
108b077aed3SPierre Pronchery             paramfile = opt_arg();
109e71b7053SJung-uk Kim             break;
110e71b7053SJung-uk Kim         case OPT_ALGORITHM:
111b077aed3SPierre Pronchery             algname = opt_arg();
112e71b7053SJung-uk Kim             break;
113e71b7053SJung-uk Kim         case OPT_PKEYOPT:
114b077aed3SPierre Pronchery             if (!sk_OPENSSL_STRING_push(keyopt, opt_arg()))
1151f13597dSJung-uk Kim                 goto end;
116b077aed3SPierre Pronchery             break;
117b077aed3SPierre Pronchery         case OPT_QUIET:
118b077aed3SPierre Pronchery             quiet = 1;
119e71b7053SJung-uk Kim             break;
120e71b7053SJung-uk Kim         case OPT_GENPARAM:
1211f13597dSJung-uk Kim             do_param = 1;
122e71b7053SJung-uk Kim             break;
123e71b7053SJung-uk Kim         case OPT_TEXT:
1241f13597dSJung-uk Kim             text = 1;
125e71b7053SJung-uk Kim             break;
126e71b7053SJung-uk Kim         case OPT_CIPHER:
127b077aed3SPierre Pronchery             ciphername = opt_unknown();
128b077aed3SPierre Pronchery             break;
129b077aed3SPierre Pronchery         case OPT_CONFIG:
130b077aed3SPierre Pronchery             conf = app_load_config_modules(opt_arg());
131b077aed3SPierre Pronchery             if (conf == NULL)
1321f13597dSJung-uk Kim                 goto end;
133b077aed3SPierre Pronchery             break;
134b077aed3SPierre Pronchery         case OPT_PROV_CASES:
135b077aed3SPierre Pronchery             if (!opt_provider(o))
136b077aed3SPierre Pronchery                 goto end;
137b077aed3SPierre Pronchery             break;
1381f13597dSJung-uk Kim         }
139e71b7053SJung-uk Kim     }
140b077aed3SPierre Pronchery 
141b077aed3SPierre Pronchery     /* No extra arguments. */
142e71b7053SJung-uk Kim     argc = opt_num_rest();
143e71b7053SJung-uk Kim     if (argc != 0)
144e71b7053SJung-uk Kim         goto opthelp;
1451f13597dSJung-uk Kim 
146b077aed3SPierre Pronchery     /* Fetch cipher, etc. */
147b077aed3SPierre Pronchery     if (paramfile != NULL) {
148b077aed3SPierre Pronchery         if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq()))
149b077aed3SPierre Pronchery             goto end;
150b077aed3SPierre Pronchery     }
151b077aed3SPierre Pronchery     if (algname != NULL) {
152b077aed3SPierre Pronchery         if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq()))
153b077aed3SPierre Pronchery             goto end;
154b077aed3SPierre Pronchery     }
155e71b7053SJung-uk Kim     if (ctx == NULL)
156e71b7053SJung-uk Kim         goto opthelp;
157e71b7053SJung-uk Kim 
158b077aed3SPierre Pronchery     for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) {
159b077aed3SPierre Pronchery         p = sk_OPENSSL_STRING_value(keyopt, i);
160b077aed3SPierre Pronchery         if (pkey_ctrl_string(ctx, p) <= 0) {
161b077aed3SPierre Pronchery             BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p);
162b077aed3SPierre Pronchery             ERR_print_errors(bio_err);
163b077aed3SPierre Pronchery             goto end;
164b077aed3SPierre Pronchery         }
165b077aed3SPierre Pronchery     }
166b077aed3SPierre Pronchery     if (ciphername != NULL)
167b077aed3SPierre Pronchery         if (!opt_cipher(ciphername, &cipher) || do_param == 1)
168b077aed3SPierre Pronchery             goto opthelp;
169b077aed3SPierre Pronchery 
170b077aed3SPierre Pronchery     private = do_param ? 0 : 1;
171b077aed3SPierre Pronchery 
172e71b7053SJung-uk Kim     if (!app_passwd(passarg, NULL, &pass, NULL)) {
1731f13597dSJung-uk Kim         BIO_puts(bio_err, "Error getting password\n");
1741f13597dSJung-uk Kim         goto end;
1751f13597dSJung-uk Kim     }
1761f13597dSJung-uk Kim 
177e71b7053SJung-uk Kim     out = bio_open_owner(outfile, outformat, private);
178e71b7053SJung-uk Kim     if (out == NULL)
1791f13597dSJung-uk Kim         goto end;
1801f13597dSJung-uk Kim 
1811f13597dSJung-uk Kim     EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
1821f13597dSJung-uk Kim     EVP_PKEY_CTX_set_app_data(ctx, bio_err);
1831f13597dSJung-uk Kim 
184b077aed3SPierre Pronchery     pkey = do_param ? app_paramgen(ctx, algname)
185b077aed3SPierre Pronchery                     : app_keygen(ctx, algname, 0, 0 /* not verbose */);
186*ad991e4cSEd Maste     if (pkey == NULL)
187*ad991e4cSEd Maste         goto end;
1881f13597dSJung-uk Kim 
189e71b7053SJung-uk Kim     if (do_param) {
1901f13597dSJung-uk Kim         rv = PEM_write_bio_Parameters(out, pkey);
191e71b7053SJung-uk Kim     } else if (outformat == FORMAT_PEM) {
192e71b7053SJung-uk Kim         assert(private);
1936f9291ceSJung-uk Kim         rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
194e71b7053SJung-uk Kim     } else if (outformat == FORMAT_ASN1) {
195e71b7053SJung-uk Kim         assert(private);
1961f13597dSJung-uk Kim         rv = i2d_PrivateKey_bio(out, pkey);
197e71b7053SJung-uk Kim     } else {
1981f13597dSJung-uk Kim         BIO_printf(bio_err, "Bad format specified for key\n");
1991f13597dSJung-uk Kim         goto end;
2001f13597dSJung-uk Kim     }
2011f13597dSJung-uk Kim 
20258f35182SJung-uk Kim     ret = 0;
20358f35182SJung-uk Kim 
2046f9291ceSJung-uk Kim     if (rv <= 0) {
2051f13597dSJung-uk Kim         BIO_puts(bio_err, "Error writing key\n");
20658f35182SJung-uk Kim         ret = 1;
2071f13597dSJung-uk Kim     }
2081f13597dSJung-uk Kim 
2096f9291ceSJung-uk Kim     if (text) {
2101f13597dSJung-uk Kim         if (do_param)
2111f13597dSJung-uk Kim             rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
2121f13597dSJung-uk Kim         else
2131f13597dSJung-uk Kim             rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
2141f13597dSJung-uk Kim 
2156f9291ceSJung-uk Kim         if (rv <= 0) {
2161f13597dSJung-uk Kim             BIO_puts(bio_err, "Error printing key\n");
21758f35182SJung-uk Kim             ret = 1;
2181f13597dSJung-uk Kim         }
2191f13597dSJung-uk Kim     }
2201f13597dSJung-uk Kim 
2211f13597dSJung-uk Kim  end:
222b077aed3SPierre Pronchery     sk_OPENSSL_STRING_free(keyopt);
223b077aed3SPierre Pronchery     if (ret != 0)
224b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
2251f13597dSJung-uk Kim     EVP_PKEY_free(pkey);
2261f13597dSJung-uk Kim     EVP_PKEY_CTX_free(ctx);
227b077aed3SPierre Pronchery     EVP_CIPHER_free(cipher);
2281f13597dSJung-uk Kim     BIO_free_all(out);
2291f13597dSJung-uk Kim     BIO_free(in);
2306cf8931aSJung-uk Kim     release_engine(e);
2311f13597dSJung-uk Kim     OPENSSL_free(pass);
232b077aed3SPierre Pronchery     NCONF_free(conf);
2331f13597dSJung-uk Kim     return ret;
2341f13597dSJung-uk Kim }
2351f13597dSJung-uk Kim 
init_keygen_file(EVP_PKEY_CTX ** pctx,const char * file,ENGINE * e,OSSL_LIB_CTX * libctx,const char * propq)236b077aed3SPierre Pronchery static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
237b077aed3SPierre Pronchery                             OSSL_LIB_CTX *libctx, const char *propq)
2381f13597dSJung-uk Kim {
2391f13597dSJung-uk Kim     BIO *pbio;
2401f13597dSJung-uk Kim     EVP_PKEY *pkey = NULL;
2411f13597dSJung-uk Kim     EVP_PKEY_CTX *ctx = NULL;
2426f9291ceSJung-uk Kim     if (*pctx) {
243e71b7053SJung-uk Kim         BIO_puts(bio_err, "Parameters already set!\n");
2441f13597dSJung-uk Kim         return 0;
2451f13597dSJung-uk Kim     }
2461f13597dSJung-uk Kim 
2471f13597dSJung-uk Kim     pbio = BIO_new_file(file, "r");
248b077aed3SPierre Pronchery     if (pbio == NULL) {
249e71b7053SJung-uk Kim         BIO_printf(bio_err, "Can't open parameter file %s\n", file);
2501f13597dSJung-uk Kim         return 0;
2511f13597dSJung-uk Kim     }
2521f13597dSJung-uk Kim 
253b077aed3SPierre Pronchery     pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq);
2541f13597dSJung-uk Kim     BIO_free(pbio);
2551f13597dSJung-uk Kim 
256b077aed3SPierre Pronchery     if (pkey == NULL) {
2571f13597dSJung-uk Kim         BIO_printf(bio_err, "Error reading parameter file %s\n", file);
2581f13597dSJung-uk Kim         return 0;
2591f13597dSJung-uk Kim     }
2601f13597dSJung-uk Kim 
261b077aed3SPierre Pronchery     if (e != NULL)
2621f13597dSJung-uk Kim         ctx = EVP_PKEY_CTX_new(pkey, e);
263b077aed3SPierre Pronchery     else
264b077aed3SPierre Pronchery         ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
265e71b7053SJung-uk Kim     if (ctx == NULL)
2661f13597dSJung-uk Kim         goto err;
2671f13597dSJung-uk Kim     if (EVP_PKEY_keygen_init(ctx) <= 0)
2681f13597dSJung-uk Kim         goto err;
2691f13597dSJung-uk Kim     EVP_PKEY_free(pkey);
2701f13597dSJung-uk Kim     *pctx = ctx;
2711f13597dSJung-uk Kim     return 1;
2721f13597dSJung-uk Kim 
2731f13597dSJung-uk Kim  err:
274e71b7053SJung-uk Kim     BIO_puts(bio_err, "Error initializing context\n");
275e71b7053SJung-uk Kim     ERR_print_errors(bio_err);
2761f13597dSJung-uk Kim     EVP_PKEY_CTX_free(ctx);
2771f13597dSJung-uk Kim     EVP_PKEY_free(pkey);
2781f13597dSJung-uk Kim     return 0;
2791f13597dSJung-uk Kim 
2801f13597dSJung-uk Kim }
2811f13597dSJung-uk Kim 
init_gen_str(EVP_PKEY_CTX ** pctx,const char * algname,ENGINE * e,int do_param,OSSL_LIB_CTX * libctx,const char * propq)282e71b7053SJung-uk Kim int init_gen_str(EVP_PKEY_CTX **pctx,
283b077aed3SPierre Pronchery                  const char *algname, ENGINE *e, int do_param,
284b077aed3SPierre Pronchery                  OSSL_LIB_CTX *libctx, const char *propq)
2851f13597dSJung-uk Kim {
2861f13597dSJung-uk Kim     EVP_PKEY_CTX *ctx = NULL;
2871f13597dSJung-uk Kim     int pkey_id;
2881f13597dSJung-uk Kim 
2896f9291ceSJung-uk Kim     if (*pctx) {
290e71b7053SJung-uk Kim         BIO_puts(bio_err, "Algorithm already set!\n");
2911f13597dSJung-uk Kim         return 0;
2921f13597dSJung-uk Kim     }
2931f13597dSJung-uk Kim 
294b077aed3SPierre Pronchery     pkey_id = get_legacy_pkey_id(libctx, algname, e);
295b077aed3SPierre Pronchery     if (pkey_id != NID_undef)
2961f13597dSJung-uk Kim         ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
297b077aed3SPierre Pronchery     else
298b077aed3SPierre Pronchery         ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
2991f13597dSJung-uk Kim 
300b077aed3SPierre Pronchery     if (ctx == NULL)
3011f13597dSJung-uk Kim         goto err;
3026f9291ceSJung-uk Kim     if (do_param) {
3031f13597dSJung-uk Kim         if (EVP_PKEY_paramgen_init(ctx) <= 0)
3041f13597dSJung-uk Kim             goto err;
3056f9291ceSJung-uk Kim     } else {
3061f13597dSJung-uk Kim         if (EVP_PKEY_keygen_init(ctx) <= 0)
3071f13597dSJung-uk Kim             goto err;
3081f13597dSJung-uk Kim     }
3091f13597dSJung-uk Kim 
3101f13597dSJung-uk Kim     *pctx = ctx;
3111f13597dSJung-uk Kim     return 1;
3121f13597dSJung-uk Kim 
3131f13597dSJung-uk Kim  err:
314e71b7053SJung-uk Kim     BIO_printf(bio_err, "Error initializing %s context\n", algname);
315e71b7053SJung-uk Kim     ERR_print_errors(bio_err);
3161f13597dSJung-uk Kim     EVP_PKEY_CTX_free(ctx);
3171f13597dSJung-uk Kim     return 0;
3181f13597dSJung-uk Kim 
3191f13597dSJung-uk Kim }
3201f13597dSJung-uk Kim 
genpkey_cb(EVP_PKEY_CTX * ctx)3211f13597dSJung-uk Kim static int genpkey_cb(EVP_PKEY_CTX *ctx)
3221f13597dSJung-uk Kim {
3231f13597dSJung-uk Kim     char c = '*';
3241f13597dSJung-uk Kim     BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
325b077aed3SPierre Pronchery 
326b077aed3SPierre Pronchery     if (quiet)
327b077aed3SPierre Pronchery         return 1;
328b077aed3SPierre Pronchery 
329b077aed3SPierre Pronchery     switch (EVP_PKEY_CTX_get_keygen_info(ctx, 0)) {
330b077aed3SPierre Pronchery     case 0:
3316f9291ceSJung-uk Kim         c = '.';
332b077aed3SPierre Pronchery         break;
333b077aed3SPierre Pronchery     case 1:
3346f9291ceSJung-uk Kim         c = '+';
335b077aed3SPierre Pronchery         break;
336b077aed3SPierre Pronchery     case 3:
3376f9291ceSJung-uk Kim         c = '\n';
338b077aed3SPierre Pronchery         break;
339b077aed3SPierre Pronchery     }
340b077aed3SPierre Pronchery 
3411f13597dSJung-uk Kim     BIO_write(b, &c, 1);
3421f13597dSJung-uk Kim     (void)BIO_flush(b);
3431f13597dSJung-uk Kim     return 1;
3441f13597dSJung-uk Kim }
345