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