1238384Sjkim/* apps/genpkey.c */ 2280304Sjkim/* 3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4280304Sjkim * 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 14280304Sjkim * 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 66280304Sjkim# include <openssl/engine.h> 67238384Sjkim#endif 68238384Sjkim 69238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx, 70280304Sjkim 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) 78280304Sjkim{ 79280304Sjkim ENGINE *e = NULL; 80280304Sjkim char **args, *outfile = NULL; 81280304Sjkim char *passarg = NULL; 82280304Sjkim BIO *in = NULL, *out = NULL; 83280304Sjkim const EVP_CIPHER *cipher = NULL; 84280304Sjkim int outformat; 85280304Sjkim int text = 0; 86280304Sjkim EVP_PKEY *pkey = NULL; 87280304Sjkim EVP_PKEY_CTX *ctx = NULL; 88280304Sjkim char *pass = NULL; 89280304Sjkim int badarg = 0; 90280304Sjkim int ret = 1, rv; 91238384Sjkim 92280304Sjkim int do_param = 0; 93238384Sjkim 94280304Sjkim if (bio_err == NULL) 95280304Sjkim bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); 96238384Sjkim 97280304Sjkim if (!load_config(bio_err, NULL)) 98280304Sjkim goto end; 99238384Sjkim 100280304Sjkim outformat = FORMAT_PEM; 101238384Sjkim 102280304Sjkim ERR_load_crypto_strings(); 103280304Sjkim OpenSSL_add_all_algorithms(); 104280304Sjkim args = argv + 1; 105280304Sjkim while (!badarg && *args && *args[0] == '-') { 106280304Sjkim if (!strcmp(*args, "-outform")) { 107280304Sjkim if (args[1]) { 108280304Sjkim args++; 109280304Sjkim outformat = str2fmt(*args); 110280304Sjkim } else 111280304Sjkim badarg = 1; 112280304Sjkim } else if (!strcmp(*args, "-pass")) { 113280304Sjkim if (!args[1]) 114280304Sjkim goto bad; 115280304Sjkim passarg = *(++args); 116280304Sjkim } 117238384Sjkim#ifndef OPENSSL_NO_ENGINE 118280304Sjkim else if (strcmp(*args, "-engine") == 0) { 119280304Sjkim if (!args[1]) 120280304Sjkim goto bad; 121280304Sjkim e = setup_engine(bio_err, *(++args), 0); 122280304Sjkim } 123238384Sjkim#endif 124280304Sjkim else if (!strcmp(*args, "-paramfile")) { 125280304Sjkim if (!args[1]) 126280304Sjkim goto bad; 127280304Sjkim args++; 128280304Sjkim if (do_param == 1) 129280304Sjkim goto bad; 130280304Sjkim if (!init_keygen_file(bio_err, &ctx, *args, e)) 131280304Sjkim goto end; 132280304Sjkim } else if (!strcmp(*args, "-out")) { 133280304Sjkim if (args[1]) { 134280304Sjkim args++; 135280304Sjkim outfile = *args; 136280304Sjkim } else 137280304Sjkim badarg = 1; 138280304Sjkim } else if (strcmp(*args, "-algorithm") == 0) { 139280304Sjkim if (!args[1]) 140280304Sjkim goto bad; 141280304Sjkim if (!init_gen_str(bio_err, &ctx, *(++args), e, do_param)) 142280304Sjkim goto end; 143280304Sjkim } else if (strcmp(*args, "-pkeyopt") == 0) { 144280304Sjkim if (!args[1]) 145280304Sjkim goto bad; 146280304Sjkim if (!ctx) { 147280304Sjkim BIO_puts(bio_err, "No keytype specified\n"); 148280304Sjkim goto bad; 149280304Sjkim } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) { 150280304Sjkim BIO_puts(bio_err, "parameter setting error\n"); 151280304Sjkim ERR_print_errors(bio_err); 152280304Sjkim goto end; 153280304Sjkim } 154280304Sjkim } else if (strcmp(*args, "-genparam") == 0) { 155280304Sjkim if (ctx) 156280304Sjkim goto bad; 157280304Sjkim do_param = 1; 158280304Sjkim } else if (strcmp(*args, "-text") == 0) 159280304Sjkim text = 1; 160280304Sjkim else { 161280304Sjkim cipher = EVP_get_cipherbyname(*args + 1); 162280304Sjkim if (!cipher) { 163280304Sjkim BIO_printf(bio_err, "Unknown cipher %s\n", *args + 1); 164280304Sjkim badarg = 1; 165280304Sjkim } 166280304Sjkim if (do_param == 1) 167280304Sjkim badarg = 1; 168280304Sjkim } 169280304Sjkim args++; 170280304Sjkim } 171238384Sjkim 172280304Sjkim if (!ctx) 173280304Sjkim badarg = 1; 174238384Sjkim 175280304Sjkim if (badarg) { 176280304Sjkim bad: 177280304Sjkim BIO_printf(bio_err, "Usage: genpkey [options]\n"); 178280304Sjkim BIO_printf(bio_err, "where options may be\n"); 179280304Sjkim BIO_printf(bio_err, "-out file output file\n"); 180280304Sjkim BIO_printf(bio_err, 181280304Sjkim "-outform X output format (DER or PEM)\n"); 182280304Sjkim BIO_printf(bio_err, 183280304Sjkim "-pass arg output file pass phrase source\n"); 184280304Sjkim BIO_printf(bio_err, 185280304Sjkim "-<cipher> use cipher <cipher> to encrypt the key\n"); 186238384Sjkim#ifndef OPENSSL_NO_ENGINE 187280304Sjkim BIO_printf(bio_err, 188280304Sjkim "-engine e use engine e, possibly a hardware device.\n"); 189238384Sjkim#endif 190280304Sjkim BIO_printf(bio_err, "-paramfile file parameters file\n"); 191280304Sjkim BIO_printf(bio_err, "-algorithm alg the public key algorithm\n"); 192280304Sjkim BIO_printf(bio_err, 193280304Sjkim "-pkeyopt opt:value set the public key algorithm option <opt>\n" 194280304Sjkim " to value <value>\n"); 195280304Sjkim BIO_printf(bio_err, 196280304Sjkim "-genparam generate parameters, not key\n"); 197280304Sjkim BIO_printf(bio_err, "-text print the in text\n"); 198280304Sjkim BIO_printf(bio_err, 199280304Sjkim "NB: options order may be important! See the manual page.\n"); 200280304Sjkim goto end; 201280304Sjkim } 202238384Sjkim 203280304Sjkim if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { 204280304Sjkim BIO_puts(bio_err, "Error getting password\n"); 205280304Sjkim goto end; 206280304Sjkim } 207238384Sjkim 208280304Sjkim if (outfile) { 209280304Sjkim if (!(out = BIO_new_file(outfile, "wb"))) { 210280304Sjkim BIO_printf(bio_err, "Can't open output file %s\n", outfile); 211280304Sjkim goto end; 212280304Sjkim } 213280304Sjkim } else { 214280304Sjkim out = BIO_new_fp(stdout, BIO_NOCLOSE); 215238384Sjkim#ifdef OPENSSL_SYS_VMS 216280304Sjkim { 217280304Sjkim BIO *tmpbio = BIO_new(BIO_f_linebuffer()); 218280304Sjkim out = BIO_push(tmpbio, out); 219280304Sjkim } 220238384Sjkim#endif 221280304Sjkim } 222238384Sjkim 223280304Sjkim EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); 224280304Sjkim EVP_PKEY_CTX_set_app_data(ctx, bio_err); 225238384Sjkim 226280304Sjkim if (do_param) { 227280304Sjkim if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { 228280304Sjkim BIO_puts(bio_err, "Error generating parameters\n"); 229280304Sjkim ERR_print_errors(bio_err); 230280304Sjkim goto end; 231280304Sjkim } 232280304Sjkim } else { 233280304Sjkim if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { 234280304Sjkim BIO_puts(bio_err, "Error generating key\n"); 235280304Sjkim ERR_print_errors(bio_err); 236280304Sjkim goto end; 237280304Sjkim } 238280304Sjkim } 239238384Sjkim 240280304Sjkim if (do_param) 241280304Sjkim rv = PEM_write_bio_Parameters(out, pkey); 242280304Sjkim else if (outformat == FORMAT_PEM) 243280304Sjkim rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass); 244280304Sjkim else if (outformat == FORMAT_ASN1) 245280304Sjkim rv = i2d_PrivateKey_bio(out, pkey); 246280304Sjkim else { 247280304Sjkim BIO_printf(bio_err, "Bad format specified for key\n"); 248280304Sjkim goto end; 249280304Sjkim } 250238384Sjkim 251280304Sjkim if (rv <= 0) { 252280304Sjkim BIO_puts(bio_err, "Error writing key\n"); 253280304Sjkim ERR_print_errors(bio_err); 254280304Sjkim } 255238384Sjkim 256280304Sjkim if (text) { 257280304Sjkim if (do_param) 258280304Sjkim rv = EVP_PKEY_print_params(out, pkey, 0, NULL); 259280304Sjkim else 260280304Sjkim rv = EVP_PKEY_print_private(out, pkey, 0, NULL); 261238384Sjkim 262280304Sjkim if (rv <= 0) { 263280304Sjkim BIO_puts(bio_err, "Error printing key\n"); 264280304Sjkim ERR_print_errors(bio_err); 265280304Sjkim } 266280304Sjkim } 267238384Sjkim 268280304Sjkim ret = 0; 269238384Sjkim 270280304Sjkim end: 271280304Sjkim if (pkey) 272280304Sjkim EVP_PKEY_free(pkey); 273280304Sjkim if (ctx) 274280304Sjkim EVP_PKEY_CTX_free(ctx); 275280304Sjkim if (out) 276280304Sjkim BIO_free_all(out); 277280304Sjkim BIO_free(in); 278280304Sjkim if (pass) 279280304Sjkim OPENSSL_free(pass); 280238384Sjkim 281280304Sjkim return ret; 282280304Sjkim} 283238384Sjkim 284238384Sjkimstatic int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx, 285280304Sjkim const char *file, ENGINE *e) 286280304Sjkim{ 287280304Sjkim BIO *pbio; 288280304Sjkim EVP_PKEY *pkey = NULL; 289280304Sjkim EVP_PKEY_CTX *ctx = NULL; 290280304Sjkim if (*pctx) { 291280304Sjkim BIO_puts(err, "Parameters already set!\n"); 292280304Sjkim return 0; 293280304Sjkim } 294238384Sjkim 295280304Sjkim pbio = BIO_new_file(file, "r"); 296280304Sjkim if (!pbio) { 297280304Sjkim BIO_printf(err, "Can't open parameter file %s\n", file); 298280304Sjkim return 0; 299280304Sjkim } 300238384Sjkim 301280304Sjkim pkey = PEM_read_bio_Parameters(pbio, NULL); 302280304Sjkim BIO_free(pbio); 303238384Sjkim 304280304Sjkim if (!pkey) { 305280304Sjkim BIO_printf(bio_err, "Error reading parameter file %s\n", file); 306280304Sjkim return 0; 307280304Sjkim } 308238384Sjkim 309280304Sjkim ctx = EVP_PKEY_CTX_new(pkey, e); 310280304Sjkim if (!ctx) 311280304Sjkim goto err; 312280304Sjkim if (EVP_PKEY_keygen_init(ctx) <= 0) 313280304Sjkim goto err; 314280304Sjkim EVP_PKEY_free(pkey); 315280304Sjkim *pctx = ctx; 316280304Sjkim return 1; 317238384Sjkim 318280304Sjkim err: 319280304Sjkim BIO_puts(err, "Error initializing context\n"); 320280304Sjkim ERR_print_errors(err); 321280304Sjkim if (ctx) 322280304Sjkim EVP_PKEY_CTX_free(ctx); 323280304Sjkim if (pkey) 324280304Sjkim EVP_PKEY_free(pkey); 325280304Sjkim return 0; 326238384Sjkim 327280304Sjkim} 328238384Sjkim 329238384Sjkimint init_gen_str(BIO *err, EVP_PKEY_CTX **pctx, 330280304Sjkim const char *algname, ENGINE *e, int do_param) 331280304Sjkim{ 332280304Sjkim EVP_PKEY_CTX *ctx = NULL; 333280304Sjkim const EVP_PKEY_ASN1_METHOD *ameth; 334280304Sjkim ENGINE *tmpeng = NULL; 335280304Sjkim int pkey_id; 336238384Sjkim 337280304Sjkim if (*pctx) { 338280304Sjkim BIO_puts(err, "Algorithm already set!\n"); 339280304Sjkim return 0; 340280304Sjkim } 341238384Sjkim 342280304Sjkim ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); 343238384Sjkim 344238384Sjkim#ifndef OPENSSL_NO_ENGINE 345280304Sjkim if (!ameth && e) 346280304Sjkim ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); 347238384Sjkim#endif 348238384Sjkim 349280304Sjkim if (!ameth) { 350280304Sjkim BIO_printf(bio_err, "Algorithm %s not found\n", algname); 351280304Sjkim return 0; 352280304Sjkim } 353238384Sjkim 354280304Sjkim ERR_clear_error(); 355238384Sjkim 356280304Sjkim EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); 357238384Sjkim#ifndef OPENSSL_NO_ENGINE 358280304Sjkim if (tmpeng) 359280304Sjkim ENGINE_finish(tmpeng); 360238384Sjkim#endif 361280304Sjkim ctx = EVP_PKEY_CTX_new_id(pkey_id, e); 362238384Sjkim 363280304Sjkim if (!ctx) 364280304Sjkim goto err; 365280304Sjkim if (do_param) { 366280304Sjkim if (EVP_PKEY_paramgen_init(ctx) <= 0) 367280304Sjkim goto err; 368280304Sjkim } else { 369280304Sjkim if (EVP_PKEY_keygen_init(ctx) <= 0) 370280304Sjkim goto err; 371280304Sjkim } 372238384Sjkim 373280304Sjkim *pctx = ctx; 374280304Sjkim return 1; 375238384Sjkim 376280304Sjkim err: 377280304Sjkim BIO_printf(err, "Error initializing %s context\n", algname); 378280304Sjkim ERR_print_errors(err); 379280304Sjkim if (ctx) 380280304Sjkim EVP_PKEY_CTX_free(ctx); 381280304Sjkim return 0; 382238384Sjkim 383280304Sjkim} 384238384Sjkim 385238384Sjkimstatic int genpkey_cb(EVP_PKEY_CTX *ctx) 386280304Sjkim{ 387280304Sjkim char c = '*'; 388280304Sjkim BIO *b = EVP_PKEY_CTX_get_app_data(ctx); 389280304Sjkim int p; 390280304Sjkim p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); 391280304Sjkim if (p == 0) 392280304Sjkim c = '.'; 393280304Sjkim if (p == 1) 394280304Sjkim c = '+'; 395280304Sjkim if (p == 2) 396280304Sjkim c = '*'; 397280304Sjkim if (p == 3) 398280304Sjkim c = '\n'; 399280304Sjkim BIO_write(b, &c, 1); 400280304Sjkim (void)BIO_flush(b); 401238384Sjkim#ifdef LINT 402280304Sjkim p = n; 403238384Sjkim#endif 404280304Sjkim return 1; 405280304Sjkim} 406