1 /* 2 * Copyright 2002-2022 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 prog = opt_init(argc, argv, ec_options); 84 while ((o = opt_next()) != OPT_EOF) { 85 switch (o) { 86 case OPT_EOF: 87 case OPT_ERR: 88 opthelp: 89 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 90 goto end; 91 case OPT_HELP: 92 opt_help(ec_options); 93 ret = 0; 94 goto end; 95 case OPT_INFORM: 96 if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) 97 goto opthelp; 98 break; 99 case OPT_IN: 100 infile = opt_arg(); 101 break; 102 case OPT_OUTFORM: 103 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) 104 goto opthelp; 105 break; 106 case OPT_OUT: 107 outfile = opt_arg(); 108 break; 109 case OPT_NOOUT: 110 noout = 1; 111 break; 112 case OPT_TEXT: 113 text = 1; 114 break; 115 case OPT_PARAM_OUT: 116 param_out = 1; 117 break; 118 case OPT_PUBIN: 119 pubin = 1; 120 break; 121 case OPT_PUBOUT: 122 pubout = 1; 123 break; 124 case OPT_PASSIN: 125 passinarg = opt_arg(); 126 break; 127 case OPT_PASSOUT: 128 passoutarg = opt_arg(); 129 break; 130 case OPT_ENGINE: 131 e = setup_engine(opt_arg(), 0); 132 break; 133 case OPT_CIPHER: 134 ciphername = opt_unknown(); 135 break; 136 case OPT_CONV_FORM: 137 point_format = opt_arg(); 138 if (!opt_string(point_format, point_format_options)) 139 goto opthelp; 140 break; 141 case OPT_PARAM_ENC: 142 asn1_encoding = opt_arg(); 143 if (!opt_string(asn1_encoding, asn1_encoding_options)) 144 goto opthelp; 145 break; 146 case OPT_NO_PUBLIC: 147 no_public = 1; 148 break; 149 case OPT_CHECK: 150 check = 1; 151 break; 152 case OPT_PROV_CASES: 153 if (!opt_provider(o)) 154 goto end; 155 break; 156 } 157 } 158 159 /* No extra arguments. */ 160 argc = opt_num_rest(); 161 if (argc != 0) 162 goto opthelp; 163 164 if (ciphername != NULL) { 165 if (!opt_cipher(ciphername, &enc)) 166 goto opthelp; 167 } 168 private = param_out || pubin || pubout ? 0 : 1; 169 if (text && !pubin) 170 private = 1; 171 172 if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 173 BIO_printf(bio_err, "Error getting passwords\n"); 174 goto end; 175 } 176 177 BIO_printf(bio_err, "read EC key\n"); 178 179 if (pubin) 180 eckey = load_pubkey(infile, informat, 1, passin, e, "public key"); 181 else 182 eckey = load_key(infile, informat, 1, passin, e, "private key"); 183 184 if (eckey == NULL) { 185 BIO_printf(bio_err, "unable to load Key\n"); 186 goto end; 187 } 188 189 out = bio_open_owner(outfile, outformat, private); 190 if (out == NULL) 191 goto end; 192 193 if (point_format 194 && !EVP_PKEY_set_utf8_string_param( 195 eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, 196 point_format)) { 197 BIO_printf(bio_err, "unable to set point conversion format\n"); 198 goto end; 199 } 200 201 if (asn1_encoding != NULL 202 && !EVP_PKEY_set_utf8_string_param( 203 eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) { 204 BIO_printf(bio_err, "unable to set asn1 encoding format\n"); 205 goto end; 206 } 207 208 if (no_public) { 209 if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) { 210 BIO_printf(bio_err, "unable to disable public key encoding\n"); 211 goto end; 212 } 213 } else { 214 if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) { 215 BIO_printf(bio_err, "unable to enable public key encoding\n"); 216 goto end; 217 } 218 } 219 220 if (text) { 221 assert(pubin || private); 222 if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0) 223 || (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) { 224 BIO_printf(bio_err, "unable to print EC key\n"); 225 goto end; 226 } 227 } 228 229 if (check) { 230 pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL); 231 if (pctx == NULL) { 232 BIO_printf(bio_err, "unable to check EC key\n"); 233 goto end; 234 } 235 if (EVP_PKEY_check(pctx) <= 0) 236 BIO_printf(bio_err, "EC Key Invalid!\n"); 237 else 238 BIO_printf(bio_err, "EC Key valid.\n"); 239 ERR_print_errors(bio_err); 240 } 241 242 if (!noout) { 243 int selection; 244 const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM"; 245 const char *output_structure = "type-specific"; 246 247 BIO_printf(bio_err, "writing EC key\n"); 248 if (param_out) { 249 selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; 250 } else if (pubin || pubout) { 251 selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS 252 | OSSL_KEYMGMT_SELECT_PUBLIC_KEY; 253 output_structure = "SubjectPublicKeyInfo"; 254 } else { 255 selection = OSSL_KEYMGMT_SELECT_ALL; 256 assert(private); 257 } 258 259 ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection, 260 output_type, output_structure, 261 NULL); 262 if (enc != NULL) { 263 OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); 264 /* Default passphrase prompter */ 265 OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); 266 if (passout != NULL) 267 /* When passout given, override the passphrase prompter */ 268 OSSL_ENCODER_CTX_set_passphrase(ectx, 269 (const unsigned char *)passout, 270 strlen(passout)); 271 } 272 if (!OSSL_ENCODER_to_bio(ectx, out)) { 273 BIO_printf(bio_err, "unable to write EC key\n"); 274 goto end; 275 } 276 } 277 278 ret = 0; 279 end: 280 if (ret != 0) 281 ERR_print_errors(bio_err); 282 BIO_free_all(out); 283 EVP_PKEY_free(eckey); 284 EVP_CIPHER_free(enc); 285 OSSL_ENCODER_CTX_free(ectx); 286 OSSL_DECODER_CTX_free(dctx); 287 EVP_PKEY_CTX_free(pctx); 288 release_engine(e); 289 if (passin != NULL) 290 OPENSSL_clear_free(passin, strlen(passin)); 291 if (passout != NULL) 292 OPENSSL_clear_free(passout, strlen(passout)); 293 return ret; 294 } 295