xref: /freebsd/crypto/openssl/apps/ec.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
13b4e3dcbSSimon L. B. Nielsen /*
2*b077aed3SPierre Pronchery  * Copyright 2002-2022 The OpenSSL Project Authors. All Rights Reserved.
33b4e3dcbSSimon L. B. Nielsen  *
4*b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
83b4e3dcbSSimon L. B. Nielsen  */
93b4e3dcbSSimon L. B. Nielsen 
103b4e3dcbSSimon L. B. Nielsen #include <string.h>
11*b077aed3SPierre Pronchery #include <openssl/opensslconf.h>
12*b077aed3SPierre Pronchery #include <openssl/evp.h>
13*b077aed3SPierre Pronchery #include <openssl/encoder.h>
14*b077aed3SPierre Pronchery #include <openssl/decoder.h>
15*b077aed3SPierre Pronchery #include <openssl/core_names.h>
16*b077aed3SPierre Pronchery #include <openssl/core_dispatch.h>
17*b077aed3SPierre Pronchery #include <openssl/params.h>
18*b077aed3SPierre Pronchery #include <openssl/err.h>
19*b077aed3SPierre Pronchery 
203b4e3dcbSSimon L. B. Nielsen #include "apps.h"
21e71b7053SJung-uk Kim #include "progs.h"
22*b077aed3SPierre Pronchery #include "ec_common.h"
233b4e3dcbSSimon L. B. Nielsen 
24e71b7053SJung-uk Kim typedef enum OPTION_choice {
25*b077aed3SPierre Pronchery     OPT_COMMON,
26e71b7053SJung-uk Kim     OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT,
27e71b7053SJung-uk Kim     OPT_NOOUT, OPT_TEXT, OPT_PARAM_OUT, OPT_PUBIN, OPT_PUBOUT,
28e71b7053SJung-uk Kim     OPT_PASSIN, OPT_PASSOUT, OPT_PARAM_ENC, OPT_CONV_FORM, OPT_CIPHER,
29*b077aed3SPierre Pronchery     OPT_NO_PUBLIC, OPT_CHECK, OPT_PROV_ENUM
30e71b7053SJung-uk Kim } OPTION_CHOICE;
313b4e3dcbSSimon L. B. Nielsen 
32e71b7053SJung-uk Kim const OPTIONS ec_options[] = {
33*b077aed3SPierre Pronchery     OPT_SECTION("General"),
34e71b7053SJung-uk Kim     {"help", OPT_HELP, '-', "Display this summary"},
35*b077aed3SPierre Pronchery #ifndef OPENSSL_NO_ENGINE
36*b077aed3SPierre Pronchery     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
37*b077aed3SPierre Pronchery #endif
38*b077aed3SPierre Pronchery 
39*b077aed3SPierre Pronchery     OPT_SECTION("Input"),
40e71b7053SJung-uk Kim     {"in", OPT_IN, 's', "Input file"},
41*b077aed3SPierre Pronchery     {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)"},
42*b077aed3SPierre Pronchery     {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"},
43*b077aed3SPierre Pronchery     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
44*b077aed3SPierre Pronchery     {"check", OPT_CHECK, '-', "check key consistency"},
45*b077aed3SPierre Pronchery     {"", OPT_CIPHER, '-', "Any supported cipher"},
46*b077aed3SPierre Pronchery     {"param_enc", OPT_PARAM_ENC, 's',
47*b077aed3SPierre Pronchery      "Specifies the way the ec parameters are encoded"},
48*b077aed3SPierre Pronchery     {"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "},
49*b077aed3SPierre Pronchery 
50*b077aed3SPierre Pronchery     OPT_SECTION("Output"),
51e71b7053SJung-uk Kim     {"out", OPT_OUT, '>', "Output file"},
52e71b7053SJung-uk Kim     {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"},
53e71b7053SJung-uk Kim     {"noout", OPT_NOOUT, '-', "Don't print key out"},
54e71b7053SJung-uk Kim     {"text", OPT_TEXT, '-', "Print the key"},
55e71b7053SJung-uk Kim     {"param_out", OPT_PARAM_OUT, '-', "Print the elliptic curve parameters"},
56e71b7053SJung-uk Kim     {"pubout", OPT_PUBOUT, '-', "Output public key, not private"},
57e71b7053SJung-uk Kim     {"no_public", OPT_NO_PUBLIC, '-', "exclude public key from private key"},
58e71b7053SJung-uk Kim     {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
59*b077aed3SPierre Pronchery 
60*b077aed3SPierre Pronchery     OPT_PROV_OPTIONS,
61e71b7053SJung-uk Kim     {NULL}
62e71b7053SJung-uk Kim };
63e71b7053SJung-uk Kim 
ec_main(int argc,char ** argv)64e71b7053SJung-uk Kim int ec_main(int argc, char **argv)
653b4e3dcbSSimon L. B. Nielsen {
66*b077aed3SPierre Pronchery     OSSL_ENCODER_CTX *ectx = NULL;
67*b077aed3SPierre Pronchery     OSSL_DECODER_CTX *dctx = NULL;
68*b077aed3SPierre Pronchery     EVP_PKEY_CTX *pctx = NULL;
69*b077aed3SPierre Pronchery     EVP_PKEY *eckey = NULL;
70*b077aed3SPierre Pronchery     BIO *out = NULL;
71e71b7053SJung-uk Kim     ENGINE *e = NULL;
72*b077aed3SPierre Pronchery     EVP_CIPHER *enc = NULL;
73*b077aed3SPierre Pronchery     char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog;
74e71b7053SJung-uk Kim     char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL;
75e71b7053SJung-uk Kim     OPTION_CHOICE o;
76*b077aed3SPierre Pronchery     int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0;
77*b077aed3SPierre Pronchery     int pubin = 0, pubout = 0, param_out = 0, ret = 1, private = 0;
78*b077aed3SPierre Pronchery     int check = 0;
79*b077aed3SPierre Pronchery     char *asn1_encoding = NULL;
80*b077aed3SPierre Pronchery     char *point_format = NULL;
81*b077aed3SPierre Pronchery     int no_public = 0;
823b4e3dcbSSimon L. B. Nielsen 
83e71b7053SJung-uk Kim     prog = opt_init(argc, argv, ec_options);
84e71b7053SJung-uk Kim     while ((o = opt_next()) != OPT_EOF) {
85e71b7053SJung-uk Kim         switch (o) {
86e71b7053SJung-uk Kim         case OPT_EOF:
87e71b7053SJung-uk Kim         case OPT_ERR:
88e71b7053SJung-uk Kim  opthelp:
89e71b7053SJung-uk Kim             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
903b4e3dcbSSimon L. B. Nielsen             goto end;
91e71b7053SJung-uk Kim         case OPT_HELP:
92e71b7053SJung-uk Kim             opt_help(ec_options);
93e71b7053SJung-uk Kim             ret = 0;
94e71b7053SJung-uk Kim             goto end;
95e71b7053SJung-uk Kim         case OPT_INFORM:
96e71b7053SJung-uk Kim             if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
97e71b7053SJung-uk Kim                 goto opthelp;
98e71b7053SJung-uk Kim             break;
99e71b7053SJung-uk Kim         case OPT_IN:
100e71b7053SJung-uk Kim             infile = opt_arg();
101e71b7053SJung-uk Kim             break;
102e71b7053SJung-uk Kim         case OPT_OUTFORM:
103e71b7053SJung-uk Kim             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
104e71b7053SJung-uk Kim                 goto opthelp;
105e71b7053SJung-uk Kim             break;
106e71b7053SJung-uk Kim         case OPT_OUT:
107e71b7053SJung-uk Kim             outfile = opt_arg();
108e71b7053SJung-uk Kim             break;
109e71b7053SJung-uk Kim         case OPT_NOOUT:
1103b4e3dcbSSimon L. B. Nielsen             noout = 1;
111e71b7053SJung-uk Kim             break;
112e71b7053SJung-uk Kim         case OPT_TEXT:
1133b4e3dcbSSimon L. B. Nielsen             text = 1;
114e71b7053SJung-uk Kim             break;
115e71b7053SJung-uk Kim         case OPT_PARAM_OUT:
1163b4e3dcbSSimon L. B. Nielsen             param_out = 1;
117e71b7053SJung-uk Kim             break;
118e71b7053SJung-uk Kim         case OPT_PUBIN:
1193b4e3dcbSSimon L. B. Nielsen             pubin = 1;
120e71b7053SJung-uk Kim             break;
121e71b7053SJung-uk Kim         case OPT_PUBOUT:
1223b4e3dcbSSimon L. B. Nielsen             pubout = 1;
123e71b7053SJung-uk Kim             break;
124e71b7053SJung-uk Kim         case OPT_PASSIN:
125e71b7053SJung-uk Kim             passinarg = opt_arg();
126e71b7053SJung-uk Kim             break;
127e71b7053SJung-uk Kim         case OPT_PASSOUT:
128e71b7053SJung-uk Kim             passoutarg = opt_arg();
129e71b7053SJung-uk Kim             break;
130e71b7053SJung-uk Kim         case OPT_ENGINE:
131e71b7053SJung-uk Kim             e = setup_engine(opt_arg(), 0);
132e71b7053SJung-uk Kim             break;
133e71b7053SJung-uk Kim         case OPT_CIPHER:
134*b077aed3SPierre Pronchery             ciphername = opt_unknown();
135e71b7053SJung-uk Kim             break;
136e71b7053SJung-uk Kim         case OPT_CONV_FORM:
137*b077aed3SPierre Pronchery             point_format = opt_arg();
138*b077aed3SPierre Pronchery             if (!opt_string(point_format, point_format_options))
139e71b7053SJung-uk Kim                 goto opthelp;
140e71b7053SJung-uk Kim             break;
141e71b7053SJung-uk Kim         case OPT_PARAM_ENC:
142*b077aed3SPierre Pronchery             asn1_encoding = opt_arg();
143*b077aed3SPierre Pronchery             if (!opt_string(asn1_encoding, asn1_encoding_options))
144e71b7053SJung-uk Kim                 goto opthelp;
145e71b7053SJung-uk Kim             break;
146e71b7053SJung-uk Kim         case OPT_NO_PUBLIC:
147e71b7053SJung-uk Kim             no_public = 1;
148e71b7053SJung-uk Kim             break;
149e71b7053SJung-uk Kim         case OPT_CHECK:
150e71b7053SJung-uk Kim             check = 1;
1513b4e3dcbSSimon L. B. Nielsen             break;
152*b077aed3SPierre Pronchery         case OPT_PROV_CASES:
153*b077aed3SPierre Pronchery             if (!opt_provider(o))
154*b077aed3SPierre Pronchery                 goto end;
155*b077aed3SPierre Pronchery             break;
1563b4e3dcbSSimon L. B. Nielsen         }
1573b4e3dcbSSimon L. B. Nielsen     }
158*b077aed3SPierre Pronchery 
159*b077aed3SPierre Pronchery     /* No extra arguments. */
160e71b7053SJung-uk Kim     argc = opt_num_rest();
161e71b7053SJung-uk Kim     if (argc != 0)
162e71b7053SJung-uk Kim         goto opthelp;
1633b4e3dcbSSimon L. B. Nielsen 
164*b077aed3SPierre Pronchery     if (ciphername != NULL) {
165*b077aed3SPierre Pronchery         if (!opt_cipher(ciphername, &enc))
166*b077aed3SPierre Pronchery             goto opthelp;
167*b077aed3SPierre Pronchery     }
168e71b7053SJung-uk Kim     private = param_out || pubin || pubout ? 0 : 1;
169e71b7053SJung-uk Kim     if (text && !pubin)
170e71b7053SJung-uk Kim         private = 1;
1713b4e3dcbSSimon L. B. Nielsen 
172e71b7053SJung-uk Kim     if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
1733b4e3dcbSSimon L. B. Nielsen         BIO_printf(bio_err, "Error getting passwords\n");
1743b4e3dcbSSimon L. B. Nielsen         goto end;
1753b4e3dcbSSimon L. B. Nielsen     }
1763b4e3dcbSSimon L. B. Nielsen 
1773b4e3dcbSSimon L. B. Nielsen     BIO_printf(bio_err, "read EC key\n");
178*b077aed3SPierre Pronchery 
1793b4e3dcbSSimon L. B. Nielsen     if (pubin)
180*b077aed3SPierre Pronchery         eckey = load_pubkey(infile, informat, 1, passin, e, "public key");
1813b4e3dcbSSimon L. B. Nielsen     else
182*b077aed3SPierre Pronchery         eckey = load_key(infile, informat, 1, passin, e, "private key");
183*b077aed3SPierre Pronchery 
1846f9291ceSJung-uk Kim     if (eckey == NULL) {
1853b4e3dcbSSimon L. B. Nielsen         BIO_printf(bio_err, "unable to load Key\n");
1863b4e3dcbSSimon L. B. Nielsen         goto end;
1873b4e3dcbSSimon L. B. Nielsen     }
1883b4e3dcbSSimon L. B. Nielsen 
189e71b7053SJung-uk Kim     out = bio_open_owner(outfile, outformat, private);
190e71b7053SJung-uk Kim     if (out == NULL)
1913b4e3dcbSSimon L. B. Nielsen         goto end;
1923b4e3dcbSSimon L. B. Nielsen 
193*b077aed3SPierre Pronchery     if (point_format
194*b077aed3SPierre Pronchery         && !EVP_PKEY_set_utf8_string_param(
195*b077aed3SPierre Pronchery                 eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
196*b077aed3SPierre Pronchery                 point_format)) {
197*b077aed3SPierre Pronchery         BIO_printf(bio_err, "unable to set point conversion format\n");
198*b077aed3SPierre Pronchery         goto end;
199*b077aed3SPierre Pronchery     }
2003b4e3dcbSSimon L. B. Nielsen 
201*b077aed3SPierre Pronchery     if (asn1_encoding != NULL
202*b077aed3SPierre Pronchery         && !EVP_PKEY_set_utf8_string_param(
203*b077aed3SPierre Pronchery                 eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) {
204*b077aed3SPierre Pronchery         BIO_printf(bio_err, "unable to set asn1 encoding format\n");
205*b077aed3SPierre Pronchery         goto end;
206*b077aed3SPierre Pronchery     }
2073b4e3dcbSSimon L. B. Nielsen 
208*b077aed3SPierre Pronchery     if (no_public) {
209*b077aed3SPierre Pronchery         if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) {
210*b077aed3SPierre Pronchery             BIO_printf(bio_err, "unable to disable public key encoding\n");
211*b077aed3SPierre Pronchery             goto end;
212*b077aed3SPierre Pronchery         }
213*b077aed3SPierre Pronchery     } else {
214*b077aed3SPierre Pronchery         if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) {
215*b077aed3SPierre Pronchery             BIO_printf(bio_err, "unable to enable public key encoding\n");
216*b077aed3SPierre Pronchery             goto end;
217*b077aed3SPierre Pronchery         }
218*b077aed3SPierre Pronchery     }
219e71b7053SJung-uk Kim 
220e71b7053SJung-uk Kim     if (text) {
221e71b7053SJung-uk Kim         assert(pubin || private);
222*b077aed3SPierre Pronchery         if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0)
223*b077aed3SPierre Pronchery             || (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) {
224*b077aed3SPierre Pronchery             BIO_printf(bio_err, "unable to print EC key\n");
2253b4e3dcbSSimon L. B. Nielsen             goto end;
2263b4e3dcbSSimon L. B. Nielsen         }
227e71b7053SJung-uk Kim     }
228e71b7053SJung-uk Kim 
229e71b7053SJung-uk Kim     if (check) {
230*b077aed3SPierre Pronchery         pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL);
231*b077aed3SPierre Pronchery         if (pctx == NULL) {
232*b077aed3SPierre Pronchery             BIO_printf(bio_err, "unable to check EC key\n");
2333b4e3dcbSSimon L. B. Nielsen             goto end;
2345471f83eSSimon L. B. Nielsen         }
235*b077aed3SPierre Pronchery         if (EVP_PKEY_check(pctx) <= 0)
236*b077aed3SPierre Pronchery             BIO_printf(bio_err, "EC Key Invalid!\n");
237*b077aed3SPierre Pronchery         else
238*b077aed3SPierre Pronchery             BIO_printf(bio_err, "EC Key valid.\n");
239*b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
240*b077aed3SPierre Pronchery     }
241*b077aed3SPierre Pronchery 
242*b077aed3SPierre Pronchery     if (!noout) {
243*b077aed3SPierre Pronchery         int selection;
244*b077aed3SPierre Pronchery         const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM";
245*b077aed3SPierre Pronchery         const char *output_structure = "type-specific";
2463b4e3dcbSSimon L. B. Nielsen 
2473b4e3dcbSSimon L. B. Nielsen         BIO_printf(bio_err, "writing EC key\n");
248e71b7053SJung-uk Kim         if (param_out) {
249*b077aed3SPierre Pronchery             selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;
250e71b7053SJung-uk Kim         } else if (pubin || pubout) {
251*b077aed3SPierre Pronchery             selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
252*b077aed3SPierre Pronchery                 | OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
253*b077aed3SPierre Pronchery             output_structure = "SubjectPublicKeyInfo";
254e71b7053SJung-uk Kim         } else {
255*b077aed3SPierre Pronchery             selection = OSSL_KEYMGMT_SELECT_ALL;
256e71b7053SJung-uk Kim             assert(private);
257e71b7053SJung-uk Kim         }
258*b077aed3SPierre Pronchery 
259*b077aed3SPierre Pronchery         ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection,
260*b077aed3SPierre Pronchery                                              output_type, output_structure,
261*b077aed3SPierre Pronchery                                              NULL);
262*b077aed3SPierre Pronchery         if (enc != NULL) {
263*b077aed3SPierre Pronchery             OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL);
264*b077aed3SPierre Pronchery             /* Default passphrase prompter */
265*b077aed3SPierre Pronchery             OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL);
266*b077aed3SPierre Pronchery             if (passout != NULL)
267*b077aed3SPierre Pronchery                 /* When passout given, override the passphrase prompter */
268*b077aed3SPierre Pronchery                 OSSL_ENCODER_CTX_set_passphrase(ectx,
269*b077aed3SPierre Pronchery                                                 (const unsigned char *)passout,
270*b077aed3SPierre Pronchery                                                 strlen(passout));
271*b077aed3SPierre Pronchery         }
272*b077aed3SPierre Pronchery         if (!OSSL_ENCODER_to_bio(ectx, out)) {
273*b077aed3SPierre Pronchery             BIO_printf(bio_err, "unable to write EC key\n");
274*b077aed3SPierre Pronchery             goto end;
275e71b7053SJung-uk Kim         }
2763b4e3dcbSSimon L. B. Nielsen     }
2773b4e3dcbSSimon L. B. Nielsen 
2783b4e3dcbSSimon L. B. Nielsen     ret = 0;
2793b4e3dcbSSimon L. B. Nielsen end:
280*b077aed3SPierre Pronchery     if (ret != 0)
281*b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
2823b4e3dcbSSimon L. B. Nielsen     BIO_free_all(out);
283*b077aed3SPierre Pronchery     EVP_PKEY_free(eckey);
284*b077aed3SPierre Pronchery     EVP_CIPHER_free(enc);
285*b077aed3SPierre Pronchery     OSSL_ENCODER_CTX_free(ectx);
286*b077aed3SPierre Pronchery     OSSL_DECODER_CTX_free(dctx);
287*b077aed3SPierre Pronchery     EVP_PKEY_CTX_free(pctx);
2886cf8931aSJung-uk Kim     release_engine(e);
289*b077aed3SPierre Pronchery     if (passin != NULL)
290*b077aed3SPierre Pronchery         OPENSSL_clear_free(passin, strlen(passin));
291*b077aed3SPierre Pronchery     if (passout != NULL)
292*b077aed3SPierre Pronchery         OPENSSL_clear_free(passout, strlen(passout));
293e71b7053SJung-uk Kim     return ret;
2943b4e3dcbSSimon L. B. Nielsen }
295