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