1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2002-2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <string.h> 11e1051a39Sopenharmony_ci#include <openssl/opensslconf.h> 12e1051a39Sopenharmony_ci#include <openssl/evp.h> 13e1051a39Sopenharmony_ci#include <openssl/encoder.h> 14e1051a39Sopenharmony_ci#include <openssl/decoder.h> 15e1051a39Sopenharmony_ci#include <openssl/core_names.h> 16e1051a39Sopenharmony_ci#include <openssl/core_dispatch.h> 17e1051a39Sopenharmony_ci#include <openssl/params.h> 18e1051a39Sopenharmony_ci#include <openssl/err.h> 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_ci#include "apps.h" 21e1051a39Sopenharmony_ci#include "progs.h" 22e1051a39Sopenharmony_ci#include "ec_common.h" 23e1051a39Sopenharmony_ci 24e1051a39Sopenharmony_citypedef enum OPTION_choice { 25e1051a39Sopenharmony_ci OPT_COMMON, 26e1051a39Sopenharmony_ci OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, 27e1051a39Sopenharmony_ci OPT_NOOUT, OPT_TEXT, OPT_PARAM_OUT, OPT_PUBIN, OPT_PUBOUT, 28e1051a39Sopenharmony_ci OPT_PASSIN, OPT_PASSOUT, OPT_PARAM_ENC, OPT_CONV_FORM, OPT_CIPHER, 29e1051a39Sopenharmony_ci OPT_NO_PUBLIC, OPT_CHECK, OPT_PROV_ENUM 30e1051a39Sopenharmony_ci} OPTION_CHOICE; 31e1051a39Sopenharmony_ci 32e1051a39Sopenharmony_ciconst OPTIONS ec_options[] = { 33e1051a39Sopenharmony_ci OPT_SECTION("General"), 34e1051a39Sopenharmony_ci {"help", OPT_HELP, '-', "Display this summary"}, 35e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_ENGINE 36e1051a39Sopenharmony_ci {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, 37e1051a39Sopenharmony_ci#endif 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_ci OPT_SECTION("Input"), 40e1051a39Sopenharmony_ci {"in", OPT_IN, 's', "Input file"}, 41e1051a39Sopenharmony_ci {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)"}, 42e1051a39Sopenharmony_ci {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, 43e1051a39Sopenharmony_ci {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, 44e1051a39Sopenharmony_ci {"check", OPT_CHECK, '-', "check key consistency"}, 45e1051a39Sopenharmony_ci {"", OPT_CIPHER, '-', "Any supported cipher"}, 46e1051a39Sopenharmony_ci {"param_enc", OPT_PARAM_ENC, 's', 47e1051a39Sopenharmony_ci "Specifies the way the ec parameters are encoded"}, 48e1051a39Sopenharmony_ci {"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "}, 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_ci OPT_SECTION("Output"), 51e1051a39Sopenharmony_ci {"out", OPT_OUT, '>', "Output file"}, 52e1051a39Sopenharmony_ci {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, 53e1051a39Sopenharmony_ci {"noout", OPT_NOOUT, '-', "Don't print key out"}, 54e1051a39Sopenharmony_ci {"text", OPT_TEXT, '-', "Print the key"}, 55e1051a39Sopenharmony_ci {"param_out", OPT_PARAM_OUT, '-', "Print the elliptic curve parameters"}, 56e1051a39Sopenharmony_ci {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, 57e1051a39Sopenharmony_ci {"no_public", OPT_NO_PUBLIC, '-', "exclude public key from private key"}, 58e1051a39Sopenharmony_ci {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_ci OPT_PROV_OPTIONS, 61e1051a39Sopenharmony_ci {NULL} 62e1051a39Sopenharmony_ci}; 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_ciint ec_main(int argc, char **argv) 65e1051a39Sopenharmony_ci{ 66e1051a39Sopenharmony_ci OSSL_ENCODER_CTX *ectx = NULL; 67e1051a39Sopenharmony_ci OSSL_DECODER_CTX *dctx = NULL; 68e1051a39Sopenharmony_ci EVP_PKEY_CTX *pctx = NULL; 69e1051a39Sopenharmony_ci EVP_PKEY *eckey = NULL; 70e1051a39Sopenharmony_ci BIO *out = NULL; 71e1051a39Sopenharmony_ci ENGINE *e = NULL; 72e1051a39Sopenharmony_ci EVP_CIPHER *enc = NULL; 73e1051a39Sopenharmony_ci char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog; 74e1051a39Sopenharmony_ci char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; 75e1051a39Sopenharmony_ci OPTION_CHOICE o; 76e1051a39Sopenharmony_ci int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0; 77e1051a39Sopenharmony_ci int pubin = 0, pubout = 0, param_out = 0, ret = 1, private = 0; 78e1051a39Sopenharmony_ci int check = 0; 79e1051a39Sopenharmony_ci char *asn1_encoding = NULL; 80e1051a39Sopenharmony_ci char *point_format = NULL; 81e1051a39Sopenharmony_ci int no_public = 0; 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci prog = opt_init(argc, argv, ec_options); 84e1051a39Sopenharmony_ci while ((o = opt_next()) != OPT_EOF) { 85e1051a39Sopenharmony_ci switch (o) { 86e1051a39Sopenharmony_ci case OPT_EOF: 87e1051a39Sopenharmony_ci case OPT_ERR: 88e1051a39Sopenharmony_ci opthelp: 89e1051a39Sopenharmony_ci BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 90e1051a39Sopenharmony_ci goto end; 91e1051a39Sopenharmony_ci case OPT_HELP: 92e1051a39Sopenharmony_ci opt_help(ec_options); 93e1051a39Sopenharmony_ci ret = 0; 94e1051a39Sopenharmony_ci goto end; 95e1051a39Sopenharmony_ci case OPT_INFORM: 96e1051a39Sopenharmony_ci if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) 97e1051a39Sopenharmony_ci goto opthelp; 98e1051a39Sopenharmony_ci break; 99e1051a39Sopenharmony_ci case OPT_IN: 100e1051a39Sopenharmony_ci infile = opt_arg(); 101e1051a39Sopenharmony_ci break; 102e1051a39Sopenharmony_ci case OPT_OUTFORM: 103e1051a39Sopenharmony_ci if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) 104e1051a39Sopenharmony_ci goto opthelp; 105e1051a39Sopenharmony_ci break; 106e1051a39Sopenharmony_ci case OPT_OUT: 107e1051a39Sopenharmony_ci outfile = opt_arg(); 108e1051a39Sopenharmony_ci break; 109e1051a39Sopenharmony_ci case OPT_NOOUT: 110e1051a39Sopenharmony_ci noout = 1; 111e1051a39Sopenharmony_ci break; 112e1051a39Sopenharmony_ci case OPT_TEXT: 113e1051a39Sopenharmony_ci text = 1; 114e1051a39Sopenharmony_ci break; 115e1051a39Sopenharmony_ci case OPT_PARAM_OUT: 116e1051a39Sopenharmony_ci param_out = 1; 117e1051a39Sopenharmony_ci break; 118e1051a39Sopenharmony_ci case OPT_PUBIN: 119e1051a39Sopenharmony_ci pubin = 1; 120e1051a39Sopenharmony_ci break; 121e1051a39Sopenharmony_ci case OPT_PUBOUT: 122e1051a39Sopenharmony_ci pubout = 1; 123e1051a39Sopenharmony_ci break; 124e1051a39Sopenharmony_ci case OPT_PASSIN: 125e1051a39Sopenharmony_ci passinarg = opt_arg(); 126e1051a39Sopenharmony_ci break; 127e1051a39Sopenharmony_ci case OPT_PASSOUT: 128e1051a39Sopenharmony_ci passoutarg = opt_arg(); 129e1051a39Sopenharmony_ci break; 130e1051a39Sopenharmony_ci case OPT_ENGINE: 131e1051a39Sopenharmony_ci e = setup_engine(opt_arg(), 0); 132e1051a39Sopenharmony_ci break; 133e1051a39Sopenharmony_ci case OPT_CIPHER: 134e1051a39Sopenharmony_ci ciphername = opt_unknown(); 135e1051a39Sopenharmony_ci break; 136e1051a39Sopenharmony_ci case OPT_CONV_FORM: 137e1051a39Sopenharmony_ci point_format = opt_arg(); 138e1051a39Sopenharmony_ci if (!opt_string(point_format, point_format_options)) 139e1051a39Sopenharmony_ci goto opthelp; 140e1051a39Sopenharmony_ci break; 141e1051a39Sopenharmony_ci case OPT_PARAM_ENC: 142e1051a39Sopenharmony_ci asn1_encoding = opt_arg(); 143e1051a39Sopenharmony_ci if (!opt_string(asn1_encoding, asn1_encoding_options)) 144e1051a39Sopenharmony_ci goto opthelp; 145e1051a39Sopenharmony_ci break; 146e1051a39Sopenharmony_ci case OPT_NO_PUBLIC: 147e1051a39Sopenharmony_ci no_public = 1; 148e1051a39Sopenharmony_ci break; 149e1051a39Sopenharmony_ci case OPT_CHECK: 150e1051a39Sopenharmony_ci check = 1; 151e1051a39Sopenharmony_ci break; 152e1051a39Sopenharmony_ci case OPT_PROV_CASES: 153e1051a39Sopenharmony_ci if (!opt_provider(o)) 154e1051a39Sopenharmony_ci goto end; 155e1051a39Sopenharmony_ci break; 156e1051a39Sopenharmony_ci } 157e1051a39Sopenharmony_ci } 158e1051a39Sopenharmony_ci 159e1051a39Sopenharmony_ci /* No extra arguments. */ 160e1051a39Sopenharmony_ci argc = opt_num_rest(); 161e1051a39Sopenharmony_ci if (argc != 0) 162e1051a39Sopenharmony_ci goto opthelp; 163e1051a39Sopenharmony_ci 164e1051a39Sopenharmony_ci if (ciphername != NULL) { 165e1051a39Sopenharmony_ci if (!opt_cipher(ciphername, &enc)) 166e1051a39Sopenharmony_ci goto opthelp; 167e1051a39Sopenharmony_ci } 168e1051a39Sopenharmony_ci private = param_out || pubin || pubout ? 0 : 1; 169e1051a39Sopenharmony_ci if (text && !pubin) 170e1051a39Sopenharmony_ci private = 1; 171e1051a39Sopenharmony_ci 172e1051a39Sopenharmony_ci if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 173e1051a39Sopenharmony_ci BIO_printf(bio_err, "Error getting passwords\n"); 174e1051a39Sopenharmony_ci goto end; 175e1051a39Sopenharmony_ci } 176e1051a39Sopenharmony_ci 177e1051a39Sopenharmony_ci BIO_printf(bio_err, "read EC key\n"); 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ci if (pubin) 180e1051a39Sopenharmony_ci eckey = load_pubkey(infile, informat, 1, passin, e, "public key"); 181e1051a39Sopenharmony_ci else 182e1051a39Sopenharmony_ci eckey = load_key(infile, informat, 1, passin, e, "private key"); 183e1051a39Sopenharmony_ci 184e1051a39Sopenharmony_ci if (eckey == NULL) { 185e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to load Key\n"); 186e1051a39Sopenharmony_ci goto end; 187e1051a39Sopenharmony_ci } 188e1051a39Sopenharmony_ci 189e1051a39Sopenharmony_ci out = bio_open_owner(outfile, outformat, private); 190e1051a39Sopenharmony_ci if (out == NULL) 191e1051a39Sopenharmony_ci goto end; 192e1051a39Sopenharmony_ci 193e1051a39Sopenharmony_ci if (point_format 194e1051a39Sopenharmony_ci && !EVP_PKEY_set_utf8_string_param( 195e1051a39Sopenharmony_ci eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, 196e1051a39Sopenharmony_ci point_format)) { 197e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to set point conversion format\n"); 198e1051a39Sopenharmony_ci goto end; 199e1051a39Sopenharmony_ci } 200e1051a39Sopenharmony_ci 201e1051a39Sopenharmony_ci if (asn1_encoding != NULL 202e1051a39Sopenharmony_ci && !EVP_PKEY_set_utf8_string_param( 203e1051a39Sopenharmony_ci eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) { 204e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to set asn1 encoding format\n"); 205e1051a39Sopenharmony_ci goto end; 206e1051a39Sopenharmony_ci } 207e1051a39Sopenharmony_ci 208e1051a39Sopenharmony_ci if (no_public) { 209e1051a39Sopenharmony_ci if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) { 210e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to disable public key encoding\n"); 211e1051a39Sopenharmony_ci goto end; 212e1051a39Sopenharmony_ci } 213e1051a39Sopenharmony_ci } else { 214e1051a39Sopenharmony_ci if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) { 215e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to enable public key encoding\n"); 216e1051a39Sopenharmony_ci goto end; 217e1051a39Sopenharmony_ci } 218e1051a39Sopenharmony_ci } 219e1051a39Sopenharmony_ci 220e1051a39Sopenharmony_ci if (text) { 221e1051a39Sopenharmony_ci assert(pubin || private); 222e1051a39Sopenharmony_ci if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0) 223e1051a39Sopenharmony_ci || (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) { 224e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to print EC key\n"); 225e1051a39Sopenharmony_ci goto end; 226e1051a39Sopenharmony_ci } 227e1051a39Sopenharmony_ci } 228e1051a39Sopenharmony_ci 229e1051a39Sopenharmony_ci if (check) { 230e1051a39Sopenharmony_ci pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL); 231e1051a39Sopenharmony_ci if (pctx == NULL) { 232e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to check EC key\n"); 233e1051a39Sopenharmony_ci goto end; 234e1051a39Sopenharmony_ci } 235e1051a39Sopenharmony_ci if (EVP_PKEY_check(pctx) <= 0) 236e1051a39Sopenharmony_ci BIO_printf(bio_err, "EC Key Invalid!\n"); 237e1051a39Sopenharmony_ci else 238e1051a39Sopenharmony_ci BIO_printf(bio_err, "EC Key valid.\n"); 239e1051a39Sopenharmony_ci ERR_print_errors(bio_err); 240e1051a39Sopenharmony_ci } 241e1051a39Sopenharmony_ci 242e1051a39Sopenharmony_ci if (!noout) { 243e1051a39Sopenharmony_ci int selection; 244e1051a39Sopenharmony_ci const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM"; 245e1051a39Sopenharmony_ci const char *output_structure = "type-specific"; 246e1051a39Sopenharmony_ci 247e1051a39Sopenharmony_ci BIO_printf(bio_err, "writing EC key\n"); 248e1051a39Sopenharmony_ci if (param_out) { 249e1051a39Sopenharmony_ci selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; 250e1051a39Sopenharmony_ci } else if (pubin || pubout) { 251e1051a39Sopenharmony_ci selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS 252e1051a39Sopenharmony_ci | OSSL_KEYMGMT_SELECT_PUBLIC_KEY; 253e1051a39Sopenharmony_ci output_structure = "SubjectPublicKeyInfo"; 254e1051a39Sopenharmony_ci } else { 255e1051a39Sopenharmony_ci selection = OSSL_KEYMGMT_SELECT_ALL; 256e1051a39Sopenharmony_ci assert(private); 257e1051a39Sopenharmony_ci } 258e1051a39Sopenharmony_ci 259e1051a39Sopenharmony_ci ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection, 260e1051a39Sopenharmony_ci output_type, output_structure, 261e1051a39Sopenharmony_ci NULL); 262e1051a39Sopenharmony_ci if (enc != NULL) { 263e1051a39Sopenharmony_ci OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); 264e1051a39Sopenharmony_ci /* Default passphrase prompter */ 265e1051a39Sopenharmony_ci OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); 266e1051a39Sopenharmony_ci if (passout != NULL) 267e1051a39Sopenharmony_ci /* When passout given, override the passphrase prompter */ 268e1051a39Sopenharmony_ci OSSL_ENCODER_CTX_set_passphrase(ectx, 269e1051a39Sopenharmony_ci (const unsigned char *)passout, 270e1051a39Sopenharmony_ci strlen(passout)); 271e1051a39Sopenharmony_ci } 272e1051a39Sopenharmony_ci if (!OSSL_ENCODER_to_bio(ectx, out)) { 273e1051a39Sopenharmony_ci BIO_printf(bio_err, "unable to write EC key\n"); 274e1051a39Sopenharmony_ci goto end; 275e1051a39Sopenharmony_ci } 276e1051a39Sopenharmony_ci } 277e1051a39Sopenharmony_ci 278e1051a39Sopenharmony_ci ret = 0; 279e1051a39Sopenharmony_ciend: 280e1051a39Sopenharmony_ci if (ret != 0) 281e1051a39Sopenharmony_ci ERR_print_errors(bio_err); 282e1051a39Sopenharmony_ci BIO_free_all(out); 283e1051a39Sopenharmony_ci EVP_PKEY_free(eckey); 284e1051a39Sopenharmony_ci EVP_CIPHER_free(enc); 285e1051a39Sopenharmony_ci OSSL_ENCODER_CTX_free(ectx); 286e1051a39Sopenharmony_ci OSSL_DECODER_CTX_free(dctx); 287e1051a39Sopenharmony_ci EVP_PKEY_CTX_free(pctx); 288e1051a39Sopenharmony_ci release_engine(e); 289e1051a39Sopenharmony_ci if (passin != NULL) 290e1051a39Sopenharmony_ci OPENSSL_clear_free(passin, strlen(passin)); 291e1051a39Sopenharmony_ci if (passout != NULL) 292e1051a39Sopenharmony_ci OPENSSL_clear_free(passout, strlen(passout)); 293e1051a39Sopenharmony_ci return ret; 294e1051a39Sopenharmony_ci} 295