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