1 /* $OpenBSD: ec.c,v 1.16 2023/03/06 14:32:06 tb 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 } cfg; 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 ((cfg.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 cfg.form = POINT_CONVERSION_COMPRESSED; 114 else if (strcmp(arg, "uncompressed") == 0) 115 cfg.form = POINT_CONVERSION_UNCOMPRESSED; 116 else if (strcmp(arg, "hybrid") == 0) 117 cfg.form = POINT_CONVERSION_HYBRID; 118 else { 119 fprintf(stderr, "Invalid point conversion: %s\n", arg); 120 return (1); 121 } 122 123 cfg.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 cfg.asn1_flag = OPENSSL_EC_NAMED_CURVE; 132 else if (strcmp(arg, "explicit") == 0) 133 cfg.asn1_flag = 0; 134 else { 135 fprintf(stderr, "Invalid curve type: %s\n", arg); 136 return (1); 137 } 138 139 cfg.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 = &cfg.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 = &cfg.informat, 165 }, 166 { 167 .name = "noout", 168 .desc = "No output", 169 .type = OPTION_FLAG, 170 .opt.flag = &cfg.noout, 171 }, 172 { 173 .name = "out", 174 .argname = "file", 175 .desc = "Output file (default stdout)", 176 .type = OPTION_ARG, 177 .opt.arg = &cfg.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 = &cfg.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 = &cfg.param_out, 199 }, 200 { 201 .name = "passin", 202 .argname = "source", 203 .desc = "Input file passphrase source", 204 .type = OPTION_ARG, 205 .opt.arg = &cfg.passargin, 206 }, 207 { 208 .name = "passout", 209 .argname = "source", 210 .desc = "Output file passphrase source", 211 .type = OPTION_ARG, 212 .opt.arg = &cfg.passargout, 213 }, 214 { 215 .name = "pubin", 216 .desc = "Read public key instead of private key from input", 217 .type = OPTION_FLAG, 218 .opt.flag = &cfg.pubin, 219 }, 220 { 221 .name = "pubout", 222 .desc = "Output public key instead of private key in output", 223 .type = OPTION_FLAG, 224 .opt.flag = &cfg.pubout, 225 }, 226 { 227 .name = "text", 228 .desc = "Print the public/private key components and parameters", 229 .type = OPTION_FLAG, 230 .opt.flag = &cfg.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 (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 271 perror("pledge"); 272 exit(1); 273 } 274 275 memset(&cfg, 0, sizeof(cfg)); 276 277 cfg.asn1_flag = OPENSSL_EC_NAMED_CURVE; 278 cfg.form = POINT_CONVERSION_UNCOMPRESSED; 279 cfg.informat = FORMAT_PEM; 280 cfg.outformat = FORMAT_PEM; 281 282 if (options_parse(argc, argv, ec_options, NULL, NULL) != 0) { 283 ec_usage(); 284 goto end; 285 } 286 287 if (!app_passwd(bio_err, cfg.passargin, cfg.passargout, 288 &passin, &passout)) { 289 BIO_printf(bio_err, "Error getting passwords\n"); 290 goto end; 291 } 292 in = BIO_new(BIO_s_file()); 293 out = BIO_new(BIO_s_file()); 294 if (in == NULL || out == NULL) { 295 ERR_print_errors(bio_err); 296 goto end; 297 } 298 if (cfg.infile == NULL) 299 BIO_set_fp(in, stdin, BIO_NOCLOSE); 300 else { 301 if (BIO_read_filename(in, cfg.infile) <= 0) { 302 perror(cfg.infile); 303 goto end; 304 } 305 } 306 307 BIO_printf(bio_err, "read EC key\n"); 308 if (cfg.informat == FORMAT_ASN1) { 309 if (cfg.pubin) 310 eckey = d2i_EC_PUBKEY_bio(in, NULL); 311 else 312 eckey = d2i_ECPrivateKey_bio(in, NULL); 313 } else if (cfg.informat == FORMAT_PEM) { 314 if (cfg.pubin) 315 eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, 316 NULL); 317 else 318 eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL, 319 passin); 320 } else { 321 BIO_printf(bio_err, "bad input format specified for key\n"); 322 goto end; 323 } 324 if (eckey == NULL) { 325 BIO_printf(bio_err, "unable to load Key\n"); 326 ERR_print_errors(bio_err); 327 goto end; 328 } 329 if (cfg.outfile == NULL) { 330 BIO_set_fp(out, stdout, BIO_NOCLOSE); 331 } else { 332 if (BIO_write_filename(out, cfg.outfile) <= 0) { 333 perror(cfg.outfile); 334 goto end; 335 } 336 } 337 338 group = EC_KEY_get0_group(eckey); 339 340 if (cfg.new_form) 341 EC_KEY_set_conv_form(eckey, cfg.form); 342 343 if (cfg.new_asn1_flag) 344 EC_KEY_set_asn1_flag(eckey, cfg.asn1_flag); 345 346 if (cfg.text) 347 if (!EC_KEY_print(out, eckey, 0)) { 348 perror(cfg.outfile); 349 ERR_print_errors(bio_err); 350 goto end; 351 } 352 if (cfg.noout) { 353 ret = 0; 354 goto end; 355 } 356 BIO_printf(bio_err, "writing EC key\n"); 357 if (cfg.outformat == FORMAT_ASN1) { 358 if (cfg.param_out) 359 i = i2d_ECPKParameters_bio(out, group); 360 else if (cfg.pubin || cfg.pubout) 361 i = i2d_EC_PUBKEY_bio(out, eckey); 362 else 363 i = i2d_ECPrivateKey_bio(out, eckey); 364 } else if (cfg.outformat == FORMAT_PEM) { 365 if (cfg.param_out) 366 i = PEM_write_bio_ECPKParameters(out, group); 367 else if (cfg.pubin || cfg.pubout) 368 i = PEM_write_bio_EC_PUBKEY(out, eckey); 369 else 370 i = PEM_write_bio_ECPrivateKey(out, eckey, 371 cfg.enc, NULL, 0, NULL, passout); 372 } else { 373 BIO_printf(bio_err, "bad output format specified for " 374 "outfile\n"); 375 goto end; 376 } 377 378 if (!i) { 379 BIO_printf(bio_err, "unable to write private key\n"); 380 ERR_print_errors(bio_err); 381 } else 382 ret = 0; 383 end: 384 BIO_free(in); 385 BIO_free_all(out); 386 EC_KEY_free(eckey); 387 free(passin); 388 free(passout); 389 390 return (ret); 391 } 392 #endif 393