version 1.3, 2014/08/28 14:25:48 |
version 1.4, 2015/01/08 11:06:12 |
|
|
#include <openssl/pem.h> |
#include <openssl/pem.h> |
#include <openssl/pkcs12.h> |
#include <openssl/pkcs12.h> |
|
|
int pkcs8_main(int, char **); |
static struct { |
|
const EVP_CIPHER *cipher; |
|
#ifndef OPENSSL_NO_ENGINE |
|
char *engine; |
|
#endif |
|
char *infile; |
|
int informat; |
|
int iter; |
|
int nocrypt; |
|
char *outfile; |
|
int outformat; |
|
int p8_broken; |
|
char *passargin; |
|
char *passargout; |
|
int pbe_nid; |
|
int topk8; |
|
} pkcs8_config; |
|
|
|
static int |
|
pkcs8_opt_v1(char *arg) |
|
{ |
|
if ((pkcs8_config.pbe_nid = OBJ_txt2nid(arg)) == NID_undef) { |
|
fprintf(stderr, "Unknown PBE algorithm '%s'\n", arg); |
|
return (1); |
|
} |
|
|
|
return (0); |
|
} |
|
|
|
static int |
|
pkcs8_opt_v2(char *arg) |
|
{ |
|
if ((pkcs8_config.cipher = EVP_get_cipherbyname(arg)) == NULL) { |
|
fprintf(stderr, "Unknown cipher '%s'\n", arg); |
|
return (1); |
|
} |
|
|
|
return (0); |
|
} |
|
|
|
static struct option pkcs8_options[] = { |
|
{ |
|
.name = "embed", |
|
.desc = "Generate DSA keys in a broken format", |
|
.type = OPTION_VALUE, |
|
.value = PKCS8_EMBEDDED_PARAM, |
|
.opt.value = &pkcs8_config.p8_broken, |
|
}, |
|
#ifndef OPENSSL_NO_ENGINE |
|
{ |
|
.name = "engine", |
|
.argname = "id", |
|
.desc = "Use the engine specified by the given identifier", |
|
.type = OPTION_ARG, |
|
.opt.arg = &pkcs8_config.engine, |
|
}, |
|
#endif |
|
{ |
|
.name = "in", |
|
.argname = "file", |
|
.desc = "Input file (default stdin)", |
|
.type = OPTION_ARG, |
|
.opt.arg = &pkcs8_config.infile, |
|
}, |
|
{ |
|
.name = "inform", |
|
.argname = "format", |
|
.desc = "Input format (DER or PEM (default))", |
|
.type = OPTION_ARG_FORMAT, |
|
.opt.value = &pkcs8_config.informat, |
|
}, |
|
{ |
|
.name = "nocrypt", |
|
.desc = "Use or expect unencrypted private key", |
|
.type = OPTION_FLAG, |
|
.opt.flag = &pkcs8_config.nocrypt, |
|
}, |
|
{ |
|
.name = "noiter", |
|
.desc = "Use 1 as iteration count", |
|
.type = OPTION_VALUE, |
|
.value = 1, |
|
.opt.value = &pkcs8_config.iter, |
|
}, |
|
{ |
|
.name = "nooct", |
|
.desc = "Generate RSA keys in a broken format (no octet)", |
|
.type = OPTION_VALUE, |
|
.value = PKCS8_NO_OCTET, |
|
.opt.value = &pkcs8_config.p8_broken, |
|
}, |
|
{ |
|
.name = "nsdb", |
|
.desc = "Generate DSA keys in the broken Netscape DB format", |
|
.type = OPTION_VALUE, |
|
.value = PKCS8_NS_DB, |
|
.opt.value = &pkcs8_config.p8_broken, |
|
}, |
|
{ |
|
.name = "out", |
|
.argname = "file", |
|
.desc = "Output file (default stdout)", |
|
.type = OPTION_ARG, |
|
.opt.arg = &pkcs8_config.outfile, |
|
}, |
|
{ |
|
.name = "outform", |
|
.argname = "format", |
|
.desc = "Output format (DER or PEM (default))", |
|
.type = OPTION_ARG_FORMAT, |
|
.opt.value = &pkcs8_config.outformat, |
|
}, |
|
{ |
|
.name = "passin", |
|
.argname = "source", |
|
.desc = "Input file passphrase source", |
|
.type = OPTION_ARG, |
|
.opt.arg = &pkcs8_config.passargin, |
|
}, |
|
{ |
|
.name = "passout", |
|
.argname = "source", |
|
.desc = "Output file passphrase source", |
|
.type = OPTION_ARG, |
|
.opt.arg = &pkcs8_config.passargout, |
|
}, |
|
{ |
|
.name = "topk8", |
|
.desc = "Read traditional format key and write PKCS#8 format" |
|
" key", |
|
.type = OPTION_FLAG, |
|
.opt.flag = &pkcs8_config.topk8, |
|
}, |
|
{ |
|
.name = "v1", |
|
.argname = "algorithm", |
|
.desc = "Use PKCS#5 v1.5 or PKCS#12 with given algorithm", |
|
.type = OPTION_ARG_FUNC, |
|
.opt.argfunc = pkcs8_opt_v1, |
|
}, |
|
{ |
|
.name = "v2", |
|
.argname = "cipher", |
|
.desc = "Use PKCS#5 v2.0 with given cipher", |
|
.type = OPTION_ARG_FUNC, |
|
.opt.argfunc = pkcs8_opt_v2, |
|
}, |
|
{ NULL }, |
|
}; |
|
|
|
static void |
|
pkcs8_usage() |
|
{ |
|
fprintf(stderr, "usage: pkcs8 [-embed] [-engine id] [-in file] " |
|
"[-inform fmt] [-nocrypt]\n" |
|
" [-noiter] [-nooct] [-nsdb] [-out file] [-outform fmt] " |
|
"[-passin src]\n" |
|
" [-passout src] [-topk8] [-v1 alg] [-v2 alg]\n\n"); |
|
options_usage(pkcs8_options); |
|
} |
|
|
int |
int |
pkcs8_main(int argc, char **argv) |
pkcs8_main(int argc, char **argv) |
{ |
{ |
ENGINE *e = NULL; |
ENGINE *e = NULL; |
char **args, *infile = NULL, *outfile = NULL; |
|
char *passargin = NULL, *passargout = NULL; |
|
BIO *in = NULL, *out = NULL; |
BIO *in = NULL, *out = NULL; |
int topk8 = 0; |
|
int pbe_nid = -1; |
|
const EVP_CIPHER *cipher = NULL; |
|
int iter = PKCS12_DEFAULT_ITER; |
|
int informat, outformat; |
|
int p8_broken = PKCS8_OK; |
|
int nocrypt = 0; |
|
X509_SIG *p8 = NULL; |
X509_SIG *p8 = NULL; |
PKCS8_PRIV_KEY_INFO *p8inf = NULL; |
PKCS8_PRIV_KEY_INFO *p8inf = NULL; |
EVP_PKEY *pkey = NULL; |
EVP_PKEY *pkey = NULL; |
char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL; |
char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL; |
int badarg = 0; |
|
int ret = 1; |
int ret = 1; |
#ifndef OPENSSL_NO_ENGINE |
|
char *engine = NULL; |
|
#endif |
|
|
|
informat = FORMAT_PEM; |
memset(&pkcs8_config, 0, sizeof(pkcs8_config)); |
outformat = FORMAT_PEM; |
|
|
|
args = argv + 1; |
pkcs8_config.iter = PKCS12_DEFAULT_ITER; |
while (!badarg && *args && *args[0] == '-') { |
pkcs8_config.informat = FORMAT_PEM; |
if (!strcmp(*args, "-v2")) { |
pkcs8_config.outformat = FORMAT_PEM; |
if (args[1]) { |
pkcs8_config.p8_broken = PKCS8_OK; |
args++; |
pkcs8_config.pbe_nid = -1; |
cipher = EVP_get_cipherbyname(*args); |
|
if (!cipher) { |
if (options_parse(argc, argv, pkcs8_options, NULL, NULL) != 0) { |
BIO_printf(bio_err, |
pkcs8_usage(); |
"Unknown cipher %s\n", *args); |
return (1); |
badarg = 1; |
|
} |
|
} else |
|
badarg = 1; |
|
} else if (!strcmp(*args, "-v1")) { |
|
if (args[1]) { |
|
args++; |
|
pbe_nid = OBJ_txt2nid(*args); |
|
if (pbe_nid == NID_undef) { |
|
BIO_printf(bio_err, |
|
"Unknown PBE algorithm %s\n", *args); |
|
badarg = 1; |
|
} |
|
} else |
|
badarg = 1; |
|
} else if (!strcmp(*args, "-inform")) { |
|
if (args[1]) { |
|
args++; |
|
informat = str2fmt(*args); |
|
} else |
|
badarg = 1; |
|
} else if (!strcmp(*args, "-outform")) { |
|
if (args[1]) { |
|
args++; |
|
outformat = str2fmt(*args); |
|
} else |
|
badarg = 1; |
|
} else if (!strcmp(*args, "-topk8")) |
|
topk8 = 1; |
|
else if (!strcmp(*args, "-noiter")) |
|
iter = 1; |
|
else if (!strcmp(*args, "-nocrypt")) |
|
nocrypt = 1; |
|
else if (!strcmp(*args, "-nooct")) |
|
p8_broken = PKCS8_NO_OCTET; |
|
else if (!strcmp(*args, "-nsdb")) |
|
p8_broken = PKCS8_NS_DB; |
|
else if (!strcmp(*args, "-embed")) |
|
p8_broken = PKCS8_EMBEDDED_PARAM; |
|
else if (!strcmp(*args, "-passin")) { |
|
if (!args[1]) |
|
goto bad; |
|
passargin = *(++args); |
|
} else if (!strcmp(*args, "-passout")) { |
|
if (!args[1]) |
|
goto bad; |
|
passargout = *(++args); |
|
} |
|
#ifndef OPENSSL_NO_ENGINE |
|
else if (strcmp(*args, "-engine") == 0) { |
|
if (!args[1]) |
|
goto bad; |
|
engine = *(++args); |
|
} |
|
#endif |
|
else if (!strcmp(*args, "-in")) { |
|
if (args[1]) { |
|
args++; |
|
infile = *args; |
|
} else |
|
badarg = 1; |
|
} else if (!strcmp(*args, "-out")) { |
|
if (args[1]) { |
|
args++; |
|
outfile = *args; |
|
} else |
|
badarg = 1; |
|
} else |
|
badarg = 1; |
|
args++; |
|
} |
} |
|
|
if (badarg) { |
|
bad: |
|
BIO_printf(bio_err, "Usage pkcs8 [options]\n"); |
|
BIO_printf(bio_err, "where options are\n"); |
|
BIO_printf(bio_err, "-in file input file\n"); |
|
BIO_printf(bio_err, "-inform X input format (DER or PEM)\n"); |
|
BIO_printf(bio_err, "-passin arg input file pass phrase source\n"); |
|
BIO_printf(bio_err, "-outform X output format (DER or PEM)\n"); |
|
BIO_printf(bio_err, "-out file output file\n"); |
|
BIO_printf(bio_err, "-passout arg output file pass phrase source\n"); |
|
BIO_printf(bio_err, "-topk8 output PKCS8 file\n"); |
|
BIO_printf(bio_err, "-nooct use (nonstandard) no octet format\n"); |
|
BIO_printf(bio_err, "-embed use (nonstandard) embedded DSA parameters format\n"); |
|
BIO_printf(bio_err, "-nsdb use (nonstandard) DSA Netscape DB format\n"); |
|
BIO_printf(bio_err, "-noiter use 1 as iteration count\n"); |
|
BIO_printf(bio_err, "-nocrypt use or expect unencrypted private key\n"); |
|
BIO_printf(bio_err, "-v2 alg use PKCS#5 v2.0 and cipher \"alg\"\n"); |
|
BIO_printf(bio_err, "-v1 obj use PKCS#5 v1.5 and cipher \"alg\"\n"); |
|
#ifndef OPENSSL_NO_ENGINE |
#ifndef OPENSSL_NO_ENGINE |
BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); |
e = setup_engine(bio_err, pkcs8_config.engine, 0); |
#endif |
#endif |
goto end; |
|
} |
|
#ifndef OPENSSL_NO_ENGINE |
|
e = setup_engine(bio_err, engine, 0); |
|
#endif |
|
|
|
if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { |
if (!app_passwd(bio_err, pkcs8_config.passargin, |
|
pkcs8_config.passargout, &passin, &passout)) { |
BIO_printf(bio_err, "Error getting passwords\n"); |
BIO_printf(bio_err, "Error getting passwords\n"); |
goto end; |
goto end; |
} |
} |
if ((pbe_nid == -1) && !cipher) |
if ((pkcs8_config.pbe_nid == -1) && !pkcs8_config.cipher) |
pbe_nid = NID_pbeWithMD5AndDES_CBC; |
pkcs8_config.pbe_nid = NID_pbeWithMD5AndDES_CBC; |
|
|
if (infile) { |
if (pkcs8_config.infile) { |
if (!(in = BIO_new_file(infile, "rb"))) { |
if (!(in = BIO_new_file(pkcs8_config.infile, "rb"))) { |
BIO_printf(bio_err, |
BIO_printf(bio_err, |
"Can't open input file %s\n", infile); |
"Can't open input file '%s'\n", |
|
pkcs8_config.infile); |
goto end; |
goto end; |
} |
} |
} else |
} else |
in = BIO_new_fp(stdin, BIO_NOCLOSE); |
in = BIO_new_fp(stdin, BIO_NOCLOSE); |
|
|
if (outfile) { |
if (pkcs8_config.outfile) { |
if (!(out = BIO_new_file(outfile, "wb"))) { |
if (!(out = BIO_new_file(pkcs8_config.outfile, "wb"))) { |
BIO_printf(bio_err, |
BIO_printf(bio_err, "Can't open output file '%s'\n", |
"Can't open output file %s\n", outfile); |
pkcs8_config.outfile); |
goto end; |
goto end; |
} |
} |
} else { |
} else { |
out = BIO_new_fp(stdout, BIO_NOCLOSE); |
out = BIO_new_fp(stdout, BIO_NOCLOSE); |
} |
} |
if (topk8) { |
if (pkcs8_config.topk8) { |
pkey = load_key(bio_err, infile, informat, 1, |
pkey = load_key(bio_err, pkcs8_config.infile, |
passin, e, "key"); |
pkcs8_config.informat, 1, passin, e, "key"); |
if (!pkey) |
if (!pkey) |
goto end; |
goto end; |
if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, p8_broken))) { |
if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, |
|
pkcs8_config.p8_broken))) { |
BIO_printf(bio_err, "Error converting key\n"); |
BIO_printf(bio_err, "Error converting key\n"); |
ERR_print_errors(bio_err); |
ERR_print_errors(bio_err); |
goto end; |
goto end; |
} |
} |
if (nocrypt) { |
if (pkcs8_config.nocrypt) { |
if (outformat == FORMAT_PEM) |
if (pkcs8_config.outformat == FORMAT_PEM) |
PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); |
PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); |
else if (outformat == FORMAT_ASN1) |
else if (pkcs8_config.outformat == FORMAT_ASN1) |
i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf); |
i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf); |
else { |
else { |
BIO_printf(bio_err, "Bad format specified for key\n"); |
BIO_printf(bio_err, |
|
"Bad format specified for key\n"); |
goto end; |
goto end; |
} |
} |
} else { |
} else { |
|
|
p8pass = passout; |
p8pass = passout; |
else { |
else { |
p8pass = pass; |
p8pass = pass; |
if (EVP_read_pw_string(pass, sizeof pass, "Enter Encryption Password:", 1)) |
if (EVP_read_pw_string(pass, sizeof pass, |
|
"Enter Encryption Password:", 1)) |
goto end; |
goto end; |
} |
} |
if (!(p8 = PKCS8_encrypt(pbe_nid, cipher, |
if (!(p8 = PKCS8_encrypt(pkcs8_config.pbe_nid, |
p8pass, strlen(p8pass), |
pkcs8_config.cipher, p8pass, strlen(p8pass), |
NULL, 0, iter, p8inf))) { |
NULL, 0, pkcs8_config.iter, p8inf))) { |
BIO_printf(bio_err, "Error encrypting key\n"); |
BIO_printf(bio_err, "Error encrypting key\n"); |
ERR_print_errors(bio_err); |
ERR_print_errors(bio_err); |
goto end; |
goto end; |
} |
} |
if (outformat == FORMAT_PEM) |
if (pkcs8_config.outformat == FORMAT_PEM) |
PEM_write_bio_PKCS8(out, p8); |
PEM_write_bio_PKCS8(out, p8); |
else if (outformat == FORMAT_ASN1) |
else if (pkcs8_config.outformat == FORMAT_ASN1) |
i2d_PKCS8_bio(out, p8); |
i2d_PKCS8_bio(out, p8); |
else { |
else { |
BIO_printf(bio_err, "Bad format specified for key\n"); |
BIO_printf(bio_err, |
|
"Bad format specified for key\n"); |
goto end; |
goto end; |
} |
} |
} |
} |
|
|
ret = 0; |
ret = 0; |
goto end; |
goto end; |
} |
} |
if (nocrypt) { |
if (pkcs8_config.nocrypt) { |
if (informat == FORMAT_PEM) |
if (pkcs8_config.informat == FORMAT_PEM) |
p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL); |
p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, |
else if (informat == FORMAT_ASN1) |
NULL, NULL); |
|
else if (pkcs8_config.informat == FORMAT_ASN1) |
p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL); |
p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL); |
else { |
else { |
BIO_printf(bio_err, "Bad format specified for key\n"); |
BIO_printf(bio_err, "Bad format specified for key\n"); |
goto end; |
goto end; |
} |
} |
} else { |
} else { |
if (informat == FORMAT_PEM) |
if (pkcs8_config.informat == FORMAT_PEM) |
p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); |
p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); |
else if (informat == FORMAT_ASN1) |
else if (pkcs8_config.informat == FORMAT_ASN1) |
p8 = d2i_PKCS8_bio(in, NULL); |
p8 = d2i_PKCS8_bio(in, NULL); |
else { |
else { |
BIO_printf(bio_err, "Bad format specified for key\n"); |
BIO_printf(bio_err, "Bad format specified for key\n"); |
|
|
p8pass = passin; |
p8pass = passin; |
else { |
else { |
p8pass = pass; |
p8pass = pass; |
EVP_read_pw_string(pass, sizeof pass, "Enter Password:", 0); |
EVP_read_pw_string(pass, sizeof pass, |
|
"Enter Password:", 0); |
} |
} |
p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass)); |
p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass)); |
} |
} |
|
|
break; |
break; |
|
|
case PKCS8_EMBEDDED_PARAM: |
case PKCS8_EMBEDDED_PARAM: |
BIO_printf(bio_err, "DSA parameters included in PrivateKey\n"); |
BIO_printf(bio_err, |
|
"DSA parameters included in PrivateKey\n"); |
break; |
break; |
|
|
case PKCS8_NS_DB: |
case PKCS8_NS_DB: |
BIO_printf(bio_err, "DSA public key include in PrivateKey\n"); |
BIO_printf(bio_err, |
|
"DSA public key include in PrivateKey\n"); |
break; |
break; |
|
|
case PKCS8_NEG_PRIVKEY: |
case PKCS8_NEG_PRIVKEY: |
|
|
break; |
break; |
} |
} |
} |
} |
if (outformat == FORMAT_PEM) |
if (pkcs8_config.outformat == FORMAT_PEM) |
PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout); |
PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, |
else if (outformat == FORMAT_ASN1) |
passout); |
|
else if (pkcs8_config.outformat == FORMAT_ASN1) |
i2d_PrivateKey_bio(out, pkey); |
i2d_PrivateKey_bio(out, pkey); |
else { |
else { |
BIO_printf(bio_err, "Bad format specified for key\n"); |
BIO_printf(bio_err, "Bad format specified for key\n"); |