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