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