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