pkey.c revision 1.1.1.6 1 1.1.1.2 spz /*
2 1.1.1.6 christos * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved.
3 1.1 christos *
4 1.1.1.6 christos * Licensed under the Apache License 2.0 (the "License"). You may not use
5 1.1.1.4 christos * this file except in compliance with the License. You can obtain a copy
6 1.1.1.4 christos * in the file LICENSE in the source distribution or at
7 1.1.1.4 christos * https://www.openssl.org/source/license.html
8 1.1 christos */
9 1.1.1.4 christos
10 1.1 christos #include <stdio.h>
11 1.1 christos #include <string.h>
12 1.1 christos #include "apps.h"
13 1.1.1.5 christos #include "progs.h"
14 1.1.1.6 christos #include "ec_common.h"
15 1.1 christos #include <openssl/pem.h>
16 1.1 christos #include <openssl/err.h>
17 1.1 christos #include <openssl/evp.h>
18 1.1.1.6 christos #include <openssl/core_names.h>
19 1.1 christos
20 1.1.1.4 christos typedef enum OPTION_choice {
21 1.1.1.6 christos OPT_COMMON,
22 1.1.1.4 christos OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE,
23 1.1.1.4 christos OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB,
24 1.1.1.6 christos OPT_TEXT, OPT_NOOUT, OPT_CIPHER, OPT_TRADITIONAL, OPT_CHECK, OPT_PUB_CHECK,
25 1.1.1.6 christos OPT_EC_PARAM_ENC, OPT_EC_CONV_FORM,
26 1.1.1.6 christos OPT_PROV_ENUM
27 1.1.1.4 christos } OPTION_CHOICE;
28 1.1.1.4 christos
29 1.1.1.5 christos const OPTIONS pkey_options[] = {
30 1.1.1.6 christos OPT_SECTION("General"),
31 1.1.1.4 christos {"help", OPT_HELP, '-', "Display this summary"},
32 1.1.1.4 christos #ifndef OPENSSL_NO_ENGINE
33 1.1.1.4 christos {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
34 1.1.1.4 christos #endif
35 1.1.1.6 christos OPT_PROV_OPTIONS,
36 1.1.1.6 christos
37 1.1.1.5 christos {"check", OPT_CHECK, '-', "Check key consistency"},
38 1.1.1.5 christos {"pubcheck", OPT_PUB_CHECK, '-', "Check public key consistency"},
39 1.1.1.6 christos
40 1.1.1.6 christos OPT_SECTION("Input"),
41 1.1.1.6 christos {"in", OPT_IN, 's', "Input key"},
42 1.1.1.6 christos {"inform", OPT_INFORM, 'f',
43 1.1.1.6 christos "Key input format (ENGINE, other values ignored)"},
44 1.1.1.6 christos {"passin", OPT_PASSIN, 's', "Key input pass phrase source"},
45 1.1.1.6 christos {"pubin", OPT_PUBIN, '-',
46 1.1.1.6 christos "Read only public components from key input"},
47 1.1.1.6 christos
48 1.1.1.6 christos OPT_SECTION("Output"),
49 1.1.1.6 christos {"out", OPT_OUT, '>', "Output file for encoded and/or text output"},
50 1.1.1.6 christos {"outform", OPT_OUTFORM, 'F', "Output encoding format (DER or PEM)"},
51 1.1.1.6 christos {"", OPT_CIPHER, '-', "Any supported cipher to be used for encryption"},
52 1.1.1.6 christos {"passout", OPT_PASSOUT, 's', "Output PEM file pass phrase source"},
53 1.1.1.6 christos {"traditional", OPT_TRADITIONAL, '-',
54 1.1.1.6 christos "Use traditional format for private key PEM output"},
55 1.1.1.6 christos {"pubout", OPT_PUBOUT, '-', "Restrict encoded output to public components"},
56 1.1.1.6 christos {"noout", OPT_NOOUT, '-', "Do not output the key in encoded form"},
57 1.1.1.6 christos {"text", OPT_TEXT, '-', "Output key components in plaintext"},
58 1.1.1.6 christos {"text_pub", OPT_TEXT_PUB, '-',
59 1.1.1.6 christos "Output only public key components in text form"},
60 1.1.1.6 christos {"ec_conv_form", OPT_EC_CONV_FORM, 's',
61 1.1.1.6 christos "Specifies the EC point conversion form in the encoding"},
62 1.1.1.6 christos {"ec_param_enc", OPT_EC_PARAM_ENC, 's',
63 1.1.1.6 christos "Specifies the way the EC parameters are encoded"},
64 1.1.1.6 christos
65 1.1.1.4 christos {NULL}
66 1.1.1.4 christos };
67 1.1 christos
68 1.1.1.4 christos int pkey_main(int argc, char **argv)
69 1.1.1.2 spz {
70 1.1.1.6 christos BIO *out = NULL;
71 1.1.1.4 christos ENGINE *e = NULL;
72 1.1.1.2 spz EVP_PKEY *pkey = NULL;
73 1.1.1.6 christos EVP_PKEY_CTX *ctx = NULL;
74 1.1.1.6 christos EVP_CIPHER *cipher = NULL;
75 1.1.1.4 christos char *infile = NULL, *outfile = NULL, *passin = NULL, *passout = NULL;
76 1.1.1.6 christos char *passinarg = NULL, *passoutarg = NULL, *ciphername = NULL, *prog;
77 1.1.1.4 christos OPTION_CHOICE o;
78 1.1.1.6 christos int informat = FORMAT_UNDEF, outformat = FORMAT_PEM;
79 1.1.1.6 christos int pubin = 0, pubout = 0, text_pub = 0, text = 0, noout = 0, ret = 1;
80 1.1.1.5 christos int private = 0, traditional = 0, check = 0, pub_check = 0;
81 1.1.1.6 christos #ifndef OPENSSL_NO_EC
82 1.1.1.6 christos char *asn1_encoding = NULL;
83 1.1.1.6 christos char *point_format = NULL;
84 1.1.1.6 christos #endif
85 1.1.1.4 christos
86 1.1.1.4 christos prog = opt_init(argc, argv, pkey_options);
87 1.1.1.4 christos while ((o = opt_next()) != OPT_EOF) {
88 1.1.1.4 christos switch (o) {
89 1.1.1.4 christos case OPT_EOF:
90 1.1.1.4 christos case OPT_ERR:
91 1.1.1.4 christos opthelp:
92 1.1.1.4 christos BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
93 1.1.1.4 christos goto end;
94 1.1.1.4 christos case OPT_HELP:
95 1.1.1.4 christos opt_help(pkey_options);
96 1.1.1.4 christos ret = 0;
97 1.1.1.4 christos goto end;
98 1.1.1.4 christos case OPT_INFORM:
99 1.1.1.4 christos if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
100 1.1.1.4 christos goto opthelp;
101 1.1.1.4 christos break;
102 1.1.1.4 christos case OPT_OUTFORM:
103 1.1.1.4 christos if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
104 1.1.1.4 christos goto opthelp;
105 1.1.1.4 christos break;
106 1.1.1.4 christos case OPT_PASSIN:
107 1.1.1.4 christos passinarg = opt_arg();
108 1.1.1.4 christos break;
109 1.1.1.4 christos case OPT_PASSOUT:
110 1.1.1.4 christos passoutarg = opt_arg();
111 1.1.1.4 christos break;
112 1.1.1.4 christos case OPT_ENGINE:
113 1.1.1.4 christos e = setup_engine(opt_arg(), 0);
114 1.1.1.4 christos break;
115 1.1.1.4 christos case OPT_IN:
116 1.1.1.4 christos infile = opt_arg();
117 1.1.1.4 christos break;
118 1.1.1.4 christos case OPT_OUT:
119 1.1.1.4 christos outfile = opt_arg();
120 1.1.1.4 christos break;
121 1.1.1.4 christos case OPT_PUBIN:
122 1.1.1.6 christos pubin = pubout = 1;
123 1.1.1.4 christos break;
124 1.1.1.4 christos case OPT_PUBOUT:
125 1.1.1.2 spz pubout = 1;
126 1.1.1.4 christos break;
127 1.1.1.4 christos case OPT_TEXT_PUB:
128 1.1.1.6 christos text_pub = 1;
129 1.1.1.4 christos break;
130 1.1.1.4 christos case OPT_TEXT:
131 1.1.1.2 spz text = 1;
132 1.1.1.4 christos break;
133 1.1.1.4 christos case OPT_NOOUT:
134 1.1.1.2 spz noout = 1;
135 1.1.1.4 christos break;
136 1.1.1.4 christos case OPT_TRADITIONAL:
137 1.1.1.4 christos traditional = 1;
138 1.1.1.4 christos break;
139 1.1.1.5 christos case OPT_CHECK:
140 1.1.1.5 christos check = 1;
141 1.1.1.5 christos break;
142 1.1.1.5 christos case OPT_PUB_CHECK:
143 1.1.1.5 christos pub_check = 1;
144 1.1.1.5 christos break;
145 1.1.1.6 christos case OPT_CIPHER:
146 1.1.1.6 christos ciphername = opt_unknown();
147 1.1.1.6 christos break;
148 1.1.1.6 christos case OPT_EC_CONV_FORM:
149 1.1.1.6 christos #ifdef OPENSSL_NO_EC
150 1.1.1.6 christos goto opthelp;
151 1.1.1.6 christos #else
152 1.1.1.6 christos point_format = opt_arg();
153 1.1.1.6 christos if (!opt_string(point_format, point_format_options))
154 1.1.1.4 christos goto opthelp;
155 1.1.1.6 christos break;
156 1.1.1.6 christos #endif
157 1.1.1.6 christos case OPT_EC_PARAM_ENC:
158 1.1.1.6 christos #ifdef OPENSSL_NO_EC
159 1.1.1.6 christos goto opthelp;
160 1.1.1.6 christos #else
161 1.1.1.6 christos asn1_encoding = opt_arg();
162 1.1.1.6 christos if (!opt_string(asn1_encoding, asn1_encoding_options))
163 1.1.1.6 christos goto opthelp;
164 1.1.1.6 christos break;
165 1.1.1.6 christos #endif
166 1.1.1.6 christos case OPT_PROV_CASES:
167 1.1.1.6 christos if (!opt_provider(o))
168 1.1.1.6 christos goto end;
169 1.1.1.6 christos break;
170 1.1.1.4 christos }
171 1.1.1.4 christos }
172 1.1.1.6 christos
173 1.1.1.6 christos /* No extra arguments. */
174 1.1.1.4 christos argc = opt_num_rest();
175 1.1.1.4 christos if (argc != 0)
176 1.1.1.4 christos goto opthelp;
177 1.1.1.4 christos
178 1.1.1.6 christos if (text && text_pub)
179 1.1.1.6 christos BIO_printf(bio_err,
180 1.1.1.6 christos "Warning: The -text option is ignored with -text_pub\n");
181 1.1.1.6 christos if (traditional && (noout || outformat != FORMAT_PEM))
182 1.1.1.6 christos BIO_printf(bio_err,
183 1.1.1.6 christos "Warning: The -traditional is ignored since there is no PEM output\n");
184 1.1.1.6 christos
185 1.1.1.6 christos /* -pubout and -text is the same as -text_pub */
186 1.1.1.6 christos if (!text_pub && pubout && text) {
187 1.1.1.6 christos text = 0;
188 1.1.1.6 christos text_pub = 1;
189 1.1.1.6 christos }
190 1.1 christos
191 1.1.1.6 christos private = (!noout && !pubout) || (text && !text_pub);
192 1.1.1.6 christos
193 1.1.1.6 christos if (ciphername != NULL) {
194 1.1.1.6 christos if (!opt_cipher(ciphername, &cipher))
195 1.1.1.6 christos goto opthelp;
196 1.1.1.6 christos }
197 1.1.1.6 christos if (cipher == NULL) {
198 1.1.1.6 christos if (passoutarg != NULL)
199 1.1.1.6 christos BIO_printf(bio_err,
200 1.1.1.6 christos "Warning: The -passout option is ignored without a cipher option\n");
201 1.1.1.6 christos } else {
202 1.1.1.6 christos if (noout || outformat != FORMAT_PEM) {
203 1.1.1.6 christos BIO_printf(bio_err,
204 1.1.1.6 christos "Error: Cipher options are supported only for PEM output\n");
205 1.1.1.6 christos goto end;
206 1.1.1.6 christos }
207 1.1.1.6 christos }
208 1.1.1.4 christos if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
209 1.1.1.2 spz BIO_printf(bio_err, "Error getting passwords\n");
210 1.1.1.2 spz goto end;
211 1.1.1.2 spz }
212 1.1.1.2 spz
213 1.1.1.4 christos out = bio_open_owner(outfile, outformat, private);
214 1.1.1.4 christos if (out == NULL)
215 1.1.1.4 christos goto end;
216 1.1 christos
217 1.1.1.2 spz if (pubin)
218 1.1.1.4 christos pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key");
219 1.1.1.2 spz else
220 1.1.1.4 christos pkey = load_key(infile, informat, 1, passin, e, "key");
221 1.1.1.5 christos if (pkey == NULL)
222 1.1.1.2 spz goto end;
223 1.1.1.2 spz
224 1.1.1.6 christos #ifndef OPENSSL_NO_EC
225 1.1.1.6 christos if (asn1_encoding != NULL || point_format != NULL) {
226 1.1.1.6 christos OSSL_PARAM params[3], *p = params;
227 1.1.1.6 christos
228 1.1.1.6 christos if (!EVP_PKEY_is_a(pkey, "EC"))
229 1.1.1.6 christos goto end;
230 1.1.1.6 christos
231 1.1.1.6 christos if (asn1_encoding != NULL)
232 1.1.1.6 christos *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING,
233 1.1.1.6 christos asn1_encoding, 0);
234 1.1.1.6 christos if (point_format != NULL)
235 1.1.1.6 christos *p++ = OSSL_PARAM_construct_utf8_string(
236 1.1.1.6 christos OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
237 1.1.1.6 christos point_format, 0);
238 1.1.1.6 christos *p = OSSL_PARAM_construct_end();
239 1.1.1.6 christos if (EVP_PKEY_set_params(pkey, params) <= 0)
240 1.1.1.6 christos goto end;
241 1.1.1.6 christos }
242 1.1.1.6 christos #endif
243 1.1.1.6 christos
244 1.1.1.5 christos if (check || pub_check) {
245 1.1.1.5 christos int r;
246 1.1.1.5 christos
247 1.1.1.5 christos ctx = EVP_PKEY_CTX_new(pkey, e);
248 1.1.1.5 christos if (ctx == NULL) {
249 1.1.1.5 christos ERR_print_errors(bio_err);
250 1.1.1.5 christos goto end;
251 1.1.1.5 christos }
252 1.1.1.5 christos
253 1.1.1.6 christos if (check && !pubin)
254 1.1.1.5 christos r = EVP_PKEY_check(ctx);
255 1.1.1.5 christos else
256 1.1.1.5 christos r = EVP_PKEY_public_check(ctx);
257 1.1.1.5 christos
258 1.1.1.5 christos if (r == 1) {
259 1.1.1.5 christos BIO_printf(out, "Key is valid\n");
260 1.1.1.5 christos } else {
261 1.1.1.5 christos /*
262 1.1.1.5 christos * Note: at least for RSA keys if this function returns
263 1.1.1.5 christos * -1, there will be no error reasons.
264 1.1.1.5 christos */
265 1.1.1.6 christos BIO_printf(bio_err, "Key is invalid\n");
266 1.1.1.6 christos ERR_print_errors(bio_err);
267 1.1.1.6 christos goto end;
268 1.1.1.5 christos }
269 1.1.1.5 christos }
270 1.1.1.5 christos
271 1.1.1.2 spz if (!noout) {
272 1.1.1.2 spz if (outformat == FORMAT_PEM) {
273 1.1.1.5 christos if (pubout) {
274 1.1.1.5 christos if (!PEM_write_bio_PUBKEY(out, pkey))
275 1.1.1.5 christos goto end;
276 1.1.1.5 christos } else {
277 1.1.1.4 christos assert(private);
278 1.1.1.5 christos if (traditional) {
279 1.1.1.5 christos if (!PEM_write_bio_PrivateKey_traditional(out, pkey, cipher,
280 1.1.1.5 christos NULL, 0, NULL,
281 1.1.1.5 christos passout))
282 1.1.1.5 christos goto end;
283 1.1.1.5 christos } else {
284 1.1.1.5 christos if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
285 1.1.1.5 christos NULL, 0, NULL, passout))
286 1.1.1.5 christos goto end;
287 1.1.1.5 christos }
288 1.1.1.4 christos }
289 1.1.1.2 spz } else if (outformat == FORMAT_ASN1) {
290 1.1.1.6 christos if (text || text_pub) {
291 1.1.1.6 christos BIO_printf(bio_err,
292 1.1.1.6 christos "Error: Text output cannot be combined with DER output\n");
293 1.1.1.6 christos goto end;
294 1.1.1.6 christos }
295 1.1.1.5 christos if (pubout) {
296 1.1.1.5 christos if (!i2d_PUBKEY_bio(out, pkey))
297 1.1.1.5 christos goto end;
298 1.1.1.5 christos } else {
299 1.1.1.4 christos assert(private);
300 1.1.1.5 christos if (!i2d_PrivateKey_bio(out, pkey))
301 1.1.1.5 christos goto end;
302 1.1.1.4 christos }
303 1.1.1.2 spz } else {
304 1.1.1.2 spz BIO_printf(bio_err, "Bad format specified for key\n");
305 1.1.1.2 spz goto end;
306 1.1.1.2 spz }
307 1.1.1.2 spz }
308 1.1.1.2 spz
309 1.1.1.6 christos if (text_pub) {
310 1.1.1.6 christos if (EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0)
311 1.1.1.6 christos goto end;
312 1.1.1.6 christos } else if (text) {
313 1.1.1.6 christos assert(private);
314 1.1.1.6 christos if (EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)
315 1.1.1.6 christos goto end;
316 1.1.1.2 spz }
317 1.1.1.2 spz
318 1.1.1.2 spz ret = 0;
319 1.1.1.2 spz
320 1.1.1.2 spz end:
321 1.1.1.5 christos if (ret != 0)
322 1.1.1.5 christos ERR_print_errors(bio_err);
323 1.1.1.6 christos EVP_PKEY_CTX_free(ctx);
324 1.1.1.2 spz EVP_PKEY_free(pkey);
325 1.1.1.6 christos EVP_CIPHER_free(cipher);
326 1.1.1.3 spz release_engine(e);
327 1.1.1.2 spz BIO_free_all(out);
328 1.1.1.4 christos OPENSSL_free(passin);
329 1.1.1.4 christos OPENSSL_free(passout);
330 1.1 christos
331 1.1.1.2 spz return ret;
332 1.1.1.2 spz }
333