xref: /dragonfly/crypto/libressl/apps/openssl/ec.c (revision f5b1c8a1)
1 /* $OpenBSD: ec.c,v 1.7 2015/10/17 07:51:10 semarie 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 <ctype.h>
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 
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,
257 	    "usage: ec [-conv_form form] [-in file]\n"
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 }
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;
276 	int i;
277 	BIO *in = NULL, *out = NULL;
278 	char *passin = NULL, *passout = NULL;
279 
280 	if (single_execution) {
281 		if (pledge("stdio rpath wpath cpath tty", NULL) == -1) {
282 			perror("pledge");
283 			exit(1);
284 		}
285 	}
286 
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();
296 		goto end;
297 	}
298 
299 	if (!app_passwd(bio_err, ec_config.passargin, ec_config.passargout,
300 	    &passin, &passout)) {
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());
306 	if (in == NULL || out == NULL) {
307 		ERR_print_errors(bio_err);
308 		goto end;
309 	}
310 	if (ec_config.infile == NULL)
311 		BIO_set_fp(in, stdin, BIO_NOCLOSE);
312 	else {
313 		if (BIO_read_filename(in, ec_config.infile) <= 0) {
314 			perror(ec_config.infile);
315 			goto end;
316 		}
317 	}
318 
319 	BIO_printf(bio_err, "read EC key\n");
320 	if (ec_config.informat == FORMAT_ASN1) {
321 		if (ec_config.pubin)
322 			eckey = d2i_EC_PUBKEY_bio(in, NULL);
323 		else
324 			eckey = d2i_ECPrivateKey_bio(in, NULL);
325 	} else if (ec_config.informat == FORMAT_PEM) {
326 		if (ec_config.pubin)
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 	}
341 	if (ec_config.outfile == NULL) {
342 		BIO_set_fp(out, stdout, BIO_NOCLOSE);
343 	} else {
344 		if (BIO_write_filename(out, ec_config.outfile) <= 0) {
345 			perror(ec_config.outfile);
346 			goto end;
347 		}
348 	}
349 
350 	group = EC_KEY_get0_group(eckey);
351 
352 	if (ec_config.new_form)
353 		EC_KEY_set_conv_form(eckey, ec_config.form);
354 
355 	if (ec_config.new_asn1_flag)
356 		EC_KEY_set_asn1_flag(eckey, ec_config.asn1_flag);
357 
358 	if (ec_config.text)
359 		if (!EC_KEY_print(out, eckey, 0)) {
360 			perror(ec_config.outfile);
361 			ERR_print_errors(bio_err);
362 			goto end;
363 		}
364 	if (ec_config.noout) {
365 		ret = 0;
366 		goto end;
367 	}
368 	BIO_printf(bio_err, "writing EC key\n");
369 	if (ec_config.outformat == FORMAT_ASN1) {
370 		if (ec_config.param_out)
371 			i = i2d_ECPKParameters_bio(out, group);
372 		else if (ec_config.pubin || ec_config.pubout)
373 			i = i2d_EC_PUBKEY_bio(out, eckey);
374 		else
375 			i = i2d_ECPrivateKey_bio(out, eckey);
376 	} else if (ec_config.outformat == FORMAT_PEM) {
377 		if (ec_config.param_out)
378 			i = PEM_write_bio_ECPKParameters(out, group);
379 		else if (ec_config.pubin || ec_config.pubout)
380 			i = PEM_write_bio_EC_PUBKEY(out, eckey);
381 		else
382 			i = PEM_write_bio_ECPrivateKey(out, eckey,
383 			    ec_config.enc, NULL, 0, NULL, passout);
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
407