1 /* $OpenBSD: pkey.c,v 1.17 2022/01/14 10:17:30 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 int check;
70 const EVP_CIPHER *cipher;
71 char *infile;
72 int informat;
73 int noout;
74 char *outfile;
75 int outformat;
76 char *passargin;
77 char *passargout;
78 int pubcheck;
79 int pubin;
80 int pubout;
81 int pubtext;
82 int text;
83 } pkey_config;
84
85 static int
pkey_opt_cipher(int argc,char ** argv,int * argsused)86 pkey_opt_cipher(int argc, char **argv, int *argsused)
87 {
88 char *name = argv[0];
89
90 if (*name++ != '-')
91 return (1);
92
93 if ((pkey_config.cipher = EVP_get_cipherbyname(name)) == NULL) {
94 BIO_printf(bio_err, "Unknown cipher %s\n", name);
95 return (1);
96 }
97
98 *argsused = 1;
99 return (0);
100 }
101
102 static const struct option pkey_options[] = {
103 {
104 .name = "check",
105 .desc = "Check validity of key",
106 .type = OPTION_FLAG,
107 .opt.flag = &pkey_config.check,
108 },
109 {
110 .name = "in",
111 .argname = "file",
112 .desc = "Input file (default stdin)",
113 .type = OPTION_ARG,
114 .opt.arg = &pkey_config.infile,
115 },
116 {
117 .name = "inform",
118 .argname = "format",
119 .desc = "Input format (DER or PEM (default))",
120 .type = OPTION_ARG_FORMAT,
121 .opt.value = &pkey_config.informat,
122 },
123 {
124 .name = "noout",
125 .desc = "Do not print encoded version of the key",
126 .type = OPTION_FLAG,
127 .opt.flag = &pkey_config.noout,
128 },
129 {
130 .name = "out",
131 .argname = "file",
132 .desc = "Output file (default stdout)",
133 .type = OPTION_ARG,
134 .opt.arg = &pkey_config.outfile,
135 },
136 {
137 .name = "outform",
138 .argname = "format",
139 .desc = "Output format (DER or PEM (default))",
140 .type = OPTION_ARG_FORMAT,
141 .opt.value = &pkey_config.outformat,
142 },
143 {
144 .name = "passin",
145 .argname = "src",
146 .desc = "Input file passphrase source",
147 .type = OPTION_ARG,
148 .opt.arg = &pkey_config.passargin,
149 },
150 {
151 .name = "passout",
152 .argname = "src",
153 .desc = "Output file passphrase source",
154 .type = OPTION_ARG,
155 .opt.arg = &pkey_config.passargout,
156 },
157 {
158 .name = "pubcheck",
159 .desc = "Check validity of public key",
160 .type = OPTION_FLAG,
161 .opt.flag = &pkey_config.pubcheck,
162 },
163 {
164 .name = "pubin",
165 .desc = "Expect a public key (default private key)",
166 .type = OPTION_VALUE,
167 .value = 1,
168 .opt.value = &pkey_config.pubin,
169 },
170 {
171 .name = "pubout",
172 .desc = "Output a public key (default private key)",
173 .type = OPTION_VALUE,
174 .value = 1,
175 .opt.value = &pkey_config.pubout,
176 },
177 {
178 .name = "text",
179 .desc = "Print the public/private key in plain text",
180 .type = OPTION_FLAG,
181 .opt.flag = &pkey_config.text,
182 },
183 {
184 .name = "text_pub",
185 .desc = "Print out only public key in plain text",
186 .type = OPTION_FLAG,
187 .opt.flag = &pkey_config.pubtext,
188 },
189 {
190 .name = NULL,
191 .type = OPTION_ARGV_FUNC,
192 .opt.argvfunc = pkey_opt_cipher,
193 },
194 { NULL }
195 };
196
197 static void
pkey_usage()198 pkey_usage()
199 {
200 int n = 0;
201
202 fprintf(stderr,
203 "usage: pkey [-check] [-ciphername] [-in file] [-inform fmt] "
204 "[-noout] [-out file]\n"
205 " [-outform fmt] [-passin src] [-passout src] [-pubcheck] "
206 "[-pubin] [-pubout]\n"
207 " [-text] [-text_pub]\n\n");
208 options_usage(pkey_options);
209 fprintf(stderr, "\n");
210
211 fprintf(stderr, "Valid ciphername values:\n\n");
212 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_cipher, &n);
213 fprintf(stderr, "\n");
214 }
215
216 int
pkey_main(int argc,char ** argv)217 pkey_main(int argc, char **argv)
218 {
219 BIO *in = NULL, *out = NULL;
220 EVP_PKEY *pkey = NULL;
221 char *passin = NULL, *passout = NULL;
222 int ret = 1;
223
224 if (single_execution) {
225 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
226 perror("pledge");
227 exit(1);
228 }
229 }
230
231 memset(&pkey_config, 0, sizeof(pkey_config));
232 pkey_config.informat = FORMAT_PEM;
233 pkey_config.outformat = FORMAT_PEM;
234
235 if (options_parse(argc, argv, pkey_options, NULL, NULL) != 0) {
236 pkey_usage();
237 goto end;
238 }
239
240 if (pkey_config.pubtext)
241 pkey_config.text = 1;
242 if (pkey_config.pubin)
243 pkey_config.pubout = pkey_config.pubtext = 1;
244
245 if (!app_passwd(bio_err, pkey_config.passargin, pkey_config.passargout,
246 &passin, &passout)) {
247 BIO_printf(bio_err, "Error getting passwords\n");
248 goto end;
249 }
250 if (pkey_config.outfile) {
251 if (!(out = BIO_new_file(pkey_config.outfile, "wb"))) {
252 BIO_printf(bio_err,
253 "Can't open output file %s\n", pkey_config.outfile);
254 goto end;
255 }
256 } else {
257 out = BIO_new_fp(stdout, BIO_NOCLOSE);
258 }
259
260 if (pkey_config.pubin)
261 pkey = load_pubkey(bio_err, pkey_config.infile,
262 pkey_config.informat, 1, passin, "Public Key");
263 else
264 pkey = load_key(bio_err, pkey_config.infile,
265 pkey_config.informat, 1, passin, "key");
266 if (!pkey)
267 goto end;
268
269 if (pkey_config.check) {
270 if (!pkey_check(out, pkey, EVP_PKEY_check, "Key pair"))
271 goto end;
272 } else if (pkey_config.pubcheck) {
273 if (!pkey_check(out, pkey, EVP_PKEY_public_check, "Public key"))
274 goto end;
275 }
276
277 if (!pkey_config.noout) {
278 if (pkey_config.outformat == FORMAT_PEM) {
279 if (pkey_config.pubout)
280 PEM_write_bio_PUBKEY(out, pkey);
281 else
282 PEM_write_bio_PrivateKey(out, pkey,
283 pkey_config.cipher, NULL, 0, NULL, passout);
284 } else if (pkey_config.outformat == FORMAT_ASN1) {
285 if (pkey_config.pubout)
286 i2d_PUBKEY_bio(out, pkey);
287 else
288 i2d_PrivateKey_bio(out, pkey);
289 } else {
290 BIO_printf(bio_err, "Bad format specified for key\n");
291 goto end;
292 }
293
294 }
295 if (pkey_config.text) {
296 if (pkey_config.pubtext)
297 EVP_PKEY_print_public(out, pkey, 0, NULL);
298 else
299 EVP_PKEY_print_private(out, pkey, 0, NULL);
300 }
301 ret = 0;
302
303 end:
304 EVP_PKEY_free(pkey);
305 BIO_free_all(out);
306 BIO_free(in);
307 free(passin);
308 free(passout);
309
310 return ret;
311 }
312