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