]>
Commit | Line | Data |
---|---|---|
d4a8f90c | 1 | /* |
fecb3aae | 2 | * Copyright 2002-2022 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 { | |
b0f96018 | 25 | OPT_COMMON, |
7e1b7485 RS |
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; | |
57cea5ba | 70 | BIO *out = NULL; |
396ba1ca | 71 | ENGINE *e = NULL; |
606a417f | 72 | 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; |
d382e796 | 76 | int informat = FORMAT_UNDEF, 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 | |
2c272447 | 83 | opt_set_unknown_name("cipher"); |
7e1b7485 RS |
84 | prog = opt_init(argc, argv, ec_options); |
85 | while ((o = opt_next()) != OPT_EOF) { | |
86 | switch (o) { | |
87 | case OPT_EOF: | |
88 | case OPT_ERR: | |
89 | opthelp: | |
90 | BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); | |
91 | goto end; | |
92 | case OPT_HELP: | |
93 | opt_help(ec_options); | |
94 | ret = 0; | |
95 | goto end; | |
96 | case OPT_INFORM: | |
d18ba3cc | 97 | if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) |
7e1b7485 RS |
98 | goto opthelp; |
99 | break; | |
100 | case OPT_IN: | |
101 | infile = opt_arg(); | |
102 | break; | |
103 | case OPT_OUTFORM: | |
104 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) | |
105 | goto opthelp; | |
106 | break; | |
107 | case OPT_OUT: | |
108 | outfile = opt_arg(); | |
109 | break; | |
110 | case OPT_NOOUT: | |
0f113f3e | 111 | noout = 1; |
7e1b7485 RS |
112 | break; |
113 | case OPT_TEXT: | |
0f113f3e | 114 | text = 1; |
7e1b7485 RS |
115 | break; |
116 | case OPT_PARAM_OUT: | |
0f113f3e | 117 | param_out = 1; |
7e1b7485 RS |
118 | break; |
119 | case OPT_PUBIN: | |
0f113f3e | 120 | pubin = 1; |
7e1b7485 RS |
121 | break; |
122 | case OPT_PUBOUT: | |
0f113f3e | 123 | pubout = 1; |
7e1b7485 RS |
124 | break; |
125 | case OPT_PASSIN: | |
126 | passinarg = opt_arg(); | |
127 | break; | |
128 | case OPT_PASSOUT: | |
129 | passoutarg = opt_arg(); | |
130 | break; | |
131 | case OPT_ENGINE: | |
d18ba3cc | 132 | e = setup_engine(opt_arg(), 0); |
7e1b7485 RS |
133 | break; |
134 | case OPT_CIPHER: | |
03bbd346 | 135 | ciphername = opt_unknown(); |
cc630cdb | 136 | break; |
7e1b7485 | 137 | case OPT_CONV_FORM: |
5b5eea4b SL |
138 | point_format = opt_arg(); |
139 | if (!opt_string(point_format, point_format_options)) | |
7e1b7485 | 140 | goto opthelp; |
7e1b7485 RS |
141 | break; |
142 | case OPT_PARAM_ENC: | |
5b5eea4b SL |
143 | asn1_encoding = opt_arg(); |
144 | if (!opt_string(asn1_encoding, asn1_encoding_options)) | |
7e1b7485 | 145 | goto opthelp; |
0f113f3e | 146 | break; |
16754806 DSH |
147 | case OPT_NO_PUBLIC: |
148 | no_public = 1; | |
149 | break; | |
7565cbc4 DSH |
150 | case OPT_CHECK: |
151 | check = 1; | |
152 | break; | |
6bd4e3f2 P |
153 | case OPT_PROV_CASES: |
154 | if (!opt_provider(o)) | |
155 | goto end; | |
156 | break; | |
0f113f3e | 157 | } |
0f113f3e | 158 | } |
021410ea RS |
159 | |
160 | /* No extra arguments. */ | |
d9f07357 | 161 | if (!opt_check_rest_arg(NULL)) |
03358517 KR |
162 | goto opthelp; |
163 | ||
d9f07357 DDO |
164 | if (!opt_cipher(ciphername, &enc)) |
165 | goto opthelp; | |
3b061a00 | 166 | private = param_out || pubin || pubout ? 0 : 1; |
7eff6aa0 | 167 | if (text && !pubin) |
3b061a00 | 168 | private = 1; |
4d94ae00 | 169 | |
7e1b7485 | 170 | if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { |
0f113f3e MC |
171 | BIO_printf(bio_err, "Error getting passwords\n"); |
172 | goto end; | |
173 | } | |
4d94ae00 | 174 | |
0f113f3e | 175 | BIO_printf(bio_err, "read EC key\n"); |
5b5eea4b SL |
176 | |
177 | if (pubin) | |
178 | eckey = load_pubkey(infile, informat, 1, passin, e, "public key"); | |
179 | else | |
180 | eckey = load_key(infile, informat, 1, passin, e, "private key"); | |
181 | ||
0f113f3e MC |
182 | if (eckey == NULL) { |
183 | BIO_printf(bio_err, "unable to load Key\n"); | |
0f113f3e MC |
184 | goto end; |
185 | } | |
4d94ae00 | 186 | |
bdd58d98 | 187 | out = bio_open_owner(outfile, outformat, private); |
7e1b7485 RS |
188 | if (out == NULL) |
189 | goto end; | |
4d94ae00 | 190 | |
5b5eea4b SL |
191 | if (point_format |
192 | && !EVP_PKEY_set_utf8_string_param( | |
193 | eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, | |
194 | point_format)) { | |
195 | BIO_printf(bio_err, "unable to set point conversion format\n"); | |
196 | goto end; | |
197 | } | |
4d94ae00 | 198 | |
5b5eea4b SL |
199 | if (asn1_encoding != NULL |
200 | && !EVP_PKEY_set_utf8_string_param( | |
201 | eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) { | |
202 | BIO_printf(bio_err, "unable to set asn1 encoding format\n"); | |
203 | goto end; | |
204 | } | |
eefa6e4e | 205 | |
b5644c2a W |
206 | if (no_public) { |
207 | if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) { | |
208 | BIO_printf(bio_err, "unable to disable public key encoding\n"); | |
209 | goto end; | |
210 | } | |
211 | } else { | |
212 | if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) { | |
213 | BIO_printf(bio_err, "unable to enable public key encoding\n"); | |
214 | goto end; | |
215 | } | |
5b5eea4b | 216 | } |
16754806 | 217 | |
3b061a00 | 218 | if (text) { |
7eff6aa0 | 219 | assert(pubin || private); |
5b5eea4b SL |
220 | if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0) |
221 | || (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) { | |
222 | BIO_printf(bio_err, "unable to print EC key\n"); | |
0f113f3e MC |
223 | goto end; |
224 | } | |
3b061a00 | 225 | } |
4d94ae00 | 226 | |
7565cbc4 | 227 | if (check) { |
5b5eea4b SL |
228 | pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL); |
229 | if (pctx == NULL) { | |
230 | BIO_printf(bio_err, "unable to check EC key\n"); | |
231 | goto end; | |
7565cbc4 | 232 | } |
5b5eea4b SL |
233 | if (!EVP_PKEY_check(pctx)) |
234 | BIO_printf(bio_err, "EC Key Invalid!\n"); | |
235 | else | |
236 | BIO_printf(bio_err, "EC Key valid.\n"); | |
237 | ERR_print_errors(bio_err); | |
7565cbc4 DSH |
238 | } |
239 | ||
5b5eea4b SL |
240 | if (!noout) { |
241 | int selection; | |
242 | const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM"; | |
243 | const char *output_structure = "type-specific"; | |
eefa6e4e | 244 | |
5b5eea4b | 245 | BIO_printf(bio_err, "writing EC key\n"); |
2234212c | 246 | if (param_out) { |
5b5eea4b | 247 | selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; |
2234212c | 248 | } else if (pubin || pubout) { |
5b5eea4b SL |
249 | selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS |
250 | | OSSL_KEYMGMT_SELECT_PUBLIC_KEY; | |
251 | output_structure = "SubjectPublicKeyInfo"; | |
2234212c | 252 | } else { |
5b5eea4b | 253 | selection = OSSL_KEYMGMT_SELECT_ALL; |
3b061a00 | 254 | assert(private); |
3b061a00 | 255 | } |
5b5eea4b | 256 | |
fe75766c TM |
257 | ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection, |
258 | output_type, output_structure, | |
259 | NULL); | |
5b5eea4b | 260 | if (enc != NULL) { |
ed576acd | 261 | OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); |
49ce0037 RL |
262 | /* Default passphrase prompter */ |
263 | OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); | |
5b5eea4b | 264 | if (passout != NULL) |
49ce0037 | 265 | /* When passout given, override the passphrase prompter */ |
5b5eea4b SL |
266 | OSSL_ENCODER_CTX_set_passphrase(ectx, |
267 | (const unsigned char *)passout, | |
268 | strlen(passout)); | |
269 | } | |
270 | if (!OSSL_ENCODER_to_bio(ectx, out)) { | |
271 | BIO_printf(bio_err, "unable to write EC key\n"); | |
272 | goto end; | |
3b061a00 | 273 | } |
0f113f3e | 274 | } |
eefa6e4e | 275 | |
5b5eea4b SL |
276 | ret = 0; |
277 | end: | |
278 | if (ret != 0) | |
0f113f3e | 279 | ERR_print_errors(bio_err); |
ca3a82c3 | 280 | BIO_free_all(out); |
5b5eea4b | 281 | EVP_PKEY_free(eckey); |
606a417f | 282 | EVP_CIPHER_free(enc); |
5b5eea4b SL |
283 | OSSL_ENCODER_CTX_free(ectx); |
284 | OSSL_DECODER_CTX_free(dctx); | |
285 | EVP_PKEY_CTX_free(pctx); | |
dd1abd44 | 286 | release_engine(e); |
5b5eea4b SL |
287 | if (passin != NULL) |
288 | OPENSSL_clear_free(passin, strlen(passin)); | |
289 | if (passout != NULL) | |
290 | OPENSSL_clear_free(passout, strlen(passout)); | |
26a7d938 | 291 | return ret; |
4d94ae00 | 292 | } |