Blob Blame History Raw
From 137832b2892dfc596ed067a86242d341f2c325e7 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal@redhat.com>
Date: Thu, 14 Sep 2017 12:22:47 +1000
Subject: [PATCH] Make PKCS #12 files compatible with OpenSSL, NSS >= 3.31

For compatibility with OpenSSL and NSS >= 3.31, the passphrase must
not be BMPString-encoded when non-PKCS #12 PBE schemes such as
PBES2.

Fixes: https://pagure.io/dogtagpki/issue/2809

Change-Id: Ic78ad337ac0b9b2f5d2e75581cc0ee55e6d82782
(cherry picked from commit ed5cccefebf98e588a5385191e43f727349b54a9)
---
 base/kra/src/com/netscape/kra/RecoveryService.java | 26 +++++++++++++++----
 .../cms/servlet/csadmin/ConfigurationUtils.java    | 15 ++++++++---
 .../src/netscape/security/pkcs/PKCS12Util.java     | 29 ++++++++++++++++++----
 3 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/base/kra/src/com/netscape/kra/RecoveryService.java b/base/kra/src/com/netscape/kra/RecoveryService.java
index a7d639208..0d293e411 100644
--- a/base/kra/src/com/netscape/kra/RecoveryService.java
+++ b/base/kra/src/com/netscape/kra/RecoveryService.java
@@ -508,10 +508,21 @@ public class RecoveryService implements IService {
                 }
             } else {
                 byte[] epkiBytes = ct.getCryptoStore().getEncryptedPrivateKeyInfo(
+                    /* For compatibility with OpenSSL and NSS >= 3.31,
+                     * do not BMPString-encode the passphrase when using
+                     * non-PKCS #12 PBE scheme such as PKCS #5 PBES2.
+                     *
+                     * The resulting PKCS #12 is not compatible with
+                     * NSS < 3.31.
+                     */
+                    null /* passConverter */,
+                    pass,
                     /* NSS has a bug that causes any AES CBC encryption
                      * to use AES-256, but AlgorithmID contains chosen
                      * alg.  To avoid mismatch, use AES_256_CBC. */
-                    passConverter, pass, EncryptionAlgorithm.AES_256_CBC, 0, priKey);
+                    EncryptionAlgorithm.AES_256_CBC,
+                    0 /* iterations (use default) */,
+                    priKey);
                 CMS.debug("RecoverService: createPFX() getEncryptedPrivateKeyInfo() returned");
                 if (epkiBytes == null) {
                     CMS.debug("RecoverService: createPFX() epkiBytes null");
@@ -646,8 +657,6 @@ public class RecoveryService implements IService {
                             pwd.toCharArray());
 
             SEQUENCE safeContents = new SEQUENCE();
-            PasswordConverter passConverter = new
-                    PasswordConverter();
             PrivateKeyInfo pki = (PrivateKeyInfo)
                     ASN1Util.decode(PrivateKeyInfo.getTemplate(),
                             priData);
@@ -662,14 +671,21 @@ public class RecoveryService implements IService {
                 byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
                 epki = EncryptedPrivateKeyInfo.createPBE(
                     PBEAlgorithm.PBE_SHA1_DES3_CBC,
-                    pass, salt, 1, passConverter, pki);
+                    pass, salt, 1, new PasswordConverter(), pki);
             } else {
                 epki = EncryptedPrivateKeyInfo.createPBES2(
                     16, // saltLen
                     2000, // kdfIterations
                     EncryptionAlgorithm.AES_128_CBC_PAD,
                     pass,
-                    passConverter,
+                    /* For compatibility with OpenSSL and NSS >= 3.31,
+                     * do not BMPString-encode the passphrase when using
+                     * non-PKCS #12 PBE scheme such as PKCS #5 PBES2.
+                     *
+                     * The resulting PKCS #12 is not compatible with
+                     * NSS < 3.31.
+                     */
+                    null /* passConverter */,
                     pki);
             }
 
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index ebade36bc..df3b4672d 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -1058,9 +1058,18 @@ public class ConfigurationUtils {
                 // this is OK
             }
 
-            // import private key into database
-            store.importEncryptedPrivateKeyInfo(
-                new PasswordConverter(), password, nickname, publicKey, epki);
+            try {
+                // first true without BMPString-encoding the passphrase.
+                store.importEncryptedPrivateKeyInfo(
+                    null, password, nickname, publicKey, epki);
+            } catch (Exception e) {
+                // if that failed, try again with BMPString-encoded
+                // passphrase.  This is required for PKCS #12 PBE
+                // schemes and for PKCS #12 files using PBES2 generated
+                // by NSS < 3.31
+                store.importEncryptedPrivateKeyInfo(
+                    new PasswordConverter(), password, nickname, publicKey, epki);
+            }
         }
 
         CMS.debug("Importing new certificates:");
diff --git a/base/util/src/netscape/security/pkcs/PKCS12Util.java b/base/util/src/netscape/security/pkcs/PKCS12Util.java
index 1bc1baee5..1018b21f6 100644
--- a/base/util/src/netscape/security/pkcs/PKCS12Util.java
+++ b/base/util/src/netscape/security/pkcs/PKCS12Util.java
@@ -134,16 +134,25 @@ public class PKCS12Util {
             }
             logger.debug("Encrypting private key for " + keyInfo.subjectDN);
 
-            PasswordConverter passConverter = new PasswordConverter();
             epkiBytes = CryptoManager.getInstance()
                 .getInternalKeyStorageToken()
                 .getCryptoStore()
                 .getEncryptedPrivateKeyInfo(
+                    /* For compatibility with OpenSSL and NSS >= 3.31,
+                     * do not BMPString-encode the passphrase when using
+                     * non-PKCS #12 PBE scheme such as PKCS #5 PBES2.
+                     *
+                     * The resulting PKCS #12 is not compatible with
+                     * NSS < 3.31.
+                     */
+                    null /* passConverter */,
+                    password,
                     /* NSS has a bug that causes any AES CBC encryption
                      * to use AES-256, but AlgorithmID contains chosen
                      * alg.  To avoid mismatch, use AES_256_CBC. */
-                    passConverter, password,
-                    EncryptionAlgorithm.AES_256_CBC, 0, k);
+                    EncryptionAlgorithm.AES_256_CBC,
+                    0 /* iterations (default) */,
+                    k);
         }
 
         SET keyAttrs = createKeyBagAttrs(keyInfo);
@@ -616,8 +625,18 @@ public class PKCS12Util {
                 "No EncryptedPrivateKeyInfo for key '"
                 + keyInfo.subjectDN + "'; skipping key");
         }
-        store.importEncryptedPrivateKeyInfo(
-            new PasswordConverter(), password, nickname, publicKey, epkiBytes);
+        try {
+            // first true without BMPString-encoding the passphrase.
+            store.importEncryptedPrivateKeyInfo(
+                null, password, nickname, publicKey, epkiBytes);
+        } catch (Exception e) {
+            // if that failed, try again with BMPString-encoded
+            // passphrase.  This is required for PKCS #12 PBE
+            // schemes and for PKCS #12 files using PBES2 generated
+            // by NSS < 3.31
+            store.importEncryptedPrivateKeyInfo(
+                new PasswordConverter(), password, nickname, publicKey, epkiBytes);
+        }
 
         // delete the cert again (it will be imported again later
         // with the correct nickname)
-- 
2.13.5