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