Home | History | Annotate | Line # | Download | only in apps
      1 /*
      2  * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the OpenSSL license (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include <stdio.h>
     11 #include <string.h>
     12 #include "apps.h"
     13 #include "progs.h"
     14 #include <openssl/pem.h>
     15 #include <openssl/err.h>
     16 #include <openssl/evp.h>
     17 #ifndef OPENSSL_NO_ENGINE
     18 # include <openssl/engine.h>
     19 #endif
     20 
     21 static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e);
     22 static int genpkey_cb(EVP_PKEY_CTX *ctx);
     23 
     24 typedef enum OPTION_choice {
     25     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
     26     OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE,
     27     OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER
     28 } OPTION_CHOICE;
     29 
     30 const OPTIONS genpkey_options[] = {
     31     {"help", OPT_HELP, '-', "Display this summary"},
     32     {"out", OPT_OUT, '>', "Output file"},
     33     {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"},
     34     {"pass", OPT_PASS, 's', "Output file pass phrase source"},
     35     {"paramfile", OPT_PARAMFILE, '<', "Parameters file"},
     36     {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"},
     37     {"pkeyopt", OPT_PKEYOPT, 's',
     38      "Set the public key algorithm option as opt:value"},
     39     {"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"},
     40     {"text", OPT_TEXT, '-', "Print the in text"},
     41     {"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"},
     42 #ifndef OPENSSL_NO_ENGINE
     43     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
     44 #endif
     45     /* This is deliberately last. */
     46     {OPT_HELP_STR, 1, 1,
     47      "Order of options may be important!  See the documentation.\n"},
     48     {NULL}
     49 };
     50 
     51 int genpkey_main(int argc, char **argv)
     52 {
     53     BIO *in = NULL, *out = NULL;
     54     ENGINE *e = NULL;
     55     EVP_PKEY *pkey = NULL;
     56     EVP_PKEY_CTX *ctx = NULL;
     57     char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog;
     58     const EVP_CIPHER *cipher = NULL;
     59     OPTION_CHOICE o;
     60     int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
     61     int private = 0;
     62 
     63     prog = opt_init(argc, argv, genpkey_options);
     64     while ((o = opt_next()) != OPT_EOF) {
     65         switch (o) {
     66         case OPT_EOF:
     67         case OPT_ERR:
     68  opthelp:
     69             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
     70             goto end;
     71         case OPT_HELP:
     72             ret = 0;
     73             opt_help(genpkey_options);
     74             goto end;
     75         case OPT_OUTFORM:
     76             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
     77                 goto opthelp;
     78             break;
     79         case OPT_OUT:
     80             outfile = opt_arg();
     81             break;
     82         case OPT_PASS:
     83             passarg = opt_arg();
     84             break;
     85         case OPT_ENGINE:
     86             e = setup_engine(opt_arg(), 0);
     87             break;
     88         case OPT_PARAMFILE:
     89             if (do_param == 1)
     90                 goto opthelp;
     91             if (!init_keygen_file(&ctx, opt_arg(), e))
     92                 goto end;
     93             break;
     94         case OPT_ALGORITHM:
     95             if (!init_gen_str(&ctx, opt_arg(), e, do_param))
     96                 goto end;
     97             break;
     98         case OPT_PKEYOPT:
     99             if (ctx == NULL) {
    100                 BIO_printf(bio_err, "%s: No keytype specified.\n", prog);
    101                 goto opthelp;
    102             }
    103             if (pkey_ctrl_string(ctx, opt_arg()) <= 0) {
    104                 BIO_printf(bio_err,
    105                            "%s: Error setting %s parameter:\n",
    106                            prog, opt_arg());
    107                 ERR_print_errors(bio_err);
    108                 goto end;
    109             }
    110             break;
    111         case OPT_GENPARAM:
    112             if (ctx != NULL)
    113                 goto opthelp;
    114             do_param = 1;
    115             break;
    116         case OPT_TEXT:
    117             text = 1;
    118             break;
    119         case OPT_CIPHER:
    120             if (!opt_cipher(opt_unknown(), &cipher)
    121                 || do_param == 1)
    122                 goto opthelp;
    123             if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE ||
    124                 EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE ||
    125                 EVP_CIPHER_mode(cipher) == EVP_CIPH_XTS_MODE ||
    126                 EVP_CIPHER_mode(cipher) == EVP_CIPH_OCB_MODE) {
    127                 BIO_printf(bio_err, "%s: cipher mode not supported\n", prog);
    128                 goto end;
    129             }
    130         }
    131     }
    132     argc = opt_num_rest();
    133     if (argc != 0)
    134         goto opthelp;
    135 
    136     private = do_param ? 0 : 1;
    137 
    138     if (ctx == NULL)
    139         goto opthelp;
    140 
    141     if (!app_passwd(passarg, NULL, &pass, NULL)) {
    142         BIO_puts(bio_err, "Error getting password\n");
    143         goto end;
    144     }
    145 
    146     out = bio_open_owner(outfile, outformat, private);
    147     if (out == NULL)
    148         goto end;
    149 
    150     EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
    151     EVP_PKEY_CTX_set_app_data(ctx, bio_err);
    152 
    153     if (do_param) {
    154         if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) {
    155             BIO_puts(bio_err, "Error generating parameters\n");
    156             ERR_print_errors(bio_err);
    157             goto end;
    158         }
    159     } else {
    160         if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
    161             BIO_puts(bio_err, "Error generating key\n");
    162             ERR_print_errors(bio_err);
    163             goto end;
    164         }
    165     }
    166 
    167     if (do_param) {
    168         rv = PEM_write_bio_Parameters(out, pkey);
    169     } else if (outformat == FORMAT_PEM) {
    170         assert(private);
    171         rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
    172     } else if (outformat == FORMAT_ASN1) {
    173         assert(private);
    174         rv = i2d_PrivateKey_bio(out, pkey);
    175     } else {
    176         BIO_printf(bio_err, "Bad format specified for key\n");
    177         goto end;
    178     }
    179 
    180     ret = 0;
    181 
    182     if (rv <= 0) {
    183         BIO_puts(bio_err, "Error writing key\n");
    184         ERR_print_errors(bio_err);
    185         ret = 1;
    186     }
    187 
    188     if (text) {
    189         if (do_param)
    190             rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
    191         else
    192             rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
    193 
    194         if (rv <= 0) {
    195             BIO_puts(bio_err, "Error printing key\n");
    196             ERR_print_errors(bio_err);
    197             ret = 1;
    198         }
    199     }
    200 
    201  end:
    202     EVP_PKEY_free(pkey);
    203     EVP_PKEY_CTX_free(ctx);
    204     BIO_free_all(out);
    205     BIO_free(in);
    206     release_engine(e);
    207     OPENSSL_free(pass);
    208     return ret;
    209 }
    210 
    211 static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e)
    212 {
    213     BIO *pbio;
    214     EVP_PKEY *pkey = NULL;
    215     EVP_PKEY_CTX *ctx = NULL;
    216     if (*pctx) {
    217         BIO_puts(bio_err, "Parameters already set!\n");
    218         return 0;
    219     }
    220 
    221     pbio = BIO_new_file(file, "r");
    222     if (!pbio) {
    223         BIO_printf(bio_err, "Can't open parameter file %s\n", file);
    224         return 0;
    225     }
    226 
    227     pkey = PEM_read_bio_Parameters(pbio, NULL);
    228     BIO_free(pbio);
    229 
    230     if (!pkey) {
    231         BIO_printf(bio_err, "Error reading parameter file %s\n", file);
    232         return 0;
    233     }
    234 
    235     ctx = EVP_PKEY_CTX_new(pkey, e);
    236     if (ctx == NULL)
    237         goto err;
    238     if (EVP_PKEY_keygen_init(ctx) <= 0)
    239         goto err;
    240     EVP_PKEY_free(pkey);
    241     *pctx = ctx;
    242     return 1;
    243 
    244  err:
    245     BIO_puts(bio_err, "Error initializing context\n");
    246     ERR_print_errors(bio_err);
    247     EVP_PKEY_CTX_free(ctx);
    248     EVP_PKEY_free(pkey);
    249     return 0;
    250 
    251 }
    252 
    253 int init_gen_str(EVP_PKEY_CTX **pctx,
    254                  const char *algname, ENGINE *e, int do_param)
    255 {
    256     EVP_PKEY_CTX *ctx = NULL;
    257     const EVP_PKEY_ASN1_METHOD *ameth;
    258     ENGINE *tmpeng = NULL;
    259     int pkey_id;
    260 
    261     if (*pctx) {
    262         BIO_puts(bio_err, "Algorithm already set!\n");
    263         return 0;
    264     }
    265 
    266     ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
    267 
    268 #ifndef OPENSSL_NO_ENGINE
    269     if (!ameth && e)
    270         ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
    271 #endif
    272 
    273     if (!ameth) {
    274         BIO_printf(bio_err, "Algorithm %s not found\n", algname);
    275         return 0;
    276     }
    277 
    278     ERR_clear_error();
    279 
    280     EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
    281 #ifndef OPENSSL_NO_ENGINE
    282     ENGINE_finish(tmpeng);
    283 #endif
    284     ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
    285 
    286     if (!ctx)
    287         goto err;
    288     if (do_param) {
    289         if (EVP_PKEY_paramgen_init(ctx) <= 0)
    290             goto err;
    291     } else {
    292         if (EVP_PKEY_keygen_init(ctx) <= 0)
    293             goto err;
    294     }
    295 
    296     *pctx = ctx;
    297     return 1;
    298 
    299  err:
    300     BIO_printf(bio_err, "Error initializing %s context\n", algname);
    301     ERR_print_errors(bio_err);
    302     EVP_PKEY_CTX_free(ctx);
    303     return 0;
    304 
    305 }
    306 
    307 static int genpkey_cb(EVP_PKEY_CTX *ctx)
    308 {
    309     char c = '*';
    310     BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
    311     int p;
    312     p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
    313     if (p == 0)
    314         c = '.';
    315     if (p == 1)
    316         c = '+';
    317     if (p == 2)
    318         c = '*';
    319     if (p == 3)
    320         c = '\n';
    321     BIO_write(b, &c, 1);
    322     (void)BIO_flush(b);
    323     return 1;
    324 }
    325