The following bug has been reproduced on RedHat Enterprise Linux with OpenSSL
1.0.1e.
When upgrading from 0.9.8e to 1.0.1e we noticed that a call to PKCS12_parse()
would sometimes fail with the following:
3073869560:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad
decrypt:evp_enc.c:535:
3073869560:error:23077074:PKCS12 routines:PKCS12_pbe_crypt:pkcs12 cipherfinal
error:p12_decr.c:97:
3073869560:error:2306A075:PKCS12 routines:PKCS12_item_decrypt_d2i:pkcs12 pbe
crypt error:p12_decr.c:123:
3073869560:error:23076072:PKCS12 routines:PKCS12_parse:parse
error:p12_kiss.c:129:
We determined that the cause was an existing PBE registration within our
application via EVP_PBE_alg_add():
EVP_PBE_alg_add(NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc(), EVP_sha1(),
PKCS12_PBE_keyivgen);
Under OpenSSL 1.0.0 and beyond, this causes a PBE to be added with a cipher NID
of RC2-CBC instead of RC2-40-CBC. A change to this API uses an incorrect cipher
NID returned by EVP_CIPHER_type(). The decryption of PKCS12 components that are
encrypted with RC2-40-CBC fails because RC2-CBC is used instead.
Enclosed is a modified version of demos/pkcs12/pkread.c. When linked against
OpenSSL 1.x.x the code will fail to decrypt a PKCS12 file encrypted with
RC2-40-CBC. The same code works fine when linked against 0.9.8*. The code can
be made to work with 1.x.x by removing the call to EVP_PBE_alg_add(), allowing
the builtin version of this PBE (with the correct cipher NID) to be used.
Thank you.
Doug Gibbons | Consulting Engineer | Avaya Inc. | 1300 W. 120th Ave | B3-C61 |
Westminster, CO 80234 | 303-538-3538 |
[email protected]<mailto:[email protected]>
/* pkread.c */
#include <stdio.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
/* Simple PKCS#12 file reader */
int main(int argc, char **argv)
{
FILE *fp;
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12;
int i;
if (argc != 4) {
fprintf(stderr, "Usage: pkread p12file password opfile\n");
exit (1);
}
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
#if 1
/* With OpenSSL 1.x.x next line creates PBE with incorrect cipher NID */
EVP_PBE_alg_add(NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc(),
EVP_sha1(), PKCS12_PBE_keyivgen);
#endif
if (!(fp = fopen(argv[1], "rb"))) {
fprintf(stderr, "Error opening file %s\n", argv[1]);
exit(1);
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit (1);
}
if (!PKCS12_parse(p12, argv[2], &pkey, &cert, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit (1);
}
PKCS12_free(p12);
if (!(fp = fopen(argv[3], "w"))) {
fprintf(stderr, "Error opening file %s\n", argv[1]);
exit(1);
}
if (pkey) {
fprintf(fp, "***Private Key***\n");
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
}
if (cert) {
fprintf(fp, "***User Certificate***\n");
PEM_write_X509_AUX(fp, cert);
}
if (ca && sk_X509_num(ca)) {
fprintf(fp, "***Other Certificates***\n");
for (i = 0; i < sk_X509_num(ca); i++)
PEM_write_X509_AUX(fp, sk_X509_value(ca, i));
}
fclose(fp);
return 0;
}