1 /*
2 * Copyright 2002-2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <string.h>
11 #include <openssl/opensslconf.h>
12 #include <openssl/evp.h>
13 #include <openssl/encoder.h>
14 #include <openssl/decoder.h>
15 #include <openssl/core_names.h>
16 #include <openssl/core_dispatch.h>
17 #include <openssl/params.h>
18 #include <openssl/err.h>
19
20 #include "apps.h"
21 #include "progs.h"
22 #include "ec_common.h"
23
24 typedef enum OPTION_choice {
25 OPT_COMMON,
26 OPT_INFORM,
27 OPT_OUTFORM,
28 OPT_ENGINE,
29 OPT_IN,
30 OPT_OUT,
31 OPT_NOOUT,
32 OPT_TEXT,
33 OPT_PARAM_OUT,
34 OPT_PUBIN,
35 OPT_PUBOUT,
36 OPT_PASSIN,
37 OPT_PASSOUT,
38 OPT_PARAM_ENC,
39 OPT_CONV_FORM,
40 OPT_CIPHER,
41 OPT_NO_PUBLIC,
42 OPT_CHECK,
43 OPT_PROV_ENUM
44 } OPTION_CHOICE;
45
46 const OPTIONS ec_options[] = {
47 OPT_SECTION("General"),
48 { "help", OPT_HELP, '-', "Display this summary" },
49 #ifndef OPENSSL_NO_ENGINE
50 { "engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device" },
51 #endif
52
53 OPT_SECTION("Input"),
54 { "in", OPT_IN, 's', "Input file" },
55 { "inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)" },
56 { "pubin", OPT_PUBIN, '-', "Expect a public key in input file" },
57 { "passin", OPT_PASSIN, 's', "Input file pass phrase source" },
58 { "check", OPT_CHECK, '-', "check key consistency" },
59 { "", OPT_CIPHER, '-', "Any supported cipher" },
60 { "param_enc", OPT_PARAM_ENC, 's',
61 "Specifies the way the ec parameters are encoded" },
62 { "conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form " },
63
64 OPT_SECTION("Output"),
65 { "out", OPT_OUT, '>', "Output file" },
66 { "outform", OPT_OUTFORM, 'F', "Output format - DER or PEM" },
67 { "noout", OPT_NOOUT, '-', "Don't print key out" },
68 { "text", OPT_TEXT, '-', "Print the key" },
69 { "param_out", OPT_PARAM_OUT, '-', "Print the elliptic curve parameters" },
70 { "pubout", OPT_PUBOUT, '-', "Output public key, not private" },
71 { "no_public", OPT_NO_PUBLIC, '-', "exclude public key from private key" },
72 { "passout", OPT_PASSOUT, 's', "Output file pass phrase source" },
73
74 OPT_PROV_OPTIONS,
75 { NULL }
76 };
77
ec_main(int argc,char ** argv)78 int ec_main(int argc, char **argv)
79 {
80 OSSL_ENCODER_CTX *ectx = NULL;
81 OSSL_DECODER_CTX *dctx = NULL;
82 EVP_PKEY_CTX *pctx = NULL;
83 EVP_PKEY *eckey = NULL;
84 BIO *out = NULL;
85 ENGINE *e = NULL;
86 EVP_CIPHER *enc = NULL;
87 char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog;
88 char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL;
89 OPTION_CHOICE o;
90 int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0;
91 int pubin = 0, pubout = 0, param_out = 0, ret = 1, private = 0;
92 int check = 0;
93 char *asn1_encoding = NULL;
94 char *point_format = NULL;
95 int no_public = 0;
96
97 opt_set_unknown_name("cipher");
98 prog = opt_init(argc, argv, ec_options);
99 while ((o = opt_next()) != OPT_EOF) {
100 switch (o) {
101 case OPT_EOF:
102 case OPT_ERR:
103 opthelp:
104 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
105 goto end;
106 case OPT_HELP:
107 opt_help(ec_options);
108 ret = 0;
109 goto end;
110 case OPT_INFORM:
111 if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
112 goto opthelp;
113 break;
114 case OPT_IN:
115 infile = opt_arg();
116 break;
117 case OPT_OUTFORM:
118 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
119 goto opthelp;
120 break;
121 case OPT_OUT:
122 outfile = opt_arg();
123 break;
124 case OPT_NOOUT:
125 noout = 1;
126 break;
127 case OPT_TEXT:
128 text = 1;
129 break;
130 case OPT_PARAM_OUT:
131 param_out = 1;
132 break;
133 case OPT_PUBIN:
134 pubin = 1;
135 break;
136 case OPT_PUBOUT:
137 pubout = 1;
138 break;
139 case OPT_PASSIN:
140 passinarg = opt_arg();
141 break;
142 case OPT_PASSOUT:
143 passoutarg = opt_arg();
144 break;
145 case OPT_ENGINE:
146 e = setup_engine(opt_arg(), 0);
147 break;
148 case OPT_CIPHER:
149 ciphername = opt_unknown();
150 break;
151 case OPT_CONV_FORM:
152 point_format = opt_arg();
153 if (!opt_string(point_format, point_format_options))
154 goto opthelp;
155 break;
156 case OPT_PARAM_ENC:
157 asn1_encoding = opt_arg();
158 if (!opt_string(asn1_encoding, asn1_encoding_options))
159 goto opthelp;
160 break;
161 case OPT_NO_PUBLIC:
162 no_public = 1;
163 break;
164 case OPT_CHECK:
165 check = 1;
166 break;
167 case OPT_PROV_CASES:
168 if (!opt_provider(o))
169 goto end;
170 break;
171 }
172 }
173
174 /* No extra arguments. */
175 if (!opt_check_rest_arg(NULL))
176 goto opthelp;
177
178 if (!opt_cipher(ciphername, &enc))
179 goto opthelp;
180 private = !pubin && (text || (!param_out && !pubout));
181
182 if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
183 BIO_printf(bio_err, "Error getting passwords\n");
184 goto end;
185 }
186
187 BIO_printf(bio_err, "read EC key\n");
188
189 if (pubin)
190 eckey = load_pubkey(infile, informat, 1, passin, e, "public key");
191 else
192 eckey = load_key(infile, informat, 1, passin, e, "private key");
193
194 if (eckey == NULL) {
195 BIO_printf(bio_err, "unable to load Key\n");
196 goto end;
197 }
198
199 out = bio_open_owner(outfile, outformat, private);
200 if (out == NULL)
201 goto end;
202
203 if (point_format
204 && !EVP_PKEY_set_utf8_string_param(
205 eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
206 point_format)) {
207 BIO_printf(bio_err, "unable to set point conversion format\n");
208 goto end;
209 }
210
211 if (asn1_encoding != NULL
212 && !EVP_PKEY_set_utf8_string_param(
213 eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) {
214 BIO_printf(bio_err, "unable to set asn1 encoding format\n");
215 goto end;
216 }
217
218 if (no_public) {
219 if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) {
220 BIO_printf(bio_err, "unable to disable public key encoding\n");
221 goto end;
222 }
223 } else {
224 if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) {
225 BIO_printf(bio_err, "unable to enable public key encoding\n");
226 goto end;
227 }
228 }
229
230 if (text) {
231 assert(pubin || private);
232 if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0)
233 || (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) {
234 BIO_printf(bio_err, "unable to print EC key\n");
235 goto end;
236 }
237 }
238
239 if (check) {
240 pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL);
241 if (pctx == NULL) {
242 BIO_printf(bio_err, "unable to check EC key\n");
243 goto end;
244 }
245 if (EVP_PKEY_check(pctx) <= 0)
246 BIO_printf(bio_err, "EC Key Invalid!\n");
247 else
248 BIO_printf(bio_err, "EC Key valid.\n");
249 ERR_print_errors(bio_err);
250 }
251
252 if (!noout) {
253 int selection;
254 const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM";
255 const char *output_structure = "type-specific";
256
257 BIO_printf(bio_err, "writing EC key\n");
258 if (param_out) {
259 selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;
260 } else if (pubin || pubout) {
261 selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
262 | OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
263 output_structure = "SubjectPublicKeyInfo";
264 } else {
265 selection = OSSL_KEYMGMT_SELECT_ALL;
266 assert(private);
267 }
268
269 ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection,
270 output_type, output_structure,
271 NULL);
272 if (enc != NULL) {
273 OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL);
274 /* Default passphrase prompter */
275 OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL);
276 if (passout != NULL)
277 /* When passout given, override the passphrase prompter */
278 OSSL_ENCODER_CTX_set_passphrase(ectx,
279 (const unsigned char *)passout,
280 strlen(passout));
281 }
282 if (!OSSL_ENCODER_to_bio(ectx, out)) {
283 BIO_printf(bio_err, "unable to write EC key\n");
284 goto end;
285 }
286 }
287
288 ret = 0;
289 end:
290 if (ret != 0)
291 ERR_print_errors(bio_err);
292 BIO_free_all(out);
293 EVP_PKEY_free(eckey);
294 EVP_CIPHER_free(enc);
295 OSSL_ENCODER_CTX_free(ectx);
296 OSSL_DECODER_CTX_free(dctx);
297 EVP_PKEY_CTX_free(pctx);
298 release_engine(e);
299 if (passin != NULL)
300 OPENSSL_clear_free(passin, strlen(passin));
301 if (passout != NULL)
302 OPENSSL_clear_free(passout, strlen(passout));
303 return ret;
304 }
305