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