1 /* $OpenBSD: ec.c,v 1.14 2019/07/14 03:30:45 guenther Exp $ */ 2 /* 3 * Written by Nils Larsch for the OpenSSL project. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * openssl-core@openssl.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59 #include <openssl/opensslconf.h> 60 61 #ifndef OPENSSL_NO_EC 62 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 67 #include "apps.h" 68 69 #include <openssl/bio.h> 70 #include <openssl/err.h> 71 #include <openssl/evp.h> 72 #include <openssl/pem.h> 73 74 static struct { 75 int asn1_flag; 76 const EVP_CIPHER *enc; 77 point_conversion_form_t form; 78 char *infile; 79 int informat; 80 char *outfile; 81 int outformat; 82 int new_asn1_flag; 83 int new_form; 84 int noout; 85 int param_out; 86 char *passargin; 87 char *passargout; 88 int pubin; 89 int pubout; 90 int text; 91 } ec_config; 92 93 static int 94 ec_opt_enc(int argc, char **argv, int *argsused) 95 { 96 char *name = argv[0]; 97 98 if (*name++ != '-') 99 return (1); 100 101 if ((ec_config.enc = EVP_get_cipherbyname(name)) != NULL) { 102 *argsused = 1; 103 return (0); 104 } 105 106 return (1); 107 } 108 109 static int 110 ec_opt_form(char *arg) 111 { 112 if (strcmp(arg, "compressed") == 0) 113 ec_config.form = POINT_CONVERSION_COMPRESSED; 114 else if (strcmp(arg, "uncompressed") == 0) 115 ec_config.form = POINT_CONVERSION_UNCOMPRESSED; 116 else if (strcmp(arg, "hybrid") == 0) 117 ec_config.form = POINT_CONVERSION_HYBRID; 118 else { 119 fprintf(stderr, "Invalid point conversion: %s\n", arg); 120 return (1); 121 } 122 123 ec_config.new_form = 1; 124 return (0); 125 } 126 127 static int 128 ec_opt_named(char *arg) 129 { 130 if (strcmp(arg, "named_curve") == 0) 131 ec_config.asn1_flag = OPENSSL_EC_NAMED_CURVE; 132 else if (strcmp(arg, "explicit") == 0) 133 ec_config.asn1_flag = 0; 134 else { 135 fprintf(stderr, "Invalid curve type: %s\n", arg); 136 return (1); 137 } 138 139 ec_config.new_asn1_flag = 1; 140 return (0); 141 } 142 143 static const struct option ec_options[] = { 144 { 145 .name = "conv_form", 146 .argname = "form", 147 .desc = "Specify the point conversion form (default" 148 " \"named_curve\")", 149 .type = OPTION_ARG_FUNC, 150 .opt.argfunc = ec_opt_form, 151 }, 152 { 153 .name = "in", 154 .argname = "file", 155 .desc = "Input file (default stdin)", 156 .type = OPTION_ARG, 157 .opt.arg = &ec_config.infile, 158 }, 159 { 160 .name = "inform", 161 .argname = "format", 162 .desc = "Input format (DER or PEM (default))", 163 .type = OPTION_ARG_FORMAT, 164 .opt.value = &ec_config.informat, 165 }, 166 { 167 .name = "noout", 168 .desc = "No output", 169 .type = OPTION_FLAG, 170 .opt.flag = &ec_config.noout, 171 }, 172 { 173 .name = "out", 174 .argname = "file", 175 .desc = "Output file (default stdout)", 176 .type = OPTION_ARG, 177 .opt.arg = &ec_config.outfile, 178 }, 179 { 180 .name = "outform", 181 .argname = "format", 182 .desc = "Output format (DER or PEM (default))", 183 .type = OPTION_ARG_FORMAT, 184 .opt.value = &ec_config.outformat, 185 }, 186 { 187 .name = "param_enc", 188 .argname = "type", 189 .desc = "Specify the way the ec parameters are encoded" 190 " (default \"uncompressed\")", 191 .type = OPTION_ARG_FUNC, 192 .opt.argfunc = ec_opt_named, 193 }, 194 { 195 .name = "param_out", 196 .desc = "Print the elliptic curve parameters", 197 .type = OPTION_FLAG, 198 .opt.flag = &ec_config.param_out, 199 }, 200 { 201 .name = "passin", 202 .argname = "source", 203 .desc = "Input file passphrase source", 204 .type = OPTION_ARG, 205 .opt.arg = &ec_config.passargin, 206 }, 207 { 208 .name = "passout", 209 .argname = "source", 210 .desc = "Output file passphrase source", 211 .type = OPTION_ARG, 212 .opt.arg = &ec_config.passargout, 213 }, 214 { 215 .name = "pubin", 216 .desc = "Read public key instead of private key from input", 217 .type = OPTION_FLAG, 218 .opt.flag = &ec_config.pubin, 219 }, 220 { 221 .name = "pubout", 222 .desc = "Output public key instead of private key in output", 223 .type = OPTION_FLAG, 224 .opt.flag = &ec_config.pubout, 225 }, 226 { 227 .name = "text", 228 .desc = "Print the public/private key components and parameters", 229 .type = OPTION_FLAG, 230 .opt.flag = &ec_config.text, 231 }, 232 { 233 .name = NULL, 234 .desc = "Cipher to encrypt the output if using PEM format", 235 .type = OPTION_ARGV_FUNC, 236 .opt.argvfunc = ec_opt_enc, 237 }, 238 { NULL }, 239 }; 240 241 static void 242 ec_usage(void) 243 { 244 int n = 0; 245 246 fprintf(stderr, 247 "usage: ec [-conv_form form] [-in file]\n" 248 " [-inform format] [-noout] [-out file] [-outform format]\n" 249 " [-param_enc type] [-param_out] [-passin file]\n" 250 " [-passout file] [-pubin] [-pubout] [-text] [-ciphername]\n\n"); 251 options_usage(ec_options); 252 253 fprintf(stderr, "\n"); 254 255 fprintf(stderr, "Valid ciphername values:\n\n"); 256 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_cipher, &n); 257 fprintf(stderr, "\n"); 258 } 259 260 int 261 ec_main(int argc, char **argv) 262 { 263 int ret = 1; 264 EC_KEY *eckey = NULL; 265 const EC_GROUP *group; 266 int i; 267 BIO *in = NULL, *out = NULL; 268 char *passin = NULL, *passout = NULL; 269 270 if (single_execution) { 271 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 272 perror("pledge"); 273 exit(1); 274 } 275 } 276 277 memset(&ec_config, 0, sizeof(ec_config)); 278 279 ec_config.asn1_flag = OPENSSL_EC_NAMED_CURVE; 280 ec_config.form = POINT_CONVERSION_UNCOMPRESSED; 281 ec_config.informat = FORMAT_PEM; 282 ec_config.outformat = FORMAT_PEM; 283 284 if (options_parse(argc, argv, ec_options, NULL, NULL) != 0) { 285 ec_usage(); 286 goto end; 287 } 288 289 if (!app_passwd(bio_err, ec_config.passargin, ec_config.passargout, 290 &passin, &passout)) { 291 BIO_printf(bio_err, "Error getting passwords\n"); 292 goto end; 293 } 294 in = BIO_new(BIO_s_file()); 295 out = BIO_new(BIO_s_file()); 296 if (in == NULL || out == NULL) { 297 ERR_print_errors(bio_err); 298 goto end; 299 } 300 if (ec_config.infile == NULL) 301 BIO_set_fp(in, stdin, BIO_NOCLOSE); 302 else { 303 if (BIO_read_filename(in, ec_config.infile) <= 0) { 304 perror(ec_config.infile); 305 goto end; 306 } 307 } 308 309 BIO_printf(bio_err, "read EC key\n"); 310 if (ec_config.informat == FORMAT_ASN1) { 311 if (ec_config.pubin) 312 eckey = d2i_EC_PUBKEY_bio(in, NULL); 313 else 314 eckey = d2i_ECPrivateKey_bio(in, NULL); 315 } else if (ec_config.informat == FORMAT_PEM) { 316 if (ec_config.pubin) 317 eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, 318 NULL); 319 else 320 eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL, 321 passin); 322 } else { 323 BIO_printf(bio_err, "bad input format specified for key\n"); 324 goto end; 325 } 326 if (eckey == NULL) { 327 BIO_printf(bio_err, "unable to load Key\n"); 328 ERR_print_errors(bio_err); 329 goto end; 330 } 331 if (ec_config.outfile == NULL) { 332 BIO_set_fp(out, stdout, BIO_NOCLOSE); 333 } else { 334 if (BIO_write_filename(out, ec_config.outfile) <= 0) { 335 perror(ec_config.outfile); 336 goto end; 337 } 338 } 339 340 group = EC_KEY_get0_group(eckey); 341 342 if (ec_config.new_form) 343 EC_KEY_set_conv_form(eckey, ec_config.form); 344 345 if (ec_config.new_asn1_flag) 346 EC_KEY_set_asn1_flag(eckey, ec_config.asn1_flag); 347 348 if (ec_config.text) 349 if (!EC_KEY_print(out, eckey, 0)) { 350 perror(ec_config.outfile); 351 ERR_print_errors(bio_err); 352 goto end; 353 } 354 if (ec_config.noout) { 355 ret = 0; 356 goto end; 357 } 358 BIO_printf(bio_err, "writing EC key\n"); 359 if (ec_config.outformat == FORMAT_ASN1) { 360 if (ec_config.param_out) 361 i = i2d_ECPKParameters_bio(out, group); 362 else if (ec_config.pubin || ec_config.pubout) 363 i = i2d_EC_PUBKEY_bio(out, eckey); 364 else 365 i = i2d_ECPrivateKey_bio(out, eckey); 366 } else if (ec_config.outformat == FORMAT_PEM) { 367 if (ec_config.param_out) 368 i = PEM_write_bio_ECPKParameters(out, group); 369 else if (ec_config.pubin || ec_config.pubout) 370 i = PEM_write_bio_EC_PUBKEY(out, eckey); 371 else 372 i = PEM_write_bio_ECPrivateKey(out, eckey, 373 ec_config.enc, NULL, 0, NULL, passout); 374 } else { 375 BIO_printf(bio_err, "bad output format specified for " 376 "outfile\n"); 377 goto end; 378 } 379 380 if (!i) { 381 BIO_printf(bio_err, "unable to write private key\n"); 382 ERR_print_errors(bio_err); 383 } else 384 ret = 0; 385 end: 386 BIO_free(in); 387 BIO_free_all(out); 388 EC_KEY_free(eckey); 389 free(passin); 390 free(passout); 391 392 return (ret); 393 } 394 #endif 395