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