xref: /dflybsd-src/crypto/libressl/apps/openssl/pkey.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: pkey.c,v 1.17 2022/01/14 10:17:30 tb Exp $ */
2f5b1c8a1SJohn Marino /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3f5b1c8a1SJohn Marino  * project 2006
4f5b1c8a1SJohn Marino  */
5f5b1c8a1SJohn Marino /* ====================================================================
6f5b1c8a1SJohn Marino  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7f5b1c8a1SJohn Marino  *
8f5b1c8a1SJohn Marino  * Redistribution and use in source and binary forms, with or without
9f5b1c8a1SJohn Marino  * modification, are permitted provided that the following conditions
10f5b1c8a1SJohn Marino  * are met:
11f5b1c8a1SJohn Marino  *
12f5b1c8a1SJohn Marino  * 1. Redistributions of source code must retain the above copyright
13f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer.
14f5b1c8a1SJohn Marino  *
15f5b1c8a1SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
16f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer in
17f5b1c8a1SJohn Marino  *    the documentation and/or other materials provided with the
18f5b1c8a1SJohn Marino  *    distribution.
19f5b1c8a1SJohn Marino  *
20f5b1c8a1SJohn Marino  * 3. All advertising materials mentioning features or use of this
21f5b1c8a1SJohn Marino  *    software must display the following acknowledgment:
22f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
23f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24f5b1c8a1SJohn Marino  *
25f5b1c8a1SJohn Marino  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26f5b1c8a1SJohn Marino  *    endorse or promote products derived from this software without
27f5b1c8a1SJohn Marino  *    prior written permission. For written permission, please contact
28f5b1c8a1SJohn Marino  *    licensing@OpenSSL.org.
29f5b1c8a1SJohn Marino  *
30f5b1c8a1SJohn Marino  * 5. Products derived from this software may not be called "OpenSSL"
31f5b1c8a1SJohn Marino  *    nor may "OpenSSL" appear in their names without prior written
32f5b1c8a1SJohn Marino  *    permission of the OpenSSL Project.
33f5b1c8a1SJohn Marino  *
34f5b1c8a1SJohn Marino  * 6. Redistributions of any form whatsoever must retain the following
35f5b1c8a1SJohn Marino  *    acknowledgment:
36f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
37f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38f5b1c8a1SJohn Marino  *
39f5b1c8a1SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40f5b1c8a1SJohn Marino  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41f5b1c8a1SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42f5b1c8a1SJohn Marino  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43f5b1c8a1SJohn Marino  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44f5b1c8a1SJohn Marino  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45f5b1c8a1SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46f5b1c8a1SJohn Marino  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47f5b1c8a1SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48f5b1c8a1SJohn Marino  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49f5b1c8a1SJohn Marino  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50f5b1c8a1SJohn Marino  * OF THE POSSIBILITY OF SUCH DAMAGE.
51f5b1c8a1SJohn Marino  * ====================================================================
52f5b1c8a1SJohn Marino  *
53f5b1c8a1SJohn Marino  * This product includes cryptographic software written by Eric Young
54f5b1c8a1SJohn Marino  * (eay@cryptsoft.com).  This product includes software written by Tim
55f5b1c8a1SJohn Marino  * Hudson (tjh@cryptsoft.com).
56f5b1c8a1SJohn Marino  *
57f5b1c8a1SJohn Marino  */
58f5b1c8a1SJohn Marino 
59f5b1c8a1SJohn Marino #include <stdio.h>
60f5b1c8a1SJohn Marino #include <string.h>
61f5b1c8a1SJohn Marino 
62f5b1c8a1SJohn Marino #include "apps.h"
63f5b1c8a1SJohn Marino 
64f5b1c8a1SJohn Marino #include <openssl/err.h>
65f5b1c8a1SJohn Marino #include <openssl/evp.h>
66f5b1c8a1SJohn Marino #include <openssl/pem.h>
67f5b1c8a1SJohn Marino 
6872c33676SMaxim Ag static struct {
69*de0e0e4dSAntonio Huete Jimenez 	int check;
7072c33676SMaxim Ag 	const EVP_CIPHER *cipher;
7172c33676SMaxim Ag 	char *infile;
7272c33676SMaxim Ag 	int informat;
7372c33676SMaxim Ag 	int noout;
7472c33676SMaxim Ag 	char *outfile;
7572c33676SMaxim Ag 	int outformat;
7672c33676SMaxim Ag 	char *passargin;
7772c33676SMaxim Ag 	char *passargout;
78*de0e0e4dSAntonio Huete Jimenez 	int pubcheck;
7972c33676SMaxim Ag 	int pubin;
8072c33676SMaxim Ag 	int pubout;
8172c33676SMaxim Ag 	int pubtext;
8272c33676SMaxim Ag 	int text;
8372c33676SMaxim Ag } pkey_config;
8472c33676SMaxim Ag 
8572c33676SMaxim Ag static int
pkey_opt_cipher(int argc,char ** argv,int * argsused)8672c33676SMaxim Ag pkey_opt_cipher(int argc, char **argv, int *argsused)
8772c33676SMaxim Ag {
8872c33676SMaxim Ag 	char *name = argv[0];
8972c33676SMaxim Ag 
9072c33676SMaxim Ag 	if (*name++ != '-')
9172c33676SMaxim Ag 		return (1);
9272c33676SMaxim Ag 
9372c33676SMaxim Ag 	if ((pkey_config.cipher = EVP_get_cipherbyname(name)) == NULL) {
9472c33676SMaxim Ag 		BIO_printf(bio_err, "Unknown cipher %s\n", name);
9572c33676SMaxim Ag 		return (1);
9672c33676SMaxim Ag 	}
9772c33676SMaxim Ag 
9872c33676SMaxim Ag 	*argsused = 1;
9972c33676SMaxim Ag 	return (0);
10072c33676SMaxim Ag }
10172c33676SMaxim Ag 
102cca6fc52SDaniel Fojt static const struct option pkey_options[] = {
10372c33676SMaxim Ag 	{
104*de0e0e4dSAntonio Huete Jimenez 		.name = "check",
105*de0e0e4dSAntonio Huete Jimenez 		.desc = "Check validity of key",
106*de0e0e4dSAntonio Huete Jimenez 		.type = OPTION_FLAG,
107*de0e0e4dSAntonio Huete Jimenez 		.opt.flag = &pkey_config.check,
108*de0e0e4dSAntonio Huete Jimenez 	},
109*de0e0e4dSAntonio Huete Jimenez 	{
11072c33676SMaxim Ag 		.name = "in",
11172c33676SMaxim Ag 		.argname = "file",
11272c33676SMaxim Ag 		.desc = "Input file (default stdin)",
11372c33676SMaxim Ag 		.type = OPTION_ARG,
11472c33676SMaxim Ag 		.opt.arg = &pkey_config.infile,
11572c33676SMaxim Ag 	},
11672c33676SMaxim Ag 	{
11772c33676SMaxim Ag 		.name = "inform",
11872c33676SMaxim Ag 		.argname = "format",
11972c33676SMaxim Ag 		.desc = "Input format (DER or PEM (default))",
12072c33676SMaxim Ag 		.type = OPTION_ARG_FORMAT,
12172c33676SMaxim Ag 		.opt.value = &pkey_config.informat,
12272c33676SMaxim Ag 	},
12372c33676SMaxim Ag 	{
12472c33676SMaxim Ag 		.name = "noout",
12572c33676SMaxim Ag 		.desc = "Do not print encoded version of the key",
12672c33676SMaxim Ag 		.type = OPTION_FLAG,
12772c33676SMaxim Ag 		.opt.flag = &pkey_config.noout,
12872c33676SMaxim Ag 	},
12972c33676SMaxim Ag 	{
13072c33676SMaxim Ag 		.name = "out",
13172c33676SMaxim Ag 		.argname = "file",
13272c33676SMaxim Ag 		.desc = "Output file (default stdout)",
13372c33676SMaxim Ag 		.type = OPTION_ARG,
13472c33676SMaxim Ag 		.opt.arg = &pkey_config.outfile,
13572c33676SMaxim Ag 	},
13672c33676SMaxim Ag 	{
13772c33676SMaxim Ag 		.name = "outform",
13872c33676SMaxim Ag 		.argname = "format",
13972c33676SMaxim Ag 		.desc = "Output format (DER or PEM (default))",
14072c33676SMaxim Ag 		.type = OPTION_ARG_FORMAT,
14172c33676SMaxim Ag 		.opt.value = &pkey_config.outformat,
14272c33676SMaxim Ag 	},
14372c33676SMaxim Ag 	{
14472c33676SMaxim Ag 		.name = "passin",
14572c33676SMaxim Ag 		.argname = "src",
14672c33676SMaxim Ag 		.desc = "Input file passphrase source",
14772c33676SMaxim Ag 		.type = OPTION_ARG,
14872c33676SMaxim Ag 		.opt.arg = &pkey_config.passargin,
14972c33676SMaxim Ag 	},
15072c33676SMaxim Ag 	{
15172c33676SMaxim Ag 		.name = "passout",
15272c33676SMaxim Ag 		.argname = "src",
15372c33676SMaxim Ag 		.desc = "Output file passphrase source",
15472c33676SMaxim Ag 		.type = OPTION_ARG,
15572c33676SMaxim Ag 		.opt.arg = &pkey_config.passargout,
15672c33676SMaxim Ag 	},
15772c33676SMaxim Ag 	{
158*de0e0e4dSAntonio Huete Jimenez 		.name = "pubcheck",
159*de0e0e4dSAntonio Huete Jimenez 		.desc = "Check validity of public key",
160*de0e0e4dSAntonio Huete Jimenez 		.type = OPTION_FLAG,
161*de0e0e4dSAntonio Huete Jimenez 		.opt.flag = &pkey_config.pubcheck,
162*de0e0e4dSAntonio Huete Jimenez 	},
163*de0e0e4dSAntonio Huete Jimenez 	{
16472c33676SMaxim Ag 		.name = "pubin",
16572c33676SMaxim Ag 		.desc = "Expect a public key (default private key)",
16672c33676SMaxim Ag 		.type = OPTION_VALUE,
16772c33676SMaxim Ag 		.value = 1,
16872c33676SMaxim Ag 		.opt.value = &pkey_config.pubin,
16972c33676SMaxim Ag 	},
17072c33676SMaxim Ag 	{
17172c33676SMaxim Ag 		.name = "pubout",
17272c33676SMaxim Ag 		.desc = "Output a public key (default private key)",
17372c33676SMaxim Ag 		.type = OPTION_VALUE,
17472c33676SMaxim Ag 		.value = 1,
17572c33676SMaxim Ag 		.opt.value = &pkey_config.pubout,
17672c33676SMaxim Ag 	},
17772c33676SMaxim Ag 	{
17872c33676SMaxim Ag 		.name = "text",
17972c33676SMaxim Ag 		.desc = "Print the public/private key in plain text",
18072c33676SMaxim Ag 		.type = OPTION_FLAG,
18172c33676SMaxim Ag 		.opt.flag = &pkey_config.text,
18272c33676SMaxim Ag 	},
18372c33676SMaxim Ag 	{
18472c33676SMaxim Ag 		.name = "text_pub",
18572c33676SMaxim Ag 		.desc = "Print out only public key in plain text",
18672c33676SMaxim Ag 		.type = OPTION_FLAG,
18772c33676SMaxim Ag 		.opt.flag = &pkey_config.pubtext,
18872c33676SMaxim Ag 	},
18972c33676SMaxim Ag 	{
19072c33676SMaxim Ag 		.name = NULL,
19172c33676SMaxim Ag 		.type = OPTION_ARGV_FUNC,
19272c33676SMaxim Ag 		.opt.argvfunc = pkey_opt_cipher,
19372c33676SMaxim Ag 	},
19472c33676SMaxim Ag 	{ NULL }
19572c33676SMaxim Ag };
19672c33676SMaxim Ag 
19772c33676SMaxim Ag static void
pkey_usage()19872c33676SMaxim Ag pkey_usage()
19972c33676SMaxim Ag {
20072c33676SMaxim Ag 	int n = 0;
20172c33676SMaxim Ag 
20272c33676SMaxim Ag 	fprintf(stderr,
203*de0e0e4dSAntonio Huete Jimenez 	    "usage: pkey [-check] [-ciphername] [-in file] [-inform fmt] "
204*de0e0e4dSAntonio Huete Jimenez 	    "[-noout] [-out file]\n"
205*de0e0e4dSAntonio Huete Jimenez 	    "    [-outform fmt] [-passin src] [-passout src] [-pubcheck] "
206*de0e0e4dSAntonio Huete Jimenez 	    "[-pubin] [-pubout]\n"
207*de0e0e4dSAntonio Huete Jimenez 	    "    [-text] [-text_pub]\n\n");
20872c33676SMaxim Ag 	options_usage(pkey_options);
20972c33676SMaxim Ag 	fprintf(stderr, "\n");
21072c33676SMaxim Ag 
21172c33676SMaxim Ag 	fprintf(stderr, "Valid ciphername values:\n\n");
21272c33676SMaxim Ag 	OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_cipher, &n);
21372c33676SMaxim Ag 	fprintf(stderr, "\n");
21472c33676SMaxim Ag }
21572c33676SMaxim Ag 
216f5b1c8a1SJohn Marino int
pkey_main(int argc,char ** argv)217f5b1c8a1SJohn Marino pkey_main(int argc, char **argv)
218f5b1c8a1SJohn Marino {
219f5b1c8a1SJohn Marino 	BIO *in = NULL, *out = NULL;
220f5b1c8a1SJohn Marino 	EVP_PKEY *pkey = NULL;
221f5b1c8a1SJohn Marino 	char *passin = NULL, *passout = NULL;
222f5b1c8a1SJohn Marino 	int ret = 1;
223f5b1c8a1SJohn Marino 
224f5b1c8a1SJohn Marino 	if (single_execution) {
22572c33676SMaxim Ag 		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
226f5b1c8a1SJohn Marino 			perror("pledge");
227f5b1c8a1SJohn Marino 			exit(1);
228f5b1c8a1SJohn Marino 		}
229f5b1c8a1SJohn Marino 	}
230f5b1c8a1SJohn Marino 
23172c33676SMaxim Ag 	memset(&pkey_config, 0, sizeof(pkey_config));
23272c33676SMaxim Ag 	pkey_config.informat = FORMAT_PEM;
23372c33676SMaxim Ag 	pkey_config.outformat = FORMAT_PEM;
234f5b1c8a1SJohn Marino 
23572c33676SMaxim Ag 	if (options_parse(argc, argv, pkey_options, NULL, NULL) != 0) {
23672c33676SMaxim Ag 		pkey_usage();
23772c33676SMaxim Ag 		goto end;
238f5b1c8a1SJohn Marino 	}
239f5b1c8a1SJohn Marino 
24072c33676SMaxim Ag 	if (pkey_config.pubtext)
24172c33676SMaxim Ag 		pkey_config.text = 1;
24272c33676SMaxim Ag 	if (pkey_config.pubin)
24372c33676SMaxim Ag 		pkey_config.pubout = pkey_config.pubtext = 1;
244f5b1c8a1SJohn Marino 
24572c33676SMaxim Ag 	if (!app_passwd(bio_err, pkey_config.passargin, pkey_config.passargout,
24672c33676SMaxim Ag 	    &passin, &passout)) {
247f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error getting passwords\n");
248f5b1c8a1SJohn Marino 		goto end;
249f5b1c8a1SJohn Marino 	}
25072c33676SMaxim Ag 	if (pkey_config.outfile) {
25172c33676SMaxim Ag 		if (!(out = BIO_new_file(pkey_config.outfile, "wb"))) {
252f5b1c8a1SJohn Marino 			BIO_printf(bio_err,
25372c33676SMaxim Ag 			    "Can't open output file %s\n", pkey_config.outfile);
254f5b1c8a1SJohn Marino 			goto end;
255f5b1c8a1SJohn Marino 		}
256f5b1c8a1SJohn Marino 	} else {
257f5b1c8a1SJohn Marino 		out = BIO_new_fp(stdout, BIO_NOCLOSE);
258f5b1c8a1SJohn Marino 	}
259f5b1c8a1SJohn Marino 
26072c33676SMaxim Ag 	if (pkey_config.pubin)
26172c33676SMaxim Ag 		pkey = load_pubkey(bio_err, pkey_config.infile,
26272c33676SMaxim Ag 		    pkey_config.informat, 1, passin, "Public Key");
263f5b1c8a1SJohn Marino 	else
26472c33676SMaxim Ag 		pkey = load_key(bio_err, pkey_config.infile,
26572c33676SMaxim Ag 		    pkey_config.informat, 1, passin, "key");
266f5b1c8a1SJohn Marino 	if (!pkey)
267f5b1c8a1SJohn Marino 		goto end;
268f5b1c8a1SJohn Marino 
269*de0e0e4dSAntonio Huete Jimenez 	if (pkey_config.check) {
270*de0e0e4dSAntonio Huete Jimenez 		if (!pkey_check(out, pkey, EVP_PKEY_check, "Key pair"))
271*de0e0e4dSAntonio Huete Jimenez 			goto end;
272*de0e0e4dSAntonio Huete Jimenez 	} else if (pkey_config.pubcheck) {
273*de0e0e4dSAntonio Huete Jimenez 		if (!pkey_check(out, pkey, EVP_PKEY_public_check, "Public key"))
274*de0e0e4dSAntonio Huete Jimenez 			goto end;
275*de0e0e4dSAntonio Huete Jimenez 	}
276*de0e0e4dSAntonio Huete Jimenez 
27772c33676SMaxim Ag 	if (!pkey_config.noout) {
27872c33676SMaxim Ag 		if (pkey_config.outformat == FORMAT_PEM) {
27972c33676SMaxim Ag 			if (pkey_config.pubout)
280f5b1c8a1SJohn Marino 				PEM_write_bio_PUBKEY(out, pkey);
281f5b1c8a1SJohn Marino 			else
28272c33676SMaxim Ag 				PEM_write_bio_PrivateKey(out, pkey,
28372c33676SMaxim Ag 				    pkey_config.cipher, NULL, 0, NULL, passout);
28472c33676SMaxim Ag 		} else if (pkey_config.outformat == FORMAT_ASN1) {
28572c33676SMaxim Ag 			if (pkey_config.pubout)
286f5b1c8a1SJohn Marino 				i2d_PUBKEY_bio(out, pkey);
287f5b1c8a1SJohn Marino 			else
288f5b1c8a1SJohn Marino 				i2d_PrivateKey_bio(out, pkey);
289f5b1c8a1SJohn Marino 		} else {
290f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Bad format specified for key\n");
291f5b1c8a1SJohn Marino 			goto end;
292f5b1c8a1SJohn Marino 		}
293f5b1c8a1SJohn Marino 
294f5b1c8a1SJohn Marino 	}
29572c33676SMaxim Ag 	if (pkey_config.text) {
29672c33676SMaxim Ag 		if (pkey_config.pubtext)
297f5b1c8a1SJohn Marino 			EVP_PKEY_print_public(out, pkey, 0, NULL);
298f5b1c8a1SJohn Marino 		else
299f5b1c8a1SJohn Marino 			EVP_PKEY_print_private(out, pkey, 0, NULL);
300f5b1c8a1SJohn Marino 	}
301f5b1c8a1SJohn Marino 	ret = 0;
302f5b1c8a1SJohn Marino 
303f5b1c8a1SJohn Marino  end:
304f5b1c8a1SJohn Marino 	EVP_PKEY_free(pkey);
305f5b1c8a1SJohn Marino 	BIO_free_all(out);
306f5b1c8a1SJohn Marino 	BIO_free(in);
307f5b1c8a1SJohn Marino 	free(passin);
308f5b1c8a1SJohn Marino 	free(passout);
309f5b1c8a1SJohn Marino 
310f5b1c8a1SJohn Marino 	return ret;
311f5b1c8a1SJohn Marino }
312