Home | History | Annotate | Line # | Download | only in apps
ecparam.c revision 1.1.1.1
      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, &params_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