Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/apps/genpkey.c
105419 views
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
427