1 /*
2 * Copyright 2002-2025 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4 *
5 * Licensed under the Apache License 2.0 (the "License"). You may not use
6 * this file except in compliance with the License. You can obtain a copy
7 * in the file LICENSE in the source distribution or at
8 * https://www.openssl.org/source/license.html
9 */
10
11 #include <string.h>
12 #include <openssl/opensslconf.h>
13 #include <openssl/evp.h>
14 #include <openssl/encoder.h>
15 #include <openssl/decoder.h>
16 #include <openssl/core_names.h>
17 #include <openssl/core_dispatch.h>
18 #include <openssl/params.h>
19 #include <openssl/err.h>
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_IN,
29 OPT_OUT,
30 OPT_TEXT,
31 OPT_CHECK,
32 OPT_LIST_CURVES,
33 OPT_NO_SEED,
34 OPT_NOOUT,
35 OPT_NAME,
36 OPT_CONV_FORM,
37 OPT_PARAM_ENC,
38 OPT_GENKEY,
39 OPT_ENGINE,
40 OPT_CHECK_NAMED,
41 OPT_R_ENUM,
42 OPT_PROV_ENUM
43 } OPTION_CHOICE;
44
45 const OPTIONS ecparam_options[] = {
46 OPT_SECTION("General"),
47 { "help", OPT_HELP, '-', "Display this summary" },
48 { "list_curves", OPT_LIST_CURVES, '-',
49 "Prints a list of all curve 'short names'" },
50 #ifndef OPENSSL_NO_ENGINE
51 { "engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device" },
52 #endif
53
54 { "genkey", OPT_GENKEY, '-', "Generate ec key" },
55 { "in", OPT_IN, '<', "Input file - default stdin" },
56 { "inform", OPT_INFORM, 'F', "Input format - default PEM (DER or PEM)" },
57 { "out", OPT_OUT, '>', "Output file - default stdout" },
58 { "outform", OPT_OUTFORM, 'F', "Output format - default PEM" },
59
60 OPT_SECTION("Output"),
61 { "text", OPT_TEXT, '-', "Print the ec parameters in text form" },
62 { "noout", OPT_NOOUT, '-', "Do not print the ec parameter" },
63 { "param_enc", OPT_PARAM_ENC, 's',
64 "Specifies the way the ec parameters are encoded" },
65
66 OPT_SECTION("Parameter"),
67 { "check", OPT_CHECK, '-', "Validate the ec parameters" },
68 { "check_named", OPT_CHECK_NAMED, '-',
69 "Check that named EC curve parameters have not been modified" },
70 { "no_seed", OPT_NO_SEED, '-',
71 "If 'explicit' parameters are chosen do not use the seed" },
72 { "name", OPT_NAME, 's',
73 "Use the ec parameters with specified 'short name'" },
74 { "conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form " },
75
76 OPT_R_OPTIONS,
77 OPT_PROV_OPTIONS,
78 { NULL }
79 };
80
list_builtin_curves(BIO * out)81 static int list_builtin_curves(BIO *out)
82 {
83 EC_builtin_curve *curves = NULL;
84 size_t n, crv_len = EC_get_builtin_curves(NULL, 0);
85
86 curves = app_malloc((int)sizeof(*curves) * crv_len, "list curves");
87 EC_get_builtin_curves(curves, crv_len);
88
89 for (n = 0; n < crv_len; n++) {
90 const char *comment = curves[n].comment;
91 const char *sname = OBJ_nid2sn(curves[n].nid);
92
93 if (comment == NULL)
94 comment = "CURVE DESCRIPTION NOT AVAILABLE";
95 if (sname == NULL)
96 sname = "";
97
98 BIO_printf(out, " %-10s: ", sname);
99 BIO_printf(out, "%s\n", comment);
100 }
101 OPENSSL_free(curves);
102 return 1;
103 }
104
ecparam_main(int argc,char ** argv)105 int ecparam_main(int argc, char **argv)
106 {
107 EVP_PKEY_CTX *gctx_params = NULL, *gctx_key = NULL, *pctx = NULL;
108 EVP_PKEY *params_key = NULL, *key = NULL;
109 OSSL_ENCODER_CTX *ectx_key = NULL, *ectx_params = NULL;
110 OSSL_DECODER_CTX *dctx_params = NULL;
111 ENGINE *e = NULL;
112 BIO *out = NULL;
113 char *curve_name = NULL;
114 char *asn1_encoding = NULL;
115 char *point_format = NULL;
116 char *infile = NULL, *outfile = NULL, *prog;
117 OPTION_CHOICE o;
118 int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0;
119 int ret = 1, private = 0;
120 int no_seed = 0, check = 0, check_named = 0, text = 0, genkey = 0;
121 int list_curves = 0;
122
123 prog = opt_init(argc, argv, ecparam_options);
124 while ((o = opt_next()) != OPT_EOF) {
125 switch (o) {
126 case OPT_EOF:
127 case OPT_ERR:
128 opthelp:
129 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
130 goto end;
131 case OPT_HELP:
132 opt_help(ecparam_options);
133 ret = 0;
134 goto end;
135 case OPT_INFORM:
136 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat))
137 goto opthelp;
138 break;
139 case OPT_IN:
140 infile = opt_arg();
141 break;
142 case OPT_OUTFORM:
143 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
144 goto opthelp;
145 break;
146 case OPT_OUT:
147 outfile = opt_arg();
148 break;
149 case OPT_TEXT:
150 text = 1;
151 break;
152 case OPT_CHECK:
153 check = 1;
154 break;
155 case OPT_CHECK_NAMED:
156 check_named = 1;
157 break;
158 case OPT_LIST_CURVES:
159 list_curves = 1;
160 break;
161 case OPT_NO_SEED:
162 no_seed = 1;
163 break;
164 case OPT_NOOUT:
165 noout = 1;
166 break;
167 case OPT_NAME:
168 curve_name = opt_arg();
169 break;
170 case OPT_CONV_FORM:
171 point_format = opt_arg();
172 if (!opt_string(point_format, point_format_options))
173 goto opthelp;
174 break;
175 case OPT_PARAM_ENC:
176 asn1_encoding = opt_arg();
177 if (!opt_string(asn1_encoding, asn1_encoding_options))
178 goto opthelp;
179 break;
180 case OPT_GENKEY:
181 genkey = 1;
182 break;
183 case OPT_R_CASES:
184 if (!opt_rand(o))
185 goto end;
186 break;
187 case OPT_PROV_CASES:
188 if (!opt_provider(o))
189 goto end;
190 break;
191 case OPT_ENGINE:
192 e = setup_engine(opt_arg(), 0);
193 break;
194 }
195 }
196
197 /* No extra args. */
198 if (!opt_check_rest_arg(NULL))
199 goto opthelp;
200
201 if (!app_RAND_load())
202 goto end;
203
204 if (list_curves) {
205 out = bio_open_owner(outfile, outformat, private);
206 if (out == NULL)
207 goto end;
208
209 if (list_builtin_curves(out))
210 ret = 0;
211 goto end;
212 }
213
214 private = genkey ? 1 : 0;
215
216 if (curve_name != NULL) {
217 OSSL_PARAM params[4];
218 OSSL_PARAM *p = params;
219
220 if (strcmp(curve_name, "secp192r1") == 0) {
221 BIO_printf(bio_err,
222 "using curve name prime192v1 instead of secp192r1\n");
223 curve_name = SN_X9_62_prime192v1;
224 } else if (strcmp(curve_name, "secp256r1") == 0) {
225 BIO_printf(bio_err,
226 "using curve name prime256v1 instead of secp256r1\n");
227 curve_name = SN_X9_62_prime256v1;
228 }
229 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
230 curve_name, 0);
231 if (asn1_encoding != NULL)
232 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING,
233 asn1_encoding, 0);
234 if (point_format != NULL)
235 *p++ = OSSL_PARAM_construct_utf8_string(
236 OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
237 point_format, 0);
238 *p = OSSL_PARAM_construct_end();
239
240 if (OPENSSL_strcasecmp(curve_name, "SM2") == 0)
241 gctx_params = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "sm2",
242 app_get0_propq());
243 else
244 gctx_params = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "ec",
245 app_get0_propq());
246 if (gctx_params == NULL
247 || EVP_PKEY_keygen_init(gctx_params) <= 0
248 || EVP_PKEY_CTX_set_params(gctx_params, params) <= 0
249 || EVP_PKEY_keygen(gctx_params, ¶ms_key) <= 0) {
250 BIO_printf(bio_err, "unable to generate key\n");
251 goto end;
252 }
253 } else {
254 params_key = load_keyparams_suppress(infile, informat, 1, "EC",
255 "EC parameters", 1);
256 if (params_key == NULL)
257 params_key = load_keyparams_suppress(infile, informat, 1, "SM2",
258 "SM2 parameters", 1);
259
260 if (params_key == NULL) {
261 BIO_printf(bio_err, "Unable to load parameters from %s\n", infile);
262 goto end;
263 }
264
265 if (point_format
266 && !EVP_PKEY_set_utf8_string_param(
267 params_key, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
268 point_format)) {
269 BIO_printf(bio_err, "unable to set point conversion format\n");
270 goto end;
271 }
272
273 if (asn1_encoding != NULL
274 && !EVP_PKEY_set_utf8_string_param(
275 params_key, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) {
276 BIO_printf(bio_err, "unable to set asn1 encoding format\n");
277 goto end;
278 }
279 }
280
281 if (no_seed
282 && !EVP_PKEY_set_octet_string_param(params_key, OSSL_PKEY_PARAM_EC_SEED,
283 NULL, 0)) {
284 BIO_printf(bio_err, "unable to clear seed\n");
285 goto end;
286 }
287
288 out = bio_open_owner(outfile, outformat, private);
289 if (out == NULL)
290 goto end;
291
292 if (text
293 && EVP_PKEY_print_params(out, params_key, 0, NULL) <= 0) {
294 BIO_printf(bio_err, "unable to print params\n");
295 goto end;
296 }
297
298 if (check || check_named) {
299 BIO_printf(bio_err, "checking elliptic curve parameters: ");
300
301 if (check_named
302 && !EVP_PKEY_set_utf8_string_param(params_key,
303 OSSL_PKEY_PARAM_EC_GROUP_CHECK_TYPE,
304 OSSL_PKEY_EC_GROUP_CHECK_NAMED)) {
305 BIO_printf(bio_err, "unable to set check_type\n");
306 goto end;
307 }
308 pctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), params_key,
309 app_get0_propq());
310 if (pctx == NULL || EVP_PKEY_param_check(pctx) <= 0) {
311 BIO_printf(bio_err, "failed\n");
312 goto end;
313 }
314 BIO_printf(bio_err, "ok\n");
315 }
316
317 if (outformat == FORMAT_ASN1 && genkey)
318 noout = 1;
319
320 if (!noout) {
321 ectx_params = OSSL_ENCODER_CTX_new_for_pkey(
322 params_key, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS,
323 outformat == FORMAT_ASN1 ? "DER" : "PEM", NULL, NULL);
324 if (!OSSL_ENCODER_to_bio(ectx_params, out)) {
325 BIO_printf(bio_err, "unable to write elliptic curve parameters\n");
326 goto end;
327 }
328 }
329
330 if (genkey) {
331 /*
332 * NOTE: EC keygen does not normally need to pass in the param_key
333 * for named curves. This can be achieved using:
334 * gctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
335 * EVP_PKEY_keygen_init(gctx);
336 * EVP_PKEY_CTX_set_group_name(gctx, curvename);
337 * EVP_PKEY_keygen(gctx, &key) <= 0)
338 */
339 gctx_key = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), params_key,
340 app_get0_propq());
341 if (EVP_PKEY_keygen_init(gctx_key) <= 0
342 || EVP_PKEY_keygen(gctx_key, &key) <= 0) {
343 BIO_printf(bio_err, "unable to generate key\n");
344 goto end;
345 }
346 assert(private);
347 ectx_key = OSSL_ENCODER_CTX_new_for_pkey(
348 key, OSSL_KEYMGMT_SELECT_ALL,
349 outformat == FORMAT_ASN1 ? "DER" : "PEM", NULL, NULL);
350 if (!OSSL_ENCODER_to_bio(ectx_key, out)) {
351 BIO_printf(bio_err, "unable to write elliptic "
352 "curve parameters\n");
353 goto end;
354 }
355 }
356
357 ret = 0;
358 end:
359 if (ret != 0)
360 ERR_print_errors(bio_err);
361 release_engine(e);
362 EVP_PKEY_free(params_key);
363 EVP_PKEY_free(key);
364 EVP_PKEY_CTX_free(pctx);
365 EVP_PKEY_CTX_free(gctx_params);
366 EVP_PKEY_CTX_free(gctx_key);
367 OSSL_DECODER_CTX_free(dctx_params);
368 OSSL_ENCODER_CTX_free(ectx_params);
369 OSSL_ENCODER_CTX_free(ectx_key);
370 BIO_free_all(out);
371 return ret;
372 }
373