The "openssl pkcs8" CLI tool fails to properly decrypt a file containing an
EncryptedPrivateKeyInfo structure encrypted with an empty password (see
error below). This happens when a PKCS #12 algorithm is used (such as
PBE-SHA1-3DES); I have not investigated PKCS #5 algorithms. I hit this bug
when attempting to decrypt Chrome's Channel ID/Origin Bound Certs private
keys which are encrypted by (non-broken) NSS.

The PKCS #12 standard explains that if the password is empty, then P should
be empty when concatenating I=S||P (see section B.2, step 3, in
ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf). But openssl
accidentally
makes P an array of NUL bytes. This corrupts the calculation of the key and
iv, causing the error.

The following patch fixes the bug:

 --- ./openssl-1.0.1c/crypto/pkcs12/p12_key.c    2011-06-03
13:52:59.000000000 -0700
+++ p12_key.c   2014-03-18 22:17:49.440922335 -0700
@@ -82,7 +82,7 @@
        unsigned char *unipass;
        int uniplen;

-       if(!pass) {
+       if(!pass || !passlen) {
                unipass = NULL;
                uniplen = 0;
        } else if (!OPENSSL_asc2uni(pass, passlen, &unipass, &uniplen)) {

Here is a non-sensitive test key file encrypted with an empty password to
reproduce the issue (c.key.pem):

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIG4MCMGCiqGSIb3DQEMAQMwFQQQR9OULaNdA8urOek0ctO63QIBAQSBkA6coyL6
Q5PBiPezjbBYursIzB3iedW5YNWIeHLoNUJ7TEQjeBd69rAXx3AFdEJJ7ngpkAko
m5pE/48sf1LsJpeXfFDLPQxgWe5cflc96j/siVVUa5QNssX7hTMVQ6AYujFtqOBH
QedhUrUyDlJSo+1cF0eG0+rvYz2Rj/dLnLxgP94V8NldChOulFIxqMThXw==
-----END ENCRYPTED PRIVATE KEY-----

Before applying the patch, we get this error:

$ openssl pkcs8 -passin pass: -in c.key.pem
Error decrypting key
140145364022944:error:06065064:digital envelope
routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:539:
140145364022944:error:23077074:PKCS12 routines:PKCS12_pbe_crypt:pkcs12
cipherfinal error:p12_decr.c:104:
140145364022944:error:2306A075:PKCS12
routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:p12_decr.c:130:

After applying the patch:

$ openssl pkcs8 -passin pass: -in c.key.pem
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----

Note that applying the patch will of course make ALL PKCS8 FILES encrypted
by openssl with an empty password UNREADABLE by the patched openssl. If you
guys deem this to be a serious problem, then I suggest that we leave the
p12_key.c API unmodified, and instead patch the bug at a higher level in
pkcs8.c. The two ways of computing the key & iv are actually already
supported by the PKCS8_decrypt(X509_SIG *p8, const char *pass, int passlen):

PKCS8_decrypt(..., "", 0)  computes the key/iv in a broken way (P as an
array of NUL bytes)
PKCS8_decrypt(..., NULL, 0)  computes the key/iv in a standard-compliant
way (empty P)

And we could add a command line option to pkcs8.c (-brokenemptypw) to
enable the broken behavior. The PKCS8_decrypt() documentation need to
clearly document that the standard-compliant way to encrypt with a empty
password is to pass NULL as the password argument.

-- 
Cheers,
mbevand

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to