1 /* 2 * Copyright 2006-2021 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 187 if (do_param) { 188 rv = PEM_write_bio_Parameters(out, pkey); 189 } else if (outformat == FORMAT_PEM) { 190 assert(private); 191 rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass); 192 } else if (outformat == FORMAT_ASN1) { 193 assert(private); 194 rv = i2d_PrivateKey_bio(out, pkey); 195 } else { 196 BIO_printf(bio_err, "Bad format specified for key\n"); 197 goto end; 198 } 199 200 ret = 0; 201 202 if (rv <= 0) { 203 BIO_puts(bio_err, "Error writing key\n"); 204 ret = 1; 205 } 206 207 if (text) { 208 if (do_param) 209 rv = EVP_PKEY_print_params(out, pkey, 0, NULL); 210 else 211 rv = EVP_PKEY_print_private(out, pkey, 0, NULL); 212 213 if (rv <= 0) { 214 BIO_puts(bio_err, "Error printing key\n"); 215 ret = 1; 216 } 217 } 218 219 end: 220 sk_OPENSSL_STRING_free(keyopt); 221 if (ret != 0) 222 ERR_print_errors(bio_err); 223 EVP_PKEY_free(pkey); 224 EVP_PKEY_CTX_free(ctx); 225 EVP_CIPHER_free(cipher); 226 BIO_free_all(out); 227 BIO_free(in); 228 release_engine(e); 229 OPENSSL_free(pass); 230 NCONF_free(conf); 231 return ret; 232 } 233 234 static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e, 235 OSSL_LIB_CTX *libctx, const char *propq) 236 { 237 BIO *pbio; 238 EVP_PKEY *pkey = NULL; 239 EVP_PKEY_CTX *ctx = NULL; 240 if (*pctx) { 241 BIO_puts(bio_err, "Parameters already set!\n"); 242 return 0; 243 } 244 245 pbio = BIO_new_file(file, "r"); 246 if (pbio == NULL) { 247 BIO_printf(bio_err, "Can't open parameter file %s\n", file); 248 return 0; 249 } 250 251 pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq); 252 BIO_free(pbio); 253 254 if (pkey == NULL) { 255 BIO_printf(bio_err, "Error reading parameter file %s\n", file); 256 return 0; 257 } 258 259 if (e != NULL) 260 ctx = EVP_PKEY_CTX_new(pkey, e); 261 else 262 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); 263 if (ctx == NULL) 264 goto err; 265 if (EVP_PKEY_keygen_init(ctx) <= 0) 266 goto err; 267 EVP_PKEY_free(pkey); 268 *pctx = ctx; 269 return 1; 270 271 err: 272 BIO_puts(bio_err, "Error initializing context\n"); 273 ERR_print_errors(bio_err); 274 EVP_PKEY_CTX_free(ctx); 275 EVP_PKEY_free(pkey); 276 return 0; 277 278 } 279 280 int init_gen_str(EVP_PKEY_CTX **pctx, 281 const char *algname, ENGINE *e, int do_param, 282 OSSL_LIB_CTX *libctx, const char *propq) 283 { 284 EVP_PKEY_CTX *ctx = NULL; 285 int pkey_id; 286 287 if (*pctx) { 288 BIO_puts(bio_err, "Algorithm already set!\n"); 289 return 0; 290 } 291 292 pkey_id = get_legacy_pkey_id(libctx, algname, e); 293 if (pkey_id != NID_undef) 294 ctx = EVP_PKEY_CTX_new_id(pkey_id, e); 295 else 296 ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq); 297 298 if (ctx == NULL) 299 goto err; 300 if (do_param) { 301 if (EVP_PKEY_paramgen_init(ctx) <= 0) 302 goto err; 303 } else { 304 if (EVP_PKEY_keygen_init(ctx) <= 0) 305 goto err; 306 } 307 308 *pctx = ctx; 309 return 1; 310 311 err: 312 BIO_printf(bio_err, "Error initializing %s context\n", algname); 313 ERR_print_errors(bio_err); 314 EVP_PKEY_CTX_free(ctx); 315 return 0; 316 317 } 318 319 static int genpkey_cb(EVP_PKEY_CTX *ctx) 320 { 321 char c = '*'; 322 BIO *b = EVP_PKEY_CTX_get_app_data(ctx); 323 324 if (quiet) 325 return 1; 326 327 switch (EVP_PKEY_CTX_get_keygen_info(ctx, 0)) { 328 case 0: 329 c = '.'; 330 break; 331 case 1: 332 c = '+'; 333 break; 334 case 3: 335 c = '\n'; 336 break; 337 } 338 339 BIO_write(b, &c, 1); 340 (void)BIO_flush(b); 341 return 1; 342 } 343