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