blob: dcb9ad1dd8303fec397c8ac2a59dd010eab2d3d6 [file] [log] [blame]
Matt Caswell0f113f32015-01-22 03:40:55 +00001/*
Matt Caswellfecb3aa2022-05-03 11:52:38 +01002 * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.
Rich Salz846e33c2016-05-17 14:18:30 -04003 *
Richard Levittedffa7522018-12-06 13:00:26 +01004 * Licensed under the Apache License 2.0 (the "License"). You may not use
Rich Salz846e33c2016-05-17 14:18:30 -04005 * 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
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +00008 */
Rich Salz846e33c2016-05-17 14:18:30 -04009
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +000010#include <stdio.h>
11#include <string.h>
12#include "apps.h"
Richard Levittedab2cd62018-01-31 11:13:10 +010013#include "progs.h"
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +000014#include <openssl/pem.h>
15#include <openssl/err.h>
16#include <openssl/evp.h>
17
Philip Prindevillea414fd62021-12-21 20:44:07 -070018static int verbose = 1;
Rich Salz7d72dc72021-05-12 11:45:37 -040019
Shane Lontis7c9a7cf2020-06-16 13:04:57 +100020static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
Dr. Matthias St. Pierreb4250012020-10-15 12:55:50 +030021 OSSL_LIB_CTX *libctx, const char *propq);
Rich Salz7e1b7482015-04-24 15:26:15 -040022typedef enum OPTION_choice {
Dr. David von Oheimbb0f96012021-05-01 15:29:00 +020023 OPT_COMMON,
Rich Salz7e1b7482015-04-24 15:26:15 -040024 OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE,
Pauli6bd4e3f2020-02-25 14:29:30 +100025 OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER,
Philip Prindevillea414fd62021-12-21 20:44:07 -070026 OPT_VERBOSE, OPT_QUIET, OPT_CONFIG,
Pauli6bd4e3f2020-02-25 14:29:30 +100027 OPT_PROV_ENUM
Rich Salz7e1b7482015-04-24 15:26:15 -040028} OPTION_CHOICE;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +000029
FdaSilvaYY44c83eb2016-03-13 14:07:50 +010030const OPTIONS genpkey_options[] = {
Rich Salz5388f982019-11-08 06:08:30 +100031 OPT_SECTION("General"),
Rich Salz7e1b7482015-04-24 15:26:15 -040032 {"help", OPT_HELP, '-', "Display this summary"},
Rich Salz5388f982019-11-08 06:08:30 +100033#ifndef OPENSSL_NO_ENGINE
34 {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
35#endif
Rich Salz7e1b7482015-04-24 15:26:15 -040036 {"paramfile", OPT_PARAMFILE, '<', "Parameters file"},
37 {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"},
Philip Prindevillea414fd62021-12-21 20:44:07 -070038 {"verbose", OPT_VERBOSE, '-', "Output status while generating keys"},
Paulidbd02442021-08-06 10:01:15 +100039 {"quiet", OPT_QUIET, '-', "Do not output status while generating keys"},
Rich Salz7e1b7482015-04-24 15:26:15 -040040 {"pkeyopt", OPT_PKEYOPT, 's',
41 "Set the public key algorithm option as opt:value"},
Shane Lontis7c9a7cf2020-06-16 13:04:57 +100042 OPT_CONFIG_OPTION,
Rich Salz5388f982019-11-08 06:08:30 +100043
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"},
Rich Salz7e1b7482015-04-24 15:26:15 -040048 {"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"},
Rich Salz5388f982019-11-08 06:08:30 +100051
Pauli6bd4e3f2020-02-25 14:29:30 +100052 OPT_PROV_OPTIONS,
53
Rich Salz9c3bcfa2015-05-15 13:50:38 -040054 /* This is deliberately last. */
Rich Salz7e1b7482015-04-24 15:26:15 -040055 {OPT_HELP_STR, 1, 1,
56 "Order of options may be important! See the documentation.\n"},
57 {NULL}
58};
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +000059
Rich Salz7e1b7482015-04-24 15:26:15 -040060int genpkey_main(int argc, char **argv)
Matt Caswell0f113f32015-01-22 03:40:55 +000061{
Shane Lontis7c9a7cf2020-06-16 13:04:57 +100062 CONF *conf = NULL;
Matt Caswell0f113f32015-01-22 03:40:55 +000063 BIO *in = NULL, *out = NULL;
Rich Salz7e1b7482015-04-24 15:26:15 -040064 ENGINE *e = NULL;
Matt Caswell0f113f32015-01-22 03:40:55 +000065 EVP_PKEY *pkey = NULL;
66 EVP_PKEY_CTX *ctx = NULL;
Rich Salz182717b2021-02-07 10:42:23 -050067 char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p;
68 const char *ciphername = NULL, *paramfile = NULL, *algname = NULL;
Rich Salz606a4172021-02-17 16:15:27 -050069 EVP_CIPHER *cipher = NULL;
Rich Salz7e1b7482015-04-24 15:26:15 -040070 OPTION_CHOICE o;
71 int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
Paulif7d24272021-06-15 14:07:51 +100072 int private = 0, i;
Dr. Matthias St. Pierreb4250012020-10-15 12:55:50 +030073 OSSL_LIB_CTX *libctx = app_get0_libctx();
Rich Salz182717b2021-02-07 10:42:23 -050074 STACK_OF(OPENSSL_STRING) *keyopt = NULL;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +000075
Dr. David von Oheimb2c272442021-08-24 12:03:12 +020076 opt_set_unknown_name("cipher");
Rich Salz7e1b7482015-04-24 15:26:15 -040077 prog = opt_init(argc, argv, genpkey_options);
Rich Salz182717b2021-02-07 10:42:23 -050078 keyopt = sk_OPENSSL_STRING_new_null();
79 if (keyopt == NULL)
80 goto end;
Rich Salz7e1b7482015-04-24 15:26:15 -040081 while ((o = opt_next()) != OPT_EOF) {
82 switch (o) {
83 case OPT_EOF:
84 case OPT_ERR:
85 opthelp:
86 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
87 goto end;
88 case OPT_HELP:
89 ret = 0;
90 opt_help(genpkey_options);
91 goto end;
92 case OPT_OUTFORM:
93 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
94 goto opthelp;
95 break;
96 case OPT_OUT:
97 outfile = opt_arg();
98 break;
Rich Salz7e1b7482015-04-24 15:26:15 -040099 case OPT_PASS:
100 passarg = opt_arg();
101 break;
Rich Salz7e1b7482015-04-24 15:26:15 -0400102 case OPT_ENGINE:
103 e = setup_engine(opt_arg(), 0);
104 break;
Rich Salz7e1b7482015-04-24 15:26:15 -0400105 case OPT_PARAMFILE:
Matt Caswell0f113f32015-01-22 03:40:55 +0000106 if (do_param == 1)
Rich Salz7e1b7482015-04-24 15:26:15 -0400107 goto opthelp;
Rich Salz182717b2021-02-07 10:42:23 -0500108 paramfile = opt_arg();
Rich Salz7e1b7482015-04-24 15:26:15 -0400109 break;
110 case OPT_ALGORITHM:
Rich Salz182717b2021-02-07 10:42:23 -0500111 algname = opt_arg();
Rich Salz7e1b7482015-04-24 15:26:15 -0400112 break;
113 case OPT_PKEYOPT:
Rich Salz182717b2021-02-07 10:42:23 -0500114 if (!sk_OPENSSL_STRING_push(keyopt, opt_arg()))
Matt Caswell0f113f32015-01-22 03:40:55 +0000115 goto end;
Rich Salz7e1b7482015-04-24 15:26:15 -0400116 break;
Rich Salz7d72dc72021-05-12 11:45:37 -0400117 case OPT_QUIET:
Philip Prindevillea414fd62021-12-21 20:44:07 -0700118 verbose = 0;
119 break;
120 case OPT_VERBOSE:
121 verbose = 1;
Rich Salz7d72dc72021-05-12 11:45:37 -0400122 break;
Rich Salz7e1b7482015-04-24 15:26:15 -0400123 case OPT_GENPARAM:
Matt Caswell0f113f32015-01-22 03:40:55 +0000124 do_param = 1;
Rich Salz7e1b7482015-04-24 15:26:15 -0400125 break;
126 case OPT_TEXT:
Matt Caswell0f113f32015-01-22 03:40:55 +0000127 text = 1;
Rich Salz7e1b7482015-04-24 15:26:15 -0400128 break;
129 case OPT_CIPHER:
Rich Salz182717b2021-02-07 10:42:23 -0500130 ciphername = opt_unknown();
Pauli6bd4e3f2020-02-25 14:29:30 +1000131 break;
Shane Lontis7c9a7cf2020-06-16 13:04:57 +1000132 case OPT_CONFIG:
133 conf = app_load_config_modules(opt_arg());
134 if (conf == NULL)
135 goto end;
136 break;
Pauli6bd4e3f2020-02-25 14:29:30 +1000137 case OPT_PROV_CASES:
138 if (!opt_provider(o))
139 goto end;
140 break;
Matt Caswell0f113f32015-01-22 03:40:55 +0000141 }
Matt Caswell0f113f32015-01-22 03:40:55 +0000142 }
Rich Salz021410e2020-11-28 16:12:58 -0500143
144 /* No extra arguments. */
Dr. David von Oheimbd9f07352021-08-27 15:33:18 +0200145 if (!opt_check_rest_arg(NULL))
Kurt Roeckx03358512016-02-14 20:45:02 +0100146 goto opthelp;
147
Rich Salz182717b2021-02-07 10:42:23 -0500148 /* Fetch cipher, etc. */
149 if (paramfile != NULL) {
150 if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq()))
151 goto end;
152 }
153 if (algname != NULL) {
154 if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq()))
155 goto end;
156 }
Rich Salz7e1b7482015-04-24 15:26:15 -0400157 if (ctx == NULL)
158 goto opthelp;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000159
Rich Salz182717b2021-02-07 10:42:23 -0500160 for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) {
161 p = sk_OPENSSL_STRING_value(keyopt, i);
162 if (pkey_ctrl_string(ctx, p) <= 0) {
163 BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p);
164 ERR_print_errors(bio_err);
165 goto end;
166 }
167 }
Dr. David von Oheimbd9f07352021-08-27 15:33:18 +0200168 if (!opt_cipher(ciphername, &cipher))
169 goto opthelp;
170 if (ciphername != NULL && do_param == 1) {
171 BIO_printf(bio_err, "Cannot use cipher with -genparam option\n");
172 goto opthelp;
173 }
Rich Salz182717b2021-02-07 10:42:23 -0500174
175 private = do_param ? 0 : 1;
176
Rich Salz7e1b7482015-04-24 15:26:15 -0400177 if (!app_passwd(passarg, NULL, &pass, NULL)) {
Matt Caswell0f113f32015-01-22 03:40:55 +0000178 BIO_puts(bio_err, "Error getting password\n");
179 goto end;
180 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000181
Richard Levittebdd58d92015-09-04 12:49:06 +0200182 out = bio_open_owner(outfile, outformat, private);
Rich Salz7e1b7482015-04-24 15:26:15 -0400183 if (out == NULL)
184 goto end;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000185
Philip Prindevillea414fd62021-12-21 20:44:07 -0700186 if (verbose)
Philip Prindevillee1cd94f2021-12-21 22:00:38 -0700187 EVP_PKEY_CTX_set_cb(ctx, progress_cb);
Matt Caswell0f113f32015-01-22 03:40:55 +0000188 EVP_PKEY_CTX_set_app_data(ctx, bio_err);
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000189
Dr. David von Oheimba7e4ca52020-06-09 10:21:58 +0200190 pkey = do_param ? app_paramgen(ctx, algname)
191 : app_keygen(ctx, algname, 0, 0 /* not verbose */);
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000192
Paul Yang22342122017-06-13 01:24:02 +0800193 if (do_param) {
Matt Caswell0f113f32015-01-22 03:40:55 +0000194 rv = PEM_write_bio_Parameters(out, pkey);
Paul Yang22342122017-06-13 01:24:02 +0800195 } else if (outformat == FORMAT_PEM) {
Rich Salz3b061a02015-05-02 10:01:33 -0400196 assert(private);
Matt Caswell0f113f32015-01-22 03:40:55 +0000197 rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
Rich Salz3b061a02015-05-02 10:01:33 -0400198 } else if (outformat == FORMAT_ASN1) {
199 assert(private);
Matt Caswell0f113f32015-01-22 03:40:55 +0000200 rv = i2d_PrivateKey_bio(out, pkey);
Rich Salz3b061a02015-05-02 10:01:33 -0400201 } else {
Matt Caswell0f113f32015-01-22 03:40:55 +0000202 BIO_printf(bio_err, "Bad format specified for key\n");
203 goto end;
204 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000205
Nicola Tuveri466d30c2020-06-27 01:42:49 +0300206 ret = 0;
207
Matt Caswell0f113f32015-01-22 03:40:55 +0000208 if (rv <= 0) {
209 BIO_puts(bio_err, "Error writing key\n");
Nicola Tuveri466d30c2020-06-27 01:42:49 +0300210 ret = 1;
Matt Caswell0f113f32015-01-22 03:40:55 +0000211 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000212
Matt Caswell0f113f32015-01-22 03:40:55 +0000213 if (text) {
214 if (do_param)
215 rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
216 else
217 rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
Dr. Stephen Henson01b8b3c2006-06-05 11:52:46 +0000218
Matt Caswell0f113f32015-01-22 03:40:55 +0000219 if (rv <= 0) {
220 BIO_puts(bio_err, "Error printing key\n");
Nicola Tuveri466d30c2020-06-27 01:42:49 +0300221 ret = 1;
Matt Caswell0f113f32015-01-22 03:40:55 +0000222 }
223 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000224
Matt Caswell0f113f32015-01-22 03:40:55 +0000225 end:
Rich Salz182717b2021-02-07 10:42:23 -0500226 sk_OPENSSL_STRING_free(keyopt);
Dr. David von Oheimba7e4ca52020-06-09 10:21:58 +0200227 if (ret != 0)
228 ERR_print_errors(bio_err);
Rich Salzc5ba2d92015-03-28 10:54:15 -0400229 EVP_PKEY_free(pkey);
230 EVP_PKEY_CTX_free(ctx);
Rich Salz606a4172021-02-17 16:15:27 -0500231 EVP_CIPHER_free(cipher);
Rich Salzca3a82c2015-03-25 11:31:18 -0400232 BIO_free_all(out);
Matt Caswell0f113f32015-01-22 03:40:55 +0000233 BIO_free(in);
Richard Levittedd1abd42016-09-28 23:39:18 +0200234 release_engine(e);
Rich Salzb548a1f2015-05-01 10:02:07 -0400235 OPENSSL_free(pass);
Shane Lontis7c9a7cf2020-06-16 13:04:57 +1000236 NCONF_free(conf);
Matt Caswell0f113f32015-01-22 03:40:55 +0000237 return ret;
238}
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000239
Shane Lontis7c9a7cf2020-06-16 13:04:57 +1000240static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
Dr. Matthias St. Pierreb4250012020-10-15 12:55:50 +0300241 OSSL_LIB_CTX *libctx, const char *propq)
Matt Caswell0f113f32015-01-22 03:40:55 +0000242{
243 BIO *pbio;
244 EVP_PKEY *pkey = NULL;
245 EVP_PKEY_CTX *ctx = NULL;
246 if (*pctx) {
Rich Salz7e1b7482015-04-24 15:26:15 -0400247 BIO_puts(bio_err, "Parameters already set!\n");
Matt Caswell0f113f32015-01-22 03:40:55 +0000248 return 0;
249 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000250
Matt Caswell0f113f32015-01-22 03:40:55 +0000251 pbio = BIO_new_file(file, "r");
Rich Salz12a765a2019-09-16 15:28:57 -0400252 if (pbio == NULL) {
Rich Salz7e1b7482015-04-24 15:26:15 -0400253 BIO_printf(bio_err, "Can't open parameter file %s\n", file);
Matt Caswell0f113f32015-01-22 03:40:55 +0000254 return 0;
255 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000256
Jon Spillett3d633482021-01-19 13:43:35 +1000257 pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq);
Matt Caswell0f113f32015-01-22 03:40:55 +0000258 BIO_free(pbio);
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000259
Rich Salz12a765a2019-09-16 15:28:57 -0400260 if (pkey == NULL) {
Matt Caswell0f113f32015-01-22 03:40:55 +0000261 BIO_printf(bio_err, "Error reading parameter file %s\n", file);
262 return 0;
263 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000264
Shane Lontis7c9a7cf2020-06-16 13:04:57 +1000265 if (e != NULL)
266 ctx = EVP_PKEY_CTX_new(pkey, e);
267 else
268 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
Matt Caswell96487cd2015-10-30 11:18:04 +0000269 if (ctx == NULL)
Matt Caswell0f113f32015-01-22 03:40:55 +0000270 goto err;
271 if (EVP_PKEY_keygen_init(ctx) <= 0)
272 goto err;
273 EVP_PKEY_free(pkey);
274 *pctx = ctx;
275 return 1;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000276
Matt Caswell0f113f32015-01-22 03:40:55 +0000277 err:
Rich Salz7e1b7482015-04-24 15:26:15 -0400278 BIO_puts(bio_err, "Error initializing context\n");
279 ERR_print_errors(bio_err);
Rich Salzc5ba2d92015-03-28 10:54:15 -0400280 EVP_PKEY_CTX_free(ctx);
281 EVP_PKEY_free(pkey);
Matt Caswell0f113f32015-01-22 03:40:55 +0000282 return 0;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000283
Matt Caswell0f113f32015-01-22 03:40:55 +0000284}
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000285
Rich Salz7e1b7482015-04-24 15:26:15 -0400286int init_gen_str(EVP_PKEY_CTX **pctx,
Shane Lontis7c9a7cf2020-06-16 13:04:57 +1000287 const char *algname, ENGINE *e, int do_param,
Dr. Matthias St. Pierreb4250012020-10-15 12:55:50 +0300288 OSSL_LIB_CTX *libctx, const char *propq)
Matt Caswell0f113f32015-01-22 03:40:55 +0000289{
290 EVP_PKEY_CTX *ctx = NULL;
Matt Caswell0f113f32015-01-22 03:40:55 +0000291 int pkey_id;
Dr. Stephen Henson01b8b3c2006-06-05 11:52:46 +0000292
Matt Caswell0f113f32015-01-22 03:40:55 +0000293 if (*pctx) {
Rich Salz7e1b7482015-04-24 15:26:15 -0400294 BIO_puts(bio_err, "Algorithm already set!\n");
Matt Caswell0f113f32015-01-22 03:40:55 +0000295 return 0;
296 }
Dr. Stephen Hensonb3c6a332006-07-12 18:00:20 +0000297
Matt Caswell0f386f22020-11-02 11:04:06 +0000298 pkey_id = get_legacy_pkey_id(libctx, algname, e);
299 if (pkey_id != NID_undef)
Shane Lontis7c9a7cf2020-06-16 13:04:57 +1000300 ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
Matt Caswell0f386f22020-11-02 11:04:06 +0000301 else
Shane Lontis7c9a7cf2020-06-16 13:04:57 +1000302 ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000303
Matt Caswell0f386f22020-11-02 11:04:06 +0000304 if (ctx == NULL)
Matt Caswell0f113f32015-01-22 03:40:55 +0000305 goto err;
306 if (do_param) {
307 if (EVP_PKEY_paramgen_init(ctx) <= 0)
308 goto err;
309 } else {
310 if (EVP_PKEY_keygen_init(ctx) <= 0)
311 goto err;
312 }
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000313
Matt Caswell0f113f32015-01-22 03:40:55 +0000314 *pctx = ctx;
315 return 1;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000316
Matt Caswell0f113f32015-01-22 03:40:55 +0000317 err:
Rich Salz7e1b7482015-04-24 15:26:15 -0400318 BIO_printf(bio_err, "Error initializing %s context\n", algname);
319 ERR_print_errors(bio_err);
Rich Salzc5ba2d92015-03-28 10:54:15 -0400320 EVP_PKEY_CTX_free(ctx);
Matt Caswell0f113f32015-01-22 03:40:55 +0000321 return 0;
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000322
Matt Caswell0f113f32015-01-22 03:40:55 +0000323}
Dr. Stephen Hensonf5cda4c2006-04-11 13:28:52 +0000324