genpkey.c revision 1.1.1.2 1 /*
2 * Copyright 2006-2025 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,
25 OPT_OUTFORM,
26 OPT_OUT,
27 OPT_PASS,
28 OPT_PARAMFILE,
29 OPT_ALGORITHM,
30 OPT_PKEYOPT,
31 OPT_GENPARAM,
32 OPT_TEXT,
33 OPT_CIPHER,
34 OPT_VERBOSE,
35 OPT_QUIET,
36 OPT_CONFIG,
37 OPT_OUTPUBKEY,
38 OPT_PROV_ENUM,
39 OPT_R_ENUM
40 } OPTION_CHOICE;
41
42 const OPTIONS genpkey_options[] = {
43 OPT_SECTION("General"),
44 { "help", OPT_HELP, '-', "Display this summary" },
45 #ifndef OPENSSL_NO_ENGINE
46 { "engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device" },
47 #endif
48 { "paramfile", OPT_PARAMFILE, '<', "Parameters file" },
49 { "algorithm", OPT_ALGORITHM, 's', "The public key algorithm" },
50 { "verbose", OPT_VERBOSE, '-', "Output status while generating keys" },
51 { "quiet", OPT_QUIET, '-', "Do not output status while generating keys" },
52 { "pkeyopt", OPT_PKEYOPT, 's',
53 "Set the public key algorithm option as opt:value" },
54 OPT_CONFIG_OPTION,
55
56 OPT_SECTION("Output"),
57 { "out", OPT_OUT, '>', "Output (private key) file" },
58 { "outpubkey", OPT_OUTPUBKEY, '>', "Output public key file" },
59 { "outform", OPT_OUTFORM, 'F', "output format (DER or PEM)" },
60 { "pass", OPT_PASS, 's', "Output file pass phrase source" },
61 { "genparam", OPT_GENPARAM, '-', "Generate parameters, not key" },
62 { "text", OPT_TEXT, '-', "Print the private key in text" },
63 { "", OPT_CIPHER, '-', "Cipher to use to encrypt the key" },
64
65 OPT_PROV_OPTIONS,
66 OPT_R_OPTIONS,
67
68 /* This is deliberately last. */
69 { OPT_HELP_STR, 1, 1,
70 "Order of options may be important! See the documentation.\n" },
71 { NULL }
72 };
73
74 static const char *param_datatype_2name(unsigned int type, int *ishex)
75 {
76 *ishex = 0;
77
78 switch (type) {
79 case OSSL_PARAM_INTEGER:
80 return "int";
81 case OSSL_PARAM_UNSIGNED_INTEGER:
82 return "uint";
83 case OSSL_PARAM_REAL:
84 return "float";
85 case OSSL_PARAM_OCTET_STRING:
86 *ishex = 1;
87 return "string";
88 case OSSL_PARAM_UTF8_STRING:
89 return "string";
90 default:
91 return NULL;
92 }
93 }
94
95 static void show_gen_pkeyopt(const char *algname, OSSL_LIB_CTX *libctx, const char *propq)
96 {
97 EVP_PKEY_CTX *ctx = NULL;
98 const OSSL_PARAM *params;
99 int i, ishex = 0;
100
101 if (algname == NULL)
102 return;
103 ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
104 if (ctx == NULL)
105 return;
106
107 if (EVP_PKEY_keygen_init(ctx) <= 0)
108 goto cleanup;
109 params = EVP_PKEY_CTX_settable_params(ctx);
110 if (params == NULL)
111 goto cleanup;
112
113 BIO_printf(bio_err, "\nThe possible -pkeyopt arguments are:\n");
114 for (i = 0; params[i].key != NULL; ++i) {
115 const char *name = param_datatype_2name(params[i].data_type, &ishex);
116
117 if (name != NULL)
118 BIO_printf(bio_err, " %s%s:%s\n", ishex ? "hex" : "", params[i].key, name);
119 }
120 cleanup:
121 EVP_PKEY_CTX_free(ctx);
122 }
123
124 int genpkey_main(int argc, char **argv)
125 {
126 CONF *conf = NULL;
127 BIO *mem_out = NULL, *mem_outpubkey = NULL;
128 ENGINE *e = NULL;
129 EVP_PKEY *pkey = NULL;
130 EVP_PKEY_CTX *ctx = NULL;
131 char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p;
132 char *outpubkeyfile = NULL;
133 const char *ciphername = NULL, *paramfile = NULL, *algname = NULL;
134 EVP_CIPHER *cipher = NULL;
135 OPTION_CHOICE o;
136 int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
137 int private = 0, i;
138 OSSL_LIB_CTX *libctx = app_get0_libctx();
139 STACK_OF(OPENSSL_STRING) *keyopt = NULL;
140
141 opt_set_unknown_name("cipher");
142 prog = opt_init(argc, argv, genpkey_options);
143 keyopt = sk_OPENSSL_STRING_new_null();
144 if (keyopt == NULL)
145 goto end;
146 while ((o = opt_next()) != OPT_EOF) {
147 switch (o) {
148 case OPT_EOF:
149 case OPT_ERR:
150 opthelp:
151 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
152 goto end;
153 case OPT_HELP:
154 ret = 0;
155 opt_help(genpkey_options);
156 show_gen_pkeyopt(algname, libctx, app_get0_propq());
157 goto end;
158 case OPT_OUTFORM:
159 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
160 goto opthelp;
161 break;
162 case OPT_OUT:
163 outfile = opt_arg();
164 break;
165 case OPT_OUTPUBKEY:
166 outpubkeyfile = opt_arg();
167 break;
168 case OPT_PASS:
169 passarg = opt_arg();
170 break;
171 case OPT_ENGINE:
172 e = setup_engine(opt_arg(), 0);
173 break;
174 case OPT_PARAMFILE:
175 if (do_param == 1)
176 goto opthelp;
177 paramfile = opt_arg();
178 break;
179 case OPT_ALGORITHM:
180 algname = opt_arg();
181 break;
182 case OPT_PKEYOPT:
183 if (!sk_OPENSSL_STRING_push(keyopt, opt_arg()))
184 goto end;
185 break;
186 case OPT_QUIET:
187 verbose = 0;
188 break;
189 case OPT_VERBOSE:
190 verbose = 1;
191 break;
192 case OPT_GENPARAM:
193 do_param = 1;
194 break;
195 case OPT_TEXT:
196 text = 1;
197 break;
198 case OPT_CIPHER:
199 ciphername = opt_unknown();
200 break;
201 case OPT_CONFIG:
202 conf = app_load_config_modules(opt_arg());
203 if (conf == NULL)
204 goto end;
205 break;
206 case OPT_PROV_CASES:
207 if (!opt_provider(o))
208 goto end;
209 break;
210 case OPT_R_CASES:
211 if (!opt_rand(o))
212 goto end;
213 break;
214 }
215 }
216
217 /* No extra arguments. */
218 if (!opt_check_rest_arg(NULL))
219 goto opthelp;
220
221 if (!app_RAND_load())
222 goto end;
223
224 /* Fetch cipher, etc. */
225 if (paramfile != NULL) {
226 if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq()))
227 goto end;
228 }
229 if (algname != NULL) {
230 if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq()))
231 goto end;
232 }
233 if (ctx == NULL)
234 goto opthelp;
235
236 for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) {
237 p = sk_OPENSSL_STRING_value(keyopt, i);
238 if (pkey_ctrl_string(ctx, p) <= 0) {
239 BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p);
240 ERR_print_errors(bio_err);
241 goto end;
242 }
243 }
244 if (!opt_cipher(ciphername, &cipher))
245 goto opthelp;
246 if (ciphername != NULL && do_param == 1) {
247 BIO_printf(bio_err, "Cannot use cipher with -genparam option\n");
248 goto opthelp;
249 }
250
251 private = do_param ? 0 : 1;
252
253 if (!app_passwd(passarg, NULL, &pass, NULL)) {
254 BIO_puts(bio_err, "Error getting password\n");
255 goto end;
256 }
257
258 mem_out = BIO_new(BIO_s_mem());
259 if (mem_out == NULL)
260 goto end;
261 BIO_set_mem_eof_return(mem_out, 0);
262
263 if (outpubkeyfile != NULL) {
264 mem_outpubkey = BIO_new(BIO_s_mem());
265 if (mem_outpubkey == NULL)
266 goto end;
267 BIO_set_mem_eof_return(mem_outpubkey, 0);
268 }
269
270 if (verbose)
271 EVP_PKEY_CTX_set_cb(ctx, progress_cb);
272 EVP_PKEY_CTX_set_app_data(ctx, bio_err);
273
274 pkey = do_param ? app_paramgen(ctx, algname)
275 : app_keygen(ctx, algname, 0, 0 /* not verbose */);
276 if (pkey == NULL)
277 goto end;
278
279 if (do_param) {
280 rv = PEM_write_bio_Parameters(mem_out, pkey);
281 } else if (outformat == FORMAT_PEM) {
282 assert(private);
283 rv = PEM_write_bio_PrivateKey(mem_out, pkey, cipher, NULL, 0, NULL, pass);
284 if (rv > 0 && mem_outpubkey != NULL)
285 rv = PEM_write_bio_PUBKEY(mem_outpubkey, pkey);
286 } else if (outformat == FORMAT_ASN1) {
287 assert(private);
288 rv = i2d_PrivateKey_bio(mem_out, pkey);
289 if (rv > 0 && mem_outpubkey != NULL)
290 rv = i2d_PUBKEY_bio(mem_outpubkey, pkey);
291 } else {
292 BIO_printf(bio_err, "Bad format specified for key\n");
293 goto end;
294 }
295
296 ret = 0;
297
298 if (rv <= 0) {
299 BIO_puts(bio_err, "Error writing key(s)\n");
300 ret = 1;
301 }
302
303 if (text) {
304 if (do_param)
305 rv = EVP_PKEY_print_params(mem_out, pkey, 0, NULL);
306 else
307 rv = EVP_PKEY_print_private(mem_out, pkey, 0, NULL);
308
309 if (rv <= 0) {
310 BIO_puts(bio_err, "Error printing key\n");
311 ret = 1;
312 }
313 }
314
315 end:
316 sk_OPENSSL_STRING_free(keyopt);
317 if (ret != 0) {
318 ERR_print_errors(bio_err);
319 } else {
320 if (mem_outpubkey != NULL) {
321 rv = mem_bio_to_file(mem_outpubkey, outpubkeyfile, outformat, private);
322 if (!rv)
323 BIO_printf(bio_err, "Error writing to outpubkey: '%s'. Error: %s\n",
324 outpubkeyfile, strerror(errno));
325 }
326 if (mem_out != NULL) {
327 rv = mem_bio_to_file(mem_out, outfile, outformat, private);
328 if (!rv)
329 BIO_printf(bio_err, "Error writing to outfile: '%s'. Error: %s\n",
330 outfile, strerror(errno));
331 }
332 }
333 EVP_PKEY_free(pkey);
334 EVP_PKEY_CTX_free(ctx);
335 EVP_CIPHER_free(cipher);
336 BIO_free_all(mem_out);
337 BIO_free_all(mem_outpubkey);
338 release_engine(e);
339 OPENSSL_free(pass);
340 NCONF_free(conf);
341 return ret;
342 }
343
344 static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
345 OSSL_LIB_CTX *libctx, const char *propq)
346 {
347 BIO *pbio;
348 EVP_PKEY *pkey = NULL;
349 EVP_PKEY_CTX *ctx = NULL;
350 if (*pctx) {
351 BIO_puts(bio_err, "Parameters already set!\n");
352 return 0;
353 }
354
355 pbio = BIO_new_file(file, "r");
356 if (pbio == NULL) {
357 BIO_printf(bio_err, "Can't open parameter file %s\n", file);
358 return 0;
359 }
360
361 pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq);
362 BIO_free(pbio);
363
364 if (pkey == NULL) {
365 BIO_printf(bio_err, "Error reading parameter file %s\n", file);
366 return 0;
367 }
368
369 if (e != NULL)
370 ctx = EVP_PKEY_CTX_new(pkey, e);
371 else
372 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
373 if (ctx == NULL)
374 goto err;
375 if (EVP_PKEY_keygen_init(ctx) <= 0)
376 goto err;
377 EVP_PKEY_free(pkey);
378 *pctx = ctx;
379 return 1;
380
381 err:
382 BIO_puts(bio_err, "Error initializing context\n");
383 ERR_print_errors(bio_err);
384 EVP_PKEY_CTX_free(ctx);
385 EVP_PKEY_free(pkey);
386 return 0;
387 }
388
389 int init_gen_str(EVP_PKEY_CTX **pctx,
390 const char *algname, ENGINE *e, int do_param,
391 OSSL_LIB_CTX *libctx, const char *propq)
392 {
393 EVP_PKEY_CTX *ctx = NULL;
394 int pkey_id;
395
396 if (*pctx) {
397 BIO_puts(bio_err, "Algorithm already set!\n");
398 return 0;
399 }
400
401 pkey_id = get_legacy_pkey_id(libctx, algname, e);
402 if (pkey_id != NID_undef)
403 ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
404 else
405 ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
406
407 if (ctx == NULL)
408 goto err;
409 if (do_param) {
410 if (EVP_PKEY_paramgen_init(ctx) <= 0)
411 goto err;
412 } else {
413 if (EVP_PKEY_keygen_init(ctx) <= 0)
414 goto err;
415 }
416
417 *pctx = ctx;
418 return 1;
419
420 err:
421 BIO_printf(bio_err, "Error initializing %s context\n", algname);
422 ERR_print_errors(bio_err);
423 EVP_PKEY_CTX_free(ctx);
424 return 0;
425 }
426