mirror of
https://github.com/openssl/openssl.git
synced 2025-02-05 14:10:53 +08:00
dab2cd68e7
Everything in apps includes apps.h, because that one declares apps internal library routines. However, progs.h doesn't declare library routines, but rather the main commands and their options, and there's no reason why the library modules should include it. So, remove the inclusion of progs.h from apps.h and add that inclusion in all command source files. Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5222)
316 lines
8.2 KiB
C
316 lines
8.2 KiB
C
/*
|
|
* Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the OpenSSL license (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "apps.h"
|
|
#include "progs.h"
|
|
#include <openssl/pem.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/evp.h>
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
# include <openssl/engine.h>
|
|
#endif
|
|
|
|
static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e);
|
|
static int genpkey_cb(EVP_PKEY_CTX *ctx);
|
|
|
|
typedef enum OPTION_choice {
|
|
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
|
|
OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE,
|
|
OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER
|
|
} OPTION_CHOICE;
|
|
|
|
const OPTIONS genpkey_options[] = {
|
|
{"help", OPT_HELP, '-', "Display this summary"},
|
|
{"out", OPT_OUT, '>', "Output file"},
|
|
{"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"},
|
|
{"pass", OPT_PASS, 's', "Output file pass phrase source"},
|
|
{"paramfile", OPT_PARAMFILE, '<', "Parameters file"},
|
|
{"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"},
|
|
{"pkeyopt", OPT_PKEYOPT, 's',
|
|
"Set the public key algorithm option as opt:value"},
|
|
{"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"},
|
|
{"text", OPT_TEXT, '-', "Print the in text"},
|
|
{"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"},
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
|
|
#endif
|
|
/* This is deliberately last. */
|
|
{OPT_HELP_STR, 1, 1,
|
|
"Order of options may be important! See the documentation.\n"},
|
|
{NULL}
|
|
};
|
|
|
|
int genpkey_main(int argc, char **argv)
|
|
{
|
|
BIO *in = NULL, *out = NULL;
|
|
ENGINE *e = NULL;
|
|
EVP_PKEY *pkey = NULL;
|
|
EVP_PKEY_CTX *ctx = NULL;
|
|
char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog;
|
|
const EVP_CIPHER *cipher = NULL;
|
|
OPTION_CHOICE o;
|
|
int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
|
|
int private = 0;
|
|
|
|
prog = opt_init(argc, argv, genpkey_options);
|
|
while ((o = opt_next()) != OPT_EOF) {
|
|
switch (o) {
|
|
case OPT_EOF:
|
|
case OPT_ERR:
|
|
opthelp:
|
|
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
|
|
goto end;
|
|
case OPT_HELP:
|
|
ret = 0;
|
|
opt_help(genpkey_options);
|
|
goto end;
|
|
case OPT_OUTFORM:
|
|
if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
|
|
goto opthelp;
|
|
break;
|
|
case OPT_OUT:
|
|
outfile = opt_arg();
|
|
break;
|
|
case OPT_PASS:
|
|
passarg = opt_arg();
|
|
break;
|
|
case OPT_ENGINE:
|
|
e = setup_engine(opt_arg(), 0);
|
|
break;
|
|
case OPT_PARAMFILE:
|
|
if (do_param == 1)
|
|
goto opthelp;
|
|
if (!init_keygen_file(&ctx, opt_arg(), e))
|
|
goto end;
|
|
break;
|
|
case OPT_ALGORITHM:
|
|
if (!init_gen_str(&ctx, opt_arg(), e, do_param))
|
|
goto end;
|
|
break;
|
|
case OPT_PKEYOPT:
|
|
if (ctx == NULL) {
|
|
BIO_printf(bio_err, "%s: No keytype specified.\n", prog);
|
|
goto opthelp;
|
|
}
|
|
if (pkey_ctrl_string(ctx, opt_arg()) <= 0) {
|
|
BIO_printf(bio_err,
|
|
"%s: Error setting %s parameter:\n",
|
|
prog, opt_arg());
|
|
ERR_print_errors(bio_err);
|
|
goto end;
|
|
}
|
|
break;
|
|
case OPT_GENPARAM:
|
|
if (ctx != NULL)
|
|
goto opthelp;
|
|
do_param = 1;
|
|
break;
|
|
case OPT_TEXT:
|
|
text = 1;
|
|
break;
|
|
case OPT_CIPHER:
|
|
if (!opt_cipher(opt_unknown(), &cipher)
|
|
|| do_param == 1)
|
|
goto opthelp;
|
|
}
|
|
}
|
|
argc = opt_num_rest();
|
|
if (argc != 0)
|
|
goto opthelp;
|
|
|
|
private = do_param ? 0 : 1;
|
|
|
|
if (ctx == NULL)
|
|
goto opthelp;
|
|
|
|
if (!app_passwd(passarg, NULL, &pass, NULL)) {
|
|
BIO_puts(bio_err, "Error getting password\n");
|
|
goto end;
|
|
}
|
|
|
|
out = bio_open_owner(outfile, outformat, private);
|
|
if (out == NULL)
|
|
goto end;
|
|
|
|
EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
|
|
EVP_PKEY_CTX_set_app_data(ctx, bio_err);
|
|
|
|
if (do_param) {
|
|
if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) {
|
|
BIO_puts(bio_err, "Error generating parameters\n");
|
|
ERR_print_errors(bio_err);
|
|
goto end;
|
|
}
|
|
} else {
|
|
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
|
|
BIO_puts(bio_err, "Error generating key\n");
|
|
ERR_print_errors(bio_err);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (do_param) {
|
|
rv = PEM_write_bio_Parameters(out, pkey);
|
|
} else if (outformat == FORMAT_PEM) {
|
|
assert(private);
|
|
rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
|
|
} else if (outformat == FORMAT_ASN1) {
|
|
assert(private);
|
|
rv = i2d_PrivateKey_bio(out, pkey);
|
|
} else {
|
|
BIO_printf(bio_err, "Bad format specified for key\n");
|
|
goto end;
|
|
}
|
|
|
|
if (rv <= 0) {
|
|
BIO_puts(bio_err, "Error writing key\n");
|
|
ERR_print_errors(bio_err);
|
|
}
|
|
|
|
if (text) {
|
|
if (do_param)
|
|
rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
|
|
else
|
|
rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
|
|
|
|
if (rv <= 0) {
|
|
BIO_puts(bio_err, "Error printing key\n");
|
|
ERR_print_errors(bio_err);
|
|
}
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
end:
|
|
EVP_PKEY_free(pkey);
|
|
EVP_PKEY_CTX_free(ctx);
|
|
BIO_free_all(out);
|
|
BIO_free(in);
|
|
release_engine(e);
|
|
OPENSSL_free(pass);
|
|
return ret;
|
|
}
|
|
|
|
static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e)
|
|
{
|
|
BIO *pbio;
|
|
EVP_PKEY *pkey = NULL;
|
|
EVP_PKEY_CTX *ctx = NULL;
|
|
if (*pctx) {
|
|
BIO_puts(bio_err, "Parameters already set!\n");
|
|
return 0;
|
|
}
|
|
|
|
pbio = BIO_new_file(file, "r");
|
|
if (!pbio) {
|
|
BIO_printf(bio_err, "Can't open parameter file %s\n", file);
|
|
return 0;
|
|
}
|
|
|
|
pkey = PEM_read_bio_Parameters(pbio, NULL);
|
|
BIO_free(pbio);
|
|
|
|
if (!pkey) {
|
|
BIO_printf(bio_err, "Error reading parameter file %s\n", file);
|
|
return 0;
|
|
}
|
|
|
|
ctx = EVP_PKEY_CTX_new(pkey, e);
|
|
if (ctx == NULL)
|
|
goto err;
|
|
if (EVP_PKEY_keygen_init(ctx) <= 0)
|
|
goto err;
|
|
EVP_PKEY_free(pkey);
|
|
*pctx = ctx;
|
|
return 1;
|
|
|
|
err:
|
|
BIO_puts(bio_err, "Error initializing context\n");
|
|
ERR_print_errors(bio_err);
|
|
EVP_PKEY_CTX_free(ctx);
|
|
EVP_PKEY_free(pkey);
|
|
return 0;
|
|
|
|
}
|
|
|
|
int init_gen_str(EVP_PKEY_CTX **pctx,
|
|
const char *algname, ENGINE *e, int do_param)
|
|
{
|
|
EVP_PKEY_CTX *ctx = NULL;
|
|
const EVP_PKEY_ASN1_METHOD *ameth;
|
|
ENGINE *tmpeng = NULL;
|
|
int pkey_id;
|
|
|
|
if (*pctx) {
|
|
BIO_puts(bio_err, "Algorithm already set!\n");
|
|
return 0;
|
|
}
|
|
|
|
ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
|
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
if (!ameth && e)
|
|
ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
|
|
#endif
|
|
|
|
if (!ameth) {
|
|
BIO_printf(bio_err, "Algorithm %s not found\n", algname);
|
|
return 0;
|
|
}
|
|
|
|
ERR_clear_error();
|
|
|
|
EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
ENGINE_finish(tmpeng);
|
|
#endif
|
|
ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
|
|
|
|
if (!ctx)
|
|
goto err;
|
|
if (do_param) {
|
|
if (EVP_PKEY_paramgen_init(ctx) <= 0)
|
|
goto err;
|
|
} else {
|
|
if (EVP_PKEY_keygen_init(ctx) <= 0)
|
|
goto err;
|
|
}
|
|
|
|
*pctx = ctx;
|
|
return 1;
|
|
|
|
err:
|
|
BIO_printf(bio_err, "Error initializing %s context\n", algname);
|
|
ERR_print_errors(bio_err);
|
|
EVP_PKEY_CTX_free(ctx);
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int genpkey_cb(EVP_PKEY_CTX *ctx)
|
|
{
|
|
char c = '*';
|
|
BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
|
|
int p;
|
|
p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
|
|
if (p == 0)
|
|
c = '.';
|
|
if (p == 1)
|
|
c = '+';
|
|
if (p == 2)
|
|
c = '*';
|
|
if (p == 3)
|
|
c = '\n';
|
|
BIO_write(b, &c, 1);
|
|
(void)BIO_flush(b);
|
|
return 1;
|
|
}
|