1 /* $OpenBSD: genpkey.c,v 1.7 2015/10/17 07:51:10 semarie 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 69 init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx, const char *file); 70 static int genpkey_cb(EVP_PKEY_CTX * ctx); 71 72 int 73 genpkey_main(int argc, char **argv) 74 { 75 char **args, *outfile = NULL; 76 char *passarg = NULL; 77 BIO *in = NULL, *out = NULL; 78 const EVP_CIPHER *cipher = NULL; 79 int outformat; 80 int text = 0; 81 EVP_PKEY *pkey = NULL; 82 EVP_PKEY_CTX *ctx = NULL; 83 char *pass = NULL; 84 int badarg = 0; 85 int ret = 1, rv; 86 87 int do_param = 0; 88 89 if (single_execution) { 90 if (pledge("stdio rpath wpath cpath tty", NULL) == -1) { 91 perror("pledge"); 92 exit(1); 93 } 94 } 95 96 outformat = FORMAT_PEM; 97 98 args = argv + 1; 99 while (!badarg && *args && *args[0] == '-') { 100 if (!strcmp(*args, "-outform")) { 101 if (args[1]) { 102 args++; 103 outformat = str2fmt(*args); 104 } else 105 badarg = 1; 106 } else if (!strcmp(*args, "-pass")) { 107 if (!args[1]) 108 goto bad; 109 passarg = *(++args); 110 } 111 else if (!strcmp(*args, "-paramfile")) { 112 if (!args[1]) 113 goto bad; 114 args++; 115 if (do_param == 1) 116 goto bad; 117 if (!init_keygen_file(bio_err, &ctx, *args)) 118 goto end; 119 } else if (!strcmp(*args, "-out")) { 120 if (args[1]) { 121 args++; 122 outfile = *args; 123 } else 124 badarg = 1; 125 } else if (strcmp(*args, "-algorithm") == 0) { 126 if (!args[1]) 127 goto bad; 128 if (!init_gen_str(bio_err, &ctx, *(++args), do_param)) 129 goto end; 130 } else if (strcmp(*args, "-pkeyopt") == 0) { 131 if (!args[1]) 132 goto bad; 133 if (!ctx) { 134 BIO_puts(bio_err, "No keytype specified\n"); 135 goto bad; 136 } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) { 137 BIO_puts(bio_err, "parameter setting error\n"); 138 ERR_print_errors(bio_err); 139 goto end; 140 } 141 } else if (strcmp(*args, "-genparam") == 0) { 142 if (ctx) 143 goto bad; 144 do_param = 1; 145 } else if (strcmp(*args, "-text") == 0) 146 text = 1; 147 else { 148 cipher = EVP_get_cipherbyname(*args + 1); 149 if (!cipher) { 150 BIO_printf(bio_err, "Unknown cipher %s\n", 151 *args + 1); 152 badarg = 1; 153 } 154 if (do_param == 1) 155 badarg = 1; 156 } 157 args++; 158 } 159 160 if (!ctx) 161 badarg = 1; 162 163 if (badarg) { 164 bad: 165 BIO_printf(bio_err, "Usage: genpkey [options]\n"); 166 BIO_printf(bio_err, "where options may be\n"); 167 BIO_printf(bio_err, "-out file output file\n"); 168 BIO_printf(bio_err, "-outform X output format (DER or PEM)\n"); 169 BIO_printf(bio_err, "-pass arg output file pass phrase source\n"); 170 BIO_printf(bio_err, "-<cipher> use cipher <cipher> to encrypt the key\n"); 171 BIO_printf(bio_err, "-paramfile file parameters file\n"); 172 BIO_printf(bio_err, "-algorithm alg the public key algorithm\n"); 173 BIO_printf(bio_err, "-pkeyopt opt:value set the public key algorithm option <opt>\n" 174 " to value <value>\n"); 175 BIO_printf(bio_err, "-genparam generate parameters, not key\n"); 176 BIO_printf(bio_err, "-text print the in text\n"); 177 BIO_printf(bio_err, "NB: options order may be important! See the manual page.\n"); 178 goto end; 179 } 180 if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { 181 BIO_puts(bio_err, "Error getting password\n"); 182 goto end; 183 } 184 if (outfile) { 185 if (!(out = BIO_new_file(outfile, "wb"))) { 186 BIO_printf(bio_err, 187 "Can't open output file %s\n", outfile); 188 goto end; 189 } 190 } else { 191 out = BIO_new_fp(stdout, BIO_NOCLOSE); 192 } 193 194 EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); 195 EVP_PKEY_CTX_set_app_data(ctx, bio_err); 196 197 if (do_param) { 198 if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { 199 BIO_puts(bio_err, "Error generating parameters\n"); 200 ERR_print_errors(bio_err); 201 goto end; 202 } 203 } else { 204 if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { 205 BIO_puts(bio_err, "Error generating key\n"); 206 ERR_print_errors(bio_err); 207 goto end; 208 } 209 } 210 211 if (do_param) 212 rv = PEM_write_bio_Parameters(out, pkey); 213 else if (outformat == FORMAT_PEM) 214 rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, 215 NULL, pass); 216 else if (outformat == FORMAT_ASN1) 217 rv = i2d_PrivateKey_bio(out, pkey); 218 else { 219 BIO_printf(bio_err, "Bad format specified for key\n"); 220 goto end; 221 } 222 223 if (rv <= 0) { 224 BIO_puts(bio_err, "Error writing key\n"); 225 ERR_print_errors(bio_err); 226 } 227 if (text) { 228 if (do_param) 229 rv = EVP_PKEY_print_params(out, pkey, 0, NULL); 230 else 231 rv = EVP_PKEY_print_private(out, pkey, 0, NULL); 232 233 if (rv <= 0) { 234 BIO_puts(bio_err, "Error printing key\n"); 235 ERR_print_errors(bio_err); 236 } 237 } 238 ret = 0; 239 240 end: 241 if (pkey) 242 EVP_PKEY_free(pkey); 243 if (ctx) 244 EVP_PKEY_CTX_free(ctx); 245 if (out) 246 BIO_free_all(out); 247 BIO_free(in); 248 free(pass); 249 250 return ret; 251 } 252 253 static int 254 init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx, 255 const char *file) 256 { 257 BIO *pbio; 258 EVP_PKEY *pkey = NULL; 259 EVP_PKEY_CTX *ctx = NULL; 260 if (*pctx) { 261 BIO_puts(err, "Parameters already set!\n"); 262 return 0; 263 } 264 pbio = BIO_new_file(file, "r"); 265 if (!pbio) { 266 BIO_printf(err, "Can't open parameter file %s\n", file); 267 return 0; 268 } 269 pkey = PEM_read_bio_Parameters(pbio, NULL); 270 BIO_free(pbio); 271 272 if (!pkey) { 273 BIO_printf(bio_err, "Error reading parameter file %s\n", file); 274 return 0; 275 } 276 ctx = EVP_PKEY_CTX_new(pkey, NULL); 277 if (!ctx) 278 goto err; 279 if (EVP_PKEY_keygen_init(ctx) <= 0) 280 goto err; 281 EVP_PKEY_free(pkey); 282 *pctx = ctx; 283 return 1; 284 285 err: 286 BIO_puts(err, "Error initializing context\n"); 287 ERR_print_errors(err); 288 if (ctx) 289 EVP_PKEY_CTX_free(ctx); 290 if (pkey) 291 EVP_PKEY_free(pkey); 292 return 0; 293 294 } 295 296 int 297 init_gen_str(BIO * err, EVP_PKEY_CTX ** pctx, 298 const char *algname, int do_param) 299 { 300 EVP_PKEY_CTX *ctx = NULL; 301 const EVP_PKEY_ASN1_METHOD *ameth; 302 int pkey_id; 303 304 if (*pctx) { 305 BIO_puts(err, "Algorithm already set!\n"); 306 return 0; 307 } 308 ameth = EVP_PKEY_asn1_find_str(NULL, algname, -1); 309 310 if (!ameth) { 311 BIO_printf(bio_err, "Algorithm %s not found\n", algname); 312 return 0; 313 } 314 ERR_clear_error(); 315 316 EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); 317 ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL); 318 319 if (!ctx) 320 goto err; 321 if (do_param) { 322 if (EVP_PKEY_paramgen_init(ctx) <= 0) 323 goto err; 324 } else { 325 if (EVP_PKEY_keygen_init(ctx) <= 0) 326 goto err; 327 } 328 329 *pctx = ctx; 330 return 1; 331 332 err: 333 BIO_printf(err, "Error initializing %s context\n", algname); 334 ERR_print_errors(err); 335 if (ctx) 336 EVP_PKEY_CTX_free(ctx); 337 return 0; 338 339 } 340 341 static int 342 genpkey_cb(EVP_PKEY_CTX * ctx) 343 { 344 char c = '*'; 345 BIO *b = EVP_PKEY_CTX_get_app_data(ctx); 346 int p; 347 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); 348 if (p == 0) 349 c = '.'; 350 if (p == 1) 351 c = '+'; 352 if (p == 2) 353 c = '*'; 354 if (p == 3) 355 c = '\n'; 356 BIO_write(b, &c, 1); 357 (void) BIO_flush(b); 358 return 1; 359 } 360