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