xref: /openbsd-src/usr.bin/openssl/genrsa.c (revision e7718adaf9bdf5a32db0f291795197a85ccbb6ed)
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