1*e7718adaStb /* $OpenBSD: genrsa.c,v 1.22 2023/03/06 14:32:06 tb Exp $ */
2dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3dab3f910Sjsing * All rights reserved.
4dab3f910Sjsing *
5dab3f910Sjsing * This package is an SSL implementation written
6dab3f910Sjsing * by Eric Young (eay@cryptsoft.com).
7dab3f910Sjsing * The implementation was written so as to conform with Netscapes SSL.
8dab3f910Sjsing *
9dab3f910Sjsing * This library is free for commercial and non-commercial use as long as
10dab3f910Sjsing * the following conditions are aheared to. The following conditions
11dab3f910Sjsing * apply to all code found in this distribution, be it the RC4, RSA,
12dab3f910Sjsing * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13dab3f910Sjsing * included with this distribution is covered by the same copyright terms
14dab3f910Sjsing * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15dab3f910Sjsing *
16dab3f910Sjsing * Copyright remains Eric Young's, and as such any Copyright notices in
17dab3f910Sjsing * the code are not to be removed.
18dab3f910Sjsing * If this package is used in a product, Eric Young should be given attribution
19dab3f910Sjsing * as the author of the parts of the library used.
20dab3f910Sjsing * This can be in the form of a textual message at program startup or
21dab3f910Sjsing * in documentation (online or textual) provided with the package.
22dab3f910Sjsing *
23dab3f910Sjsing * Redistribution and use in source and binary forms, with or without
24dab3f910Sjsing * modification, are permitted provided that the following conditions
25dab3f910Sjsing * are met:
26dab3f910Sjsing * 1. Redistributions of source code must retain the copyright
27dab3f910Sjsing * notice, this list of conditions and the following disclaimer.
28dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright
29dab3f910Sjsing * notice, this list of conditions and the following disclaimer in the
30dab3f910Sjsing * documentation and/or other materials provided with the distribution.
31dab3f910Sjsing * 3. All advertising materials mentioning features or use of this software
32dab3f910Sjsing * must display the following acknowledgement:
33dab3f910Sjsing * "This product includes cryptographic software written by
34dab3f910Sjsing * Eric Young (eay@cryptsoft.com)"
35dab3f910Sjsing * The word 'cryptographic' can be left out if the rouines from the library
36dab3f910Sjsing * being used are not cryptographic related :-).
37dab3f910Sjsing * 4. If you include any Windows specific code (or a derivative thereof) from
38dab3f910Sjsing * the apps directory (application code) you must include an acknowledgement:
39dab3f910Sjsing * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40dab3f910Sjsing *
41dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42dab3f910Sjsing * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44dab3f910Sjsing * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45dab3f910Sjsing * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46dab3f910Sjsing * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47dab3f910Sjsing * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49dab3f910Sjsing * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50dab3f910Sjsing * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51dab3f910Sjsing * SUCH DAMAGE.
52dab3f910Sjsing *
53dab3f910Sjsing * The licence and distribution terms for any publically available version or
54dab3f910Sjsing * derivative of this code cannot be changed. i.e. this code cannot simply be
55dab3f910Sjsing * copied and put under another distribution licence
56dab3f910Sjsing * [including the GNU Public Licence.]
57dab3f910Sjsing */
58dab3f910Sjsing
59dab3f910Sjsing #include <openssl/opensslconf.h>
60dab3f910Sjsing
61dab3f910Sjsing /* Until the key-gen callbacks are modified to use newer prototypes, we allow
62dab3f910Sjsing * deprecated functions for openssl-internal code */
63dab3f910Sjsing #ifdef OPENSSL_NO_DEPRECATED
64dab3f910Sjsing #undef OPENSSL_NO_DEPRECATED
65dab3f910Sjsing #endif
66dab3f910Sjsing
67dab3f910Sjsing
68dab3f910Sjsing #include <sys/types.h>
69dab3f910Sjsing #include <sys/stat.h>
70dab3f910Sjsing
71dab3f910Sjsing #include <stdio.h>
72dab3f910Sjsing #include <string.h>
73dab3f910Sjsing
74dab3f910Sjsing #include "apps.h"
75dab3f910Sjsing
76dab3f910Sjsing #include <openssl/bio.h>
77dab3f910Sjsing #include <openssl/bn.h>
78dab3f910Sjsing #include <openssl/err.h>
79dab3f910Sjsing #include <openssl/evp.h>
80dab3f910Sjsing #include <openssl/pem.h>
81dab3f910Sjsing #include <openssl/rsa.h>
82dab3f910Sjsing #include <openssl/x509.h>
83dab3f910Sjsing
84dab3f910Sjsing #define DEFBITS 2048
85dab3f910Sjsing
86dab3f910Sjsing static int genrsa_cb(int p, int n, BN_GENCB *cb);
87dab3f910Sjsing
88e724e435Sinoguchi static struct {
89e724e435Sinoguchi const EVP_CIPHER *enc;
90e724e435Sinoguchi unsigned long f4;
91e724e435Sinoguchi char *outfile;
92e724e435Sinoguchi char *passargout;
93*e7718adaStb } cfg;
94e724e435Sinoguchi
9519db20daSinoguchi static int
set_public_exponent(int argc,char ** argv,int * argsused)9619db20daSinoguchi set_public_exponent(int argc, char **argv, int *argsused)
9719db20daSinoguchi {
9819db20daSinoguchi char *option = argv[0];
9919db20daSinoguchi
10019db20daSinoguchi if (strcmp(option, "-3") == 0)
101*e7718adaStb cfg.f4 = 3;
10219db20daSinoguchi else if (strcmp(option, "-f4") == 0 || strcmp(option, "-F4") == 0)
103*e7718adaStb cfg.f4 = RSA_F4;
10419db20daSinoguchi else
10519db20daSinoguchi return (1);
10619db20daSinoguchi
10719db20daSinoguchi *argsused = 1;
10819db20daSinoguchi return (0);
10919db20daSinoguchi }
11019db20daSinoguchi
get_cipher_by_name(char * name)11119db20daSinoguchi static const EVP_CIPHER *get_cipher_by_name(char *name)
11219db20daSinoguchi {
11319db20daSinoguchi if (name == NULL || strcmp(name, "") == 0)
11419db20daSinoguchi return (NULL);
11519db20daSinoguchi #ifndef OPENSSL_NO_AES
11619db20daSinoguchi else if (strcmp(name, "aes128") == 0)
11719db20daSinoguchi return EVP_aes_128_cbc();
11819db20daSinoguchi else if (strcmp(name, "aes192") == 0)
11919db20daSinoguchi return EVP_aes_192_cbc();
12019db20daSinoguchi else if (strcmp(name, "aes256") == 0)
12119db20daSinoguchi return EVP_aes_256_cbc();
12219db20daSinoguchi #endif
12319db20daSinoguchi #ifndef OPENSSL_NO_CAMELLIA
12419db20daSinoguchi else if (strcmp(name, "camellia128") == 0)
12519db20daSinoguchi return EVP_camellia_128_cbc();
12619db20daSinoguchi else if (strcmp(name, "camellia192") == 0)
12719db20daSinoguchi return EVP_camellia_192_cbc();
12819db20daSinoguchi else if (strcmp(name, "camellia256") == 0)
12919db20daSinoguchi return EVP_camellia_256_cbc();
13019db20daSinoguchi #endif
13119db20daSinoguchi #ifndef OPENSSL_NO_DES
13219db20daSinoguchi else if (strcmp(name, "des") == 0)
13319db20daSinoguchi return EVP_des_cbc();
13419db20daSinoguchi else if (strcmp(name, "des3") == 0)
13519db20daSinoguchi return EVP_des_ede3_cbc();
13619db20daSinoguchi #endif
13719db20daSinoguchi #ifndef OPENSSL_NO_IDEA
13819db20daSinoguchi else if (strcmp(name, "idea") == 0)
13919db20daSinoguchi return EVP_idea_cbc();
14019db20daSinoguchi #endif
14119db20daSinoguchi else
14219db20daSinoguchi return (NULL);
14319db20daSinoguchi }
14419db20daSinoguchi
14519db20daSinoguchi static int
set_enc(int argc,char ** argv,int * argsused)14619db20daSinoguchi set_enc(int argc, char **argv, int *argsused)
14719db20daSinoguchi {
14819db20daSinoguchi char *name = argv[0];
14919db20daSinoguchi
15019db20daSinoguchi if (*name++ != '-')
15119db20daSinoguchi return (1);
15219db20daSinoguchi
153*e7718adaStb if ((cfg.enc = get_cipher_by_name(name)) == NULL)
15419db20daSinoguchi return (1);
15519db20daSinoguchi
15619db20daSinoguchi *argsused = 1;
15719db20daSinoguchi return (0);
15819db20daSinoguchi }
15919db20daSinoguchi
160ea149709Sguenther static const struct option genrsa_options[] = {
16119db20daSinoguchi {
16219db20daSinoguchi .name = "3",
16319db20daSinoguchi .desc = "Use 3 for the E value",
16419db20daSinoguchi .type = OPTION_ARGV_FUNC,
16519db20daSinoguchi .opt.argvfunc = set_public_exponent,
16619db20daSinoguchi },
16719db20daSinoguchi {
16819db20daSinoguchi .name = "f4",
16919db20daSinoguchi .desc = "Use F4 (0x10001) for the E value",
17019db20daSinoguchi .type = OPTION_ARGV_FUNC,
17119db20daSinoguchi .opt.argvfunc = set_public_exponent,
17219db20daSinoguchi },
17319db20daSinoguchi {
17419db20daSinoguchi .name = "F4",
17519db20daSinoguchi .desc = "Use F4 (0x10001) for the E value",
17619db20daSinoguchi .type = OPTION_ARGV_FUNC,
17719db20daSinoguchi .opt.argvfunc = set_public_exponent,
17819db20daSinoguchi },
17919db20daSinoguchi #ifndef OPENSSL_NO_AES
18019db20daSinoguchi {
18119db20daSinoguchi .name = "aes128",
18207a5d217Sinoguchi .desc = "Encrypt PEM output with CBC AES",
18319db20daSinoguchi .type = OPTION_ARGV_FUNC,
18419db20daSinoguchi .opt.argvfunc = set_enc,
18519db20daSinoguchi },
18619db20daSinoguchi {
18719db20daSinoguchi .name = "aes192",
18807a5d217Sinoguchi .desc = "Encrypt PEM output with CBC AES",
18919db20daSinoguchi .type = OPTION_ARGV_FUNC,
19019db20daSinoguchi .opt.argvfunc = set_enc,
19119db20daSinoguchi },
19219db20daSinoguchi {
19319db20daSinoguchi .name = "aes256",
19407a5d217Sinoguchi .desc = "Encrypt PEM output with CBC AES",
19519db20daSinoguchi .type = OPTION_ARGV_FUNC,
19619db20daSinoguchi .opt.argvfunc = set_enc,
19719db20daSinoguchi },
19819db20daSinoguchi #endif
19919db20daSinoguchi #ifndef OPENSSL_NO_CAMELLIA
20019db20daSinoguchi {
20119db20daSinoguchi .name = "camellia128",
20207a5d217Sinoguchi .desc = "Encrypt PEM output with CBC Camellia",
20319db20daSinoguchi .type = OPTION_ARGV_FUNC,
20419db20daSinoguchi .opt.argvfunc = set_enc,
20519db20daSinoguchi },
20619db20daSinoguchi {
20719db20daSinoguchi .name = "camellia192",
20807a5d217Sinoguchi .desc = "Encrypt PEM output with CBC Camellia",
20919db20daSinoguchi .type = OPTION_ARGV_FUNC,
21019db20daSinoguchi .opt.argvfunc = set_enc,
21119db20daSinoguchi },
21219db20daSinoguchi {
21319db20daSinoguchi .name = "camellia256",
21407a5d217Sinoguchi .desc = "Encrypt PEM output with CBC Camellia",
21519db20daSinoguchi .type = OPTION_ARGV_FUNC,
21619db20daSinoguchi .opt.argvfunc = set_enc,
21719db20daSinoguchi },
21819db20daSinoguchi #endif
21919db20daSinoguchi #ifndef OPENSSL_NO_DES
22019db20daSinoguchi {
22119db20daSinoguchi .name = "des",
22207a5d217Sinoguchi .desc = "Encrypt the generated key with DES in CBC mode",
22319db20daSinoguchi .type = OPTION_ARGV_FUNC,
22419db20daSinoguchi .opt.argvfunc = set_enc,
22519db20daSinoguchi },
22619db20daSinoguchi {
22719db20daSinoguchi .name = "des3",
22807a5d217Sinoguchi .desc = "Encrypt the generated key with DES in EDE CBC mode (168 bit key)",
22919db20daSinoguchi .type = OPTION_ARGV_FUNC,
23019db20daSinoguchi .opt.argvfunc = set_enc,
23119db20daSinoguchi },
23219db20daSinoguchi #endif
23319db20daSinoguchi #ifndef OPENSSL_NO_IDEA
23419db20daSinoguchi {
23519db20daSinoguchi .name = "idea",
23607a5d217Sinoguchi .desc = "Encrypt the generated key with IDEA in CBC mode",
23719db20daSinoguchi .type = OPTION_ARGV_FUNC,
23819db20daSinoguchi .opt.argvfunc = set_enc,
23919db20daSinoguchi },
24019db20daSinoguchi #endif
24119db20daSinoguchi {
24219db20daSinoguchi .name = "out",
24319db20daSinoguchi .argname = "file",
24419db20daSinoguchi .desc = "Output the key to 'file'",
24519db20daSinoguchi .type = OPTION_ARG,
246*e7718adaStb .opt.arg = &cfg.outfile,
24719db20daSinoguchi },
24819db20daSinoguchi {
24919db20daSinoguchi .name = "passout",
25019db20daSinoguchi .argname = "arg",
25119db20daSinoguchi .desc = "Output file passphrase source",
25219db20daSinoguchi .type = OPTION_ARG,
253*e7718adaStb .opt.arg = &cfg.passargout,
25419db20daSinoguchi },
25519db20daSinoguchi { NULL },
25619db20daSinoguchi };
25719db20daSinoguchi
25819db20daSinoguchi static void
genrsa_usage(void)25919db20daSinoguchi genrsa_usage(void)
26019db20daSinoguchi {
26119db20daSinoguchi fprintf(stderr, "usage: genrsa [-3 | -f4] [-aes128 | -aes192 |");
26219db20daSinoguchi fprintf(stderr, " -aes256 |\n");
26319db20daSinoguchi fprintf(stderr, " -camellia128 | -camellia192 | -camellia256 |");
26419db20daSinoguchi fprintf(stderr, " -des | -des3 | -idea]\n");
26519db20daSinoguchi fprintf(stderr, " [-out file] [-passout arg] [numbits]\n\n");
26619db20daSinoguchi options_usage(genrsa_options);
26719db20daSinoguchi fprintf(stderr, "\n");
26819db20daSinoguchi }
26919db20daSinoguchi
270dab3f910Sjsing int
genrsa_main(int argc,char ** argv)271dab3f910Sjsing genrsa_main(int argc, char **argv)
272dab3f910Sjsing {
273e0a955c7Stb BN_GENCB *cb = NULL;
274dab3f910Sjsing int ret = 1;
275e0a955c7Stb int num = DEFBITS;
27619db20daSinoguchi char *numbits = NULL;
277e724e435Sinoguchi char *passout = NULL;
278dab3f910Sjsing BIO *out = NULL;
279e0a955c7Stb BIGNUM *bn = NULL;
280dab3f910Sjsing RSA *rsa = NULL;
281e0a955c7Stb char *rsa_e_hex = NULL, *rsa_e_dec = NULL;
282dab3f910Sjsing
28351811eadSderaadt if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
2849bc487adSdoug perror("pledge");
285e370f0eeSdoug exit(1);
286e370f0eeSdoug }
2879bc487adSdoug
288e0a955c7Stb if ((bn = BN_new()) == NULL)
289dab3f910Sjsing goto err;
290dab3f910Sjsing
291e0a955c7Stb if ((cb = BN_GENCB_new()) == NULL) {
292e0a955c7Stb BIO_printf(bio_err, "Error allocating BN_GENCB object\n");
293e0a955c7Stb goto err;
294e0a955c7Stb }
295e0a955c7Stb
296e0a955c7Stb BN_GENCB_set(cb, genrsa_cb, bio_err);
297dab3f910Sjsing
298dab3f910Sjsing if ((out = BIO_new(BIO_s_file())) == NULL) {
299dab3f910Sjsing BIO_printf(bio_err, "unable to create BIO for output\n");
300dab3f910Sjsing goto err;
301dab3f910Sjsing }
302e724e435Sinoguchi
303*e7718adaStb memset(&cfg, 0, sizeof(cfg));
304*e7718adaStb cfg.f4 = RSA_F4;
305e724e435Sinoguchi
30619db20daSinoguchi if (options_parse(argc, argv, genrsa_options, &numbits, NULL) != 0) {
30719db20daSinoguchi genrsa_usage();
30819db20daSinoguchi goto err;
309dab3f910Sjsing }
31019db20daSinoguchi
311279a27cfSinoguchi if ((numbits != NULL) &&
312279a27cfSinoguchi ((sscanf(numbits, "%d", &num) == 0) || (num < 0))) {
31319db20daSinoguchi genrsa_usage();
314dab3f910Sjsing goto err;
315dab3f910Sjsing }
316dab3f910Sjsing
317*e7718adaStb if (!app_passwd(bio_err, NULL, cfg.passargout, NULL,
318279a27cfSinoguchi &passout)) {
319dab3f910Sjsing BIO_printf(bio_err, "Error getting password\n");
320dab3f910Sjsing goto err;
321dab3f910Sjsing }
322dab3f910Sjsing
323*e7718adaStb if (cfg.outfile == NULL) {
324dab3f910Sjsing BIO_set_fp(out, stdout, BIO_NOCLOSE);
325dab3f910Sjsing } else {
326*e7718adaStb if (BIO_write_filename(out, cfg.outfile) <= 0) {
327*e7718adaStb perror(cfg.outfile);
328dab3f910Sjsing goto err;
329dab3f910Sjsing }
330dab3f910Sjsing }
331dab3f910Sjsing
332dab3f910Sjsing BIO_printf(bio_err, "Generating RSA private key, %d bit long modulus\n",
333dab3f910Sjsing num);
334dab3f910Sjsing rsa = RSA_new();
335dab3f910Sjsing if (!rsa)
336dab3f910Sjsing goto err;
337dab3f910Sjsing
338*e7718adaStb if (!BN_set_word(bn, cfg.f4) ||
339e0a955c7Stb !RSA_generate_key_ex(rsa, num, bn, cb))
340dab3f910Sjsing goto err;
341dab3f910Sjsing
3425161c7ccStb if ((rsa_e_hex = BN_bn2hex(RSA_get0_e(rsa))) == NULL)
343e0a955c7Stb goto err;
3445161c7ccStb if ((rsa_e_dec = BN_bn2dec(RSA_get0_e(rsa))) == NULL)
345e0a955c7Stb goto err;
346e0a955c7Stb
347e856d5e6Sespie BIO_printf(bio_err, "e is %s (0x%s)\n", rsa_e_dec, rsa_e_hex);
348dab3f910Sjsing {
349dab3f910Sjsing PW_CB_DATA cb_data;
350dab3f910Sjsing cb_data.password = passout;
351*e7718adaStb cb_data.prompt_info = cfg.outfile;
352*e7718adaStb if (!PEM_write_bio_RSAPrivateKey(out, rsa, cfg.enc,
353279a27cfSinoguchi NULL, 0, password_callback, &cb_data))
354dab3f910Sjsing goto err;
355dab3f910Sjsing }
356dab3f910Sjsing
357dab3f910Sjsing ret = 0;
358dab3f910Sjsing err:
359dab3f910Sjsing BN_free(bn);
360e0a955c7Stb BN_GENCB_free(cb);
361dab3f910Sjsing RSA_free(rsa);
362dab3f910Sjsing BIO_free_all(out);
363e0a955c7Stb free(rsa_e_dec);
364e0a955c7Stb free(rsa_e_hex);
365dab3f910Sjsing free(passout);
3664fe8ecddSjsing
367dab3f910Sjsing if (ret != 0)
368dab3f910Sjsing ERR_print_errors(bio_err);
369dab3f910Sjsing
370dab3f910Sjsing return (ret);
371dab3f910Sjsing }
372dab3f910Sjsing
373dab3f910Sjsing static int
genrsa_cb(int p,int n,BN_GENCB * cb)374dab3f910Sjsing genrsa_cb(int p, int n, BN_GENCB *cb)
375dab3f910Sjsing {
376dab3f910Sjsing char c = '*';
377dab3f910Sjsing
378dab3f910Sjsing if (p == 0)
379dab3f910Sjsing c = '.';
380dab3f910Sjsing if (p == 1)
381dab3f910Sjsing c = '+';
382dab3f910Sjsing if (p == 2)
383dab3f910Sjsing c = '*';
384dab3f910Sjsing if (p == 3)
385dab3f910Sjsing c = '\n';
386e0a955c7Stb BIO_write(BN_GENCB_get_arg(cb), &c, 1);
387e0a955c7Stb (void) BIO_flush(BN_GENCB_get_arg(cb));
388dab3f910Sjsing return 1;
389dab3f910Sjsing }
390