1 1.1.1.2 spz /* 2 1.1.1.6 christos * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos * 4 1.1.1.6 christos * Licensed under the Apache License 2.0 (the "License"). You may not use 5 1.1.1.4 christos * this file except in compliance with the License. You can obtain a copy 6 1.1.1.4 christos * in the file LICENSE in the source distribution or at 7 1.1.1.4 christos * https://www.openssl.org/source/license.html 8 1.1 christos */ 9 1.1.1.4 christos 10 1.1 christos #include <stdio.h> 11 1.1 christos #include <string.h> 12 1.1 christos #include "apps.h" 13 1.1.1.5 christos #include "progs.h" 14 1.1.1.6 christos #include "ec_common.h" 15 1.1 christos #include <openssl/pem.h> 16 1.1 christos #include <openssl/err.h> 17 1.1 christos #include <openssl/evp.h> 18 1.1.1.6 christos #include <openssl/core_names.h> 19 1.1 christos 20 1.1.1.4 christos typedef enum OPTION_choice { 21 1.1.1.6 christos OPT_COMMON, 22 1.1.1.4 christos OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, 23 1.1.1.4 christos OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB, 24 1.1.1.6 christos OPT_TEXT, OPT_NOOUT, OPT_CIPHER, OPT_TRADITIONAL, OPT_CHECK, OPT_PUB_CHECK, 25 1.1.1.6 christos OPT_EC_PARAM_ENC, OPT_EC_CONV_FORM, 26 1.1.1.6 christos OPT_PROV_ENUM 27 1.1.1.4 christos } OPTION_CHOICE; 28 1.1.1.4 christos 29 1.1.1.5 christos const OPTIONS pkey_options[] = { 30 1.1.1.6 christos OPT_SECTION("General"), 31 1.1.1.4 christos {"help", OPT_HELP, '-', "Display this summary"}, 32 1.1.1.4 christos #ifndef OPENSSL_NO_ENGINE 33 1.1.1.4 christos {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, 34 1.1.1.4 christos #endif 35 1.1.1.6 christos OPT_PROV_OPTIONS, 36 1.1.1.6 christos 37 1.1.1.5 christos {"check", OPT_CHECK, '-', "Check key consistency"}, 38 1.1.1.5 christos {"pubcheck", OPT_PUB_CHECK, '-', "Check public key consistency"}, 39 1.1.1.6 christos 40 1.1.1.6 christos OPT_SECTION("Input"), 41 1.1.1.6 christos {"in", OPT_IN, 's', "Input key"}, 42 1.1.1.6 christos {"inform", OPT_INFORM, 'f', 43 1.1.1.6 christos "Key input format (ENGINE, other values ignored)"}, 44 1.1.1.6 christos {"passin", OPT_PASSIN, 's', "Key input pass phrase source"}, 45 1.1.1.6 christos {"pubin", OPT_PUBIN, '-', 46 1.1.1.6 christos "Read only public components from key input"}, 47 1.1.1.6 christos 48 1.1.1.6 christos OPT_SECTION("Output"), 49 1.1.1.6 christos {"out", OPT_OUT, '>', "Output file for encoded and/or text output"}, 50 1.1.1.6 christos {"outform", OPT_OUTFORM, 'F', "Output encoding format (DER or PEM)"}, 51 1.1.1.6 christos {"", OPT_CIPHER, '-', "Any supported cipher to be used for encryption"}, 52 1.1.1.6 christos {"passout", OPT_PASSOUT, 's', "Output PEM file pass phrase source"}, 53 1.1.1.6 christos {"traditional", OPT_TRADITIONAL, '-', 54 1.1.1.6 christos "Use traditional format for private key PEM output"}, 55 1.1.1.6 christos {"pubout", OPT_PUBOUT, '-', "Restrict encoded output to public components"}, 56 1.1.1.6 christos {"noout", OPT_NOOUT, '-', "Do not output the key in encoded form"}, 57 1.1.1.6 christos {"text", OPT_TEXT, '-', "Output key components in plaintext"}, 58 1.1.1.6 christos {"text_pub", OPT_TEXT_PUB, '-', 59 1.1.1.6 christos "Output only public key components in text form"}, 60 1.1.1.6 christos {"ec_conv_form", OPT_EC_CONV_FORM, 's', 61 1.1.1.6 christos "Specifies the EC point conversion form in the encoding"}, 62 1.1.1.6 christos {"ec_param_enc", OPT_EC_PARAM_ENC, 's', 63 1.1.1.6 christos "Specifies the way the EC parameters are encoded"}, 64 1.1.1.6 christos 65 1.1.1.4 christos {NULL} 66 1.1.1.4 christos }; 67 1.1 christos 68 1.1.1.4 christos int pkey_main(int argc, char **argv) 69 1.1.1.2 spz { 70 1.1.1.6 christos BIO *out = NULL; 71 1.1.1.4 christos ENGINE *e = NULL; 72 1.1.1.2 spz EVP_PKEY *pkey = NULL; 73 1.1.1.6 christos EVP_PKEY_CTX *ctx = NULL; 74 1.1.1.6 christos EVP_CIPHER *cipher = NULL; 75 1.1.1.4 christos char *infile = NULL, *outfile = NULL, *passin = NULL, *passout = NULL; 76 1.1.1.6 christos char *passinarg = NULL, *passoutarg = NULL, *ciphername = NULL, *prog; 77 1.1.1.4 christos OPTION_CHOICE o; 78 1.1.1.6 christos int informat = FORMAT_UNDEF, outformat = FORMAT_PEM; 79 1.1.1.6 christos int pubin = 0, pubout = 0, text_pub = 0, text = 0, noout = 0, ret = 1; 80 1.1.1.5 christos int private = 0, traditional = 0, check = 0, pub_check = 0; 81 1.1.1.6 christos #ifndef OPENSSL_NO_EC 82 1.1.1.6 christos char *asn1_encoding = NULL; 83 1.1.1.6 christos char *point_format = NULL; 84 1.1.1.6 christos #endif 85 1.1.1.4 christos 86 1.1.1.4 christos prog = opt_init(argc, argv, pkey_options); 87 1.1.1.4 christos while ((o = opt_next()) != OPT_EOF) { 88 1.1.1.4 christos switch (o) { 89 1.1.1.4 christos case OPT_EOF: 90 1.1.1.4 christos case OPT_ERR: 91 1.1.1.4 christos opthelp: 92 1.1.1.4 christos BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 93 1.1.1.4 christos goto end; 94 1.1.1.4 christos case OPT_HELP: 95 1.1.1.4 christos opt_help(pkey_options); 96 1.1.1.4 christos ret = 0; 97 1.1.1.4 christos goto end; 98 1.1.1.4 christos case OPT_INFORM: 99 1.1.1.4 christos if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) 100 1.1.1.4 christos goto opthelp; 101 1.1.1.4 christos break; 102 1.1.1.4 christos case OPT_OUTFORM: 103 1.1.1.4 christos if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) 104 1.1.1.4 christos goto opthelp; 105 1.1.1.4 christos break; 106 1.1.1.4 christos case OPT_PASSIN: 107 1.1.1.4 christos passinarg = opt_arg(); 108 1.1.1.4 christos break; 109 1.1.1.4 christos case OPT_PASSOUT: 110 1.1.1.4 christos passoutarg = opt_arg(); 111 1.1.1.4 christos break; 112 1.1.1.4 christos case OPT_ENGINE: 113 1.1.1.4 christos e = setup_engine(opt_arg(), 0); 114 1.1.1.4 christos break; 115 1.1.1.4 christos case OPT_IN: 116 1.1.1.4 christos infile = opt_arg(); 117 1.1.1.4 christos break; 118 1.1.1.4 christos case OPT_OUT: 119 1.1.1.4 christos outfile = opt_arg(); 120 1.1.1.4 christos break; 121 1.1.1.4 christos case OPT_PUBIN: 122 1.1.1.6 christos pubin = pubout = 1; 123 1.1.1.4 christos break; 124 1.1.1.4 christos case OPT_PUBOUT: 125 1.1.1.2 spz pubout = 1; 126 1.1.1.4 christos break; 127 1.1.1.4 christos case OPT_TEXT_PUB: 128 1.1.1.6 christos text_pub = 1; 129 1.1.1.4 christos break; 130 1.1.1.4 christos case OPT_TEXT: 131 1.1.1.2 spz text = 1; 132 1.1.1.4 christos break; 133 1.1.1.4 christos case OPT_NOOUT: 134 1.1.1.2 spz noout = 1; 135 1.1.1.4 christos break; 136 1.1.1.4 christos case OPT_TRADITIONAL: 137 1.1.1.4 christos traditional = 1; 138 1.1.1.4 christos break; 139 1.1.1.5 christos case OPT_CHECK: 140 1.1.1.5 christos check = 1; 141 1.1.1.5 christos break; 142 1.1.1.5 christos case OPT_PUB_CHECK: 143 1.1.1.5 christos pub_check = 1; 144 1.1.1.5 christos break; 145 1.1.1.6 christos case OPT_CIPHER: 146 1.1.1.6 christos ciphername = opt_unknown(); 147 1.1.1.6 christos break; 148 1.1.1.6 christos case OPT_EC_CONV_FORM: 149 1.1.1.6 christos #ifdef OPENSSL_NO_EC 150 1.1.1.6 christos goto opthelp; 151 1.1.1.6 christos #else 152 1.1.1.6 christos point_format = opt_arg(); 153 1.1.1.6 christos if (!opt_string(point_format, point_format_options)) 154 1.1.1.4 christos goto opthelp; 155 1.1.1.6 christos break; 156 1.1.1.6 christos #endif 157 1.1.1.6 christos case OPT_EC_PARAM_ENC: 158 1.1.1.6 christos #ifdef OPENSSL_NO_EC 159 1.1.1.6 christos goto opthelp; 160 1.1.1.6 christos #else 161 1.1.1.6 christos asn1_encoding = opt_arg(); 162 1.1.1.6 christos if (!opt_string(asn1_encoding, asn1_encoding_options)) 163 1.1.1.6 christos goto opthelp; 164 1.1.1.6 christos break; 165 1.1.1.6 christos #endif 166 1.1.1.6 christos case OPT_PROV_CASES: 167 1.1.1.6 christos if (!opt_provider(o)) 168 1.1.1.6 christos goto end; 169 1.1.1.6 christos break; 170 1.1.1.4 christos } 171 1.1.1.4 christos } 172 1.1.1.6 christos 173 1.1.1.6 christos /* No extra arguments. */ 174 1.1.1.4 christos argc = opt_num_rest(); 175 1.1.1.4 christos if (argc != 0) 176 1.1.1.4 christos goto opthelp; 177 1.1.1.4 christos 178 1.1.1.6 christos if (text && text_pub) 179 1.1.1.6 christos BIO_printf(bio_err, 180 1.1.1.6 christos "Warning: The -text option is ignored with -text_pub\n"); 181 1.1.1.6 christos if (traditional && (noout || outformat != FORMAT_PEM)) 182 1.1.1.6 christos BIO_printf(bio_err, 183 1.1.1.6 christos "Warning: The -traditional is ignored since there is no PEM output\n"); 184 1.1.1.6 christos 185 1.1.1.6 christos /* -pubout and -text is the same as -text_pub */ 186 1.1.1.6 christos if (!text_pub && pubout && text) { 187 1.1.1.6 christos text = 0; 188 1.1.1.6 christos text_pub = 1; 189 1.1.1.6 christos } 190 1.1 christos 191 1.1.1.6 christos private = (!noout && !pubout) || (text && !text_pub); 192 1.1.1.6 christos 193 1.1.1.6 christos if (ciphername != NULL) { 194 1.1.1.6 christos if (!opt_cipher(ciphername, &cipher)) 195 1.1.1.6 christos goto opthelp; 196 1.1.1.6 christos } 197 1.1.1.6 christos if (cipher == NULL) { 198 1.1.1.6 christos if (passoutarg != NULL) 199 1.1.1.6 christos BIO_printf(bio_err, 200 1.1.1.6 christos "Warning: The -passout option is ignored without a cipher option\n"); 201 1.1.1.6 christos } else { 202 1.1.1.6 christos if (noout || outformat != FORMAT_PEM) { 203 1.1.1.6 christos BIO_printf(bio_err, 204 1.1.1.6 christos "Error: Cipher options are supported only for PEM output\n"); 205 1.1.1.6 christos goto end; 206 1.1.1.6 christos } 207 1.1.1.6 christos } 208 1.1.1.4 christos if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 209 1.1.1.2 spz BIO_printf(bio_err, "Error getting passwords\n"); 210 1.1.1.2 spz goto end; 211 1.1.1.2 spz } 212 1.1.1.2 spz 213 1.1.1.4 christos out = bio_open_owner(outfile, outformat, private); 214 1.1.1.4 christos if (out == NULL) 215 1.1.1.4 christos goto end; 216 1.1 christos 217 1.1.1.2 spz if (pubin) 218 1.1.1.4 christos pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key"); 219 1.1.1.2 spz else 220 1.1.1.4 christos pkey = load_key(infile, informat, 1, passin, e, "key"); 221 1.1.1.5 christos if (pkey == NULL) 222 1.1.1.2 spz goto end; 223 1.1.1.2 spz 224 1.1.1.6 christos #ifndef OPENSSL_NO_EC 225 1.1.1.6 christos if (asn1_encoding != NULL || point_format != NULL) { 226 1.1.1.6 christos OSSL_PARAM params[3], *p = params; 227 1.1.1.6 christos 228 1.1.1.6 christos if (!EVP_PKEY_is_a(pkey, "EC")) 229 1.1.1.6 christos goto end; 230 1.1.1.6 christos 231 1.1.1.6 christos if (asn1_encoding != NULL) 232 1.1.1.6 christos *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, 233 1.1.1.6 christos asn1_encoding, 0); 234 1.1.1.6 christos if (point_format != NULL) 235 1.1.1.6 christos *p++ = OSSL_PARAM_construct_utf8_string( 236 1.1.1.6 christos OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, 237 1.1.1.6 christos point_format, 0); 238 1.1.1.6 christos *p = OSSL_PARAM_construct_end(); 239 1.1.1.6 christos if (EVP_PKEY_set_params(pkey, params) <= 0) 240 1.1.1.6 christos goto end; 241 1.1.1.6 christos } 242 1.1.1.6 christos #endif 243 1.1.1.6 christos 244 1.1.1.5 christos if (check || pub_check) { 245 1.1.1.5 christos int r; 246 1.1.1.5 christos 247 1.1.1.5 christos ctx = EVP_PKEY_CTX_new(pkey, e); 248 1.1.1.5 christos if (ctx == NULL) { 249 1.1.1.5 christos ERR_print_errors(bio_err); 250 1.1.1.5 christos goto end; 251 1.1.1.5 christos } 252 1.1.1.5 christos 253 1.1.1.6 christos if (check && !pubin) 254 1.1.1.5 christos r = EVP_PKEY_check(ctx); 255 1.1.1.5 christos else 256 1.1.1.5 christos r = EVP_PKEY_public_check(ctx); 257 1.1.1.5 christos 258 1.1.1.5 christos if (r == 1) { 259 1.1.1.5 christos BIO_printf(out, "Key is valid\n"); 260 1.1.1.5 christos } else { 261 1.1.1.5 christos /* 262 1.1.1.5 christos * Note: at least for RSA keys if this function returns 263 1.1.1.5 christos * -1, there will be no error reasons. 264 1.1.1.5 christos */ 265 1.1.1.6 christos BIO_printf(bio_err, "Key is invalid\n"); 266 1.1.1.6 christos ERR_print_errors(bio_err); 267 1.1.1.6 christos goto end; 268 1.1.1.5 christos } 269 1.1.1.5 christos } 270 1.1.1.5 christos 271 1.1.1.2 spz if (!noout) { 272 1.1.1.2 spz if (outformat == FORMAT_PEM) { 273 1.1.1.5 christos if (pubout) { 274 1.1.1.5 christos if (!PEM_write_bio_PUBKEY(out, pkey)) 275 1.1.1.5 christos goto end; 276 1.1.1.5 christos } else { 277 1.1.1.4 christos assert(private); 278 1.1.1.5 christos if (traditional) { 279 1.1.1.5 christos if (!PEM_write_bio_PrivateKey_traditional(out, pkey, cipher, 280 1.1.1.5 christos NULL, 0, NULL, 281 1.1.1.5 christos passout)) 282 1.1.1.5 christos goto end; 283 1.1.1.5 christos } else { 284 1.1.1.5 christos if (!PEM_write_bio_PrivateKey(out, pkey, cipher, 285 1.1.1.5 christos NULL, 0, NULL, passout)) 286 1.1.1.5 christos goto end; 287 1.1.1.5 christos } 288 1.1.1.4 christos } 289 1.1.1.2 spz } else if (outformat == FORMAT_ASN1) { 290 1.1.1.6 christos if (text || text_pub) { 291 1.1.1.6 christos BIO_printf(bio_err, 292 1.1.1.6 christos "Error: Text output cannot be combined with DER output\n"); 293 1.1.1.6 christos goto end; 294 1.1.1.6 christos } 295 1.1.1.5 christos if (pubout) { 296 1.1.1.5 christos if (!i2d_PUBKEY_bio(out, pkey)) 297 1.1.1.5 christos goto end; 298 1.1.1.5 christos } else { 299 1.1.1.4 christos assert(private); 300 1.1.1.5 christos if (!i2d_PrivateKey_bio(out, pkey)) 301 1.1.1.5 christos goto end; 302 1.1.1.4 christos } 303 1.1.1.2 spz } else { 304 1.1.1.2 spz BIO_printf(bio_err, "Bad format specified for key\n"); 305 1.1.1.2 spz goto end; 306 1.1.1.2 spz } 307 1.1.1.2 spz } 308 1.1.1.2 spz 309 1.1.1.6 christos if (text_pub) { 310 1.1.1.6 christos if (EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) 311 1.1.1.6 christos goto end; 312 1.1.1.6 christos } else if (text) { 313 1.1.1.6 christos assert(private); 314 1.1.1.6 christos if (EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0) 315 1.1.1.6 christos goto end; 316 1.1.1.2 spz } 317 1.1.1.2 spz 318 1.1.1.2 spz ret = 0; 319 1.1.1.2 spz 320 1.1.1.2 spz end: 321 1.1.1.5 christos if (ret != 0) 322 1.1.1.5 christos ERR_print_errors(bio_err); 323 1.1.1.6 christos EVP_PKEY_CTX_free(ctx); 324 1.1.1.2 spz EVP_PKEY_free(pkey); 325 1.1.1.6 christos EVP_CIPHER_free(cipher); 326 1.1.1.3 spz release_engine(e); 327 1.1.1.2 spz BIO_free_all(out); 328 1.1.1.4 christos OPENSSL_free(passin); 329 1.1.1.4 christos OPENSSL_free(passout); 330 1.1 christos 331 1.1.1.2 spz return ret; 332 1.1.1.2 spz } 333