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