xref: /openbsd-src/usr.bin/openssl/pkey.c (revision 646e9a2ff357c2d5ef38314b399014ad7522b2ae)
1*646e9a2fStb /* $OpenBSD: pkey.c,v 1.21 2024/08/29 17:01:02 tb Exp $ */
2dab3f910Sjsing /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3dab3f910Sjsing  * project 2006
4dab3f910Sjsing  */
5dab3f910Sjsing /* ====================================================================
6dab3f910Sjsing  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7dab3f910Sjsing  *
8dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
9dab3f910Sjsing  * modification, are permitted provided that the following conditions
10dab3f910Sjsing  * are met:
11dab3f910Sjsing  *
12dab3f910Sjsing  * 1. Redistributions of source code must retain the above copyright
13dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
14dab3f910Sjsing  *
15dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
16dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in
17dab3f910Sjsing  *    the documentation and/or other materials provided with the
18dab3f910Sjsing  *    distribution.
19dab3f910Sjsing  *
20dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this
21dab3f910Sjsing  *    software must display the following acknowledgment:
22dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
23dab3f910Sjsing  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24dab3f910Sjsing  *
25dab3f910Sjsing  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26dab3f910Sjsing  *    endorse or promote products derived from this software without
27dab3f910Sjsing  *    prior written permission. For written permission, please contact
28dab3f910Sjsing  *    licensing@OpenSSL.org.
29dab3f910Sjsing  *
30dab3f910Sjsing  * 5. Products derived from this software may not be called "OpenSSL"
31dab3f910Sjsing  *    nor may "OpenSSL" appear in their names without prior written
32dab3f910Sjsing  *    permission of the OpenSSL Project.
33dab3f910Sjsing  *
34dab3f910Sjsing  * 6. Redistributions of any form whatsoever must retain the following
35dab3f910Sjsing  *    acknowledgment:
36dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
37dab3f910Sjsing  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38dab3f910Sjsing  *
39dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40dab3f910Sjsing  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42dab3f910Sjsing  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43dab3f910Sjsing  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44dab3f910Sjsing  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45dab3f910Sjsing  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46dab3f910Sjsing  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48dab3f910Sjsing  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49dab3f910Sjsing  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50dab3f910Sjsing  * OF THE POSSIBILITY OF SUCH DAMAGE.
51dab3f910Sjsing  * ====================================================================
52dab3f910Sjsing  *
53dab3f910Sjsing  * This product includes cryptographic software written by Eric Young
54dab3f910Sjsing  * (eay@cryptsoft.com).  This product includes software written by Tim
55dab3f910Sjsing  * Hudson (tjh@cryptsoft.com).
56dab3f910Sjsing  *
57dab3f910Sjsing  */
58dab3f910Sjsing 
59dab3f910Sjsing #include <stdio.h>
60dab3f910Sjsing #include <string.h>
61dab3f910Sjsing 
62dab3f910Sjsing #include "apps.h"
63dab3f910Sjsing 
64dab3f910Sjsing #include <openssl/err.h>
65dab3f910Sjsing #include <openssl/evp.h>
66dab3f910Sjsing #include <openssl/pem.h>
67dab3f910Sjsing 
68fe082ddbSinoguchi static struct {
69fe082ddbSinoguchi 	const EVP_CIPHER *cipher;
70fe082ddbSinoguchi 	char *infile;
71fe082ddbSinoguchi 	int informat;
72fe082ddbSinoguchi 	int noout;
73fe082ddbSinoguchi 	char *outfile;
74fe082ddbSinoguchi 	int outformat;
75fe082ddbSinoguchi 	char *passargin;
76fe082ddbSinoguchi 	char *passargout;
77fe082ddbSinoguchi 	int pubin;
78fe082ddbSinoguchi 	int pubout;
79fe082ddbSinoguchi 	int pubtext;
80fe082ddbSinoguchi 	int text;
81e7718adaStb } cfg;
82fe082ddbSinoguchi 
83fe082ddbSinoguchi static int
84fe082ddbSinoguchi pkey_opt_cipher(int argc, char **argv, int *argsused)
85fe082ddbSinoguchi {
86fe082ddbSinoguchi 	char *name = argv[0];
87fe082ddbSinoguchi 
88fe082ddbSinoguchi 	if (*name++ != '-')
89fe082ddbSinoguchi 		return (1);
90fe082ddbSinoguchi 
91e7718adaStb 	if ((cfg.cipher = EVP_get_cipherbyname(name)) == NULL) {
92fe082ddbSinoguchi 		BIO_printf(bio_err, "Unknown cipher %s\n", name);
93fe082ddbSinoguchi 		return (1);
94fe082ddbSinoguchi 	}
95fe082ddbSinoguchi 
96fe082ddbSinoguchi 	*argsused = 1;
97fe082ddbSinoguchi 	return (0);
98fe082ddbSinoguchi }
99fe082ddbSinoguchi 
100ea149709Sguenther static const struct option pkey_options[] = {
101fe082ddbSinoguchi 	{
102fe082ddbSinoguchi 		.name = "in",
103fe082ddbSinoguchi 		.argname = "file",
104fe082ddbSinoguchi 		.desc = "Input file (default stdin)",
105fe082ddbSinoguchi 		.type = OPTION_ARG,
106e7718adaStb 		.opt.arg = &cfg.infile,
107fe082ddbSinoguchi 	},
108fe082ddbSinoguchi 	{
109fe082ddbSinoguchi 		.name = "inform",
110fe082ddbSinoguchi 		.argname = "format",
111fe082ddbSinoguchi 		.desc = "Input format (DER or PEM (default))",
112fe082ddbSinoguchi 		.type = OPTION_ARG_FORMAT,
113e7718adaStb 		.opt.value = &cfg.informat,
114fe082ddbSinoguchi 	},
115fe082ddbSinoguchi 	{
116fe082ddbSinoguchi 		.name = "noout",
117fe082ddbSinoguchi 		.desc = "Do not print encoded version of the key",
118fe082ddbSinoguchi 		.type = OPTION_FLAG,
119e7718adaStb 		.opt.flag = &cfg.noout,
120fe082ddbSinoguchi 	},
121fe082ddbSinoguchi 	{
122fe082ddbSinoguchi 		.name = "out",
123fe082ddbSinoguchi 		.argname = "file",
124fe082ddbSinoguchi 		.desc = "Output file (default stdout)",
125fe082ddbSinoguchi 		.type = OPTION_ARG,
126e7718adaStb 		.opt.arg = &cfg.outfile,
127fe082ddbSinoguchi 	},
128fe082ddbSinoguchi 	{
129fe082ddbSinoguchi 		.name = "outform",
130fe082ddbSinoguchi 		.argname = "format",
131fe082ddbSinoguchi 		.desc = "Output format (DER or PEM (default))",
132fe082ddbSinoguchi 		.type = OPTION_ARG_FORMAT,
133e7718adaStb 		.opt.value = &cfg.outformat,
134fe082ddbSinoguchi 	},
135fe082ddbSinoguchi 	{
136fe082ddbSinoguchi 		.name = "passin",
137fe082ddbSinoguchi 		.argname = "src",
138fe082ddbSinoguchi 		.desc = "Input file passphrase source",
139fe082ddbSinoguchi 		.type = OPTION_ARG,
140e7718adaStb 		.opt.arg = &cfg.passargin,
141fe082ddbSinoguchi 	},
142fe082ddbSinoguchi 	{
143fe082ddbSinoguchi 		.name = "passout",
144fe082ddbSinoguchi 		.argname = "src",
145fe082ddbSinoguchi 		.desc = "Output file passphrase source",
146fe082ddbSinoguchi 		.type = OPTION_ARG,
147e7718adaStb 		.opt.arg = &cfg.passargout,
148fe082ddbSinoguchi 	},
149fe082ddbSinoguchi 	{
150fe082ddbSinoguchi 		.name = "pubin",
151fe082ddbSinoguchi 		.desc = "Expect a public key (default private key)",
152fe082ddbSinoguchi 		.type = OPTION_VALUE,
153fe082ddbSinoguchi 		.value = 1,
154e7718adaStb 		.opt.value = &cfg.pubin,
155fe082ddbSinoguchi 	},
156fe082ddbSinoguchi 	{
157fe082ddbSinoguchi 		.name = "pubout",
158fe082ddbSinoguchi 		.desc = "Output a public key (default private key)",
159fe082ddbSinoguchi 		.type = OPTION_VALUE,
160fe082ddbSinoguchi 		.value = 1,
161e7718adaStb 		.opt.value = &cfg.pubout,
162fe082ddbSinoguchi 	},
163fe082ddbSinoguchi 	{
164fe082ddbSinoguchi 		.name = "text",
165fe082ddbSinoguchi 		.desc = "Print the public/private key in plain text",
166fe082ddbSinoguchi 		.type = OPTION_FLAG,
167e7718adaStb 		.opt.flag = &cfg.text,
168fe082ddbSinoguchi 	},
169fe082ddbSinoguchi 	{
170fe082ddbSinoguchi 		.name = "text_pub",
171fe082ddbSinoguchi 		.desc = "Print out only public key in plain text",
172fe082ddbSinoguchi 		.type = OPTION_FLAG,
173e7718adaStb 		.opt.flag = &cfg.pubtext,
174fe082ddbSinoguchi 	},
175fe082ddbSinoguchi 	{
176fe082ddbSinoguchi 		.name = NULL,
177fe082ddbSinoguchi 		.type = OPTION_ARGV_FUNC,
178fe082ddbSinoguchi 		.opt.argvfunc = pkey_opt_cipher,
179fe082ddbSinoguchi 	},
180fe082ddbSinoguchi 	{ NULL }
181fe082ddbSinoguchi };
182fe082ddbSinoguchi 
183fe082ddbSinoguchi static void
184440d1414Stb pkey_usage(void)
185fe082ddbSinoguchi {
1866685372aSinoguchi 	int n = 0;
1876685372aSinoguchi 
188fe082ddbSinoguchi 	fprintf(stderr,
189*646e9a2fStb 	    "usage: pkey [-ciphername] [-in file] [-inform fmt] "
190d40b1e08Stb 	    "[-noout] [-out file]\n"
191*646e9a2fStb 	    "    [-outform fmt] [-passin src] [-passout src] "
192d40b1e08Stb 	    "[-pubin] [-pubout]\n"
193d40b1e08Stb 	    "    [-text] [-text_pub]\n\n");
194fe082ddbSinoguchi 	options_usage(pkey_options);
195fe082ddbSinoguchi 	fprintf(stderr, "\n");
196fe082ddbSinoguchi 
197fe082ddbSinoguchi 	fprintf(stderr, "Valid ciphername values:\n\n");
1986685372aSinoguchi 	OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_cipher, &n);
199fe082ddbSinoguchi 	fprintf(stderr, "\n");
200fe082ddbSinoguchi }
201fe082ddbSinoguchi 
202dab3f910Sjsing int
203dab3f910Sjsing pkey_main(int argc, char **argv)
204dab3f910Sjsing {
205dab3f910Sjsing 	BIO *in = NULL, *out = NULL;
206dab3f910Sjsing 	EVP_PKEY *pkey = NULL;
207dab3f910Sjsing 	char *passin = NULL, *passout = NULL;
208dab3f910Sjsing 	int ret = 1;
209dab3f910Sjsing 
21051811eadSderaadt 	if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
2119bc487adSdoug 		perror("pledge");
212e370f0eeSdoug 		exit(1);
213e370f0eeSdoug 	}
2149bc487adSdoug 
215e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
216e7718adaStb 	cfg.informat = FORMAT_PEM;
217e7718adaStb 	cfg.outformat = FORMAT_PEM;
218dab3f910Sjsing 
219fe082ddbSinoguchi 	if (options_parse(argc, argv, pkey_options, NULL, NULL) != 0) {
220fe082ddbSinoguchi 		pkey_usage();
221fe082ddbSinoguchi 		goto end;
222dab3f910Sjsing 	}
223dab3f910Sjsing 
224e7718adaStb 	if (cfg.pubtext)
225e7718adaStb 		cfg.text = 1;
226e7718adaStb 	if (cfg.pubin)
227e7718adaStb 		cfg.pubout = cfg.pubtext = 1;
228dab3f910Sjsing 
229e7718adaStb 	if (!app_passwd(bio_err, cfg.passargin, cfg.passargout,
230fe082ddbSinoguchi 	    &passin, &passout)) {
231dab3f910Sjsing 		BIO_printf(bio_err, "Error getting passwords\n");
232dab3f910Sjsing 		goto end;
233dab3f910Sjsing 	}
234e7718adaStb 	if (cfg.outfile) {
235e7718adaStb 		if (!(out = BIO_new_file(cfg.outfile, "wb"))) {
236dab3f910Sjsing 			BIO_printf(bio_err,
237e7718adaStb 			    "Can't open output file %s\n", cfg.outfile);
238dab3f910Sjsing 			goto end;
239dab3f910Sjsing 		}
240dab3f910Sjsing 	} else {
241dab3f910Sjsing 		out = BIO_new_fp(stdout, BIO_NOCLOSE);
242dab3f910Sjsing 	}
243dab3f910Sjsing 
244e7718adaStb 	if (cfg.pubin)
245e7718adaStb 		pkey = load_pubkey(bio_err, cfg.infile,
246e7718adaStb 		    cfg.informat, 1, passin, "Public Key");
247dab3f910Sjsing 	else
248e7718adaStb 		pkey = load_key(bio_err, cfg.infile,
249e7718adaStb 		    cfg.informat, 1, passin, "key");
250dab3f910Sjsing 	if (!pkey)
251dab3f910Sjsing 		goto end;
252dab3f910Sjsing 
253e7718adaStb 	if (!cfg.noout) {
254e7718adaStb 		if (cfg.outformat == FORMAT_PEM) {
255e7718adaStb 			if (cfg.pubout)
256dab3f910Sjsing 				PEM_write_bio_PUBKEY(out, pkey);
257dab3f910Sjsing 			else
258fe082ddbSinoguchi 				PEM_write_bio_PrivateKey(out, pkey,
259e7718adaStb 				    cfg.cipher, NULL, 0, NULL, passout);
260e7718adaStb 		} else if (cfg.outformat == FORMAT_ASN1) {
261e7718adaStb 			if (cfg.pubout)
262dab3f910Sjsing 				i2d_PUBKEY_bio(out, pkey);
263dab3f910Sjsing 			else
264dab3f910Sjsing 				i2d_PrivateKey_bio(out, pkey);
265dab3f910Sjsing 		} else {
266dab3f910Sjsing 			BIO_printf(bio_err, "Bad format specified for key\n");
267dab3f910Sjsing 			goto end;
268dab3f910Sjsing 		}
269dab3f910Sjsing 
270dab3f910Sjsing 	}
271e7718adaStb 	if (cfg.text) {
272e7718adaStb 		if (cfg.pubtext)
273dab3f910Sjsing 			EVP_PKEY_print_public(out, pkey, 0, NULL);
274dab3f910Sjsing 		else
275dab3f910Sjsing 			EVP_PKEY_print_private(out, pkey, 0, NULL);
276dab3f910Sjsing 	}
277dab3f910Sjsing 	ret = 0;
278dab3f910Sjsing 
279dab3f910Sjsing  end:
280dab3f910Sjsing 	EVP_PKEY_free(pkey);
281dab3f910Sjsing 	BIO_free_all(out);
282dab3f910Sjsing 	BIO_free(in);
283dab3f910Sjsing 	free(passin);
284dab3f910Sjsing 	free(passout);
285dab3f910Sjsing 
286dab3f910Sjsing 	return ret;
287dab3f910Sjsing }
288