xref: /openbsd-src/usr.bin/openssl/ec.c (revision e7718adaf9bdf5a32db0f291795197a85ccbb6ed)
1*e7718adaStb /* $OpenBSD: ec.c,v 1.16 2023/03/06 14:32:06 tb Exp $ */
2dab3f910Sjsing /*
3dab3f910Sjsing  * Written by Nils Larsch for the OpenSSL project.
4dab3f910Sjsing  */
5dab3f910Sjsing /* ====================================================================
6dab3f910Sjsing  * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
7dab3f910Sjsing  *
8dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
9dab3f910Sjsing  * modification, are permitted provided that the following conditions
10dab3f910Sjsing  * are met:
11dab3f910Sjsing  *
12dab3f910Sjsing  * 1. Redistributions of source code must retain the above copyright
13dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
14dab3f910Sjsing  *
15dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
16dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in
17dab3f910Sjsing  *    the documentation and/or other materials provided with the
18dab3f910Sjsing  *    distribution.
19dab3f910Sjsing  *
20dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this
21dab3f910Sjsing  *    software must display the following acknowledgment:
22dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
23dab3f910Sjsing  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
24dab3f910Sjsing  *
25dab3f910Sjsing  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26dab3f910Sjsing  *    endorse or promote products derived from this software without
27dab3f910Sjsing  *    prior written permission. For written permission, please contact
28dab3f910Sjsing  *    openssl-core@openssl.org.
29dab3f910Sjsing  *
30dab3f910Sjsing  * 5. Products derived from this software may not be called "OpenSSL"
31dab3f910Sjsing  *    nor may "OpenSSL" appear in their names without prior written
32dab3f910Sjsing  *    permission of the OpenSSL Project.
33dab3f910Sjsing  *
34dab3f910Sjsing  * 6. Redistributions of any form whatsoever must retain the following
35dab3f910Sjsing  *    acknowledgment:
36dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
37dab3f910Sjsing  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
38dab3f910Sjsing  *
39dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40dab3f910Sjsing  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42dab3f910Sjsing  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43dab3f910Sjsing  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44dab3f910Sjsing  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45dab3f910Sjsing  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46dab3f910Sjsing  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48dab3f910Sjsing  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49dab3f910Sjsing  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50dab3f910Sjsing  * OF THE POSSIBILITY OF SUCH DAMAGE.
51dab3f910Sjsing  * ====================================================================
52dab3f910Sjsing  *
53dab3f910Sjsing  * This product includes cryptographic software written by Eric Young
54dab3f910Sjsing  * (eay@cryptsoft.com).  This product includes software written by Tim
55dab3f910Sjsing  * Hudson (tjh@cryptsoft.com).
56dab3f910Sjsing  *
57dab3f910Sjsing  */
58dab3f910Sjsing 
59dab3f910Sjsing #include <openssl/opensslconf.h>
60dab3f910Sjsing 
61dab3f910Sjsing #ifndef OPENSSL_NO_EC
62dab3f910Sjsing 
63dab3f910Sjsing #include <stdio.h>
64dab3f910Sjsing #include <stdlib.h>
65dab3f910Sjsing #include <string.h>
66dab3f910Sjsing 
67dab3f910Sjsing #include "apps.h"
68dab3f910Sjsing 
69dab3f910Sjsing #include <openssl/bio.h>
70dab3f910Sjsing #include <openssl/err.h>
71dab3f910Sjsing #include <openssl/evp.h>
72dab3f910Sjsing #include <openssl/pem.h>
73dab3f910Sjsing 
74406ec002Sdoug static struct {
75406ec002Sdoug 	int asn1_flag;
76406ec002Sdoug 	const EVP_CIPHER *enc;
77406ec002Sdoug 	point_conversion_form_t form;
78406ec002Sdoug 	char *infile;
79406ec002Sdoug 	int informat;
80406ec002Sdoug 	char *outfile;
81406ec002Sdoug 	int outformat;
82406ec002Sdoug 	int new_asn1_flag;
83406ec002Sdoug 	int new_form;
84406ec002Sdoug 	int noout;
85406ec002Sdoug 	int param_out;
86406ec002Sdoug 	char *passargin;
87406ec002Sdoug 	char *passargout;
88406ec002Sdoug 	int pubin;
89406ec002Sdoug 	int pubout;
90406ec002Sdoug 	int text;
91*e7718adaStb } cfg;
92406ec002Sdoug 
93406ec002Sdoug static int
ec_opt_enc(int argc,char ** argv,int * argsused)94406ec002Sdoug ec_opt_enc(int argc, char **argv, int *argsused)
95406ec002Sdoug {
96406ec002Sdoug 	char *name = argv[0];
97406ec002Sdoug 
98406ec002Sdoug 	if (*name++ != '-')
99406ec002Sdoug 		return (1);
100406ec002Sdoug 
101*e7718adaStb 	if ((cfg.enc = EVP_get_cipherbyname(name)) != NULL) {
102406ec002Sdoug 		*argsused = 1;
103406ec002Sdoug 		return (0);
104406ec002Sdoug 	}
105406ec002Sdoug 
106406ec002Sdoug 	return (1);
107406ec002Sdoug }
108406ec002Sdoug 
109406ec002Sdoug static int
ec_opt_form(char * arg)110406ec002Sdoug ec_opt_form(char *arg)
111406ec002Sdoug {
112406ec002Sdoug 	if (strcmp(arg, "compressed") == 0)
113*e7718adaStb 		cfg.form = POINT_CONVERSION_COMPRESSED;
114406ec002Sdoug 	else if (strcmp(arg, "uncompressed") == 0)
115*e7718adaStb 		cfg.form = POINT_CONVERSION_UNCOMPRESSED;
116406ec002Sdoug 	else if (strcmp(arg, "hybrid") == 0)
117*e7718adaStb 		cfg.form = POINT_CONVERSION_HYBRID;
118406ec002Sdoug 	else {
119406ec002Sdoug 		fprintf(stderr, "Invalid point conversion: %s\n", arg);
120406ec002Sdoug 		return (1);
121406ec002Sdoug 	}
122406ec002Sdoug 
123*e7718adaStb 	cfg.new_form = 1;
124406ec002Sdoug 	return (0);
125406ec002Sdoug }
126406ec002Sdoug 
127406ec002Sdoug static int
ec_opt_named(char * arg)128406ec002Sdoug ec_opt_named(char *arg)
129406ec002Sdoug {
130406ec002Sdoug 	if (strcmp(arg, "named_curve") == 0)
131*e7718adaStb 		cfg.asn1_flag = OPENSSL_EC_NAMED_CURVE;
132406ec002Sdoug 	else if (strcmp(arg, "explicit") == 0)
133*e7718adaStb 		cfg.asn1_flag = 0;
134406ec002Sdoug 	else {
135406ec002Sdoug 		fprintf(stderr, "Invalid curve type: %s\n", arg);
136406ec002Sdoug 		return (1);
137406ec002Sdoug 	}
138406ec002Sdoug 
139*e7718adaStb 	cfg.new_asn1_flag = 1;
140406ec002Sdoug 	return (0);
141406ec002Sdoug }
142406ec002Sdoug 
143ea149709Sguenther static const struct option ec_options[] = {
144406ec002Sdoug 	{
145406ec002Sdoug 		.name = "conv_form",
146406ec002Sdoug 		.argname = "form",
147406ec002Sdoug 		.desc = "Specify the point conversion form (default"
148406ec002Sdoug 		    " \"named_curve\")",
149406ec002Sdoug 		.type = OPTION_ARG_FUNC,
150406ec002Sdoug 		.opt.argfunc = ec_opt_form,
151406ec002Sdoug 	},
152406ec002Sdoug 	{
153406ec002Sdoug 		.name = "in",
154406ec002Sdoug 		.argname = "file",
155406ec002Sdoug 		.desc = "Input file (default stdin)",
156406ec002Sdoug 		.type = OPTION_ARG,
157*e7718adaStb 		.opt.arg = &cfg.infile,
158406ec002Sdoug 	},
159406ec002Sdoug 	{
160406ec002Sdoug 		.name = "inform",
161406ec002Sdoug 		.argname = "format",
162406ec002Sdoug 		.desc = "Input format (DER or PEM (default))",
163406ec002Sdoug 		.type = OPTION_ARG_FORMAT,
164*e7718adaStb 		.opt.value = &cfg.informat,
165406ec002Sdoug 	},
166406ec002Sdoug 	{
167406ec002Sdoug 		.name = "noout",
168406ec002Sdoug 		.desc = "No output",
169406ec002Sdoug 		.type = OPTION_FLAG,
170*e7718adaStb 		.opt.flag = &cfg.noout,
171406ec002Sdoug 	},
172406ec002Sdoug 	{
173406ec002Sdoug 		.name = "out",
174406ec002Sdoug 		.argname = "file",
175406ec002Sdoug 		.desc = "Output file (default stdout)",
176406ec002Sdoug 		.type = OPTION_ARG,
177*e7718adaStb 		.opt.arg = &cfg.outfile,
178406ec002Sdoug 	},
179406ec002Sdoug 	{
180406ec002Sdoug 		.name = "outform",
181406ec002Sdoug 		.argname = "format",
182406ec002Sdoug 		.desc = "Output format (DER or PEM (default))",
183406ec002Sdoug 		.type = OPTION_ARG_FORMAT,
184*e7718adaStb 		.opt.value = &cfg.outformat,
185406ec002Sdoug 	},
186406ec002Sdoug 	{
187406ec002Sdoug 		.name = "param_enc",
188406ec002Sdoug 		.argname = "type",
189406ec002Sdoug 		.desc = "Specify the way the ec parameters are encoded"
190406ec002Sdoug 		    " (default \"uncompressed\")",
191406ec002Sdoug 		.type = OPTION_ARG_FUNC,
192406ec002Sdoug 		.opt.argfunc = ec_opt_named,
193406ec002Sdoug 	},
194406ec002Sdoug 	{
195406ec002Sdoug 		.name = "param_out",
196406ec002Sdoug 		.desc = "Print the elliptic curve parameters",
197406ec002Sdoug 		.type = OPTION_FLAG,
198*e7718adaStb 		.opt.flag = &cfg.param_out,
199406ec002Sdoug 	},
200406ec002Sdoug 	{
201406ec002Sdoug 		.name = "passin",
202406ec002Sdoug 		.argname = "source",
203406ec002Sdoug 		.desc = "Input file passphrase source",
204406ec002Sdoug 		.type = OPTION_ARG,
205*e7718adaStb 		.opt.arg = &cfg.passargin,
206406ec002Sdoug 	},
207406ec002Sdoug 	{
208406ec002Sdoug 		.name = "passout",
209406ec002Sdoug 		.argname = "source",
210406ec002Sdoug 		.desc = "Output file passphrase source",
211406ec002Sdoug 		.type = OPTION_ARG,
212*e7718adaStb 		.opt.arg = &cfg.passargout,
213406ec002Sdoug 	},
214406ec002Sdoug 	{
215406ec002Sdoug 		.name = "pubin",
216406ec002Sdoug 		.desc = "Read public key instead of private key from input",
217406ec002Sdoug 		.type = OPTION_FLAG,
218*e7718adaStb 		.opt.flag = &cfg.pubin,
219406ec002Sdoug 	},
220406ec002Sdoug 	{
221406ec002Sdoug 		.name = "pubout",
222406ec002Sdoug 		.desc = "Output public key instead of private key in output",
223406ec002Sdoug 		.type = OPTION_FLAG,
224*e7718adaStb 		.opt.flag = &cfg.pubout,
225406ec002Sdoug 	},
226406ec002Sdoug 	{
227406ec002Sdoug 		.name = "text",
228406ec002Sdoug 		.desc = "Print the public/private key components and parameters",
229406ec002Sdoug 		.type = OPTION_FLAG,
230*e7718adaStb 		.opt.flag = &cfg.text,
231406ec002Sdoug 	},
232406ec002Sdoug 	{
233406ec002Sdoug 		.name = NULL,
234406ec002Sdoug 		.desc = "Cipher to encrypt the output if using PEM format",
235406ec002Sdoug 		.type = OPTION_ARGV_FUNC,
236406ec002Sdoug 		.opt.argvfunc = ec_opt_enc,
237406ec002Sdoug 	},
238406ec002Sdoug 	{ NULL },
239406ec002Sdoug };
240406ec002Sdoug 
241406ec002Sdoug static void
ec_usage(void)242406ec002Sdoug ec_usage(void)
243406ec002Sdoug {
2446685372aSinoguchi 	int n = 0;
2456685372aSinoguchi 
246406ec002Sdoug 	fprintf(stderr,
2475284dfeaSbcook 	    "usage: ec [-conv_form form] [-in file]\n"
248406ec002Sdoug 	    "    [-inform format] [-noout] [-out file] [-outform format]\n"
249406ec002Sdoug 	    "    [-param_enc type] [-param_out] [-passin file]\n"
250406ec002Sdoug 	    "    [-passout file] [-pubin] [-pubout] [-text] [-ciphername]\n\n");
251406ec002Sdoug 	options_usage(ec_options);
252406ec002Sdoug 
253406ec002Sdoug 	fprintf(stderr, "\n");
254406ec002Sdoug 
255406ec002Sdoug 	fprintf(stderr, "Valid ciphername values:\n\n");
2566685372aSinoguchi 	OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_cipher, &n);
257406ec002Sdoug 	fprintf(stderr, "\n");
258406ec002Sdoug }
259dab3f910Sjsing 
260dab3f910Sjsing int
ec_main(int argc,char ** argv)261dab3f910Sjsing ec_main(int argc, char **argv)
262dab3f910Sjsing {
263dab3f910Sjsing 	int ret = 1;
264dab3f910Sjsing 	EC_KEY *eckey = NULL;
265dab3f910Sjsing 	const EC_GROUP *group;
266406ec002Sdoug 	int i;
267dab3f910Sjsing 	BIO *in = NULL, *out = NULL;
268dab3f910Sjsing 	char *passin = NULL, *passout = NULL;
269dab3f910Sjsing 
27051811eadSderaadt 	if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
2719bc487adSdoug 		perror("pledge");
272e370f0eeSdoug 		exit(1);
273e370f0eeSdoug 	}
2749bc487adSdoug 
275*e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
276dab3f910Sjsing 
277*e7718adaStb 	cfg.asn1_flag = OPENSSL_EC_NAMED_CURVE;
278*e7718adaStb 	cfg.form = POINT_CONVERSION_UNCOMPRESSED;
279*e7718adaStb 	cfg.informat = FORMAT_PEM;
280*e7718adaStb 	cfg.outformat = FORMAT_PEM;
281dab3f910Sjsing 
282406ec002Sdoug 	if (options_parse(argc, argv, ec_options, NULL, NULL) != 0) {
283406ec002Sdoug 		ec_usage();
284dab3f910Sjsing 		goto end;
285dab3f910Sjsing 	}
286dab3f910Sjsing 
287*e7718adaStb 	if (!app_passwd(bio_err, cfg.passargin, cfg.passargout,
288406ec002Sdoug 	    &passin, &passout)) {
289dab3f910Sjsing 		BIO_printf(bio_err, "Error getting passwords\n");
290dab3f910Sjsing 		goto end;
291dab3f910Sjsing 	}
292dab3f910Sjsing 	in = BIO_new(BIO_s_file());
293dab3f910Sjsing 	out = BIO_new(BIO_s_file());
294406ec002Sdoug 	if (in == NULL || out == NULL) {
295dab3f910Sjsing 		ERR_print_errors(bio_err);
296dab3f910Sjsing 		goto end;
297dab3f910Sjsing 	}
298*e7718adaStb 	if (cfg.infile == NULL)
299dab3f910Sjsing 		BIO_set_fp(in, stdin, BIO_NOCLOSE);
300dab3f910Sjsing 	else {
301*e7718adaStb 		if (BIO_read_filename(in, cfg.infile) <= 0) {
302*e7718adaStb 			perror(cfg.infile);
303dab3f910Sjsing 			goto end;
304dab3f910Sjsing 		}
305dab3f910Sjsing 	}
306dab3f910Sjsing 
307dab3f910Sjsing 	BIO_printf(bio_err, "read EC key\n");
308*e7718adaStb 	if (cfg.informat == FORMAT_ASN1) {
309*e7718adaStb 		if (cfg.pubin)
310dab3f910Sjsing 			eckey = d2i_EC_PUBKEY_bio(in, NULL);
311dab3f910Sjsing 		else
312dab3f910Sjsing 			eckey = d2i_ECPrivateKey_bio(in, NULL);
313*e7718adaStb 	} else if (cfg.informat == FORMAT_PEM) {
314*e7718adaStb 		if (cfg.pubin)
315dab3f910Sjsing 			eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL,
316dab3f910Sjsing 			    NULL);
317dab3f910Sjsing 		else
318dab3f910Sjsing 			eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL,
319dab3f910Sjsing 			    passin);
320dab3f910Sjsing 	} else {
321dab3f910Sjsing 		BIO_printf(bio_err, "bad input format specified for key\n");
322dab3f910Sjsing 		goto end;
323dab3f910Sjsing 	}
324dab3f910Sjsing 	if (eckey == NULL) {
325dab3f910Sjsing 		BIO_printf(bio_err, "unable to load Key\n");
326dab3f910Sjsing 		ERR_print_errors(bio_err);
327dab3f910Sjsing 		goto end;
328dab3f910Sjsing 	}
329*e7718adaStb 	if (cfg.outfile == NULL) {
330dab3f910Sjsing 		BIO_set_fp(out, stdout, BIO_NOCLOSE);
331dab3f910Sjsing 	} else {
332*e7718adaStb 		if (BIO_write_filename(out, cfg.outfile) <= 0) {
333*e7718adaStb 			perror(cfg.outfile);
334dab3f910Sjsing 			goto end;
335dab3f910Sjsing 		}
336dab3f910Sjsing 	}
337dab3f910Sjsing 
338dab3f910Sjsing 	group = EC_KEY_get0_group(eckey);
339dab3f910Sjsing 
340*e7718adaStb 	if (cfg.new_form)
341*e7718adaStb 		EC_KEY_set_conv_form(eckey, cfg.form);
342dab3f910Sjsing 
343*e7718adaStb 	if (cfg.new_asn1_flag)
344*e7718adaStb 		EC_KEY_set_asn1_flag(eckey, cfg.asn1_flag);
345dab3f910Sjsing 
346*e7718adaStb 	if (cfg.text)
347dab3f910Sjsing 		if (!EC_KEY_print(out, eckey, 0)) {
348*e7718adaStb 			perror(cfg.outfile);
349dab3f910Sjsing 			ERR_print_errors(bio_err);
350dab3f910Sjsing 			goto end;
351dab3f910Sjsing 		}
352*e7718adaStb 	if (cfg.noout) {
353dab3f910Sjsing 		ret = 0;
354dab3f910Sjsing 		goto end;
355dab3f910Sjsing 	}
356dab3f910Sjsing 	BIO_printf(bio_err, "writing EC key\n");
357*e7718adaStb 	if (cfg.outformat == FORMAT_ASN1) {
358*e7718adaStb 		if (cfg.param_out)
359dab3f910Sjsing 			i = i2d_ECPKParameters_bio(out, group);
360*e7718adaStb 		else if (cfg.pubin || cfg.pubout)
361dab3f910Sjsing 			i = i2d_EC_PUBKEY_bio(out, eckey);
362dab3f910Sjsing 		else
363dab3f910Sjsing 			i = i2d_ECPrivateKey_bio(out, eckey);
364*e7718adaStb 	} else if (cfg.outformat == FORMAT_PEM) {
365*e7718adaStb 		if (cfg.param_out)
366dab3f910Sjsing 			i = PEM_write_bio_ECPKParameters(out, group);
367*e7718adaStb 		else if (cfg.pubin || cfg.pubout)
368dab3f910Sjsing 			i = PEM_write_bio_EC_PUBKEY(out, eckey);
369dab3f910Sjsing 		else
370406ec002Sdoug 			i = PEM_write_bio_ECPrivateKey(out, eckey,
371*e7718adaStb 			    cfg.enc, NULL, 0, NULL, passout);
372dab3f910Sjsing 	} else {
373dab3f910Sjsing 		BIO_printf(bio_err, "bad output format specified for "
374dab3f910Sjsing 		    "outfile\n");
375dab3f910Sjsing 		goto end;
376dab3f910Sjsing 	}
377dab3f910Sjsing 
378dab3f910Sjsing 	if (!i) {
379dab3f910Sjsing 		BIO_printf(bio_err, "unable to write private key\n");
380dab3f910Sjsing 		ERR_print_errors(bio_err);
381dab3f910Sjsing 	} else
382dab3f910Sjsing 		ret = 0;
383dab3f910Sjsing  end:
384dab3f910Sjsing 	BIO_free(in);
385dab3f910Sjsing 	BIO_free_all(out);
386dab3f910Sjsing 	EC_KEY_free(eckey);
387dab3f910Sjsing 	free(passin);
388dab3f910Sjsing 	free(passout);
389dab3f910Sjsing 
390dab3f910Sjsing 	return (ret);
391dab3f910Sjsing }
392dab3f910Sjsing #endif
393