Home | History | Annotate | Line # | Download | only in apps
      1      1.1  christos /*
      2      1.1  christos  * Copyright 2006-2025 The OpenSSL Project Authors. All Rights Reserved.
      3      1.1  christos  *
      4      1.1  christos  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5      1.1  christos  * this file except in compliance with the License.  You can obtain a copy
      6      1.1  christos  * in the file LICENSE in the source distribution or at
      7      1.1  christos  * https://www.openssl.org/source/license.html
      8      1.1  christos  */
      9      1.1  christos 
     10      1.1  christos #include <stdio.h>
     11      1.1  christos #include <string.h>
     12      1.1  christos #include "apps.h"
     13      1.1  christos #include "progs.h"
     14      1.1  christos #include <openssl/pem.h>
     15      1.1  christos #include <openssl/err.h>
     16      1.1  christos #include <openssl/evp.h>
     17      1.1  christos 
     18      1.1  christos static int verbose = 1;
     19      1.1  christos 
     20      1.1  christos static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
     21  1.1.1.2  christos     OSSL_LIB_CTX *libctx, const char *propq);
     22      1.1  christos typedef enum OPTION_choice {
     23      1.1  christos     OPT_COMMON,
     24  1.1.1.2  christos     OPT_ENGINE,
     25  1.1.1.2  christos     OPT_OUTFORM,
     26  1.1.1.2  christos     OPT_OUT,
     27  1.1.1.2  christos     OPT_PASS,
     28  1.1.1.2  christos     OPT_PARAMFILE,
     29  1.1.1.2  christos     OPT_ALGORITHM,
     30  1.1.1.2  christos     OPT_PKEYOPT,
     31  1.1.1.2  christos     OPT_GENPARAM,
     32  1.1.1.2  christos     OPT_TEXT,
     33  1.1.1.2  christos     OPT_CIPHER,
     34  1.1.1.2  christos     OPT_VERBOSE,
     35  1.1.1.2  christos     OPT_QUIET,
     36  1.1.1.2  christos     OPT_CONFIG,
     37  1.1.1.2  christos     OPT_OUTPUBKEY,
     38  1.1.1.2  christos     OPT_PROV_ENUM,
     39  1.1.1.2  christos     OPT_R_ENUM
     40      1.1  christos } OPTION_CHOICE;
     41      1.1  christos 
     42      1.1  christos const OPTIONS genpkey_options[] = {
     43      1.1  christos     OPT_SECTION("General"),
     44  1.1.1.2  christos     { "help", OPT_HELP, '-', "Display this summary" },
     45      1.1  christos #ifndef OPENSSL_NO_ENGINE
     46  1.1.1.2  christos     { "engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device" },
     47      1.1  christos #endif
     48  1.1.1.2  christos     { "paramfile", OPT_PARAMFILE, '<', "Parameters file" },
     49  1.1.1.2  christos     { "algorithm", OPT_ALGORITHM, 's', "The public key algorithm" },
     50  1.1.1.2  christos     { "verbose", OPT_VERBOSE, '-', "Output status while generating keys" },
     51  1.1.1.2  christos     { "quiet", OPT_QUIET, '-', "Do not output status while generating keys" },
     52  1.1.1.2  christos     { "pkeyopt", OPT_PKEYOPT, 's',
     53  1.1.1.2  christos         "Set the public key algorithm option as opt:value" },
     54  1.1.1.2  christos     OPT_CONFIG_OPTION,
     55      1.1  christos 
     56      1.1  christos     OPT_SECTION("Output"),
     57  1.1.1.2  christos     { "out", OPT_OUT, '>', "Output (private key) file" },
     58  1.1.1.2  christos     { "outpubkey", OPT_OUTPUBKEY, '>', "Output public key file" },
     59  1.1.1.2  christos     { "outform", OPT_OUTFORM, 'F', "output format (DER or PEM)" },
     60  1.1.1.2  christos     { "pass", OPT_PASS, 's', "Output file pass phrase source" },
     61  1.1.1.2  christos     { "genparam", OPT_GENPARAM, '-', "Generate parameters, not key" },
     62  1.1.1.2  christos     { "text", OPT_TEXT, '-', "Print the private key in text" },
     63  1.1.1.2  christos     { "", OPT_CIPHER, '-', "Cipher to use to encrypt the key" },
     64      1.1  christos 
     65      1.1  christos     OPT_PROV_OPTIONS,
     66      1.1  christos     OPT_R_OPTIONS,
     67      1.1  christos 
     68      1.1  christos     /* This is deliberately last. */
     69  1.1.1.2  christos     { OPT_HELP_STR, 1, 1,
     70  1.1.1.2  christos         "Order of options may be important!  See the documentation.\n" },
     71  1.1.1.2  christos     { NULL }
     72      1.1  christos };
     73      1.1  christos 
     74      1.1  christos static const char *param_datatype_2name(unsigned int type, int *ishex)
     75      1.1  christos {
     76      1.1  christos     *ishex = 0;
     77      1.1  christos 
     78      1.1  christos     switch (type) {
     79  1.1.1.2  christos     case OSSL_PARAM_INTEGER:
     80  1.1.1.2  christos         return "int";
     81  1.1.1.2  christos     case OSSL_PARAM_UNSIGNED_INTEGER:
     82  1.1.1.2  christos         return "uint";
     83  1.1.1.2  christos     case OSSL_PARAM_REAL:
     84  1.1.1.2  christos         return "float";
     85  1.1.1.2  christos     case OSSL_PARAM_OCTET_STRING:
     86  1.1.1.2  christos         *ishex = 1;
     87  1.1.1.2  christos         return "string";
     88  1.1.1.2  christos     case OSSL_PARAM_UTF8_STRING:
     89  1.1.1.2  christos         return "string";
     90      1.1  christos     default:
     91      1.1  christos         return NULL;
     92      1.1  christos     }
     93      1.1  christos }
     94      1.1  christos 
     95      1.1  christos static void show_gen_pkeyopt(const char *algname, OSSL_LIB_CTX *libctx, const char *propq)
     96      1.1  christos {
     97      1.1  christos     EVP_PKEY_CTX *ctx = NULL;
     98      1.1  christos     const OSSL_PARAM *params;
     99      1.1  christos     int i, ishex = 0;
    100      1.1  christos 
    101      1.1  christos     if (algname == NULL)
    102      1.1  christos         return;
    103      1.1  christos     ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
    104      1.1  christos     if (ctx == NULL)
    105      1.1  christos         return;
    106      1.1  christos 
    107      1.1  christos     if (EVP_PKEY_keygen_init(ctx) <= 0)
    108      1.1  christos         goto cleanup;
    109      1.1  christos     params = EVP_PKEY_CTX_settable_params(ctx);
    110      1.1  christos     if (params == NULL)
    111      1.1  christos         goto cleanup;
    112      1.1  christos 
    113      1.1  christos     BIO_printf(bio_err, "\nThe possible -pkeyopt arguments are:\n");
    114      1.1  christos     for (i = 0; params[i].key != NULL; ++i) {
    115      1.1  christos         const char *name = param_datatype_2name(params[i].data_type, &ishex);
    116      1.1  christos 
    117      1.1  christos         if (name != NULL)
    118      1.1  christos             BIO_printf(bio_err, "    %s%s:%s\n", ishex ? "hex" : "", params[i].key, name);
    119      1.1  christos     }
    120      1.1  christos cleanup:
    121      1.1  christos     EVP_PKEY_CTX_free(ctx);
    122      1.1  christos }
    123      1.1  christos 
    124      1.1  christos int genpkey_main(int argc, char **argv)
    125      1.1  christos {
    126      1.1  christos     CONF *conf = NULL;
    127      1.1  christos     BIO *mem_out = NULL, *mem_outpubkey = NULL;
    128      1.1  christos     ENGINE *e = NULL;
    129      1.1  christos     EVP_PKEY *pkey = NULL;
    130      1.1  christos     EVP_PKEY_CTX *ctx = NULL;
    131      1.1  christos     char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p;
    132      1.1  christos     char *outpubkeyfile = NULL;
    133      1.1  christos     const char *ciphername = NULL, *paramfile = NULL, *algname = NULL;
    134      1.1  christos     EVP_CIPHER *cipher = NULL;
    135      1.1  christos     OPTION_CHOICE o;
    136      1.1  christos     int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
    137      1.1  christos     int private = 0, i;
    138      1.1  christos     OSSL_LIB_CTX *libctx = app_get0_libctx();
    139      1.1  christos     STACK_OF(OPENSSL_STRING) *keyopt = NULL;
    140      1.1  christos 
    141      1.1  christos     opt_set_unknown_name("cipher");
    142      1.1  christos     prog = opt_init(argc, argv, genpkey_options);
    143      1.1  christos     keyopt = sk_OPENSSL_STRING_new_null();
    144      1.1  christos     if (keyopt == NULL)
    145      1.1  christos         goto end;
    146      1.1  christos     while ((o = opt_next()) != OPT_EOF) {
    147      1.1  christos         switch (o) {
    148      1.1  christos         case OPT_EOF:
    149      1.1  christos         case OPT_ERR:
    150  1.1.1.2  christos         opthelp:
    151      1.1  christos             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
    152      1.1  christos             goto end;
    153      1.1  christos         case OPT_HELP:
    154      1.1  christos             ret = 0;
    155      1.1  christos             opt_help(genpkey_options);
    156      1.1  christos             show_gen_pkeyopt(algname, libctx, app_get0_propq());
    157      1.1  christos             goto end;
    158      1.1  christos         case OPT_OUTFORM:
    159      1.1  christos             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
    160      1.1  christos                 goto opthelp;
    161      1.1  christos             break;
    162      1.1  christos         case OPT_OUT:
    163      1.1  christos             outfile = opt_arg();
    164      1.1  christos             break;
    165      1.1  christos         case OPT_OUTPUBKEY:
    166      1.1  christos             outpubkeyfile = opt_arg();
    167      1.1  christos             break;
    168      1.1  christos         case OPT_PASS:
    169      1.1  christos             passarg = opt_arg();
    170      1.1  christos             break;
    171      1.1  christos         case OPT_ENGINE:
    172      1.1  christos             e = setup_engine(opt_arg(), 0);
    173      1.1  christos             break;
    174      1.1  christos         case OPT_PARAMFILE:
    175      1.1  christos             if (do_param == 1)
    176      1.1  christos                 goto opthelp;
    177      1.1  christos             paramfile = opt_arg();
    178      1.1  christos             break;
    179      1.1  christos         case OPT_ALGORITHM:
    180      1.1  christos             algname = opt_arg();
    181      1.1  christos             break;
    182      1.1  christos         case OPT_PKEYOPT:
    183      1.1  christos             if (!sk_OPENSSL_STRING_push(keyopt, opt_arg()))
    184      1.1  christos                 goto end;
    185      1.1  christos             break;
    186      1.1  christos         case OPT_QUIET:
    187      1.1  christos             verbose = 0;
    188      1.1  christos             break;
    189      1.1  christos         case OPT_VERBOSE:
    190      1.1  christos             verbose = 1;
    191      1.1  christos             break;
    192      1.1  christos         case OPT_GENPARAM:
    193      1.1  christos             do_param = 1;
    194      1.1  christos             break;
    195      1.1  christos         case OPT_TEXT:
    196      1.1  christos             text = 1;
    197      1.1  christos             break;
    198      1.1  christos         case OPT_CIPHER:
    199      1.1  christos             ciphername = opt_unknown();
    200      1.1  christos             break;
    201      1.1  christos         case OPT_CONFIG:
    202      1.1  christos             conf = app_load_config_modules(opt_arg());
    203      1.1  christos             if (conf == NULL)
    204      1.1  christos                 goto end;
    205      1.1  christos             break;
    206      1.1  christos         case OPT_PROV_CASES:
    207      1.1  christos             if (!opt_provider(o))
    208      1.1  christos                 goto end;
    209      1.1  christos             break;
    210      1.1  christos         case OPT_R_CASES:
    211      1.1  christos             if (!opt_rand(o))
    212      1.1  christos                 goto end;
    213      1.1  christos             break;
    214      1.1  christos         }
    215      1.1  christos     }
    216      1.1  christos 
    217      1.1  christos     /* No extra arguments. */
    218      1.1  christos     if (!opt_check_rest_arg(NULL))
    219      1.1  christos         goto opthelp;
    220      1.1  christos 
    221      1.1  christos     if (!app_RAND_load())
    222      1.1  christos         goto end;
    223      1.1  christos 
    224      1.1  christos     /* Fetch cipher, etc. */
    225      1.1  christos     if (paramfile != NULL) {
    226      1.1  christos         if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq()))
    227      1.1  christos             goto end;
    228      1.1  christos     }
    229      1.1  christos     if (algname != NULL) {
    230      1.1  christos         if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq()))
    231      1.1  christos             goto end;
    232      1.1  christos     }
    233      1.1  christos     if (ctx == NULL)
    234      1.1  christos         goto opthelp;
    235      1.1  christos 
    236      1.1  christos     for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) {
    237      1.1  christos         p = sk_OPENSSL_STRING_value(keyopt, i);
    238      1.1  christos         if (pkey_ctrl_string(ctx, p) <= 0) {
    239      1.1  christos             BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p);
    240      1.1  christos             ERR_print_errors(bio_err);
    241      1.1  christos             goto end;
    242      1.1  christos         }
    243      1.1  christos     }
    244      1.1  christos     if (!opt_cipher(ciphername, &cipher))
    245      1.1  christos         goto opthelp;
    246      1.1  christos     if (ciphername != NULL && do_param == 1) {
    247      1.1  christos         BIO_printf(bio_err, "Cannot use cipher with -genparam option\n");
    248      1.1  christos         goto opthelp;
    249      1.1  christos     }
    250      1.1  christos 
    251      1.1  christos     private = do_param ? 0 : 1;
    252      1.1  christos 
    253      1.1  christos     if (!app_passwd(passarg, NULL, &pass, NULL)) {
    254      1.1  christos         BIO_puts(bio_err, "Error getting password\n");
    255      1.1  christos         goto end;
    256      1.1  christos     }
    257      1.1  christos 
    258      1.1  christos     mem_out = BIO_new(BIO_s_mem());
    259      1.1  christos     if (mem_out == NULL)
    260      1.1  christos         goto end;
    261      1.1  christos     BIO_set_mem_eof_return(mem_out, 0);
    262      1.1  christos 
    263      1.1  christos     if (outpubkeyfile != NULL) {
    264      1.1  christos         mem_outpubkey = BIO_new(BIO_s_mem());
    265      1.1  christos         if (mem_outpubkey == NULL)
    266      1.1  christos             goto end;
    267      1.1  christos         BIO_set_mem_eof_return(mem_outpubkey, 0);
    268      1.1  christos     }
    269      1.1  christos 
    270      1.1  christos     if (verbose)
    271      1.1  christos         EVP_PKEY_CTX_set_cb(ctx, progress_cb);
    272      1.1  christos     EVP_PKEY_CTX_set_app_data(ctx, bio_err);
    273      1.1  christos 
    274      1.1  christos     pkey = do_param ? app_paramgen(ctx, algname)
    275      1.1  christos                     : app_keygen(ctx, algname, 0, 0 /* not verbose */);
    276      1.1  christos     if (pkey == NULL)
    277      1.1  christos         goto end;
    278      1.1  christos 
    279      1.1  christos     if (do_param) {
    280      1.1  christos         rv = PEM_write_bio_Parameters(mem_out, pkey);
    281      1.1  christos     } else if (outformat == FORMAT_PEM) {
    282      1.1  christos         assert(private);
    283      1.1  christos         rv = PEM_write_bio_PrivateKey(mem_out, pkey, cipher, NULL, 0, NULL, pass);
    284      1.1  christos         if (rv > 0 && mem_outpubkey != NULL)
    285      1.1  christos             rv = PEM_write_bio_PUBKEY(mem_outpubkey, pkey);
    286      1.1  christos     } else if (outformat == FORMAT_ASN1) {
    287      1.1  christos         assert(private);
    288      1.1  christos         rv = i2d_PrivateKey_bio(mem_out, pkey);
    289      1.1  christos         if (rv > 0 && mem_outpubkey != NULL)
    290      1.1  christos             rv = i2d_PUBKEY_bio(mem_outpubkey, pkey);
    291      1.1  christos     } else {
    292      1.1  christos         BIO_printf(bio_err, "Bad format specified for key\n");
    293      1.1  christos         goto end;
    294      1.1  christos     }
    295      1.1  christos 
    296      1.1  christos     ret = 0;
    297      1.1  christos 
    298      1.1  christos     if (rv <= 0) {
    299      1.1  christos         BIO_puts(bio_err, "Error writing key(s)\n");
    300      1.1  christos         ret = 1;
    301      1.1  christos     }
    302      1.1  christos 
    303      1.1  christos     if (text) {
    304      1.1  christos         if (do_param)
    305      1.1  christos             rv = EVP_PKEY_print_params(mem_out, pkey, 0, NULL);
    306      1.1  christos         else
    307      1.1  christos             rv = EVP_PKEY_print_private(mem_out, pkey, 0, NULL);
    308      1.1  christos 
    309      1.1  christos         if (rv <= 0) {
    310      1.1  christos             BIO_puts(bio_err, "Error printing key\n");
    311      1.1  christos             ret = 1;
    312      1.1  christos         }
    313      1.1  christos     }
    314      1.1  christos 
    315  1.1.1.2  christos end:
    316      1.1  christos     sk_OPENSSL_STRING_free(keyopt);
    317      1.1  christos     if (ret != 0) {
    318      1.1  christos         ERR_print_errors(bio_err);
    319      1.1  christos     } else {
    320      1.1  christos         if (mem_outpubkey != NULL) {
    321      1.1  christos             rv = mem_bio_to_file(mem_outpubkey, outpubkeyfile, outformat, private);
    322      1.1  christos             if (!rv)
    323      1.1  christos                 BIO_printf(bio_err, "Error writing to outpubkey: '%s'. Error: %s\n",
    324  1.1.1.2  christos                     outpubkeyfile, strerror(errno));
    325      1.1  christos         }
    326      1.1  christos         if (mem_out != NULL) {
    327      1.1  christos             rv = mem_bio_to_file(mem_out, outfile, outformat, private);
    328      1.1  christos             if (!rv)
    329      1.1  christos                 BIO_printf(bio_err, "Error writing to outfile: '%s'. Error: %s\n",
    330  1.1.1.2  christos                     outfile, strerror(errno));
    331      1.1  christos         }
    332      1.1  christos     }
    333      1.1  christos     EVP_PKEY_free(pkey);
    334      1.1  christos     EVP_PKEY_CTX_free(ctx);
    335      1.1  christos     EVP_CIPHER_free(cipher);
    336      1.1  christos     BIO_free_all(mem_out);
    337      1.1  christos     BIO_free_all(mem_outpubkey);
    338      1.1  christos     release_engine(e);
    339      1.1  christos     OPENSSL_free(pass);
    340      1.1  christos     NCONF_free(conf);
    341      1.1  christos     return ret;
    342      1.1  christos }
    343      1.1  christos 
    344      1.1  christos static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
    345  1.1.1.2  christos     OSSL_LIB_CTX *libctx, const char *propq)
    346      1.1  christos {
    347      1.1  christos     BIO *pbio;
    348      1.1  christos     EVP_PKEY *pkey = NULL;
    349      1.1  christos     EVP_PKEY_CTX *ctx = NULL;
    350      1.1  christos     if (*pctx) {
    351      1.1  christos         BIO_puts(bio_err, "Parameters already set!\n");
    352      1.1  christos         return 0;
    353      1.1  christos     }
    354      1.1  christos 
    355      1.1  christos     pbio = BIO_new_file(file, "r");
    356      1.1  christos     if (pbio == NULL) {
    357      1.1  christos         BIO_printf(bio_err, "Can't open parameter file %s\n", file);
    358      1.1  christos         return 0;
    359      1.1  christos     }
    360      1.1  christos 
    361      1.1  christos     pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq);
    362      1.1  christos     BIO_free(pbio);
    363      1.1  christos 
    364      1.1  christos     if (pkey == NULL) {
    365      1.1  christos         BIO_printf(bio_err, "Error reading parameter file %s\n", file);
    366      1.1  christos         return 0;
    367      1.1  christos     }
    368      1.1  christos 
    369      1.1  christos     if (e != NULL)
    370      1.1  christos         ctx = EVP_PKEY_CTX_new(pkey, e);
    371      1.1  christos     else
    372      1.1  christos         ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
    373      1.1  christos     if (ctx == NULL)
    374      1.1  christos         goto err;
    375      1.1  christos     if (EVP_PKEY_keygen_init(ctx) <= 0)
    376      1.1  christos         goto err;
    377      1.1  christos     EVP_PKEY_free(pkey);
    378      1.1  christos     *pctx = ctx;
    379      1.1  christos     return 1;
    380      1.1  christos 
    381  1.1.1.2  christos err:
    382      1.1  christos     BIO_puts(bio_err, "Error initializing context\n");
    383      1.1  christos     ERR_print_errors(bio_err);
    384      1.1  christos     EVP_PKEY_CTX_free(ctx);
    385      1.1  christos     EVP_PKEY_free(pkey);
    386      1.1  christos     return 0;
    387      1.1  christos }
    388      1.1  christos 
    389      1.1  christos int init_gen_str(EVP_PKEY_CTX **pctx,
    390  1.1.1.2  christos     const char *algname, ENGINE *e, int do_param,
    391  1.1.1.2  christos     OSSL_LIB_CTX *libctx, const char *propq)
    392      1.1  christos {
    393      1.1  christos     EVP_PKEY_CTX *ctx = NULL;
    394      1.1  christos     int pkey_id;
    395      1.1  christos 
    396      1.1  christos     if (*pctx) {
    397      1.1  christos         BIO_puts(bio_err, "Algorithm already set!\n");
    398      1.1  christos         return 0;
    399      1.1  christos     }
    400      1.1  christos 
    401      1.1  christos     pkey_id = get_legacy_pkey_id(libctx, algname, e);
    402      1.1  christos     if (pkey_id != NID_undef)
    403      1.1  christos         ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
    404      1.1  christos     else
    405      1.1  christos         ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
    406      1.1  christos 
    407      1.1  christos     if (ctx == NULL)
    408      1.1  christos         goto err;
    409      1.1  christos     if (do_param) {
    410      1.1  christos         if (EVP_PKEY_paramgen_init(ctx) <= 0)
    411      1.1  christos             goto err;
    412      1.1  christos     } else {
    413      1.1  christos         if (EVP_PKEY_keygen_init(ctx) <= 0)
    414      1.1  christos             goto err;
    415      1.1  christos     }
    416      1.1  christos 
    417      1.1  christos     *pctx = ctx;
    418      1.1  christos     return 1;
    419      1.1  christos 
    420  1.1.1.2  christos err:
    421      1.1  christos     BIO_printf(bio_err, "Error initializing %s context\n", algname);
    422      1.1  christos     ERR_print_errors(bio_err);
    423      1.1  christos     EVP_PKEY_CTX_free(ctx);
    424      1.1  christos     return 0;
    425      1.1  christos }
    426