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