Annotation of src/usr.bin/openssl/ec.c, Revision 1.9
1.9 ! deraadt 1: /* $OpenBSD: ec.c,v 1.8 2015/10/17 15:00:11 doug 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;
1.6 doug 279:
280: if (single_execution) {
1.9 ! deraadt 281: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.6 doug 282: perror("pledge");
1.8 doug 283: exit(1);
284: }
1.6 doug 285: }
1.1 jsing 286:
1.3 doug 287: memset(&ec_config, 0, sizeof(ec_config));
288:
289: ec_config.asn1_flag = OPENSSL_EC_NAMED_CURVE;
290: ec_config.form = POINT_CONVERSION_UNCOMPRESSED;
291: ec_config.informat = FORMAT_PEM;
292: ec_config.outformat = FORMAT_PEM;
293:
294: if (options_parse(argc, argv, ec_options, NULL, NULL) != 0) {
295: ec_usage();
1.1 jsing 296: goto end;
297: }
298:
1.3 doug 299: if (!app_passwd(bio_err, ec_config.passargin, ec_config.passargout,
300: &passin, &passout)) {
1.1 jsing 301: BIO_printf(bio_err, "Error getting passwords\n");
302: goto end;
303: }
304: in = BIO_new(BIO_s_file());
305: out = BIO_new(BIO_s_file());
1.3 doug 306: if (in == NULL || out == NULL) {
1.1 jsing 307: ERR_print_errors(bio_err);
308: goto end;
309: }
1.3 doug 310: if (ec_config.infile == NULL)
1.1 jsing 311: BIO_set_fp(in, stdin, BIO_NOCLOSE);
312: else {
1.3 doug 313: if (BIO_read_filename(in, ec_config.infile) <= 0) {
314: perror(ec_config.infile);
1.1 jsing 315: goto end;
316: }
317: }
318:
319: BIO_printf(bio_err, "read EC key\n");
1.3 doug 320: if (ec_config.informat == FORMAT_ASN1) {
321: if (ec_config.pubin)
1.1 jsing 322: eckey = d2i_EC_PUBKEY_bio(in, NULL);
323: else
324: eckey = d2i_ECPrivateKey_bio(in, NULL);
1.3 doug 325: } else if (ec_config.informat == FORMAT_PEM) {
326: if (ec_config.pubin)
1.1 jsing 327: eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL,
328: NULL);
329: else
330: eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL,
331: passin);
332: } else {
333: BIO_printf(bio_err, "bad input format specified for key\n");
334: goto end;
335: }
336: if (eckey == NULL) {
337: BIO_printf(bio_err, "unable to load Key\n");
338: ERR_print_errors(bio_err);
339: goto end;
340: }
1.3 doug 341: if (ec_config.outfile == NULL) {
1.1 jsing 342: BIO_set_fp(out, stdout, BIO_NOCLOSE);
343: } else {
1.3 doug 344: if (BIO_write_filename(out, ec_config.outfile) <= 0) {
345: perror(ec_config.outfile);
1.1 jsing 346: goto end;
347: }
348: }
349:
350: group = EC_KEY_get0_group(eckey);
351:
1.3 doug 352: if (ec_config.new_form)
353: EC_KEY_set_conv_form(eckey, ec_config.form);
1.1 jsing 354:
1.3 doug 355: if (ec_config.new_asn1_flag)
356: EC_KEY_set_asn1_flag(eckey, ec_config.asn1_flag);
1.1 jsing 357:
1.3 doug 358: if (ec_config.text)
1.1 jsing 359: if (!EC_KEY_print(out, eckey, 0)) {
1.3 doug 360: perror(ec_config.outfile);
1.1 jsing 361: ERR_print_errors(bio_err);
362: goto end;
363: }
1.3 doug 364: if (ec_config.noout) {
1.1 jsing 365: ret = 0;
366: goto end;
367: }
368: BIO_printf(bio_err, "writing EC key\n");
1.3 doug 369: if (ec_config.outformat == FORMAT_ASN1) {
370: if (ec_config.param_out)
1.1 jsing 371: i = i2d_ECPKParameters_bio(out, group);
1.3 doug 372: else if (ec_config.pubin || ec_config.pubout)
1.1 jsing 373: i = i2d_EC_PUBKEY_bio(out, eckey);
374: else
375: i = i2d_ECPrivateKey_bio(out, eckey);
1.3 doug 376: } else if (ec_config.outformat == FORMAT_PEM) {
377: if (ec_config.param_out)
1.1 jsing 378: i = PEM_write_bio_ECPKParameters(out, group);
1.3 doug 379: else if (ec_config.pubin || ec_config.pubout)
1.1 jsing 380: i = PEM_write_bio_EC_PUBKEY(out, eckey);
381: else
1.3 doug 382: i = PEM_write_bio_ECPrivateKey(out, eckey,
383: ec_config.enc, NULL, 0, NULL, passout);
1.1 jsing 384: } else {
385: BIO_printf(bio_err, "bad output format specified for "
386: "outfile\n");
387: goto end;
388: }
389:
390: if (!i) {
391: BIO_printf(bio_err, "unable to write private key\n");
392: ERR_print_errors(bio_err);
393: } else
394: ret = 0;
395: end:
396: BIO_free(in);
397: if (out)
398: BIO_free_all(out);
399: if (eckey)
400: EC_KEY_free(eckey);
401: free(passin);
402: free(passout);
403:
404: return (ret);
405: }
406: #endif