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