]> git.ipfire.org Git - thirdparty/openssl.git/blob - apps/genpkey.c
Add help for pkeyopt values for the genpkey commandline app.
[thirdparty/openssl.git] / apps / genpkey.c
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
60 static const char *param_datatype_2name(unsigned int type, int *ishex)
61 {
62 *ishex = 0;
63
64 switch (type) {
65 case OSSL_PARAM_INTEGER: return "int";
66 case OSSL_PARAM_UNSIGNED_INTEGER: return "uint";
67 case OSSL_PARAM_REAL: return "float";
68 case OSSL_PARAM_OCTET_STRING: *ishex = 1; return "string";
69 case OSSL_PARAM_UTF8_STRING: return "string";
70 default:
71 return NULL;
72 }
73 }
74
75 static void show_gen_pkeyopt(const char *algname, OSSL_LIB_CTX *libctx, const char *propq)
76 {
77 EVP_PKEY_CTX *ctx = NULL;
78 const OSSL_PARAM *params;
79 int i, ishex = 0;
80
81 if (algname == NULL)
82 return;
83 ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
84 if (ctx == NULL)
85 return;
86
87 if (EVP_PKEY_keygen_init(ctx) <= 0)
88 goto cleanup;
89 params = EVP_PKEY_CTX_settable_params(ctx);
90 if (params == NULL)
91 goto cleanup;
92
93 BIO_printf(bio_err, "\nThe possible -pkeyopt arguments are:\n");
94 for (i = 0; params[i].key != NULL; ++i) {
95 const char *name = param_datatype_2name(params[i].data_type, &ishex);
96
97 if (name != NULL)
98 BIO_printf(bio_err, " %s%s:%s\n", ishex ? "hex" : "", params[i].key, name);
99 }
100 cleanup:
101 EVP_PKEY_CTX_free(ctx);
102 }
103
104 int genpkey_main(int argc, char **argv)
105 {
106 CONF *conf = NULL;
107 BIO *in = NULL, *out = NULL;
108 ENGINE *e = NULL;
109 EVP_PKEY *pkey = NULL;
110 EVP_PKEY_CTX *ctx = NULL;
111 char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p;
112 const char *ciphername = NULL, *paramfile = NULL, *algname = NULL;
113 EVP_CIPHER *cipher = NULL;
114 OPTION_CHOICE o;
115 int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
116 int private = 0, i;
117 OSSL_LIB_CTX *libctx = app_get0_libctx();
118 STACK_OF(OPENSSL_STRING) *keyopt = NULL;
119
120 opt_set_unknown_name("cipher");
121 prog = opt_init(argc, argv, genpkey_options);
122 keyopt = sk_OPENSSL_STRING_new_null();
123 if (keyopt == NULL)
124 goto end;
125 while ((o = opt_next()) != OPT_EOF) {
126 switch (o) {
127 case OPT_EOF:
128 case OPT_ERR:
129 opthelp:
130 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
131 goto end;
132 case OPT_HELP:
133 ret = 0;
134 opt_help(genpkey_options);
135 show_gen_pkeyopt(algname, libctx, app_get0_propq());
136 goto end;
137 case OPT_OUTFORM:
138 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
139 goto opthelp;
140 break;
141 case OPT_OUT:
142 outfile = opt_arg();
143 break;
144 case OPT_PASS:
145 passarg = opt_arg();
146 break;
147 case OPT_ENGINE:
148 e = setup_engine(opt_arg(), 0);
149 break;
150 case OPT_PARAMFILE:
151 if (do_param == 1)
152 goto opthelp;
153 paramfile = opt_arg();
154 break;
155 case OPT_ALGORITHM:
156 algname = opt_arg();
157 break;
158 case OPT_PKEYOPT:
159 if (!sk_OPENSSL_STRING_push(keyopt, opt_arg()))
160 goto end;
161 break;
162 case OPT_QUIET:
163 verbose = 0;
164 break;
165 case OPT_VERBOSE:
166 verbose = 1;
167 break;
168 case OPT_GENPARAM:
169 do_param = 1;
170 break;
171 case OPT_TEXT:
172 text = 1;
173 break;
174 case OPT_CIPHER:
175 ciphername = opt_unknown();
176 break;
177 case OPT_CONFIG:
178 conf = app_load_config_modules(opt_arg());
179 if (conf == NULL)
180 goto end;
181 break;
182 case OPT_PROV_CASES:
183 if (!opt_provider(o))
184 goto end;
185 break;
186 }
187 }
188
189 /* No extra arguments. */
190 if (!opt_check_rest_arg(NULL))
191 goto opthelp;
192
193 /* Fetch cipher, etc. */
194 if (paramfile != NULL) {
195 if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq()))
196 goto end;
197 }
198 if (algname != NULL) {
199 if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq()))
200 goto end;
201 }
202 if (ctx == NULL)
203 goto opthelp;
204
205 for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) {
206 p = sk_OPENSSL_STRING_value(keyopt, i);
207 if (pkey_ctrl_string(ctx, p) <= 0) {
208 BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p);
209 ERR_print_errors(bio_err);
210 goto end;
211 }
212 }
213 if (!opt_cipher(ciphername, &cipher))
214 goto opthelp;
215 if (ciphername != NULL && do_param == 1) {
216 BIO_printf(bio_err, "Cannot use cipher with -genparam option\n");
217 goto opthelp;
218 }
219
220 private = do_param ? 0 : 1;
221
222 if (!app_passwd(passarg, NULL, &pass, NULL)) {
223 BIO_puts(bio_err, "Error getting password\n");
224 goto end;
225 }
226
227 out = bio_open_owner(outfile, outformat, private);
228 if (out == NULL)
229 goto end;
230
231 if (verbose)
232 EVP_PKEY_CTX_set_cb(ctx, progress_cb);
233 EVP_PKEY_CTX_set_app_data(ctx, bio_err);
234
235 pkey = do_param ? app_paramgen(ctx, algname)
236 : app_keygen(ctx, algname, 0, 0 /* not verbose */);
237
238 if (do_param) {
239 rv = PEM_write_bio_Parameters(out, pkey);
240 } else if (outformat == FORMAT_PEM) {
241 assert(private);
242 rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
243 } else if (outformat == FORMAT_ASN1) {
244 assert(private);
245 rv = i2d_PrivateKey_bio(out, pkey);
246 } else {
247 BIO_printf(bio_err, "Bad format specified for key\n");
248 goto end;
249 }
250
251 ret = 0;
252
253 if (rv <= 0) {
254 BIO_puts(bio_err, "Error writing key\n");
255 ret = 1;
256 }
257
258 if (text) {
259 if (do_param)
260 rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
261 else
262 rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
263
264 if (rv <= 0) {
265 BIO_puts(bio_err, "Error printing key\n");
266 ret = 1;
267 }
268 }
269
270 end:
271 sk_OPENSSL_STRING_free(keyopt);
272 if (ret != 0)
273 ERR_print_errors(bio_err);
274 EVP_PKEY_free(pkey);
275 EVP_PKEY_CTX_free(ctx);
276 EVP_CIPHER_free(cipher);
277 BIO_free_all(out);
278 BIO_free(in);
279 release_engine(e);
280 OPENSSL_free(pass);
281 NCONF_free(conf);
282 return ret;
283 }
284
285 static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
286 OSSL_LIB_CTX *libctx, const char *propq)
287 {
288 BIO *pbio;
289 EVP_PKEY *pkey = NULL;
290 EVP_PKEY_CTX *ctx = NULL;
291 if (*pctx) {
292 BIO_puts(bio_err, "Parameters already set!\n");
293 return 0;
294 }
295
296 pbio = BIO_new_file(file, "r");
297 if (pbio == NULL) {
298 BIO_printf(bio_err, "Can't open parameter file %s\n", file);
299 return 0;
300 }
301
302 pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq);
303 BIO_free(pbio);
304
305 if (pkey == NULL) {
306 BIO_printf(bio_err, "Error reading parameter file %s\n", file);
307 return 0;
308 }
309
310 if (e != NULL)
311 ctx = EVP_PKEY_CTX_new(pkey, e);
312 else
313 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
314 if (ctx == NULL)
315 goto err;
316 if (EVP_PKEY_keygen_init(ctx) <= 0)
317 goto err;
318 EVP_PKEY_free(pkey);
319 *pctx = ctx;
320 return 1;
321
322 err:
323 BIO_puts(bio_err, "Error initializing context\n");
324 ERR_print_errors(bio_err);
325 EVP_PKEY_CTX_free(ctx);
326 EVP_PKEY_free(pkey);
327 return 0;
328
329 }
330
331 int init_gen_str(EVP_PKEY_CTX **pctx,
332 const char *algname, ENGINE *e, int do_param,
333 OSSL_LIB_CTX *libctx, const char *propq)
334 {
335 EVP_PKEY_CTX *ctx = NULL;
336 int pkey_id;
337
338 if (*pctx) {
339 BIO_puts(bio_err, "Algorithm already set!\n");
340 return 0;
341 }
342
343 pkey_id = get_legacy_pkey_id(libctx, algname, e);
344 if (pkey_id != NID_undef)
345 ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
346 else
347 ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
348
349 if (ctx == NULL)
350 goto err;
351 if (do_param) {
352 if (EVP_PKEY_paramgen_init(ctx) <= 0)
353 goto err;
354 } else {
355 if (EVP_PKEY_keygen_init(ctx) <= 0)
356 goto err;
357 }
358
359 *pctx = ctx;
360 return 1;
361
362 err:
363 BIO_printf(bio_err, "Error initializing %s context\n", algname);
364 ERR_print_errors(bio_err);
365 EVP_PKEY_CTX_free(ctx);
366 return 0;
367
368 }
369