1238384Sjkim/* apps/genpkey.c */ 2238384Sjkim/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3238384Sjkim * project 2006 4238384Sjkim */ 5238384Sjkim/* ==================================================================== 6238384Sjkim * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 7238384Sjkim * 8238384Sjkim * Redistribution and use in source and binary forms, with or without 9238384Sjkim * modification, are permitted provided that the following conditions 10238384Sjkim * are met: 11238384Sjkim * 12238384Sjkim * 1. Redistributions of source code must retain the above copyright 13238384Sjkim * notice, this list of conditions and the following disclaimer. 14238384Sjkim * 15238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 16238384Sjkim * notice, this list of conditions and the following disclaimer in 17238384Sjkim * the documentation and/or other materials provided with the 18238384Sjkim * distribution. 19238384Sjkim * 20238384Sjkim * 3. All advertising materials mentioning features or use of this 21238384Sjkim * software must display the following acknowledgment: 22238384Sjkim * "This product includes software developed by the OpenSSL Project 23238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24238384Sjkim * 25238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26238384Sjkim * endorse or promote products derived from this software without 27238384Sjkim * prior written permission. For written permission, please contact 28238384Sjkim * licensing@OpenSSL.org. 29238384Sjkim * 30238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 31238384Sjkim * nor may "OpenSSL" appear in their names without prior written 32238384Sjkim * permission of the OpenSSL Project. 33238384Sjkim * 34238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 35238384Sjkim * acknowledgment: 36238384Sjkim * "This product includes software developed by the OpenSSL Project 37238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38238384Sjkim * 39238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 51238384Sjkim * ==================================================================== 52238384Sjkim * 53238384Sjkim * This product includes cryptographic software written by Eric Young 54238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 55238384Sjkim * Hudson (tjh@cryptsoft.com). 56238384Sjkim * 57238384Sjkim */ 58238384Sjkim#include <stdio.h> 59238384Sjkim#include <string.h> 60238384Sjkim#include "apps.h" 61238384Sjkim#include <openssl/pem.h> 62238384Sjkim#include <openssl/err.h> 63238384Sjkim#include <openssl/evp.h> 64238384Sjkim#ifndef OPENSSL_NO_ENGINE 65238384Sjkim#include <openssl/engine.h> 66238384Sjkim#endif 67238384Sjkim 68238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx, 69238384Sjkim const char *file, ENGINE *e); 70238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx); 71238384Sjkim 72238384Sjkim#define PROG genpkey_main 73238384Sjkim 74238384Sjkimint MAIN(int, char **); 75238384Sjkim 76238384Sjkimint MAIN(int argc, char **argv) 77238384Sjkim { 78238384Sjkim ENGINE *e = NULL; 79238384Sjkim char **args, *outfile = NULL; 80238384Sjkim char *passarg = NULL; 81238384Sjkim BIO *in = NULL, *out = NULL; 82238384Sjkim const EVP_CIPHER *cipher = NULL; 83238384Sjkim int outformat; 84238384Sjkim int text = 0; 85238384Sjkim EVP_PKEY *pkey=NULL; 86238384Sjkim EVP_PKEY_CTX *ctx = NULL; 87238384Sjkim char *pass = NULL; 88238384Sjkim int badarg = 0; 89238384Sjkim int ret = 1, rv; 90238384Sjkim 91238384Sjkim int do_param = 0; 92238384Sjkim 93238384Sjkim if (bio_err == NULL) 94238384Sjkim bio_err = BIO_new_fp (stderr, BIO_NOCLOSE); 95238384Sjkim 96238384Sjkim if (!load_config(bio_err, NULL)) 97238384Sjkim goto end; 98238384Sjkim 99238384Sjkim outformat=FORMAT_PEM; 100238384Sjkim 101238384Sjkim ERR_load_crypto_strings(); 102238384Sjkim OpenSSL_add_all_algorithms(); 103238384Sjkim args = argv + 1; 104238384Sjkim while (!badarg && *args && *args[0] == '-') 105238384Sjkim { 106238384Sjkim if (!strcmp(*args,"-outform")) 107238384Sjkim { 108238384Sjkim if (args[1]) 109238384Sjkim { 110238384Sjkim args++; 111238384Sjkim outformat=str2fmt(*args); 112238384Sjkim } 113238384Sjkim else badarg = 1; 114238384Sjkim } 115238384Sjkim else if (!strcmp(*args,"-pass")) 116238384Sjkim { 117238384Sjkim if (!args[1]) goto bad; 118238384Sjkim passarg= *(++args); 119238384Sjkim } 120238384Sjkim#ifndef OPENSSL_NO_ENGINE 121238384Sjkim else if (strcmp(*args,"-engine") == 0) 122238384Sjkim { 123238384Sjkim if (!args[1]) 124238384Sjkim goto bad; 125238384Sjkim e = setup_engine(bio_err, *(++args), 0); 126238384Sjkim } 127238384Sjkim#endif 128238384Sjkim else if (!strcmp (*args, "-paramfile")) 129238384Sjkim { 130238384Sjkim if (!args[1]) 131238384Sjkim goto bad; 132238384Sjkim args++; 133238384Sjkim if (do_param == 1) 134238384Sjkim goto bad; 135238384Sjkim if (!init_keygen_file(bio_err, &ctx, *args, e)) 136238384Sjkim goto end; 137238384Sjkim } 138238384Sjkim else if (!strcmp (*args, "-out")) 139238384Sjkim { 140238384Sjkim if (args[1]) 141238384Sjkim { 142238384Sjkim args++; 143238384Sjkim outfile = *args; 144238384Sjkim } 145238384Sjkim else badarg = 1; 146238384Sjkim } 147238384Sjkim else if (strcmp(*args,"-algorithm") == 0) 148238384Sjkim { 149238384Sjkim if (!args[1]) 150238384Sjkim goto bad; 151238384Sjkim if (!init_gen_str(bio_err, &ctx, *(++args),e, do_param)) 152238384Sjkim goto end; 153238384Sjkim } 154238384Sjkim else if (strcmp(*args,"-pkeyopt") == 0) 155238384Sjkim { 156238384Sjkim if (!args[1]) 157238384Sjkim goto bad; 158238384Sjkim if (!ctx) 159238384Sjkim { 160238384Sjkim BIO_puts(bio_err, "No keytype specified\n"); 161238384Sjkim goto bad; 162238384Sjkim } 163238384Sjkim else if (pkey_ctrl_string(ctx, *(++args)) <= 0) 164238384Sjkim { 165238384Sjkim BIO_puts(bio_err, "parameter setting error\n"); 166238384Sjkim ERR_print_errors(bio_err); 167238384Sjkim goto end; 168238384Sjkim } 169238384Sjkim } 170238384Sjkim else if (strcmp(*args,"-genparam") == 0) 171238384Sjkim { 172238384Sjkim if (ctx) 173238384Sjkim goto bad; 174238384Sjkim do_param = 1; 175238384Sjkim } 176238384Sjkim else if (strcmp(*args,"-text") == 0) 177238384Sjkim text=1; 178238384Sjkim else 179238384Sjkim { 180238384Sjkim cipher = EVP_get_cipherbyname(*args + 1); 181238384Sjkim if (!cipher) 182238384Sjkim { 183238384Sjkim BIO_printf(bio_err, "Unknown cipher %s\n", 184238384Sjkim *args + 1); 185238384Sjkim badarg = 1; 186238384Sjkim } 187238384Sjkim if (do_param == 1) 188238384Sjkim badarg = 1; 189238384Sjkim } 190238384Sjkim args++; 191238384Sjkim } 192238384Sjkim 193238384Sjkim if (!ctx) 194238384Sjkim badarg = 1; 195238384Sjkim 196238384Sjkim if (badarg) 197238384Sjkim { 198238384Sjkim bad: 199238384Sjkim BIO_printf(bio_err, "Usage: genpkey [options]\n"); 200238384Sjkim BIO_printf(bio_err, "where options may be\n"); 201238384Sjkim BIO_printf(bio_err, "-out file output file\n"); 202238384Sjkim BIO_printf(bio_err, "-outform X output format (DER or PEM)\n"); 203238384Sjkim BIO_printf(bio_err, "-pass arg output file pass phrase source\n"); 204238384Sjkim BIO_printf(bio_err, "-<cipher> use cipher <cipher> to encrypt the key\n"); 205238384Sjkim#ifndef OPENSSL_NO_ENGINE 206238384Sjkim BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); 207238384Sjkim#endif 208238384Sjkim BIO_printf(bio_err, "-paramfile file parameters file\n"); 209238384Sjkim BIO_printf(bio_err, "-algorithm alg the public key algorithm\n"); 210238384Sjkim BIO_printf(bio_err, "-pkeyopt opt:value set the public key algorithm option <opt>\n" 211238384Sjkim " to value <value>\n"); 212238384Sjkim BIO_printf(bio_err, "-genparam generate parameters, not key\n"); 213238384Sjkim BIO_printf(bio_err, "-text print the in text\n"); 214238384Sjkim BIO_printf(bio_err, "NB: options order may be important! See the manual page.\n"); 215238384Sjkim goto end; 216238384Sjkim } 217238384Sjkim 218238384Sjkim if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) 219238384Sjkim { 220238384Sjkim BIO_puts(bio_err, "Error getting password\n"); 221238384Sjkim goto end; 222238384Sjkim } 223238384Sjkim 224238384Sjkim if (outfile) 225238384Sjkim { 226238384Sjkim if (!(out = BIO_new_file (outfile, "wb"))) 227238384Sjkim { 228238384Sjkim BIO_printf(bio_err, 229238384Sjkim "Can't open output file %s\n", outfile); 230238384Sjkim goto end; 231238384Sjkim } 232238384Sjkim } 233238384Sjkim else 234238384Sjkim { 235238384Sjkim out = BIO_new_fp (stdout, BIO_NOCLOSE); 236238384Sjkim#ifdef OPENSSL_SYS_VMS 237238384Sjkim { 238238384Sjkim BIO *tmpbio = BIO_new(BIO_f_linebuffer()); 239238384Sjkim out = BIO_push(tmpbio, out); 240238384Sjkim } 241238384Sjkim#endif 242238384Sjkim } 243238384Sjkim 244238384Sjkim EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); 245238384Sjkim EVP_PKEY_CTX_set_app_data(ctx, bio_err); 246238384Sjkim 247238384Sjkim if (do_param) 248238384Sjkim { 249238384Sjkim if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) 250238384Sjkim { 251238384Sjkim BIO_puts(bio_err, "Error generating parameters\n"); 252238384Sjkim ERR_print_errors(bio_err); 253238384Sjkim goto end; 254238384Sjkim } 255238384Sjkim } 256238384Sjkim else 257238384Sjkim { 258238384Sjkim if (EVP_PKEY_keygen(ctx, &pkey) <= 0) 259238384Sjkim { 260238384Sjkim BIO_puts(bio_err, "Error generating key\n"); 261238384Sjkim ERR_print_errors(bio_err); 262238384Sjkim goto end; 263238384Sjkim } 264238384Sjkim } 265238384Sjkim 266238384Sjkim if (do_param) 267238384Sjkim rv = PEM_write_bio_Parameters(out, pkey); 268238384Sjkim else if (outformat == FORMAT_PEM) 269238384Sjkim rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, 270238384Sjkim NULL, pass); 271238384Sjkim else if (outformat == FORMAT_ASN1) 272238384Sjkim rv = i2d_PrivateKey_bio(out, pkey); 273238384Sjkim else 274238384Sjkim { 275238384Sjkim BIO_printf(bio_err, "Bad format specified for key\n"); 276238384Sjkim goto end; 277238384Sjkim } 278238384Sjkim 279238384Sjkim if (rv <= 0) 280238384Sjkim { 281238384Sjkim BIO_puts(bio_err, "Error writing key\n"); 282238384Sjkim ERR_print_errors(bio_err); 283238384Sjkim } 284238384Sjkim 285238384Sjkim if (text) 286238384Sjkim { 287238384Sjkim if (do_param) 288238384Sjkim rv = EVP_PKEY_print_params(out, pkey, 0, NULL); 289238384Sjkim else 290238384Sjkim rv = EVP_PKEY_print_private(out, pkey, 0, NULL); 291238384Sjkim 292238384Sjkim if (rv <= 0) 293238384Sjkim { 294238384Sjkim BIO_puts(bio_err, "Error printing key\n"); 295238384Sjkim ERR_print_errors(bio_err); 296238384Sjkim } 297238384Sjkim } 298238384Sjkim 299238384Sjkim ret = 0; 300238384Sjkim 301238384Sjkim end: 302238384Sjkim if (pkey) 303238384Sjkim EVP_PKEY_free(pkey); 304238384Sjkim if (ctx) 305238384Sjkim EVP_PKEY_CTX_free(ctx); 306238384Sjkim if (out) 307238384Sjkim BIO_free_all(out); 308238384Sjkim BIO_free(in); 309238384Sjkim if (pass) 310238384Sjkim OPENSSL_free(pass); 311238384Sjkim 312238384Sjkim return ret; 313238384Sjkim } 314238384Sjkim 315238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx, 316238384Sjkim const char *file, ENGINE *e) 317238384Sjkim { 318238384Sjkim BIO *pbio; 319238384Sjkim EVP_PKEY *pkey = NULL; 320238384Sjkim EVP_PKEY_CTX *ctx = NULL; 321238384Sjkim if (*pctx) 322238384Sjkim { 323238384Sjkim BIO_puts(err, "Parameters already set!\n"); 324238384Sjkim return 0; 325238384Sjkim } 326238384Sjkim 327238384Sjkim pbio = BIO_new_file(file, "r"); 328238384Sjkim if (!pbio) 329238384Sjkim { 330238384Sjkim BIO_printf(err, "Can't open parameter file %s\n", file); 331238384Sjkim return 0; 332238384Sjkim } 333238384Sjkim 334238384Sjkim pkey = PEM_read_bio_Parameters(pbio, NULL); 335238384Sjkim BIO_free(pbio); 336238384Sjkim 337238384Sjkim if (!pkey) 338238384Sjkim { 339238384Sjkim BIO_printf(bio_err, "Error reading parameter file %s\n", file); 340238384Sjkim return 0; 341238384Sjkim } 342238384Sjkim 343238384Sjkim ctx = EVP_PKEY_CTX_new(pkey, e); 344238384Sjkim if (!ctx) 345238384Sjkim goto err; 346238384Sjkim if (EVP_PKEY_keygen_init(ctx) <= 0) 347238384Sjkim goto err; 348238384Sjkim EVP_PKEY_free(pkey); 349238384Sjkim *pctx = ctx; 350238384Sjkim return 1; 351238384Sjkim 352238384Sjkim err: 353238384Sjkim BIO_puts(err, "Error initializing context\n"); 354238384Sjkim ERR_print_errors(err); 355238384Sjkim if (ctx) 356238384Sjkim EVP_PKEY_CTX_free(ctx); 357238384Sjkim if (pkey) 358238384Sjkim EVP_PKEY_free(pkey); 359238384Sjkim return 0; 360238384Sjkim 361238384Sjkim } 362238384Sjkim 363238384Sjkimint init_gen_str(BIO *err, EVP_PKEY_CTX **pctx, 364238384Sjkim const char *algname, ENGINE *e, int do_param) 365238384Sjkim { 366238384Sjkim EVP_PKEY_CTX *ctx = NULL; 367238384Sjkim const EVP_PKEY_ASN1_METHOD *ameth; 368238384Sjkim ENGINE *tmpeng = NULL; 369238384Sjkim int pkey_id; 370238384Sjkim 371238384Sjkim if (*pctx) 372238384Sjkim { 373238384Sjkim BIO_puts(err, "Algorithm already set!\n"); 374238384Sjkim return 0; 375238384Sjkim } 376238384Sjkim 377238384Sjkim ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); 378238384Sjkim 379238384Sjkim#ifndef OPENSSL_NO_ENGINE 380238384Sjkim if (!ameth && e) 381238384Sjkim ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); 382238384Sjkim#endif 383238384Sjkim 384238384Sjkim if (!ameth) 385238384Sjkim { 386238384Sjkim BIO_printf(bio_err, "Algorithm %s not found\n", algname); 387238384Sjkim return 0; 388238384Sjkim } 389238384Sjkim 390238384Sjkim ERR_clear_error(); 391238384Sjkim 392238384Sjkim EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); 393238384Sjkim#ifndef OPENSSL_NO_ENGINE 394238384Sjkim if (tmpeng) 395238384Sjkim ENGINE_finish(tmpeng); 396238384Sjkim#endif 397238384Sjkim ctx = EVP_PKEY_CTX_new_id(pkey_id, e); 398238384Sjkim 399238384Sjkim if (!ctx) 400238384Sjkim goto err; 401238384Sjkim if (do_param) 402238384Sjkim { 403238384Sjkim if (EVP_PKEY_paramgen_init(ctx) <= 0) 404238384Sjkim goto err; 405238384Sjkim } 406238384Sjkim else 407238384Sjkim { 408238384Sjkim if (EVP_PKEY_keygen_init(ctx) <= 0) 409238384Sjkim goto err; 410238384Sjkim } 411238384Sjkim 412238384Sjkim *pctx = ctx; 413238384Sjkim return 1; 414238384Sjkim 415238384Sjkim err: 416238384Sjkim BIO_printf(err, "Error initializing %s context\n", algname); 417238384Sjkim ERR_print_errors(err); 418238384Sjkim if (ctx) 419238384Sjkim EVP_PKEY_CTX_free(ctx); 420238384Sjkim return 0; 421238384Sjkim 422238384Sjkim } 423238384Sjkim 424238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx) 425238384Sjkim { 426238384Sjkim char c='*'; 427238384Sjkim BIO *b = EVP_PKEY_CTX_get_app_data(ctx); 428238384Sjkim int p; 429238384Sjkim p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); 430238384Sjkim if (p == 0) c='.'; 431238384Sjkim if (p == 1) c='+'; 432238384Sjkim if (p == 2) c='*'; 433238384Sjkim if (p == 3) c='\n'; 434238384Sjkim BIO_write(b,&c,1); 435238384Sjkim (void)BIO_flush(b); 436238384Sjkim#ifdef LINT 437238384Sjkim p=n; 438238384Sjkim#endif 439238384Sjkim return 1; 440238384Sjkim } 441