1 /*
2 * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include "apps.h"
13 #include "progs.h"
14 #include <openssl/pem.h>
15 #include <openssl/err.h>
16 #include <openssl/evp.h>
17
18 static int verbose = 1;
19
20 static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
21 OSSL_LIB_CTX *libctx, const char *propq);
22 typedef enum OPTION_choice {
23 OPT_COMMON,
24 OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE,
25 OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER,
26 OPT_VERBOSE, OPT_QUIET, OPT_CONFIG,
27 OPT_PROV_ENUM
28 } OPTION_CHOICE;
29
30 const OPTIONS genpkey_options[] = {
31 OPT_SECTION("General"),
32 {"help", OPT_HELP, '-', "Display this summary"},
33 #ifndef OPENSSL_NO_ENGINE
34 {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
35 #endif
36 {"paramfile", OPT_PARAMFILE, '<', "Parameters file"},
37 {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"},
38 {"verbose", OPT_VERBOSE, '-', "Output status while generating keys"},
39 {"quiet", OPT_QUIET, '-', "Do not output status while generating keys"},
40 {"pkeyopt", OPT_PKEYOPT, 's',
41 "Set the public key algorithm option as opt:value"},
42 OPT_CONFIG_OPTION,
43
44 OPT_SECTION("Output"),
45 {"out", OPT_OUT, '>', "Output file"},
46 {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"},
47 {"pass", OPT_PASS, 's', "Output file pass phrase source"},
48 {"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"},
49 {"text", OPT_TEXT, '-', "Print the in text"},
50 {"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"},
51
52 OPT_PROV_OPTIONS,
53
54 /* This is deliberately last. */
55 {OPT_HELP_STR, 1, 1,
56 "Order of options may be important! See the documentation.\n"},
57 {NULL}
58 };
59
genpkey_main(int argc,char ** argv)60 int genpkey_main(int argc, char **argv)
61 {
62 CONF *conf = NULL;
63 BIO *in = NULL, *out = NULL;
64 ENGINE *e = NULL;
65 EVP_PKEY *pkey = NULL;
66 EVP_PKEY_CTX *ctx = NULL;
67 char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p;
68 const char *ciphername = NULL, *paramfile = NULL, *algname = NULL;
69 EVP_CIPHER *cipher = NULL;
70 OPTION_CHOICE o;
71 int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
72 int private = 0, i;
73 OSSL_LIB_CTX *libctx = app_get0_libctx();
74 STACK_OF(OPENSSL_STRING) *keyopt = NULL;
75
76 opt_set_unknown_name("cipher");
77 prog = opt_init(argc, argv, genpkey_options);
78 keyopt = sk_OPENSSL_STRING_new_null();
79 if (keyopt == NULL)
80 goto end;
81 while ((o = opt_next()) != OPT_EOF) {
82 switch (o) {
83 case OPT_EOF:
84 case OPT_ERR:
85 opthelp:
86 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
87 goto end;
88 case OPT_HELP:
89 ret = 0;
90 opt_help(genpkey_options);
91 goto end;
92 case OPT_OUTFORM:
93 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
94 goto opthelp;
95 break;
96 case OPT_OUT:
97 outfile = opt_arg();
98 break;
99 case OPT_PASS:
100 passarg = opt_arg();
101 break;
102 case OPT_ENGINE:
103 e = setup_engine(opt_arg(), 0);
104 break;
105 case OPT_PARAMFILE:
106 if (do_param == 1)
107 goto opthelp;
108 paramfile = opt_arg();
109 break;
110 case OPT_ALGORITHM:
111 algname = opt_arg();
112 break;
113 case OPT_PKEYOPT:
114 if (!sk_OPENSSL_STRING_push(keyopt, opt_arg()))
115 goto end;
116 break;
117 case OPT_QUIET:
118 verbose = 0;
119 break;
120 case OPT_VERBOSE:
121 verbose = 1;
122 break;
123 case OPT_GENPARAM:
124 do_param = 1;
125 break;
126 case OPT_TEXT:
127 text = 1;
128 break;
129 case OPT_CIPHER:
130 ciphername = opt_unknown();
131 break;
132 case OPT_CONFIG:
133 conf = app_load_config_modules(opt_arg());
134 if (conf == NULL)
135 goto end;
136 break;
137 case OPT_PROV_CASES:
138 if (!opt_provider(o))
139 goto end;
140 break;
141 }
142 }
143
144 /* No extra arguments. */
145 if (!opt_check_rest_arg(NULL))
146 goto opthelp;
147
148 /* Fetch cipher, etc. */
149 if (paramfile != NULL) {
150 if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq()))
151 goto end;
152 }
153 if (algname != NULL) {
154 if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq()))
155 goto end;
156 }
157 if (ctx == NULL)
158 goto opthelp;
159
160 for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) {
161 p = sk_OPENSSL_STRING_value(keyopt, i);
162 if (pkey_ctrl_string(ctx, p) <= 0) {
163 BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p);
164 ERR_print_errors(bio_err);
165 goto end;
166 }
167 }
168 if (!opt_cipher(ciphername, &cipher))
169 goto opthelp;
170 if (ciphername != NULL && do_param == 1) {
171 BIO_printf(bio_err, "Cannot use cipher with -genparam option\n");
172 goto opthelp;
173 }
174
175 private = do_param ? 0 : 1;
176
177 if (!app_passwd(passarg, NULL, &pass, NULL)) {
178 BIO_puts(bio_err, "Error getting password\n");
179 goto end;
180 }
181
182 out = bio_open_owner(outfile, outformat, private);
183 if (out == NULL)
184 goto end;
185
186 if (verbose)
187 EVP_PKEY_CTX_set_cb(ctx, progress_cb);
188 EVP_PKEY_CTX_set_app_data(ctx, bio_err);
189
190 pkey = do_param ? app_paramgen(ctx, algname)
191 : app_keygen(ctx, algname, 0, 0 /* not verbose */);
192
193 if (do_param) {
194 rv = PEM_write_bio_Parameters(out, pkey);
195 } else if (outformat == FORMAT_PEM) {
196 assert(private);
197 rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
198 } else if (outformat == FORMAT_ASN1) {
199 assert(private);
200 rv = i2d_PrivateKey_bio(out, pkey);
201 } else {
202 BIO_printf(bio_err, "Bad format specified for key\n");
203 goto end;
204 }
205
206 ret = 0;
207
208 if (rv <= 0) {
209 BIO_puts(bio_err, "Error writing key\n");
210 ret = 1;
211 }
212
213 if (text) {
214 if (do_param)
215 rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
216 else
217 rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
218
219 if (rv <= 0) {
220 BIO_puts(bio_err, "Error printing key\n");
221 ret = 1;
222 }
223 }
224
225 end:
226 sk_OPENSSL_STRING_free(keyopt);
227 if (ret != 0)
228 ERR_print_errors(bio_err);
229 EVP_PKEY_free(pkey);
230 EVP_PKEY_CTX_free(ctx);
231 EVP_CIPHER_free(cipher);
232 BIO_free_all(out);
233 BIO_free(in);
234 release_engine(e);
235 OPENSSL_free(pass);
236 NCONF_free(conf);
237 return ret;
238 }
239
init_keygen_file(EVP_PKEY_CTX ** pctx,const char * file,ENGINE * e,OSSL_LIB_CTX * libctx,const char * propq)240 static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
241 OSSL_LIB_CTX *libctx, const char *propq)
242 {
243 BIO *pbio;
244 EVP_PKEY *pkey = NULL;
245 EVP_PKEY_CTX *ctx = NULL;
246 if (*pctx) {
247 BIO_puts(bio_err, "Parameters already set!\n");
248 return 0;
249 }
250
251 pbio = BIO_new_file(file, "r");
252 if (pbio == NULL) {
253 BIO_printf(bio_err, "Can't open parameter file %s\n", file);
254 return 0;
255 }
256
257 pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq);
258 BIO_free(pbio);
259
260 if (pkey == NULL) {
261 BIO_printf(bio_err, "Error reading parameter file %s\n", file);
262 return 0;
263 }
264
265 if (e != NULL)
266 ctx = EVP_PKEY_CTX_new(pkey, e);
267 else
268 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
269 if (ctx == NULL)
270 goto err;
271 if (EVP_PKEY_keygen_init(ctx) <= 0)
272 goto err;
273 EVP_PKEY_free(pkey);
274 *pctx = ctx;
275 return 1;
276
277 err:
278 BIO_puts(bio_err, "Error initializing context\n");
279 ERR_print_errors(bio_err);
280 EVP_PKEY_CTX_free(ctx);
281 EVP_PKEY_free(pkey);
282 return 0;
283
284 }
285
init_gen_str(EVP_PKEY_CTX ** pctx,const char * algname,ENGINE * e,int do_param,OSSL_LIB_CTX * libctx,const char * propq)286 int init_gen_str(EVP_PKEY_CTX **pctx,
287 const char *algname, ENGINE *e, int do_param,
288 OSSL_LIB_CTX *libctx, const char *propq)
289 {
290 EVP_PKEY_CTX *ctx = NULL;
291 int pkey_id;
292
293 if (*pctx) {
294 BIO_puts(bio_err, "Algorithm already set!\n");
295 return 0;
296 }
297
298 pkey_id = get_legacy_pkey_id(libctx, algname, e);
299 if (pkey_id != NID_undef)
300 ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
301 else
302 ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
303
304 if (ctx == NULL)
305 goto err;
306 if (do_param) {
307 if (EVP_PKEY_paramgen_init(ctx) <= 0)
308 goto err;
309 } else {
310 if (EVP_PKEY_keygen_init(ctx) <= 0)
311 goto err;
312 }
313
314 *pctx = ctx;
315 return 1;
316
317 err:
318 BIO_printf(bio_err, "Error initializing %s context\n", algname);
319 ERR_print_errors(bio_err);
320 EVP_PKEY_CTX_free(ctx);
321 return 0;
322
323 }
324
325