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