1 /* $OpenBSD: genrsa.c,v 1.17 2019/07/24 14:23:25 inoguchi Exp $ */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <openssl/opensslconf.h> 60 61 /* Until the key-gen callbacks are modified to use newer prototypes, we allow 62 * deprecated functions for openssl-internal code */ 63 #ifdef OPENSSL_NO_DEPRECATED 64 #undef OPENSSL_NO_DEPRECATED 65 #endif 66 67 68 #include <sys/types.h> 69 #include <sys/stat.h> 70 71 #include <stdio.h> 72 #include <string.h> 73 74 #include "apps.h" 75 76 #include <openssl/bio.h> 77 #include <openssl/bn.h> 78 #include <openssl/err.h> 79 #include <openssl/evp.h> 80 #include <openssl/pem.h> 81 #include <openssl/rsa.h> 82 #include <openssl/x509.h> 83 84 #define DEFBITS 2048 85 86 static int genrsa_cb(int p, int n, BN_GENCB * cb); 87 88 static struct { 89 const EVP_CIPHER *enc; 90 unsigned long f4; 91 char *outfile; 92 char *passargout; 93 } genrsa_config; 94 95 static int 96 set_public_exponent(int argc, char **argv, int *argsused) 97 { 98 char *option = argv[0]; 99 100 if (strcmp(option, "-3") == 0) 101 genrsa_config.f4 = 3; 102 else if (strcmp(option, "-f4") == 0 || strcmp(option, "-F4") == 0) 103 genrsa_config.f4 = RSA_F4; 104 else 105 return (1); 106 107 *argsused = 1; 108 return (0); 109 } 110 111 static const EVP_CIPHER *get_cipher_by_name(char *name) 112 { 113 if (name == NULL || strcmp(name, "") == 0) 114 return (NULL); 115 #ifndef OPENSSL_NO_AES 116 else if (strcmp(name, "aes128") == 0) 117 return EVP_aes_128_cbc(); 118 else if (strcmp(name, "aes192") == 0) 119 return EVP_aes_192_cbc(); 120 else if (strcmp(name, "aes256") == 0) 121 return EVP_aes_256_cbc(); 122 #endif 123 #ifndef OPENSSL_NO_CAMELLIA 124 else if (strcmp(name, "camellia128") == 0) 125 return EVP_camellia_128_cbc(); 126 else if (strcmp(name, "camellia192") == 0) 127 return EVP_camellia_192_cbc(); 128 else if (strcmp(name, "camellia256") == 0) 129 return EVP_camellia_256_cbc(); 130 #endif 131 #ifndef OPENSSL_NO_DES 132 else if (strcmp(name, "des") == 0) 133 return EVP_des_cbc(); 134 else if (strcmp(name, "des3") == 0) 135 return EVP_des_ede3_cbc(); 136 #endif 137 #ifndef OPENSSL_NO_IDEA 138 else if (strcmp(name, "idea") == 0) 139 return EVP_idea_cbc(); 140 #endif 141 else 142 return (NULL); 143 } 144 145 static int 146 set_enc(int argc, char **argv, int *argsused) 147 { 148 char *name = argv[0]; 149 150 if (*name++ != '-') 151 return (1); 152 153 if ((genrsa_config.enc = get_cipher_by_name(name)) == NULL) 154 return (1); 155 156 *argsused = 1; 157 return (0); 158 } 159 160 static const struct option genrsa_options[] = { 161 { 162 .name = "3", 163 .desc = "Use 3 for the E value", 164 .type = OPTION_ARGV_FUNC, 165 .opt.argvfunc = set_public_exponent, 166 }, 167 { 168 .name = "f4", 169 .desc = "Use F4 (0x10001) for the E value", 170 .type = OPTION_ARGV_FUNC, 171 .opt.argvfunc = set_public_exponent, 172 }, 173 { 174 .name = "F4", 175 .desc = "Use F4 (0x10001) for the E value", 176 .type = OPTION_ARGV_FUNC, 177 .opt.argvfunc = set_public_exponent, 178 }, 179 #ifndef OPENSSL_NO_AES 180 { 181 .name = "aes128", 182 .desc = "Encrypt PEM output with CBC AES", 183 .type = OPTION_ARGV_FUNC, 184 .opt.argvfunc = set_enc, 185 }, 186 { 187 .name = "aes192", 188 .desc = "Encrypt PEM output with CBC AES", 189 .type = OPTION_ARGV_FUNC, 190 .opt.argvfunc = set_enc, 191 }, 192 { 193 .name = "aes256", 194 .desc = "Encrypt PEM output with CBC AES", 195 .type = OPTION_ARGV_FUNC, 196 .opt.argvfunc = set_enc, 197 }, 198 #endif 199 #ifndef OPENSSL_NO_CAMELLIA 200 { 201 .name = "camellia128", 202 .desc = "Encrypt PEM output with CBC Camellia", 203 .type = OPTION_ARGV_FUNC, 204 .opt.argvfunc = set_enc, 205 }, 206 { 207 .name = "camellia192", 208 .desc = "Encrypt PEM output with CBC Camellia", 209 .type = OPTION_ARGV_FUNC, 210 .opt.argvfunc = set_enc, 211 }, 212 { 213 .name = "camellia256", 214 .desc = "Encrypt PEM output with CBC Camellia", 215 .type = OPTION_ARGV_FUNC, 216 .opt.argvfunc = set_enc, 217 }, 218 #endif 219 #ifndef OPENSSL_NO_DES 220 { 221 .name = "des", 222 .desc = "Encrypt the generated key with DES in CBC mode", 223 .type = OPTION_ARGV_FUNC, 224 .opt.argvfunc = set_enc, 225 }, 226 { 227 .name = "des3", 228 .desc = "Encrypt the generated key with DES in EDE CBC mode (168 bit key)", 229 .type = OPTION_ARGV_FUNC, 230 .opt.argvfunc = set_enc, 231 }, 232 #endif 233 #ifndef OPENSSL_NO_IDEA 234 { 235 .name = "idea", 236 .desc = "Encrypt the generated key with IDEA in CBC mode", 237 .type = OPTION_ARGV_FUNC, 238 .opt.argvfunc = set_enc, 239 }, 240 #endif 241 { 242 .name = "out", 243 .argname = "file", 244 .desc = "Output the key to 'file'", 245 .type = OPTION_ARG, 246 .opt.arg = &genrsa_config.outfile, 247 }, 248 { 249 .name = "passout", 250 .argname = "arg", 251 .desc = "Output file passphrase source", 252 .type = OPTION_ARG, 253 .opt.arg = &genrsa_config.passargout, 254 }, 255 { NULL }, 256 }; 257 258 static void 259 genrsa_usage(void) 260 { 261 fprintf(stderr, "usage: genrsa [-3 | -f4] [-aes128 | -aes192 |"); 262 fprintf(stderr, " -aes256 |\n"); 263 fprintf(stderr, " -camellia128 | -camellia192 | -camellia256 |"); 264 fprintf(stderr, " -des | -des3 | -idea]\n"); 265 fprintf(stderr, " [-out file] [-passout arg] [numbits]\n\n"); 266 options_usage(genrsa_options); 267 fprintf(stderr, "\n"); 268 } 269 270 int 271 genrsa_main(int argc, char **argv) 272 { 273 BN_GENCB cb; 274 int ret = 1; 275 int i, num = DEFBITS; 276 char *numbits= NULL; 277 long l; 278 char *passout = NULL; 279 BIO *out = NULL; 280 BIGNUM *bn = BN_new(); 281 RSA *rsa = NULL; 282 283 if (single_execution) { 284 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 285 perror("pledge"); 286 exit(1); 287 } 288 } 289 290 if (!bn) 291 goto err; 292 293 BN_GENCB_set(&cb, genrsa_cb, bio_err); 294 295 if ((out = BIO_new(BIO_s_file())) == NULL) { 296 BIO_printf(bio_err, "unable to create BIO for output\n"); 297 goto err; 298 } 299 300 memset(&genrsa_config, 0, sizeof(genrsa_config)); 301 genrsa_config.f4 = RSA_F4; 302 303 if (options_parse(argc, argv, genrsa_options, &numbits, NULL) != 0) { 304 genrsa_usage(); 305 goto err; 306 } 307 308 if ((numbits != NULL) && 309 ((sscanf(numbits, "%d", &num) == 0) || (num < 0))) { 310 genrsa_usage(); 311 goto err; 312 } 313 314 if (!app_passwd(bio_err, NULL, genrsa_config.passargout, NULL, 315 &passout)) { 316 BIO_printf(bio_err, "Error getting password\n"); 317 goto err; 318 } 319 320 if (genrsa_config.outfile == NULL) { 321 BIO_set_fp(out, stdout, BIO_NOCLOSE); 322 } else { 323 if (BIO_write_filename(out, genrsa_config.outfile) <= 0) { 324 perror(genrsa_config.outfile); 325 goto err; 326 } 327 } 328 329 BIO_printf(bio_err, "Generating RSA private key, %d bit long modulus\n", 330 num); 331 rsa = RSA_new(); 332 if (!rsa) 333 goto err; 334 335 if (!BN_set_word(bn, genrsa_config.f4) || 336 !RSA_generate_key_ex(rsa, num, bn, &cb)) 337 goto err; 338 339 /* 340 * We need to do the following for when the base number size is < 341 * long, esp windows 3.1 :-(. 342 */ 343 l = 0L; 344 for (i = 0; i < rsa->e->top; i++) { 345 #ifndef _LP64 346 l <<= BN_BITS4; 347 l <<= BN_BITS4; 348 #endif 349 l += rsa->e->d[i]; 350 } 351 BIO_printf(bio_err, "e is %ld (0x%lX)\n", l, l); 352 { 353 PW_CB_DATA cb_data; 354 cb_data.password = passout; 355 cb_data.prompt_info = genrsa_config.outfile; 356 if (!PEM_write_bio_RSAPrivateKey(out, rsa, genrsa_config.enc, 357 NULL, 0, password_callback, &cb_data)) 358 goto err; 359 } 360 361 ret = 0; 362 err: 363 BN_free(bn); 364 RSA_free(rsa); 365 BIO_free_all(out); 366 free(passout); 367 368 if (ret != 0) 369 ERR_print_errors(bio_err); 370 371 return (ret); 372 } 373 374 static int 375 genrsa_cb(int p, int n, BN_GENCB * cb) 376 { 377 char c = '*'; 378 379 if (p == 0) 380 c = '.'; 381 if (p == 1) 382 c = '+'; 383 if (p == 2) 384 c = '*'; 385 if (p == 3) 386 c = '\n'; 387 BIO_write(cb->arg, &c, 1); 388 (void) BIO_flush(cb->arg); 389 return 1; 390 } 391