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