mirror of
https://github.com/openssl/openssl.git
synced 2024-11-23 18:13:39 +08:00
Support for traditional format private keys.
Add new function PEM_write_bio_PrivateKey_traditional() to enforce the use of legacy "traditional" private key format. Add -traditional option to pkcs8 and pkey utilities. Reviewed-by: Matt Caswell <matt@openssl.org>
This commit is contained in:
parent
07930a75a1
commit
05dba8151b
21
apps/pkcs8.c
21
apps/pkcs8.c
@ -23,7 +23,8 @@ typedef enum OPTION_choice {
|
||||
#ifndef OPENSSL_NO_SCRYPT
|
||||
OPT_SCRYPT, OPT_SCRYPT_N, OPT_SCRYPT_R, OPT_SCRYPT_P,
|
||||
#endif
|
||||
OPT_V2, OPT_V1, OPT_V2PRF, OPT_ITER, OPT_PASSIN, OPT_PASSOUT
|
||||
OPT_V2, OPT_V1, OPT_V2PRF, OPT_ITER, OPT_PASSIN, OPT_PASSOUT,
|
||||
OPT_TRADITIONAL
|
||||
} OPTION_CHOICE;
|
||||
|
||||
OPTIONS pkcs8_options[] = {
|
||||
@ -41,6 +42,7 @@ OPTIONS pkcs8_options[] = {
|
||||
{"iter", OPT_ITER, 'p', "Specify the iteration count"},
|
||||
{"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
|
||||
{"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
|
||||
{"traditional", OPT_TRADITIONAL, '-', "use traditional format private key"},
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
|
||||
#endif
|
||||
@ -70,7 +72,7 @@ int pkcs8_main(int argc, char **argv)
|
||||
OPTION_CHOICE o;
|
||||
int nocrypt = 0, ret = 1, iter = PKCS12_DEFAULT_ITER;
|
||||
int informat = FORMAT_PEM, outformat = FORMAT_PEM, topk8 = 0, pbe_nid = -1;
|
||||
int private = 0;
|
||||
int private = 0, traditional = 0;
|
||||
#ifndef OPENSSL_NO_SCRYPT
|
||||
long scrypt_N = 0, scrypt_r = 0, scrypt_p = 0;
|
||||
#endif
|
||||
@ -110,6 +112,9 @@ int pkcs8_main(int argc, char **argv)
|
||||
case OPT_NOCRYPT:
|
||||
nocrypt = 1;
|
||||
break;
|
||||
case OPT_TRADITIONAL:
|
||||
traditional = 1;
|
||||
break;
|
||||
case OPT_V2:
|
||||
if (!opt_cipher(opt_arg(), &cipher))
|
||||
goto opthelp;
|
||||
@ -320,11 +325,15 @@ int pkcs8_main(int argc, char **argv)
|
||||
}
|
||||
|
||||
assert(private);
|
||||
if (outformat == FORMAT_PEM)
|
||||
PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout);
|
||||
else if (outformat == FORMAT_ASN1)
|
||||
if (outformat == FORMAT_PEM) {
|
||||
if (traditional)
|
||||
PEM_write_bio_PrivateKey_traditional(out, pkey, NULL, NULL, 0,
|
||||
NULL, passout);
|
||||
else
|
||||
PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout);
|
||||
} else if (outformat == FORMAT_ASN1) {
|
||||
i2d_PrivateKey_bio(out, pkey);
|
||||
else {
|
||||
} else {
|
||||
BIO_printf(bio_err, "Bad format specified for key\n");
|
||||
goto end;
|
||||
}
|
||||
|
18
apps/pkey.c
18
apps/pkey.c
@ -18,7 +18,7 @@ typedef enum OPTION_choice {
|
||||
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
|
||||
OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE,
|
||||
OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB,
|
||||
OPT_TEXT, OPT_NOOUT, OPT_MD
|
||||
OPT_TEXT, OPT_NOOUT, OPT_MD, OPT_TRADITIONAL
|
||||
} OPTION_CHOICE;
|
||||
|
||||
OPTIONS pkey_options[] = {
|
||||
@ -36,6 +36,8 @@ OPTIONS pkey_options[] = {
|
||||
{"text", OPT_TEXT, '-', "Output in plaintext as well"},
|
||||
{"noout", OPT_NOOUT, '-', "Don't output the key"},
|
||||
{"", OPT_MD, '-', "Any supported cipher"},
|
||||
{"traditional", OPT_TRADITIONAL, '-',
|
||||
"Use traditional format for private keys"},
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
|
||||
#endif
|
||||
@ -53,7 +55,7 @@ int pkey_main(int argc, char **argv)
|
||||
OPTION_CHOICE o;
|
||||
int informat = FORMAT_PEM, outformat = FORMAT_PEM;
|
||||
int pubin = 0, pubout = 0, pubtext = 0, text = 0, noout = 0, ret = 1;
|
||||
int private = 0;
|
||||
int private = 0, traditional = 0;
|
||||
|
||||
prog = opt_init(argc, argv, pkey_options);
|
||||
while ((o = opt_next()) != OPT_EOF) {
|
||||
@ -105,6 +107,9 @@ int pkey_main(int argc, char **argv)
|
||||
case OPT_NOOUT:
|
||||
noout = 1;
|
||||
break;
|
||||
case OPT_TRADITIONAL:
|
||||
traditional = 1;
|
||||
break;
|
||||
case OPT_MD:
|
||||
if (!opt_cipher(opt_unknown(), &cipher))
|
||||
goto opthelp;
|
||||
@ -140,8 +145,13 @@ int pkey_main(int argc, char **argv)
|
||||
PEM_write_bio_PUBKEY(out, pkey);
|
||||
else {
|
||||
assert(private);
|
||||
PEM_write_bio_PrivateKey(out, pkey, cipher,
|
||||
NULL, 0, NULL, passout);
|
||||
if (traditional)
|
||||
PEM_write_bio_PrivateKey_traditional(out, pkey, cipher,
|
||||
NULL, 0, NULL,
|
||||
passout);
|
||||
else
|
||||
PEM_write_bio_PrivateKey(out, pkey, cipher,
|
||||
NULL, 0, NULL, passout);
|
||||
}
|
||||
} else if (outformat == FORMAT_ASN1) {
|
||||
if (pubout)
|
||||
|
@ -95,11 +95,18 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
|
||||
unsigned char *kstr, int klen,
|
||||
pem_password_cb *cb, void *u)
|
||||
{
|
||||
char pem_str[80];
|
||||
if (!x->ameth || x->ameth->priv_encode)
|
||||
if (x->ameth == NULL || x->ameth->priv_encode != NULL)
|
||||
return PEM_write_bio_PKCS8PrivateKey(bp, x, enc,
|
||||
(char *)kstr, klen, cb, u);
|
||||
return PEM_write_bio_PrivateKey_traditional(bp, x, enc, kstr, klen, cb, u);
|
||||
}
|
||||
|
||||
int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x,
|
||||
const EVP_CIPHER *enc,
|
||||
unsigned char *kstr, int klen,
|
||||
pem_password_cb *cb, void *u)
|
||||
{
|
||||
char pem_str[80];
|
||||
BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str);
|
||||
return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey,
|
||||
pem_str, bp, x, enc, kstr, klen, cb, u);
|
||||
|
@ -18,6 +18,7 @@ B<openssl> B<pkcs8>
|
||||
[B<-iter count>]
|
||||
[B<-noiter>]
|
||||
[B<-nocrypt>]
|
||||
[B<-traditional>]
|
||||
[B<-v2 alg>]
|
||||
[B<-v2prf alg>]
|
||||
[B<-v1 alg>]
|
||||
@ -43,22 +44,22 @@ Print out a usage message.
|
||||
|
||||
=item B<-topk8>
|
||||
|
||||
Normally a PKCS#8 private key is expected on input and a traditional format
|
||||
private key will be written. With the B<-topk8> option the situation is
|
||||
reversed: it reads a traditional format private key and writes a PKCS#8
|
||||
format key.
|
||||
Normally a PKCS#8 private key is expected on input and a private key will be
|
||||
written to the output file. With the B<-topk8> option the situation is
|
||||
reversed: it reads a private key and writes a PKCS#8 format key.
|
||||
|
||||
=item B<-inform DER|PEM>
|
||||
|
||||
This specifies the input format. If a PKCS#8 format key is expected on input
|
||||
then either a B<DER> or B<PEM> encoded version of a PKCS#8 key will be
|
||||
expected. Otherwise the B<DER> or B<PEM> format of the traditional format
|
||||
private key is used.
|
||||
This specifies the input format: see L<KEY FORMATS> for more details.
|
||||
|
||||
=item B<-outform DER|PEM>
|
||||
|
||||
This specifies the output format, the options have the same meaning as the
|
||||
B<-inform> option.
|
||||
This specifies the output format: see L<KEY FORMATS> for more details.
|
||||
|
||||
=item B<-traditional>
|
||||
|
||||
When this option is present and B<-topk8> is not a traditional format private
|
||||
key is written.
|
||||
|
||||
=item B<-in filename>
|
||||
|
||||
@ -119,7 +120,7 @@ the B<hmacWithSHA1> option to work.
|
||||
|
||||
This option indicates a PKCS#5 v1.5 or PKCS#12 algorithm should be used. Some
|
||||
older implementations may not support PKCS#5 v2.0 and may require this option.
|
||||
If not specified PKCS#5 v2.0 for is used.
|
||||
If not specified PKCS#5 v2.0 form is used.
|
||||
|
||||
=item B<-engine id>
|
||||
|
||||
@ -141,6 +142,27 @@ sets the scrypt B<N>, B<r> or B<p> parameters.
|
||||
|
||||
=back
|
||||
|
||||
=head1 KEY FORMATS
|
||||
|
||||
Various different formats are used by the pkcs8 utility. These are detailed
|
||||
below.
|
||||
|
||||
If a key is being converted from PKCS#8 form (i.e. the B<-topk8> option is
|
||||
not used) then the input file must be in PKCS#8 format. An encrypted
|
||||
key is expected unless B<-nocrypt> is included.
|
||||
|
||||
If B<-topk8> is not used and B<PEM> mode is set the output file will be an
|
||||
unencrypted private key in PKCS#8 format. If the B<-traditional> option is
|
||||
used then a traditional format private key is written instead.
|
||||
|
||||
If B<-topk8> is not used and B<DER> mode is set the output file will be an
|
||||
unencrypted private key in traditional DER format.
|
||||
|
||||
If B<-topk8> is used then any supported private key can be used for the input
|
||||
file in a format specified by B<-inform>. The output file will be encrypted
|
||||
PKCS#8 format using the specified encryption parameters unless B<-nocrypt>
|
||||
is included.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
By default, when converting a key to PKCS#8 format, PKCS#5 v2.0 using 256 bit
|
||||
@ -199,20 +221,28 @@ allow strong encryption algorithms like triple DES or 128 bit RC2 to be used.
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Convert a private from traditional to PKCS#5 v2.0 format using triple
|
||||
DES:
|
||||
Convert a private key to PKCS#8 format using default parameters (AES with
|
||||
256 bit key and B<hmacWithSHA256>):
|
||||
|
||||
openssl pkcs8 -in key.pem -topk8 -out enckey.pem
|
||||
|
||||
Convert a private key to PKCS#8 unencrypted format:
|
||||
|
||||
openssl pkcs8 -in key.pem -topk8 -nocrypt -out enckey.pem
|
||||
|
||||
Convert a private key to PKCS#5 v2.0 format using triple DES:
|
||||
|
||||
openssl pkcs8 -in key.pem -topk8 -v2 des3 -out enckey.pem
|
||||
|
||||
Convert a private from traditional to PKCS#5 v2.0 format using AES with
|
||||
256 bits in CBC mode and B<hmacWithSHA256> PRF:
|
||||
Convert a private key to PKCS#5 v2.0 format using AES with 256 bits in CBC
|
||||
mode and B<hmacWithSHA512> PRF:
|
||||
|
||||
openssl pkcs8 -in key.pem -topk8 -v2 aes-256-cbc -v2prf hmacWithSHA256 -out enckey.pem
|
||||
openssl pkcs8 -in key.pem -topk8 -v2 aes-256-cbc -v2prf hmacWithSHA512 -out enckey.pem
|
||||
|
||||
Convert a private key to PKCS#8 using a PKCS#5 1.5 compatible algorithm
|
||||
(DES):
|
||||
|
||||
openssl pkcs8 -in key.pem -topk8 -out enckey.pem
|
||||
openssl pkcs8 -in key.pem -topk8 -v1 PBE-MD5-DES -out enckey.pem
|
||||
|
||||
Convert a private key to PKCS#8 using a PKCS#12 compatible algorithm
|
||||
(3DES):
|
||||
@ -223,14 +253,14 @@ Read a DER unencrypted PKCS#8 format private key:
|
||||
|
||||
openssl pkcs8 -inform DER -nocrypt -in key.der -out key.pem
|
||||
|
||||
Convert a private key from any PKCS#8 format to traditional format:
|
||||
Convert a private key from any PKCS#8 encrypted format to traditional format:
|
||||
|
||||
openssl pkcs8 -in pk8.pem -out key.pem
|
||||
openssl pkcs8 -in pk8.pem -traditional -out key.pem
|
||||
|
||||
Convert a private key to PKCS#8 format, encrypting with AES-256 and with
|
||||
one million iterations of the password:
|
||||
|
||||
openssl pkcs8 -in raw.pem -topk8 -v2 aes-256-cbc -iter 1000000 -out pk8.pem
|
||||
openssl pkcs8 -in key.pem -topk8 -v2 aes-256-cbc -iter 1000000 -out pk8.pem
|
||||
|
||||
=head1 STANDARDS
|
||||
|
||||
@ -250,10 +280,6 @@ PKCS#8 private key format complies with this standard.
|
||||
There should be an option that prints out the encryption algorithm
|
||||
in use and other details such as the iteration count.
|
||||
|
||||
PKCS#8 using triple DES and PKCS#5 v2.0 should be the default private
|
||||
key format for OpenSSL: for compatibility several of the utilities use
|
||||
the old format at present.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<dsa(1)>, L<rsa(1)>, L<genrsa(1)>,
|
||||
|
@ -14,6 +14,7 @@ B<openssl> B<pkey>
|
||||
[B<-passin arg>]
|
||||
[B<-out filename>]
|
||||
[B<-passout arg>]
|
||||
[B<-traditional>]
|
||||
[B<-cipher>]
|
||||
[B<-text>]
|
||||
[B<-text_pub>]
|
||||
@ -67,6 +68,12 @@ filename.
|
||||
the output file password source. For more information about the format of B<arg>
|
||||
see the B<PASS PHRASE ARGUMENTS> section in L<openssl(1)>.
|
||||
|
||||
=item B<-traditional>
|
||||
|
||||
normally a private key is written using standard format: this is PKCS#8 form
|
||||
with the appropriate encryption algorithm (if any). If the B<-traditional>
|
||||
option is specified then the older "traditional" format is used instead.
|
||||
|
||||
=item B<-cipher>
|
||||
|
||||
These options encrypt the private key with the supplied cipher. Any algorithm
|
||||
|
@ -3,7 +3,8 @@
|
||||
=head1 NAME
|
||||
|
||||
PEM, PEM_read_bio_PrivateKey, PEM_read_PrivateKey, PEM_write_bio_PrivateKey,
|
||||
PEM_write_PrivateKey, PEM_write_bio_PKCS8PrivateKey, PEM_write_PKCS8PrivateKey,
|
||||
PEM_write_bio_PrivateKey_traditional, PEM_write_PrivateKey,
|
||||
PEM_write_bio_PKCS8PrivateKey, PEM_write_PKCS8PrivateKey,
|
||||
PEM_write_bio_PKCS8PrivateKey_nid, PEM_write_PKCS8PrivateKey_nid,
|
||||
PEM_read_bio_PUBKEY, PEM_read_PUBKEY, PEM_write_bio_PUBKEY, PEM_write_PUBKEY,
|
||||
PEM_read_bio_RSAPrivateKey, PEM_read_RSAPrivateKey,
|
||||
@ -35,6 +36,10 @@ PEM_write_bio_PKCS7, PEM_write_PKCS7 - PEM routines
|
||||
int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
|
||||
unsigned char *kstr, int klen,
|
||||
pem_password_cb *cb, void *u);
|
||||
int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x,
|
||||
const EVP_CIPHER *enc,
|
||||
unsigned char *kstr, int klen,
|
||||
pem_password_cb *cb, void *u);
|
||||
int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
|
||||
unsigned char *kstr, int klen,
|
||||
pem_password_cb *cb, void *u);
|
||||
@ -157,19 +162,21 @@ clarity the term "B<foobar> functions" will be used to collectively
|
||||
refer to the PEM_read_bio_foobar(), PEM_read_foobar(),
|
||||
PEM_write_bio_foobar() and PEM_write_foobar() functions.
|
||||
|
||||
The B<PrivateKey> functions read or write a private key in
|
||||
PEM format using an EVP_PKEY structure. The write routines use
|
||||
"traditional" private key format and can handle both RSA and DSA
|
||||
private keys. The read functions can additionally transparently
|
||||
handle PKCS#8 format encrypted and unencrypted keys too.
|
||||
The B<PrivateKey> functions read or write a private key in PEM format using an
|
||||
EVP_PKEY structure. The write routines use PKCS#8 private key format and are
|
||||
equivalent to PEM_write_bio_PKCS8PrivateKey().The read functions transparently
|
||||
handle traditional and PKCS#8 format encrypted and unencrypted keys.
|
||||
|
||||
PEM_write_bio_PKCS8PrivateKey() and PEM_write_PKCS8PrivateKey()
|
||||
write a private key in an EVP_PKEY structure in PKCS#8
|
||||
EncryptedPrivateKeyInfo format using PKCS#5 v2.0 password based encryption
|
||||
algorithms. The B<cipher> argument specifies the encryption algorithm to
|
||||
use: unlike all other PEM routines the encryption is applied at the
|
||||
PKCS#8 level and not in the PEM headers. If B<cipher> is NULL then no
|
||||
encryption is used and a PKCS#8 PrivateKeyInfo structure is used instead.
|
||||
PEM_write_bio_PrivateKey_traditional() writes out a private key in legacy
|
||||
"traditional" format.
|
||||
|
||||
PEM_write_bio_PKCS8PrivateKey() and PEM_write_PKCS8PrivateKey() write a private
|
||||
key in an EVP_PKEY structure in PKCS#8 EncryptedPrivateKeyInfo format using
|
||||
PKCS#5 v2.0 password based encryption algorithms. The B<cipher> argument
|
||||
specifies the encryption algorithm to use: unlike some other PEM routines the
|
||||
encryption is applied at the PKCS#8 level and not in the PEM headers. If
|
||||
B<cipher> is NULL then no encryption is used and a PKCS#8 PrivateKeyInfo
|
||||
structure is used instead.
|
||||
|
||||
PEM_write_bio_PKCS8PrivateKey_nid() and PEM_write_PKCS8PrivateKey_nid()
|
||||
also write out a private key as a PKCS#8 EncryptedPrivateKeyInfo however
|
||||
@ -182,7 +189,8 @@ structure. The public key is encoded as a SubjectPublicKeyInfo
|
||||
structure.
|
||||
|
||||
The B<RSAPrivateKey> functions process an RSA private key using an
|
||||
RSA structure. It handles the same formats as the B<PrivateKey>
|
||||
RSA structure. The write routines uses traditional format. The read
|
||||
routines handles the same formats as the B<PrivateKey>
|
||||
functions but an error occurs if the private key is not RSA.
|
||||
|
||||
The B<RSAPublicKey> functions process an RSA public key using an
|
||||
@ -195,7 +203,8 @@ SubjectPublicKeyInfo structure and an error occurs if the public
|
||||
key is not RSA.
|
||||
|
||||
The B<DSAPrivateKey> functions process a DSA private key using a
|
||||
DSA structure. It handles the same formats as the B<PrivateKey>
|
||||
DSA structure. The write routines uses traditional format. The read
|
||||
routines handles the same formats as the B<PrivateKey>
|
||||
functions but an error occurs if the private key is not DSA.
|
||||
|
||||
The B<DSA_PUBKEY> functions process a DSA public key using
|
||||
@ -403,7 +412,7 @@ password is passed to EVP_BytesToKey() using the B<data> and B<datal>
|
||||
parameters. Finally, the library uses an iteration count of 1 for
|
||||
EVP_BytesToKey().
|
||||
|
||||
he B<key> derived by EVP_BytesToKey() along with the original initialization
|
||||
The B<key> derived by EVP_BytesToKey() along with the original initialization
|
||||
vector is then used to decrypt the encrypted data. The B<iv> produced by
|
||||
EVP_BytesToKey() is not utilized or needed, and NULL should be passed to
|
||||
the function.
|
||||
|
@ -359,6 +359,11 @@ DECLARE_PEM_write_const(DHxparams, DH)
|
||||
DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY)
|
||||
DECLARE_PEM_rw(PUBKEY, EVP_PKEY)
|
||||
|
||||
int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x,
|
||||
const EVP_CIPHER *enc,
|
||||
unsigned char *kstr, int klen,
|
||||
pem_password_cb *cb, void *u);
|
||||
|
||||
int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid,
|
||||
char *kstr, int klen,
|
||||
pem_password_cb *cb, void *u);
|
||||
|
Loading…
Reference in New Issue
Block a user