Annotation of src/usr.bin/openssl/ec.c, Revision 1.3
1.3 ! doug 1: /* $OpenBSD: ec.c,v 1.2 2014/08/28 14:23:52 jsing Exp $ */
1.1 jsing 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:
1.3 ! doug 63: #include <ctype.h>
1.1 jsing 64: #include <stdio.h>
65: #include <stdlib.h>
66: #include <string.h>
67:
68: #include "apps.h"
69:
70: #include <openssl/bio.h>
71: #include <openssl/err.h>
72: #include <openssl/evp.h>
73: #include <openssl/pem.h>
74:
1.3 ! doug 75: static struct {
! 76: int asn1_flag;
! 77: const EVP_CIPHER *enc;
! 78: #ifndef OPENSSL_NO_ENGINE
! 79: char *engine;
! 80: #endif
! 81: point_conversion_form_t form;
! 82: char *infile;
! 83: int informat;
! 84: char *outfile;
! 85: int outformat;
! 86: int new_asn1_flag;
! 87: int new_form;
! 88: int noout;
! 89: int param_out;
! 90: char *passargin;
! 91: char *passargout;
! 92: int pubin;
! 93: int pubout;
! 94: int text;
! 95: } ec_config;
! 96:
! 97: static int
! 98: ec_opt_enc(int argc, char **argv, int *argsused)
! 99: {
! 100: char *name = argv[0];
! 101:
! 102: if (*name++ != '-')
! 103: return (1);
! 104:
! 105: if ((ec_config.enc = EVP_get_cipherbyname(name)) != NULL) {
! 106: *argsused = 1;
! 107: return (0);
! 108: }
! 109:
! 110: return (1);
! 111: }
! 112:
! 113: static int
! 114: ec_opt_form(char *arg)
! 115: {
! 116: if (strcmp(arg, "compressed") == 0)
! 117: ec_config.form = POINT_CONVERSION_COMPRESSED;
! 118: else if (strcmp(arg, "uncompressed") == 0)
! 119: ec_config.form = POINT_CONVERSION_UNCOMPRESSED;
! 120: else if (strcmp(arg, "hybrid") == 0)
! 121: ec_config.form = POINT_CONVERSION_HYBRID;
! 122: else {
! 123: fprintf(stderr, "Invalid point conversion: %s\n", arg);
! 124: return (1);
! 125: }
! 126:
! 127: ec_config.new_form = 1;
! 128: return (0);
! 129: }
! 130:
! 131: static int
! 132: ec_opt_named(char *arg)
! 133: {
! 134: if (strcmp(arg, "named_curve") == 0)
! 135: ec_config.asn1_flag = OPENSSL_EC_NAMED_CURVE;
! 136: else if (strcmp(arg, "explicit") == 0)
! 137: ec_config.asn1_flag = 0;
! 138: else {
! 139: fprintf(stderr, "Invalid curve type: %s\n", arg);
! 140: return (1);
! 141: }
! 142:
! 143: ec_config.new_asn1_flag = 1;
! 144: return (0);
! 145: }
! 146:
! 147: static struct option ec_options[] = {
! 148: {
! 149: .name = "conv_form",
! 150: .argname = "form",
! 151: .desc = "Specify the point conversion form (default"
! 152: " \"named_curve\")",
! 153: .type = OPTION_ARG_FUNC,
! 154: .opt.argfunc = ec_opt_form,
! 155: },
! 156: #ifndef OPENSSL_NO_ENGINE
! 157: {
! 158: .name = "engine",
! 159: .argname = "id",
! 160: .desc = "Use the engine specified by the given identifier",
! 161: .type = OPTION_ARG,
! 162: .opt.arg = &ec_config.engine,
! 163: },
! 164: #endif
! 165: {
! 166: .name = "in",
! 167: .argname = "file",
! 168: .desc = "Input file (default stdin)",
! 169: .type = OPTION_ARG,
! 170: .opt.arg = &ec_config.infile,
! 171: },
! 172: {
! 173: .name = "inform",
! 174: .argname = "format",
! 175: .desc = "Input format (DER or PEM (default))",
! 176: .type = OPTION_ARG_FORMAT,
! 177: .opt.value = &ec_config.informat,
! 178: },
! 179: {
! 180: .name = "noout",
! 181: .desc = "No output",
! 182: .type = OPTION_FLAG,
! 183: .opt.flag = &ec_config.noout,
! 184: },
! 185: {
! 186: .name = "out",
! 187: .argname = "file",
! 188: .desc = "Output file (default stdout)",
! 189: .type = OPTION_ARG,
! 190: .opt.arg = &ec_config.outfile,
! 191: },
! 192: {
! 193: .name = "outform",
! 194: .argname = "format",
! 195: .desc = "Output format (DER or PEM (default))",
! 196: .type = OPTION_ARG_FORMAT,
! 197: .opt.value = &ec_config.outformat,
! 198: },
! 199: {
! 200: .name = "param_enc",
! 201: .argname = "type",
! 202: .desc = "Specify the way the ec parameters are encoded"
! 203: " (default \"uncompressed\")",
! 204: .type = OPTION_ARG_FUNC,
! 205: .opt.argfunc = ec_opt_named,
! 206: },
! 207: {
! 208: .name = "param_out",
! 209: .desc = "Print the elliptic curve parameters",
! 210: .type = OPTION_FLAG,
! 211: .opt.flag = &ec_config.param_out,
! 212: },
! 213: {
! 214: .name = "passin",
! 215: .argname = "source",
! 216: .desc = "Input file passphrase source",
! 217: .type = OPTION_ARG,
! 218: .opt.arg = &ec_config.passargin,
! 219: },
! 220: {
! 221: .name = "passout",
! 222: .argname = "source",
! 223: .desc = "Output file passphrase source",
! 224: .type = OPTION_ARG,
! 225: .opt.arg = &ec_config.passargout,
! 226: },
! 227: {
! 228: .name = "pubin",
! 229: .desc = "Read public key instead of private key from input",
! 230: .type = OPTION_FLAG,
! 231: .opt.flag = &ec_config.pubin,
! 232: },
! 233: {
! 234: .name = "pubout",
! 235: .desc = "Output public key instead of private key in output",
! 236: .type = OPTION_FLAG,
! 237: .opt.flag = &ec_config.pubout,
! 238: },
! 239: {
! 240: .name = "text",
! 241: .desc = "Print the public/private key components and parameters",
! 242: .type = OPTION_FLAG,
! 243: .opt.flag = &ec_config.text,
! 244: },
! 245: {
! 246: .name = NULL,
! 247: .desc = "Cipher to encrypt the output if using PEM format",
! 248: .type = OPTION_ARGV_FUNC,
! 249: .opt.argvfunc = ec_opt_enc,
! 250: },
! 251: { NULL },
! 252: };
! 253:
! 254: static void
! 255: show_ciphers(const OBJ_NAME *name, void *arg)
! 256: {
! 257: static int n;
! 258:
! 259: if (!islower((unsigned char)*name->name))
! 260: return;
! 261:
! 262: fprintf(stderr, " -%-24s%s", name->name, (++n % 3 ? "" : "\n"));
! 263: }
! 264:
! 265: static void
! 266: ec_usage(void)
! 267: {
! 268: fprintf(stderr,
! 269: "usage: ec [-conv_form form] [-engine id] [-in file]\n"
! 270: " [-inform format] [-noout] [-out file] [-outform format]\n"
! 271: " [-param_enc type] [-param_out] [-passin file]\n"
! 272: " [-passout file] [-pubin] [-pubout] [-text] [-ciphername]\n\n");
! 273: options_usage(ec_options);
! 274:
! 275: fprintf(stderr, "\n");
! 276:
! 277: fprintf(stderr, "Valid ciphername values:\n\n");
! 278: OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_ciphers, NULL);
! 279: fprintf(stderr, "\n");
! 280: }
1.1 jsing 281:
282: int ec_main(int, char **);
283:
284: int
285: ec_main(int argc, char **argv)
286: {
287: int ret = 1;
288: EC_KEY *eckey = NULL;
289: const EC_GROUP *group;
1.3 ! doug 290: int i;
1.1 jsing 291: BIO *in = NULL, *out = NULL;
292: char *passin = NULL, *passout = NULL;
293:
1.3 ! doug 294: memset(&ec_config, 0, sizeof(ec_config));
! 295:
! 296: ec_config.asn1_flag = OPENSSL_EC_NAMED_CURVE;
! 297: ec_config.form = POINT_CONVERSION_UNCOMPRESSED;
! 298: ec_config.informat = FORMAT_PEM;
! 299: ec_config.outformat = FORMAT_PEM;
! 300:
! 301: if (options_parse(argc, argv, ec_options, NULL, NULL) != 0) {
! 302: ec_usage();
1.1 jsing 303: goto end;
304: }
305:
306: #ifndef OPENSSL_NO_ENGINE
1.3 ! doug 307: setup_engine(bio_err, ec_config.engine, 0);
1.1 jsing 308: #endif
309:
1.3 ! doug 310: if (!app_passwd(bio_err, ec_config.passargin, ec_config.passargout,
! 311: &passin, &passout)) {
1.1 jsing 312: BIO_printf(bio_err, "Error getting passwords\n");
313: goto end;
314: }
315: in = BIO_new(BIO_s_file());
316: out = BIO_new(BIO_s_file());
1.3 ! doug 317: if (in == NULL || out == NULL) {
1.1 jsing 318: ERR_print_errors(bio_err);
319: goto end;
320: }
1.3 ! doug 321: if (ec_config.infile == NULL)
1.1 jsing 322: BIO_set_fp(in, stdin, BIO_NOCLOSE);
323: else {
1.3 ! doug 324: if (BIO_read_filename(in, ec_config.infile) <= 0) {
! 325: perror(ec_config.infile);
1.1 jsing 326: goto end;
327: }
328: }
329:
330: BIO_printf(bio_err, "read EC key\n");
1.3 ! doug 331: if (ec_config.informat == FORMAT_ASN1) {
! 332: if (ec_config.pubin)
1.1 jsing 333: eckey = d2i_EC_PUBKEY_bio(in, NULL);
334: else
335: eckey = d2i_ECPrivateKey_bio(in, NULL);
1.3 ! doug 336: } else if (ec_config.informat == FORMAT_PEM) {
! 337: if (ec_config.pubin)
1.1 jsing 338: eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL,
339: NULL);
340: else
341: eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL,
342: passin);
343: } else {
344: BIO_printf(bio_err, "bad input format specified for key\n");
345: goto end;
346: }
347: if (eckey == NULL) {
348: BIO_printf(bio_err, "unable to load Key\n");
349: ERR_print_errors(bio_err);
350: goto end;
351: }
1.3 ! doug 352: if (ec_config.outfile == NULL) {
1.1 jsing 353: BIO_set_fp(out, stdout, BIO_NOCLOSE);
354: } else {
1.3 ! doug 355: if (BIO_write_filename(out, ec_config.outfile) <= 0) {
! 356: perror(ec_config.outfile);
1.1 jsing 357: goto end;
358: }
359: }
360:
361: group = EC_KEY_get0_group(eckey);
362:
1.3 ! doug 363: if (ec_config.new_form)
! 364: EC_KEY_set_conv_form(eckey, ec_config.form);
1.1 jsing 365:
1.3 ! doug 366: if (ec_config.new_asn1_flag)
! 367: EC_KEY_set_asn1_flag(eckey, ec_config.asn1_flag);
1.1 jsing 368:
1.3 ! doug 369: if (ec_config.text)
1.1 jsing 370: if (!EC_KEY_print(out, eckey, 0)) {
1.3 ! doug 371: perror(ec_config.outfile);
1.1 jsing 372: ERR_print_errors(bio_err);
373: goto end;
374: }
1.3 ! doug 375: if (ec_config.noout) {
1.1 jsing 376: ret = 0;
377: goto end;
378: }
379: BIO_printf(bio_err, "writing EC key\n");
1.3 ! doug 380: if (ec_config.outformat == FORMAT_ASN1) {
! 381: if (ec_config.param_out)
1.1 jsing 382: i = i2d_ECPKParameters_bio(out, group);
1.3 ! doug 383: else if (ec_config.pubin || ec_config.pubout)
1.1 jsing 384: i = i2d_EC_PUBKEY_bio(out, eckey);
385: else
386: i = i2d_ECPrivateKey_bio(out, eckey);
1.3 ! doug 387: } else if (ec_config.outformat == FORMAT_PEM) {
! 388: if (ec_config.param_out)
1.1 jsing 389: i = PEM_write_bio_ECPKParameters(out, group);
1.3 ! doug 390: else if (ec_config.pubin || ec_config.pubout)
1.1 jsing 391: i = PEM_write_bio_EC_PUBKEY(out, eckey);
392: else
1.3 ! doug 393: i = PEM_write_bio_ECPrivateKey(out, eckey,
! 394: ec_config.enc, NULL, 0, NULL, passout);
1.1 jsing 395: } else {
396: BIO_printf(bio_err, "bad output format specified for "
397: "outfile\n");
398: goto end;
399: }
400:
401: if (!i) {
402: BIO_printf(bio_err, "unable to write private key\n");
403: ERR_print_errors(bio_err);
404: } else
405: ret = 0;
406: end:
407: BIO_free(in);
408: if (out)
409: BIO_free_all(out);
410: if (eckey)
411: EC_KEY_free(eckey);
412: free(passin);
413: free(passout);
414:
415: return (ret);
416: }
417: #endif