1238384Sjkim/* apps/genpkey.c */ 2280297Sjkim/* 3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4280297Sjkim * 2006 5238384Sjkim */ 6238384Sjkim/* ==================================================================== 7238384Sjkim * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 8238384Sjkim * 9238384Sjkim * Redistribution and use in source and binary forms, with or without 10238384Sjkim * modification, are permitted provided that the following conditions 11238384Sjkim * are met: 12238384Sjkim * 13238384Sjkim * 1. Redistributions of source code must retain the above copyright 14280297Sjkim * notice, this list of conditions and the following disclaimer. 15238384Sjkim * 16238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 17238384Sjkim * notice, this list of conditions and the following disclaimer in 18238384Sjkim * the documentation and/or other materials provided with the 19238384Sjkim * distribution. 20238384Sjkim * 21238384Sjkim * 3. All advertising materials mentioning features or use of this 22238384Sjkim * software must display the following acknowledgment: 23238384Sjkim * "This product includes software developed by the OpenSSL Project 24238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25238384Sjkim * 26238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27238384Sjkim * endorse or promote products derived from this software without 28238384Sjkim * prior written permission. For written permission, please contact 29238384Sjkim * licensing@OpenSSL.org. 30238384Sjkim * 31238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 32238384Sjkim * nor may "OpenSSL" appear in their names without prior written 33238384Sjkim * permission of the OpenSSL Project. 34238384Sjkim * 35238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 36238384Sjkim * acknowledgment: 37238384Sjkim * "This product includes software developed by the OpenSSL Project 38238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39238384Sjkim * 40238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 52238384Sjkim * ==================================================================== 53238384Sjkim * 54238384Sjkim * This product includes cryptographic software written by Eric Young 55238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 56238384Sjkim * Hudson (tjh@cryptsoft.com). 57238384Sjkim * 58238384Sjkim */ 59238384Sjkim#include <stdio.h> 60238384Sjkim#include <string.h> 61238384Sjkim#include "apps.h" 62238384Sjkim#include <openssl/pem.h> 63238384Sjkim#include <openssl/err.h> 64238384Sjkim#include <openssl/evp.h> 65238384Sjkim#ifndef OPENSSL_NO_ENGINE 66280297Sjkim# include <openssl/engine.h> 67238384Sjkim#endif 68238384Sjkim 69238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx, 70280297Sjkim const char *file, ENGINE *e); 71238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx); 72238384Sjkim 73238384Sjkim#define PROG genpkey_main 74238384Sjkim 75238384Sjkimint MAIN(int, char **); 76238384Sjkim 77238384Sjkimint MAIN(int argc, char **argv) 78280297Sjkim{ 79280297Sjkim ENGINE *e = NULL; 80280297Sjkim char **args, *outfile = NULL; 81280297Sjkim char *passarg = NULL; 82280297Sjkim BIO *in = NULL, *out = NULL; 83280297Sjkim const EVP_CIPHER *cipher = NULL; 84280297Sjkim int outformat; 85280297Sjkim int text = 0; 86280297Sjkim EVP_PKEY *pkey = NULL; 87280297Sjkim EVP_PKEY_CTX *ctx = NULL; 88280297Sjkim char *pass = NULL; 89280297Sjkim int badarg = 0; 90280297Sjkim int ret = 1, rv; 91238384Sjkim 92280297Sjkim int do_param = 0; 93238384Sjkim 94280297Sjkim if (bio_err == NULL) 95280297Sjkim bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); 96238384Sjkim 97280297Sjkim if (!load_config(bio_err, NULL)) 98280297Sjkim goto end; 99238384Sjkim 100280297Sjkim outformat = FORMAT_PEM; 101238384Sjkim 102280297Sjkim ERR_load_crypto_strings(); 103280297Sjkim OpenSSL_add_all_algorithms(); 104280297Sjkim args = argv + 1; 105280297Sjkim while (!badarg && *args && *args[0] == '-') { 106280297Sjkim if (!strcmp(*args, "-outform")) { 107280297Sjkim if (args[1]) { 108280297Sjkim args++; 109280297Sjkim outformat = str2fmt(*args); 110280297Sjkim } else 111280297Sjkim badarg = 1; 112280297Sjkim } else if (!strcmp(*args, "-pass")) { 113280297Sjkim if (!args[1]) 114280297Sjkim goto bad; 115280297Sjkim passarg = *(++args); 116280297Sjkim } 117238384Sjkim#ifndef OPENSSL_NO_ENGINE 118280297Sjkim else if (strcmp(*args, "-engine") == 0) { 119280297Sjkim if (!args[1]) 120280297Sjkim goto bad; 121280297Sjkim e = setup_engine(bio_err, *(++args), 0); 122280297Sjkim } 123238384Sjkim#endif 124280297Sjkim else if (!strcmp(*args, "-paramfile")) { 125280297Sjkim if (!args[1]) 126280297Sjkim goto bad; 127280297Sjkim args++; 128280297Sjkim if (do_param == 1) 129280297Sjkim goto bad; 130280297Sjkim if (!init_keygen_file(bio_err, &ctx, *args, e)) 131280297Sjkim goto end; 132280297Sjkim } else if (!strcmp(*args, "-out")) { 133280297Sjkim if (args[1]) { 134280297Sjkim args++; 135280297Sjkim outfile = *args; 136280297Sjkim } else 137280297Sjkim badarg = 1; 138280297Sjkim } else if (strcmp(*args, "-algorithm") == 0) { 139280297Sjkim if (!args[1]) 140280297Sjkim goto bad; 141280297Sjkim if (!init_gen_str(bio_err, &ctx, *(++args), e, do_param)) 142280297Sjkim goto end; 143280297Sjkim } else if (strcmp(*args, "-pkeyopt") == 0) { 144280297Sjkim if (!args[1]) 145280297Sjkim goto bad; 146280297Sjkim if (!ctx) { 147280297Sjkim BIO_puts(bio_err, "No keytype specified\n"); 148280297Sjkim goto bad; 149280297Sjkim } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) { 150280297Sjkim BIO_puts(bio_err, "parameter setting error\n"); 151280297Sjkim ERR_print_errors(bio_err); 152280297Sjkim goto end; 153280297Sjkim } 154280297Sjkim } else if (strcmp(*args, "-genparam") == 0) { 155280297Sjkim if (ctx) 156280297Sjkim goto bad; 157280297Sjkim do_param = 1; 158280297Sjkim } else if (strcmp(*args, "-text") == 0) 159280297Sjkim text = 1; 160280297Sjkim else { 161280297Sjkim cipher = EVP_get_cipherbyname(*args + 1); 162280297Sjkim if (!cipher) { 163280297Sjkim BIO_printf(bio_err, "Unknown cipher %s\n", *args + 1); 164280297Sjkim badarg = 1; 165280297Sjkim } 166280297Sjkim if (do_param == 1) 167280297Sjkim badarg = 1; 168280297Sjkim } 169280297Sjkim args++; 170280297Sjkim } 171238384Sjkim 172280297Sjkim if (!ctx) 173280297Sjkim badarg = 1; 174238384Sjkim 175280297Sjkim if (badarg) { 176280297Sjkim bad: 177280297Sjkim BIO_printf(bio_err, "Usage: genpkey [options]\n"); 178280297Sjkim BIO_printf(bio_err, "where options may be\n"); 179280297Sjkim BIO_printf(bio_err, "-out file output file\n"); 180280297Sjkim BIO_printf(bio_err, 181280297Sjkim "-outform X output format (DER or PEM)\n"); 182280297Sjkim BIO_printf(bio_err, 183280297Sjkim "-pass arg output file pass phrase source\n"); 184280297Sjkim BIO_printf(bio_err, 185280297Sjkim "-<cipher> use cipher <cipher> to encrypt the key\n"); 186238384Sjkim#ifndef OPENSSL_NO_ENGINE 187280297Sjkim BIO_printf(bio_err, 188280297Sjkim "-engine e use engine e, possibly a hardware device.\n"); 189238384Sjkim#endif 190280297Sjkim BIO_printf(bio_err, "-paramfile file parameters file\n"); 191280297Sjkim BIO_printf(bio_err, "-algorithm alg the public key algorithm\n"); 192280297Sjkim BIO_printf(bio_err, 193280297Sjkim "-pkeyopt opt:value set the public key algorithm option <opt>\n" 194280297Sjkim " to value <value>\n"); 195280297Sjkim BIO_printf(bio_err, 196280297Sjkim "-genparam generate parameters, not key\n"); 197280297Sjkim BIO_printf(bio_err, "-text print the in text\n"); 198280297Sjkim BIO_printf(bio_err, 199280297Sjkim "NB: options order may be important! See the manual page.\n"); 200280297Sjkim goto end; 201280297Sjkim } 202238384Sjkim 203280297Sjkim if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { 204280297Sjkim BIO_puts(bio_err, "Error getting password\n"); 205280297Sjkim goto end; 206280297Sjkim } 207238384Sjkim 208280297Sjkim if (outfile) { 209280297Sjkim if (!(out = BIO_new_file(outfile, "wb"))) { 210280297Sjkim BIO_printf(bio_err, "Can't open output file %s\n", outfile); 211280297Sjkim goto end; 212280297Sjkim } 213280297Sjkim } else { 214280297Sjkim out = BIO_new_fp(stdout, BIO_NOCLOSE); 215238384Sjkim#ifdef OPENSSL_SYS_VMS 216280297Sjkim { 217280297Sjkim BIO *tmpbio = BIO_new(BIO_f_linebuffer()); 218280297Sjkim out = BIO_push(tmpbio, out); 219280297Sjkim } 220238384Sjkim#endif 221280297Sjkim } 222238384Sjkim 223280297Sjkim EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); 224280297Sjkim EVP_PKEY_CTX_set_app_data(ctx, bio_err); 225238384Sjkim 226280297Sjkim if (do_param) { 227280297Sjkim if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { 228280297Sjkim BIO_puts(bio_err, "Error generating parameters\n"); 229280297Sjkim ERR_print_errors(bio_err); 230280297Sjkim goto end; 231280297Sjkim } 232280297Sjkim } else { 233280297Sjkim if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { 234280297Sjkim BIO_puts(bio_err, "Error generating key\n"); 235280297Sjkim ERR_print_errors(bio_err); 236280297Sjkim goto end; 237280297Sjkim } 238280297Sjkim } 239238384Sjkim 240280297Sjkim if (do_param) 241280297Sjkim rv = PEM_write_bio_Parameters(out, pkey); 242280297Sjkim else if (outformat == FORMAT_PEM) 243280297Sjkim rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass); 244280297Sjkim else if (outformat == FORMAT_ASN1) 245280297Sjkim rv = i2d_PrivateKey_bio(out, pkey); 246280297Sjkim else { 247280297Sjkim BIO_printf(bio_err, "Bad format specified for key\n"); 248280297Sjkim goto end; 249280297Sjkim } 250238384Sjkim 251280297Sjkim if (rv <= 0) { 252280297Sjkim BIO_puts(bio_err, "Error writing key\n"); 253280297Sjkim ERR_print_errors(bio_err); 254280297Sjkim } 255238384Sjkim 256280297Sjkim if (text) { 257280297Sjkim if (do_param) 258280297Sjkim rv = EVP_PKEY_print_params(out, pkey, 0, NULL); 259280297Sjkim else 260280297Sjkim rv = EVP_PKEY_print_private(out, pkey, 0, NULL); 261238384Sjkim 262280297Sjkim if (rv <= 0) { 263280297Sjkim BIO_puts(bio_err, "Error printing key\n"); 264280297Sjkim ERR_print_errors(bio_err); 265280297Sjkim } 266280297Sjkim } 267238384Sjkim 268280297Sjkim ret = 0; 269238384Sjkim 270280297Sjkim end: 271280297Sjkim if (pkey) 272280297Sjkim EVP_PKEY_free(pkey); 273280297Sjkim if (ctx) 274280297Sjkim EVP_PKEY_CTX_free(ctx); 275280297Sjkim if (out) 276280297Sjkim BIO_free_all(out); 277280297Sjkim BIO_free(in); 278312826Sjkim release_engine(e); 279280297Sjkim if (pass) 280280297Sjkim OPENSSL_free(pass); 281280297Sjkim return ret; 282280297Sjkim} 283238384Sjkim 284238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx, 285280297Sjkim const char *file, ENGINE *e) 286280297Sjkim{ 287280297Sjkim BIO *pbio; 288280297Sjkim EVP_PKEY *pkey = NULL; 289280297Sjkim EVP_PKEY_CTX *ctx = NULL; 290280297Sjkim if (*pctx) { 291280297Sjkim BIO_puts(err, "Parameters already set!\n"); 292280297Sjkim return 0; 293280297Sjkim } 294238384Sjkim 295280297Sjkim pbio = BIO_new_file(file, "r"); 296280297Sjkim if (!pbio) { 297280297Sjkim BIO_printf(err, "Can't open parameter file %s\n", file); 298280297Sjkim return 0; 299280297Sjkim } 300238384Sjkim 301280297Sjkim pkey = PEM_read_bio_Parameters(pbio, NULL); 302280297Sjkim BIO_free(pbio); 303238384Sjkim 304280297Sjkim if (!pkey) { 305280297Sjkim BIO_printf(bio_err, "Error reading parameter file %s\n", file); 306280297Sjkim return 0; 307280297Sjkim } 308238384Sjkim 309280297Sjkim ctx = EVP_PKEY_CTX_new(pkey, e); 310280297Sjkim if (!ctx) 311280297Sjkim goto err; 312280297Sjkim if (EVP_PKEY_keygen_init(ctx) <= 0) 313280297Sjkim goto err; 314280297Sjkim EVP_PKEY_free(pkey); 315280297Sjkim *pctx = ctx; 316280297Sjkim return 1; 317238384Sjkim 318280297Sjkim err: 319280297Sjkim BIO_puts(err, "Error initializing context\n"); 320280297Sjkim ERR_print_errors(err); 321280297Sjkim if (ctx) 322280297Sjkim EVP_PKEY_CTX_free(ctx); 323280297Sjkim if (pkey) 324280297Sjkim EVP_PKEY_free(pkey); 325280297Sjkim return 0; 326238384Sjkim 327280297Sjkim} 328238384Sjkim 329238384Sjkimint init_gen_str(BIO *err, EVP_PKEY_CTX **pctx, 330280297Sjkim const char *algname, ENGINE *e, int do_param) 331280297Sjkim{ 332280297Sjkim EVP_PKEY_CTX *ctx = NULL; 333280297Sjkim const EVP_PKEY_ASN1_METHOD *ameth; 334280297Sjkim ENGINE *tmpeng = NULL; 335280297Sjkim int pkey_id; 336238384Sjkim 337280297Sjkim if (*pctx) { 338280297Sjkim BIO_puts(err, "Algorithm already set!\n"); 339280297Sjkim return 0; 340280297Sjkim } 341238384Sjkim 342280297Sjkim ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); 343238384Sjkim 344238384Sjkim#ifndef OPENSSL_NO_ENGINE 345280297Sjkim if (!ameth && e) 346280297Sjkim ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); 347238384Sjkim#endif 348238384Sjkim 349280297Sjkim if (!ameth) { 350280297Sjkim BIO_printf(bio_err, "Algorithm %s not found\n", algname); 351280297Sjkim return 0; 352280297Sjkim } 353238384Sjkim 354280297Sjkim ERR_clear_error(); 355238384Sjkim 356280297Sjkim EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); 357238384Sjkim#ifndef OPENSSL_NO_ENGINE 358280297Sjkim if (tmpeng) 359280297Sjkim ENGINE_finish(tmpeng); 360238384Sjkim#endif 361280297Sjkim ctx = EVP_PKEY_CTX_new_id(pkey_id, e); 362238384Sjkim 363280297Sjkim if (!ctx) 364280297Sjkim goto err; 365280297Sjkim if (do_param) { 366280297Sjkim if (EVP_PKEY_paramgen_init(ctx) <= 0) 367280297Sjkim goto err; 368280297Sjkim } else { 369280297Sjkim if (EVP_PKEY_keygen_init(ctx) <= 0) 370280297Sjkim goto err; 371280297Sjkim } 372238384Sjkim 373280297Sjkim *pctx = ctx; 374280297Sjkim return 1; 375238384Sjkim 376280297Sjkim err: 377280297Sjkim BIO_printf(err, "Error initializing %s context\n", algname); 378280297Sjkim ERR_print_errors(err); 379280297Sjkim if (ctx) 380280297Sjkim EVP_PKEY_CTX_free(ctx); 381280297Sjkim return 0; 382238384Sjkim 383280297Sjkim} 384238384Sjkim 385238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx) 386280297Sjkim{ 387280297Sjkim char c = '*'; 388280297Sjkim BIO *b = EVP_PKEY_CTX_get_app_data(ctx); 389280297Sjkim int p; 390280297Sjkim p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); 391280297Sjkim if (p == 0) 392280297Sjkim c = '.'; 393280297Sjkim if (p == 1) 394280297Sjkim c = '+'; 395280297Sjkim if (p == 2) 396280297Sjkim c = '*'; 397280297Sjkim if (p == 3) 398280297Sjkim c = '\n'; 399280297Sjkim BIO_write(b, &c, 1); 400280297Sjkim (void)BIO_flush(b); 401238384Sjkim#ifdef LINT 402280297Sjkim p = n; 403238384Sjkim#endif 404280297Sjkim return 1; 405280297Sjkim} 406