]> git.ipfire.org Git - thirdparty/openssl.git/blame - apps/genpkey.c
Update copyright year
[thirdparty/openssl.git] / apps / genpkey.c
CommitLineData
0f113f3e 1/*
33388b44 2 * Copyright 2006-2020 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>
01b8b3c7 17#ifndef OPENSSL_NO_ENGINE
0f113f3e 18# include <openssl/engine.h>
01b8b3c7 19#endif
f5cda4cb 20
7e1b7485 21static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e);
f5cda4cb
DSH
22static int genpkey_cb(EVP_PKEY_CTX *ctx);
23
7e1b7485
RS
24typedef enum OPTION_choice {
25 OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
26 OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE,
6bd4e3f2
P
27 OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER,
28 OPT_PROV_ENUM
7e1b7485
RS
29} OPTION_CHOICE;
30
44c83ebd 31const OPTIONS genpkey_options[] = {
5388f986 32 OPT_SECTION("General"),
7e1b7485 33 {"help", OPT_HELP, '-', "Display this summary"},
5388f986
RS
34#ifndef OPENSSL_NO_ENGINE
35 {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
36#endif
7e1b7485
RS
37 {"paramfile", OPT_PARAMFILE, '<', "Parameters file"},
38 {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"},
39 {"pkeyopt", OPT_PKEYOPT, 's',
40 "Set the public key algorithm option as opt:value"},
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 58int genpkey_main(int argc, char **argv)
0f113f3e 59{
0f113f3e 60 BIO *in = NULL, *out = NULL;
7e1b7485 61 ENGINE *e = NULL;
0f113f3e
MC
62 EVP_PKEY *pkey = NULL;
63 EVP_PKEY_CTX *ctx = NULL;
7e1b7485
RS
64 char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog;
65 const EVP_CIPHER *cipher = NULL;
66 OPTION_CHOICE o;
67 int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
3b061a00 68 int private = 0;
7e1b7485
RS
69
70 prog = opt_init(argc, argv, genpkey_options);
71 while ((o = opt_next()) != OPT_EOF) {
72 switch (o) {
73 case OPT_EOF:
74 case OPT_ERR:
75 opthelp:
76 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
77 goto end;
78 case OPT_HELP:
79 ret = 0;
80 opt_help(genpkey_options);
81 goto end;
82 case OPT_OUTFORM:
83 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
84 goto opthelp;
85 break;
86 case OPT_OUT:
87 outfile = opt_arg();
88 break;
7e1b7485
RS
89 case OPT_PASS:
90 passarg = opt_arg();
91 break;
7e1b7485
RS
92 case OPT_ENGINE:
93 e = setup_engine(opt_arg(), 0);
94 break;
7e1b7485 95 case OPT_PARAMFILE:
0f113f3e 96 if (do_param == 1)
7e1b7485
RS
97 goto opthelp;
98 if (!init_keygen_file(&ctx, opt_arg(), e))
0f113f3e 99 goto end;
7e1b7485
RS
100 break;
101 case OPT_ALGORITHM:
102 if (!init_gen_str(&ctx, opt_arg(), e, do_param))
0f113f3e 103 goto end;
7e1b7485
RS
104 break;
105 case OPT_PKEYOPT:
106 if (ctx == NULL) {
107 BIO_printf(bio_err, "%s: No keytype specified.\n", prog);
108 goto opthelp;
109 }
110 if (pkey_ctrl_string(ctx, opt_arg()) <= 0) {
111 BIO_printf(bio_err,
112 "%s: Error setting %s parameter:\n",
113 prog, opt_arg());
0f113f3e
MC
114 ERR_print_errors(bio_err);
115 goto end;
116 }
7e1b7485
RS
117 break;
118 case OPT_GENPARAM:
119 if (ctx != NULL)
120 goto opthelp;
0f113f3e 121 do_param = 1;
7e1b7485
RS
122 break;
123 case OPT_TEXT:
0f113f3e 124 text = 1;
7e1b7485
RS
125 break;
126 case OPT_CIPHER:
127 if (!opt_cipher(opt_unknown(), &cipher)
128 || do_param == 1)
129 goto opthelp;
49c9c1b3
DO
130 if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE ||
131 EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE ||
132 EVP_CIPHER_mode(cipher) == EVP_CIPH_XTS_MODE ||
133 EVP_CIPHER_mode(cipher) == EVP_CIPH_OCB_MODE) {
134 BIO_printf(bio_err, "%s: cipher mode not supported\n", prog);
135 goto end;
136 }
6bd4e3f2
P
137 break;
138 case OPT_PROV_CASES:
139 if (!opt_provider(o))
140 goto end;
141 break;
0f113f3e 142 }
0f113f3e 143 }
7e1b7485 144 argc = opt_num_rest();
03358517
KR
145 if (argc != 0)
146 goto opthelp;
147
3b061a00 148 private = do_param ? 0 : 1;
0f113f3e 149
7e1b7485
RS
150 if (ctx == NULL)
151 goto opthelp;
0f113f3e 152
7e1b7485 153 if (!app_passwd(passarg, NULL, &pass, NULL)) {
0f113f3e
MC
154 BIO_puts(bio_err, "Error getting password\n");
155 goto end;
156 }
157
bdd58d98 158 out = bio_open_owner(outfile, outformat, private);
7e1b7485
RS
159 if (out == NULL)
160 goto end;
0f113f3e
MC
161
162 EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
163 EVP_PKEY_CTX_set_app_data(ctx, bio_err);
164
165 if (do_param) {
166 if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) {
167 BIO_puts(bio_err, "Error generating parameters\n");
168 ERR_print_errors(bio_err);
169 goto end;
170 }
171 } else {
172 if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
173 BIO_puts(bio_err, "Error generating key\n");
174 ERR_print_errors(bio_err);
175 goto end;
176 }
177 }
178
2234212c 179 if (do_param) {
0f113f3e 180 rv = PEM_write_bio_Parameters(out, pkey);
2234212c 181 } else if (outformat == FORMAT_PEM) {
3b061a00 182 assert(private);
0f113f3e 183 rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
3b061a00
RS
184 } else if (outformat == FORMAT_ASN1) {
185 assert(private);
0f113f3e 186 rv = i2d_PrivateKey_bio(out, pkey);
3b061a00 187 } else {
0f113f3e
MC
188 BIO_printf(bio_err, "Bad format specified for key\n");
189 goto end;
190 }
191
192 if (rv <= 0) {
193 BIO_puts(bio_err, "Error writing key\n");
194 ERR_print_errors(bio_err);
195 }
196
197 if (text) {
198 if (do_param)
199 rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
200 else
201 rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
202
203 if (rv <= 0) {
204 BIO_puts(bio_err, "Error printing key\n");
205 ERR_print_errors(bio_err);
206 }
207 }
208
209 ret = 0;
210
211 end:
c5ba2d99
RS
212 EVP_PKEY_free(pkey);
213 EVP_PKEY_CTX_free(ctx);
ca3a82c3 214 BIO_free_all(out);
0f113f3e 215 BIO_free(in);
dd1abd44 216 release_engine(e);
b548a1f1 217 OPENSSL_free(pass);
0f113f3e
MC
218 return ret;
219}
f5cda4cb 220
7e1b7485 221static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e)
0f113f3e
MC
222{
223 BIO *pbio;
224 EVP_PKEY *pkey = NULL;
225 EVP_PKEY_CTX *ctx = NULL;
226 if (*pctx) {
7e1b7485 227 BIO_puts(bio_err, "Parameters already set!\n");
0f113f3e
MC
228 return 0;
229 }
230
231 pbio = BIO_new_file(file, "r");
12a765a5 232 if (pbio == NULL) {
7e1b7485 233 BIO_printf(bio_err, "Can't open parameter file %s\n", file);
0f113f3e
MC
234 return 0;
235 }
236
237 pkey = PEM_read_bio_Parameters(pbio, NULL);
238 BIO_free(pbio);
239
12a765a5 240 if (pkey == NULL) {
0f113f3e
MC
241 BIO_printf(bio_err, "Error reading parameter file %s\n", file);
242 return 0;
243 }
244
245 ctx = EVP_PKEY_CTX_new(pkey, e);
96487cdd 246 if (ctx == NULL)
0f113f3e
MC
247 goto err;
248 if (EVP_PKEY_keygen_init(ctx) <= 0)
249 goto err;
250 EVP_PKEY_free(pkey);
251 *pctx = ctx;
252 return 1;
253
254 err:
7e1b7485
RS
255 BIO_puts(bio_err, "Error initializing context\n");
256 ERR_print_errors(bio_err);
c5ba2d99
RS
257 EVP_PKEY_CTX_free(ctx);
258 EVP_PKEY_free(pkey);
0f113f3e
MC
259 return 0;
260
261}
f5cda4cb 262
7e1b7485 263int init_gen_str(EVP_PKEY_CTX **pctx,
0f113f3e
MC
264 const char *algname, ENGINE *e, int do_param)
265{
266 EVP_PKEY_CTX *ctx = NULL;
267 const EVP_PKEY_ASN1_METHOD *ameth;
268 ENGINE *tmpeng = NULL;
269 int pkey_id;
01b8b3c7 270
0f113f3e 271 if (*pctx) {
7e1b7485 272 BIO_puts(bio_err, "Algorithm already set!\n");
0f113f3e
MC
273 return 0;
274 }
b3c6a331 275
0f113f3e 276 ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
f5cda4cb 277
70531c14 278#ifndef OPENSSL_NO_ENGINE
0f113f3e
MC
279 if (!ameth && e)
280 ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
70531c14 281#endif
b3c6a331 282
0f113f3e
MC
283 if (!ameth) {
284 BIO_printf(bio_err, "Algorithm %s not found\n", algname);
285 return 0;
286 }
f5cda4cb 287
0f113f3e 288 ERR_clear_error();
b3c6a331 289
0f113f3e 290 EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
01b8b3c7 291#ifndef OPENSSL_NO_ENGINE
7c96dbcd 292 ENGINE_finish(tmpeng);
01b8b3c7 293#endif
0f113f3e
MC
294 ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
295
296 if (!ctx)
297 goto err;
298 if (do_param) {
299 if (EVP_PKEY_paramgen_init(ctx) <= 0)
300 goto err;
301 } else {
302 if (EVP_PKEY_keygen_init(ctx) <= 0)
303 goto err;
304 }
305
306 *pctx = ctx;
307 return 1;
308
309 err:
7e1b7485
RS
310 BIO_printf(bio_err, "Error initializing %s context\n", algname);
311 ERR_print_errors(bio_err);
c5ba2d99 312 EVP_PKEY_CTX_free(ctx);
0f113f3e
MC
313 return 0;
314
315}
f5cda4cb
DSH
316
317static int genpkey_cb(EVP_PKEY_CTX *ctx)
0f113f3e
MC
318{
319 char c = '*';
320 BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
321 int p;
322 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
323 if (p == 0)
324 c = '.';
325 if (p == 1)
326 c = '+';
327 if (p == 2)
328 c = '*';
329 if (p == 3)
330 c = '\n';
331 BIO_write(b, &c, 1);
332 (void)BIO_flush(b);
333 return 1;
334}