1 /* $OpenBSD: genpkey.c,v 1.13 2019/07/14 03:30:46 guenther Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 2006 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59 #include <stdio.h> 60 #include <string.h> 61 62 #include "apps.h" 63 64 #include <openssl/err.h> 65 #include <openssl/evp.h> 66 #include <openssl/pem.h> 67 68 static int init_keygen_file(BIO * err, EVP_PKEY_CTX **pctx, const char *file); 69 static int genpkey_cb(EVP_PKEY_CTX * ctx); 70 71 struct { 72 const EVP_CIPHER *cipher; 73 EVP_PKEY_CTX **ctx; 74 int do_param; 75 char *outfile; 76 int outformat; 77 char *passarg; 78 int text; 79 } genpkey_config; 80 81 static int 82 genpkey_opt_algorithm(char *arg) 83 { 84 if (!init_gen_str(bio_err, genpkey_config.ctx, arg, 85 genpkey_config.do_param)) 86 return (1); 87 88 return (0); 89 } 90 91 static int 92 genpkey_opt_cipher(int argc, char **argv, int *argsused) 93 { 94 char *name = argv[0]; 95 96 if (*name++ != '-') 97 return (1); 98 99 if (genpkey_config.do_param == 1) 100 return (1); 101 102 if (strcmp(name, "none") == 0) { 103 genpkey_config.cipher = NULL; 104 *argsused = 1; 105 return (0); 106 } 107 108 if ((genpkey_config.cipher = EVP_get_cipherbyname(name)) != NULL) { 109 *argsused = 1; 110 return (0); 111 } 112 113 return (1); 114 } 115 116 static int 117 genpkey_opt_paramfile(char *arg) 118 { 119 if (genpkey_config.do_param == 1) 120 return (1); 121 if (!init_keygen_file(bio_err, genpkey_config.ctx, arg)) 122 return (1); 123 124 return (0); 125 } 126 127 static int 128 genpkey_opt_pkeyopt(char *arg) 129 { 130 if (*genpkey_config.ctx == NULL) { 131 BIO_puts(bio_err, "No keytype specified\n"); 132 return (1); 133 } 134 135 if (pkey_ctrl_string(*genpkey_config.ctx, arg) <= 0) { 136 BIO_puts(bio_err, "parameter setting error\n"); 137 ERR_print_errors(bio_err); 138 return (1); 139 } 140 141 return (0); 142 } 143 144 static const struct option genpkey_options[] = { 145 { 146 .name = "algorithm", 147 .argname = "name", 148 .desc = "Public key algorithm to use (must precede -pkeyopt)", 149 .type = OPTION_ARG_FUNC, 150 .opt.argfunc = genpkey_opt_algorithm, 151 }, 152 { 153 .name = "genparam", 154 .desc = "Generate a set of parameters instead of a private key", 155 .type = OPTION_FLAG, 156 .opt.flag = &genpkey_config.do_param, 157 }, 158 { 159 .name = "out", 160 .argname = "file", 161 .desc = "Output file to write to (default stdout)", 162 .type = OPTION_ARG, 163 .opt.arg = &genpkey_config.outfile, 164 }, 165 { 166 .name = "outform", 167 .argname = "format", 168 .desc = "Output format (DER or PEM)", 169 .type = OPTION_ARG_FORMAT, 170 .opt.value = &genpkey_config.outformat, 171 }, 172 { 173 .name = "paramfile", 174 .argname = "file", 175 .desc = "File to load public key algorithm parameters from\n" 176 "(must precede -pkeyopt)", 177 .type = OPTION_ARG_FUNC, 178 .opt.argfunc = genpkey_opt_paramfile, 179 }, 180 { 181 .name = "pass", 182 .argname = "arg", 183 .desc = "Output file password source", 184 .type = OPTION_ARG, 185 .opt.arg = &genpkey_config.passarg, 186 }, 187 { 188 .name = "pkeyopt", 189 .argname = "opt:value", 190 .desc = "Set public key algorithm option to the given value", 191 .type = OPTION_ARG_FUNC, 192 .opt.argfunc = genpkey_opt_pkeyopt, 193 }, 194 { 195 .name = "text", 196 .desc = "Print the private/public key in human readable form", 197 .type = OPTION_FLAG, 198 .opt.flag = &genpkey_config.text, 199 }, 200 { 201 .name = NULL, 202 .type = OPTION_ARGV_FUNC, 203 .opt.argvfunc = genpkey_opt_cipher, 204 }, 205 {NULL}, 206 }; 207 208 static void 209 genpkey_usage() 210 { 211 fprintf(stderr, 212 "usage: genpkey [-algorithm alg] [cipher] [-genparam] [-out file]\n" 213 " [-outform der | pem] [-paramfile file] [-pass arg]\n" 214 " [-pkeyopt opt:value] [-text]\n\n"); 215 options_usage(genpkey_options); 216 } 217 218 int 219 genpkey_main(int argc, char **argv) 220 { 221 BIO *in = NULL, *out = NULL; 222 EVP_PKEY_CTX *ctx = NULL; 223 EVP_PKEY *pkey = NULL; 224 char *pass = NULL; 225 int ret = 1, rv; 226 227 if (single_execution) { 228 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 229 perror("pledge"); 230 exit(1); 231 } 232 } 233 234 memset(&genpkey_config, 0, sizeof(genpkey_config)); 235 genpkey_config.ctx = &ctx; 236 genpkey_config.outformat = FORMAT_PEM; 237 238 if (options_parse(argc, argv, genpkey_options, NULL, NULL) != 0) { 239 genpkey_usage(); 240 goto end; 241 } 242 243 if (ctx == NULL) { 244 genpkey_usage(); 245 goto end; 246 } 247 248 if (!app_passwd(bio_err, genpkey_config.passarg, NULL, &pass, NULL)) { 249 BIO_puts(bio_err, "Error getting password\n"); 250 goto end; 251 } 252 if (genpkey_config.outfile != NULL) { 253 if ((out = BIO_new_file(genpkey_config.outfile, "wb")) == 254 NULL) { 255 BIO_printf(bio_err, "Can't open output file %s\n", 256 genpkey_config.outfile); 257 goto end; 258 } 259 } else { 260 out = BIO_new_fp(stdout, BIO_NOCLOSE); 261 } 262 263 EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); 264 EVP_PKEY_CTX_set_app_data(ctx, bio_err); 265 266 if (genpkey_config.do_param) { 267 if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { 268 BIO_puts(bio_err, "Error generating parameters\n"); 269 ERR_print_errors(bio_err); 270 goto end; 271 } 272 } else { 273 if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { 274 BIO_puts(bio_err, "Error generating key\n"); 275 ERR_print_errors(bio_err); 276 goto end; 277 } 278 } 279 280 if (genpkey_config.do_param) 281 rv = PEM_write_bio_Parameters(out, pkey); 282 else if (genpkey_config.outformat == FORMAT_PEM) 283 rv = PEM_write_bio_PrivateKey(out, pkey, genpkey_config.cipher, 284 NULL, 0, NULL, pass); 285 else if (genpkey_config.outformat == FORMAT_ASN1) 286 rv = i2d_PrivateKey_bio(out, pkey); 287 else { 288 BIO_printf(bio_err, "Bad format specified for key\n"); 289 goto end; 290 } 291 292 if (rv <= 0) { 293 BIO_puts(bio_err, "Error writing key\n"); 294 ERR_print_errors(bio_err); 295 } 296 if (genpkey_config.text) { 297 if (genpkey_config.do_param) 298 rv = EVP_PKEY_print_params(out, pkey, 0, NULL); 299 else 300 rv = EVP_PKEY_print_private(out, pkey, 0, NULL); 301 302 if (rv <= 0) { 303 BIO_puts(bio_err, "Error printing key\n"); 304 ERR_print_errors(bio_err); 305 } 306 } 307 ret = 0; 308 309 end: 310 EVP_PKEY_free(pkey); 311 EVP_PKEY_CTX_free(ctx); 312 BIO_free_all(out); 313 BIO_free(in); 314 free(pass); 315 316 return ret; 317 } 318 319 static int 320 init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx, const char *file) 321 { 322 BIO *pbio; 323 EVP_PKEY *pkey = NULL; 324 EVP_PKEY_CTX *ctx = NULL; 325 if (*pctx) { 326 BIO_puts(err, "Parameters already set!\n"); 327 return 0; 328 } 329 pbio = BIO_new_file(file, "r"); 330 if (!pbio) { 331 BIO_printf(err, "Can't open parameter file %s\n", file); 332 return 0; 333 } 334 pkey = PEM_read_bio_Parameters(pbio, NULL); 335 BIO_free(pbio); 336 337 if (!pkey) { 338 BIO_printf(bio_err, "Error reading parameter file %s\n", file); 339 return 0; 340 } 341 ctx = EVP_PKEY_CTX_new(pkey, NULL); 342 if (!ctx) 343 goto err; 344 if (EVP_PKEY_keygen_init(ctx) <= 0) 345 goto err; 346 EVP_PKEY_free(pkey); 347 *pctx = ctx; 348 return 1; 349 350 err: 351 BIO_puts(err, "Error initializing context\n"); 352 ERR_print_errors(err); 353 EVP_PKEY_CTX_free(ctx); 354 EVP_PKEY_free(pkey); 355 return 0; 356 357 } 358 359 int 360 init_gen_str(BIO * err, EVP_PKEY_CTX ** pctx, const char *algname, int do_param) 361 { 362 const EVP_PKEY_ASN1_METHOD *ameth; 363 EVP_PKEY_CTX *ctx = NULL; 364 int pkey_id; 365 366 if (*pctx) { 367 BIO_puts(err, "Algorithm already set!\n"); 368 return 0; 369 } 370 ameth = EVP_PKEY_asn1_find_str(NULL, algname, -1); 371 372 if (!ameth) { 373 BIO_printf(bio_err, "Algorithm %s not found\n", algname); 374 return 0; 375 } 376 ERR_clear_error(); 377 378 EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); 379 ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL); 380 381 if (!ctx) 382 goto err; 383 if (do_param) { 384 if (EVP_PKEY_paramgen_init(ctx) <= 0) 385 goto err; 386 } else { 387 if (EVP_PKEY_keygen_init(ctx) <= 0) 388 goto err; 389 } 390 391 *pctx = ctx; 392 return 1; 393 394 err: 395 BIO_printf(err, "Error initializing %s context\n", algname); 396 ERR_print_errors(err); 397 EVP_PKEY_CTX_free(ctx); 398 return 0; 399 400 } 401 402 static int 403 genpkey_cb(EVP_PKEY_CTX * ctx) 404 { 405 char c = '*'; 406 BIO *b = EVP_PKEY_CTX_get_app_data(ctx); 407 int p; 408 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); 409 if (p == 0) 410 c = '.'; 411 if (p == 1) 412 c = '+'; 413 if (p == 2) 414 c = '*'; 415 if (p == 3) 416 c = '\n'; 417 BIO_write(b, &c, 1); 418 (void) BIO_flush(b); 419 return 1; 420 } 421