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