xref: /openbsd-src/usr.bin/openssl/ecparam.c (revision a9d90585ca40c280201dda70d6b331b26701653a)
1*a9d90585Stb /* $OpenBSD: ecparam.c,v 1.25 2025/01/19 10:24:17 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  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
60dab3f910Sjsing  *
61dab3f910Sjsing  * Portions of the attached software ("Contribution") are developed by
62dab3f910Sjsing  * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
63dab3f910Sjsing  *
64dab3f910Sjsing  * The Contribution is licensed pursuant to the OpenSSL open source
65dab3f910Sjsing  * license provided above.
66dab3f910Sjsing  *
67dab3f910Sjsing  * The elliptic curve binary polynomial software is originally written by
68dab3f910Sjsing  * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
69dab3f910Sjsing  *
70dab3f910Sjsing  */
71dab3f910Sjsing 
72dab3f910Sjsing #include <openssl/opensslconf.h>
73dab3f910Sjsing 
74dab3f910Sjsing #ifndef OPENSSL_NO_EC
75dab3f910Sjsing 
76dab3f910Sjsing #include <stdio.h>
77dab3f910Sjsing #include <stdlib.h>
78dab3f910Sjsing #include <string.h>
79dab3f910Sjsing #include <time.h>
80dab3f910Sjsing 
81dab3f910Sjsing #include "apps.h"
82dab3f910Sjsing 
83dab3f910Sjsing #include <openssl/bio.h>
84dab3f910Sjsing #include <openssl/bn.h>
85dab3f910Sjsing #include <openssl/ec.h>
86dab3f910Sjsing #include <openssl/err.h>
87dab3f910Sjsing #include <openssl/pem.h>
88dab3f910Sjsing #include <openssl/x509.h>
89dab3f910Sjsing 
906f5941c5Sjsing static struct {
916f5941c5Sjsing 	int asn1_flag;
926f5941c5Sjsing 	int check;
936f5941c5Sjsing 	char *curve_name;
946f5941c5Sjsing 	point_conversion_form_t form;
956f5941c5Sjsing 	int genkey;
966f5941c5Sjsing 	char *infile;
976f5941c5Sjsing 	int informat;
986f5941c5Sjsing 	int list_curves;
996f5941c5Sjsing 	int new_asn1_flag;
1006f5941c5Sjsing 	int new_form;
1016f5941c5Sjsing 	int no_seed;
1026f5941c5Sjsing 	int noout;
1036f5941c5Sjsing 	char *outfile;
1046f5941c5Sjsing 	int outformat;
1056f5941c5Sjsing 	int text;
106e7718adaStb } cfg;
107dab3f910Sjsing 
1086f5941c5Sjsing static int
109d16f2e55Sjsing ecparam_opt_form(char *arg)
1106f5941c5Sjsing {
1116f5941c5Sjsing 	if (strcmp(arg, "compressed") == 0)
112e7718adaStb 		cfg.form = POINT_CONVERSION_COMPRESSED;
1136f5941c5Sjsing 	else if (strcmp(arg, "uncompressed") == 0)
114e7718adaStb 		cfg.form = POINT_CONVERSION_UNCOMPRESSED;
1156f5941c5Sjsing 	else if (strcmp(arg, "hybrid") == 0)
116e7718adaStb 		cfg.form = POINT_CONVERSION_HYBRID;
1176f5941c5Sjsing 	else
1186f5941c5Sjsing 		return (1);
1196f5941c5Sjsing 
120e7718adaStb 	cfg.new_form = 1;
1216f5941c5Sjsing 	return (0);
1226f5941c5Sjsing }
1236f5941c5Sjsing 
1246f5941c5Sjsing static int
125d16f2e55Sjsing ecparam_opt_enctype(char *arg)
1266f5941c5Sjsing {
1276f5941c5Sjsing 	if (strcmp(arg, "explicit") == 0)
128e7718adaStb 		cfg.asn1_flag = 0;
1296f5941c5Sjsing 	else if (strcmp(arg, "named_curve") == 0)
130e7718adaStb 		cfg.asn1_flag = OPENSSL_EC_NAMED_CURVE;
1316f5941c5Sjsing 	else
1326f5941c5Sjsing 		return (1);
1336f5941c5Sjsing 
134e7718adaStb 	cfg.new_asn1_flag = 1;
1356f5941c5Sjsing 	return (0);
1366f5941c5Sjsing }
1376f5941c5Sjsing 
138ea149709Sguenther static const struct option ecparam_options[] = {
1396f5941c5Sjsing 	{
1406f5941c5Sjsing 		.name = "check",
1416f5941c5Sjsing 		.desc = "Validate the elliptic curve parameters",
1426f5941c5Sjsing 		.type = OPTION_FLAG,
143e7718adaStb 		.opt.flag = &cfg.check,
1446f5941c5Sjsing 	},
1456f5941c5Sjsing 	{
1466f5941c5Sjsing 		.name = "conv_form",
1476f5941c5Sjsing 		.argname = "form",
1486f5941c5Sjsing 		.desc = "Specify point conversion form:\n"
1496f5941c5Sjsing 		    "  compressed, uncompressed (default), hybrid",
1506f5941c5Sjsing 		.type = OPTION_ARG_FUNC,
151d16f2e55Sjsing 		.opt.argfunc = ecparam_opt_form,
1526f5941c5Sjsing 	},
1536f5941c5Sjsing 	{
1546f5941c5Sjsing 		.name = "genkey",
1556f5941c5Sjsing 		.desc = "Generate an EC private key using the specified "
1566f5941c5Sjsing 		    "parameters",
1576f5941c5Sjsing 		.type = OPTION_FLAG,
158e7718adaStb 		.opt.flag = &cfg.genkey,
1596f5941c5Sjsing 	},
1606f5941c5Sjsing 	{
1616f5941c5Sjsing 		.name = "in",
1626f5941c5Sjsing 		.argname = "file",
1636f5941c5Sjsing 		.desc = "Input file to read parameters from (default stdin)",
1646f5941c5Sjsing 		.type = OPTION_ARG,
165e7718adaStb 		.opt.arg = &cfg.infile,
1666f5941c5Sjsing 	},
1676f5941c5Sjsing 	{
1686f5941c5Sjsing 		.name = "inform",
1696f5941c5Sjsing 		.argname = "format",
1706f5941c5Sjsing 		.desc = "Input format (DER or PEM)",
1716f5941c5Sjsing 		.type = OPTION_ARG_FORMAT,
172e7718adaStb 		.opt.value = &cfg.informat,
1736f5941c5Sjsing 	},
1746f5941c5Sjsing 	{
1756f5941c5Sjsing 		.name = "list_curves",
1766f5941c5Sjsing 		.desc = "Print list of all currently implemented EC "
1776f5941c5Sjsing 		    "parameter names",
1786f5941c5Sjsing 		.type = OPTION_FLAG,
179e7718adaStb 		.opt.flag = &cfg.list_curves,
1806f5941c5Sjsing 	},
1816f5941c5Sjsing 	{
1826f5941c5Sjsing 		.name = "name",
1836f5941c5Sjsing 		.argname = "curve",
1846f5941c5Sjsing 		.desc = "Use the EC parameters with the specified name",
1856f5941c5Sjsing 		.type = OPTION_ARG,
186e7718adaStb 		.opt.arg = &cfg.curve_name,
1876f5941c5Sjsing 	},
1886f5941c5Sjsing 	{
1896f5941c5Sjsing 		.name = "no_seed",
1906f5941c5Sjsing 		.desc = "Do not output seed with explicit parameter encoding",
1916f5941c5Sjsing 		.type = OPTION_FLAG,
192e7718adaStb 		.opt.flag = &cfg.no_seed,
1936f5941c5Sjsing 	},
1946f5941c5Sjsing 	{
1956f5941c5Sjsing 		.name = "noout",
1966f5941c5Sjsing 		.desc = "Do not output encoded version of EC parameters",
1976f5941c5Sjsing 		.type = OPTION_FLAG,
198e7718adaStb 		.opt.flag = &cfg.noout,
1996f5941c5Sjsing 	},
2006f5941c5Sjsing 	{
2016f5941c5Sjsing 		.name = "out",
2026f5941c5Sjsing 		.argname = "file",
2036f5941c5Sjsing 		.desc = "Output file to write parameters to (default stdout)",
2046f5941c5Sjsing 		.type = OPTION_ARG,
205e7718adaStb 		.opt.arg = &cfg.outfile,
2066f5941c5Sjsing 	},
2076f5941c5Sjsing 	{
2086f5941c5Sjsing 		.name = "outform",
2096f5941c5Sjsing 		.argname = "format",
2106f5941c5Sjsing 		.desc = "Output format (DER or PEM)",
2116f5941c5Sjsing 		.type = OPTION_ARG_FORMAT,
212e7718adaStb 		.opt.value = &cfg.outformat,
2136f5941c5Sjsing 	},
2146f5941c5Sjsing 	{
2156f5941c5Sjsing 		.name = "param_enc",
2166f5941c5Sjsing 		.argname = "type",
2176f5941c5Sjsing 		.desc = "Specify EC parameter ASN.1 encoding type:\n"
2186f5941c5Sjsing 		    "  explicit, named_curve (default)",
2196f5941c5Sjsing 		.type = OPTION_ARG_FUNC,
220d16f2e55Sjsing 		.opt.argfunc = ecparam_opt_enctype,
2216f5941c5Sjsing 	},
2226f5941c5Sjsing 	{
2236f5941c5Sjsing 		.name = "text",
2246f5941c5Sjsing 		.desc = "Print out the EC parameters in human readable form",
2256f5941c5Sjsing 		.type = OPTION_FLAG,
226e7718adaStb 		.opt.flag = &cfg.text,
2276f5941c5Sjsing 	},
228d220e929Sbcook 	{NULL},
2296f5941c5Sjsing };
2306f5941c5Sjsing 
2316f5941c5Sjsing static void
2326f5941c5Sjsing ecparam_usage(void)
2336f5941c5Sjsing {
234*a9d90585Stb 	fprintf(stderr, "usage: ecparam [-check] [-conv_form arg] "
2355284dfeaSbcook 	    " [-genkey]\n"
2366f5941c5Sjsing 	    "    [-in file] [-inform DER | PEM] [-list_curves] [-name arg]\n"
2376f5941c5Sjsing 	    "    [-no_seed] [-noout] [-out file] [-outform DER | PEM]\n"
2386f5941c5Sjsing 	    "    [-param_enc arg] [-text]\n\n");
2396f5941c5Sjsing 	options_usage(ecparam_options);
2406f5941c5Sjsing }
241dab3f910Sjsing 
242dab3f910Sjsing int
243dab3f910Sjsing ecparam_main(int argc, char **argv)
244dab3f910Sjsing {
245dab3f910Sjsing 	EC_GROUP *group = NULL;
2466f5941c5Sjsing 	BIO *in = NULL, *out = NULL;
2476f5941c5Sjsing 	int i, ret = 1;
248dab3f910Sjsing 
24951811eadSderaadt 	if (pledge("stdio cpath wpath rpath", NULL) == -1) {
2509bc487adSdoug 		perror("pledge");
251e370f0eeSdoug 		exit(1);
252e370f0eeSdoug 	}
2539bc487adSdoug 
254e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
255e7718adaStb 	cfg.asn1_flag = OPENSSL_EC_NAMED_CURVE;
256e7718adaStb 	cfg.form = POINT_CONVERSION_UNCOMPRESSED;
257e7718adaStb 	cfg.informat = FORMAT_PEM;
258e7718adaStb 	cfg.outformat = FORMAT_PEM;
259dab3f910Sjsing 
260beba0da1Sjsing 	if (options_parse(argc, argv, ecparam_options, NULL, NULL) != 0) {
2616f5941c5Sjsing 		ecparam_usage();
262dab3f910Sjsing 		goto end;
263dab3f910Sjsing 	}
264dab3f910Sjsing 
265dab3f910Sjsing 	in = BIO_new(BIO_s_file());
266dab3f910Sjsing 	out = BIO_new(BIO_s_file());
267dab3f910Sjsing 	if ((in == NULL) || (out == NULL)) {
268dab3f910Sjsing 		ERR_print_errors(bio_err);
269dab3f910Sjsing 		goto end;
270dab3f910Sjsing 	}
271e7718adaStb 	if (cfg.infile == NULL)
272dab3f910Sjsing 		BIO_set_fp(in, stdin, BIO_NOCLOSE);
273dab3f910Sjsing 	else {
274e7718adaStb 		if (BIO_read_filename(in, cfg.infile) <= 0) {
275e7718adaStb 			perror(cfg.infile);
276dab3f910Sjsing 			goto end;
277dab3f910Sjsing 		}
278dab3f910Sjsing 	}
279e7718adaStb 	if (cfg.outfile == NULL) {
280dab3f910Sjsing 		BIO_set_fp(out, stdout, BIO_NOCLOSE);
281dab3f910Sjsing 	} else {
282e7718adaStb 		if (BIO_write_filename(out, cfg.outfile) <= 0) {
283e7718adaStb 			perror(cfg.outfile);
284dab3f910Sjsing 			goto end;
285dab3f910Sjsing 		}
286dab3f910Sjsing 	}
287dab3f910Sjsing 
288e7718adaStb 	if (cfg.list_curves) {
289dab3f910Sjsing 		EC_builtin_curve *curves = NULL;
290dab3f910Sjsing 		size_t crv_len = 0;
291dab3f910Sjsing 		size_t n = 0;
292dab3f910Sjsing 
293dab3f910Sjsing 		crv_len = EC_get_builtin_curves(NULL, 0);
294dab3f910Sjsing 
295dab3f910Sjsing 		curves = reallocarray(NULL, crv_len, sizeof(EC_builtin_curve));
296dab3f910Sjsing 		if (curves == NULL)
297dab3f910Sjsing 			goto end;
298dab3f910Sjsing 
299dab3f910Sjsing 		if (!EC_get_builtin_curves(curves, crv_len)) {
300dab3f910Sjsing 			free(curves);
301dab3f910Sjsing 			goto end;
302dab3f910Sjsing 		}
303dab3f910Sjsing 		for (n = 0; n < crv_len; n++) {
304dab3f910Sjsing 			const char *comment;
305dab3f910Sjsing 			const char *sname;
306dab3f910Sjsing 			comment = curves[n].comment;
307dab3f910Sjsing 			sname = OBJ_nid2sn(curves[n].nid);
308dab3f910Sjsing 			if (comment == NULL)
309dab3f910Sjsing 				comment = "CURVE DESCRIPTION NOT AVAILABLE";
310dab3f910Sjsing 			if (sname == NULL)
311dab3f910Sjsing 				sname = "";
312dab3f910Sjsing 
313dab3f910Sjsing 			BIO_printf(out, "  %-10s: ", sname);
314dab3f910Sjsing 			BIO_printf(out, "%s\n", comment);
315dab3f910Sjsing 		}
316dab3f910Sjsing 
317dab3f910Sjsing 		free(curves);
318dab3f910Sjsing 		ret = 0;
319dab3f910Sjsing 		goto end;
320dab3f910Sjsing 	}
321e7718adaStb 	if (cfg.curve_name != NULL) {
322dab3f910Sjsing 		int nid;
323dab3f910Sjsing 
324dab3f910Sjsing 		/*
325dab3f910Sjsing 		 * workaround for the SECG curve names secp192r1 and
326dab3f910Sjsing 		 * secp256r1 (which are the same as the curves prime192v1 and
327dab3f910Sjsing 		 * prime256v1 defined in X9.62)
328dab3f910Sjsing 		 */
329e7718adaStb 		if (!strcmp(cfg.curve_name, "secp192r1")) {
330dab3f910Sjsing 			BIO_printf(bio_err, "using curve name prime192v1 "
331dab3f910Sjsing 			    "instead of secp192r1\n");
332dab3f910Sjsing 			nid = NID_X9_62_prime192v1;
333e7718adaStb 		} else if (!strcmp(cfg.curve_name, "secp256r1")) {
334dab3f910Sjsing 			BIO_printf(bio_err, "using curve name prime256v1 "
335dab3f910Sjsing 			    "instead of secp256r1\n");
336dab3f910Sjsing 			nid = NID_X9_62_prime256v1;
337dab3f910Sjsing 		} else
338e7718adaStb 			nid = OBJ_sn2nid(cfg.curve_name);
339dab3f910Sjsing 
340b4c4114dSjsing 		if (nid == 0)
341e7718adaStb 			nid = EC_curve_nist2nid(cfg.curve_name);
342b4c4114dSjsing 
343dab3f910Sjsing 		if (nid == 0) {
344dab3f910Sjsing 			BIO_printf(bio_err, "unknown curve name (%s)\n",
345e7718adaStb 			    cfg.curve_name);
346dab3f910Sjsing 			goto end;
347dab3f910Sjsing 		}
348dab3f910Sjsing 		group = EC_GROUP_new_by_curve_name(nid);
349dab3f910Sjsing 		if (group == NULL) {
350dab3f910Sjsing 			BIO_printf(bio_err, "unable to create curve (%s)\n",
351e7718adaStb 			    cfg.curve_name);
352dab3f910Sjsing 			goto end;
353dab3f910Sjsing 		}
354e7718adaStb 		EC_GROUP_set_asn1_flag(group, cfg.asn1_flag);
355e7718adaStb 		EC_GROUP_set_point_conversion_form(group, cfg.form);
356e7718adaStb 	} else if (cfg.informat == FORMAT_ASN1) {
357dab3f910Sjsing 		group = d2i_ECPKParameters_bio(in, NULL);
358e7718adaStb 	} else if (cfg.informat == FORMAT_PEM) {
359dab3f910Sjsing 		group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
360dab3f910Sjsing 	} else {
361dab3f910Sjsing 		BIO_printf(bio_err, "bad input format specified\n");
362dab3f910Sjsing 		goto end;
363dab3f910Sjsing 	}
364dab3f910Sjsing 
365dab3f910Sjsing 	if (group == NULL) {
366dab3f910Sjsing 		BIO_printf(bio_err,
367dab3f910Sjsing 		    "unable to load elliptic curve parameters\n");
368dab3f910Sjsing 		ERR_print_errors(bio_err);
369dab3f910Sjsing 		goto end;
370dab3f910Sjsing 	}
371e7718adaStb 	if (cfg.new_form)
372e7718adaStb 		EC_GROUP_set_point_conversion_form(group, cfg.form);
373dab3f910Sjsing 
374e7718adaStb 	if (cfg.new_asn1_flag)
375e7718adaStb 		EC_GROUP_set_asn1_flag(group, cfg.asn1_flag);
376dab3f910Sjsing 
377e7718adaStb 	if (cfg.no_seed)
378dab3f910Sjsing 		EC_GROUP_set_seed(group, NULL, 0);
3796f5941c5Sjsing 
380e7718adaStb 	if (cfg.text) {
381dab3f910Sjsing 		if (!ECPKParameters_print(out, group, 0))
382dab3f910Sjsing 			goto end;
383dab3f910Sjsing 	}
384e7718adaStb 	if (cfg.check) {
385dab3f910Sjsing 		BIO_printf(bio_err, "checking elliptic curve parameters: ");
386dab3f910Sjsing 		if (!EC_GROUP_check(group, NULL)) {
387dab3f910Sjsing 			BIO_printf(bio_err, "failed\n");
388dab3f910Sjsing 			ERR_print_errors(bio_err);
389dab3f910Sjsing 		} else
390dab3f910Sjsing 			BIO_printf(bio_err, "ok\n");
391dab3f910Sjsing 
392dab3f910Sjsing 	}
393e7718adaStb 	if (!cfg.noout) {
394e7718adaStb 		if (cfg.outformat == FORMAT_ASN1)
395dab3f910Sjsing 			i = i2d_ECPKParameters_bio(out, group);
396e7718adaStb 		else if (cfg.outformat == FORMAT_PEM)
397dab3f910Sjsing 			i = PEM_write_bio_ECPKParameters(out, group);
398dab3f910Sjsing 		else {
399dab3f910Sjsing 			BIO_printf(bio_err, "bad output format specified for"
400dab3f910Sjsing 			    " outfile\n");
401dab3f910Sjsing 			goto end;
402dab3f910Sjsing 		}
403dab3f910Sjsing 		if (!i) {
404dab3f910Sjsing 			BIO_printf(bio_err, "unable to write elliptic "
405dab3f910Sjsing 			    "curve parameters\n");
406dab3f910Sjsing 			ERR_print_errors(bio_err);
407dab3f910Sjsing 			goto end;
408dab3f910Sjsing 		}
409dab3f910Sjsing 	}
410e7718adaStb 	if (cfg.genkey) {
411dab3f910Sjsing 		EC_KEY *eckey = EC_KEY_new();
412dab3f910Sjsing 
413dab3f910Sjsing 		if (eckey == NULL)
414dab3f910Sjsing 			goto end;
415dab3f910Sjsing 
416dab3f910Sjsing 		if (EC_KEY_set_group(eckey, group) == 0) {
417dab3f910Sjsing 			EC_KEY_free(eckey);
418dab3f910Sjsing 			goto end;
419dab3f910Sjsing 		}
420dab3f910Sjsing 
421dab3f910Sjsing 		if (!EC_KEY_generate_key(eckey)) {
422dab3f910Sjsing 			EC_KEY_free(eckey);
423dab3f910Sjsing 			goto end;
424dab3f910Sjsing 		}
425e7718adaStb 		if (cfg.outformat == FORMAT_ASN1)
426dab3f910Sjsing 			i = i2d_ECPrivateKey_bio(out, eckey);
427e7718adaStb 		else if (cfg.outformat == FORMAT_PEM)
428dab3f910Sjsing 			i = PEM_write_bio_ECPrivateKey(out, eckey, NULL,
429dab3f910Sjsing 			    NULL, 0, NULL, NULL);
430dab3f910Sjsing 		else {
431dab3f910Sjsing 			BIO_printf(bio_err, "bad output format specified "
432dab3f910Sjsing 			    "for outfile\n");
433dab3f910Sjsing 			EC_KEY_free(eckey);
434dab3f910Sjsing 			goto end;
435dab3f910Sjsing 		}
436dab3f910Sjsing 		EC_KEY_free(eckey);
437dab3f910Sjsing 	}
438dab3f910Sjsing 	ret = 0;
43963188486Sjsing 
440dab3f910Sjsing  end:
441dab3f910Sjsing 	BIO_free(in);
442dab3f910Sjsing 	BIO_free_all(out);
443dab3f910Sjsing 	EC_GROUP_free(group);
444dab3f910Sjsing 
445dab3f910Sjsing 	return (ret);
446dab3f910Sjsing }
447dab3f910Sjsing 
448dab3f910Sjsing #endif
449