Blob Blame History Raw
diff -up nss/cmd/pk12util/pk12util.c.pk12util-force-unicode nss/cmd/pk12util/pk12util.c
--- nss/cmd/pk12util/pk12util.c.pk12util-force-unicode	2017-09-21 09:49:22.371039588 +0200
+++ nss/cmd/pk12util/pk12util.c	2017-09-21 09:49:22.389039181 +0200
@@ -23,6 +23,7 @@
 static char *progName;
 PRBool pk12_debugging = PR_FALSE;
 PRBool dumpRawFile;
+static PRBool pk12uForceUnicode;
 
 PRIntn pk12uErrno = 0;
 
@@ -357,6 +358,7 @@ p12U_ReadPKCS12File(SECItem *uniPwp, cha
     SECItem p12file = { 0 };
     SECStatus rv = SECFailure;
     PRBool swapUnicode = PR_FALSE;
+    PRBool forceUnicode = pk12uForceUnicode;
     PRBool trypw;
     int error;
 
@@ -424,6 +426,18 @@ p12U_ReadPKCS12File(SECItem *uniPwp, cha
                 SEC_PKCS12DecoderFinish(p12dcx);
                 uniPwp->len = 0;
                 trypw = PR_TRUE;
+            } else if (forceUnicode == pk12uForceUnicode) {
+                /* try again with a different password encoding */
+                forceUnicode = !pk12uForceUnicode;
+                rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
+                                   forceUnicode);
+                if (rv != SECSuccess) {
+                    SECU_PrintError(progName, "PKCS12 decoding failed to set option");
+                    pk12uErrno = PK12UERR_DECODEVERIFY;
+                    break;
+                }
+                SEC_PKCS12DecoderFinish(p12dcx);
+                trypw = PR_TRUE;
             } else {
                 SECU_PrintError(progName, "PKCS12 decode not verified");
                 pk12uErrno = PK12UERR_DECODEVERIFY;
@@ -431,6 +445,15 @@ p12U_ReadPKCS12File(SECItem *uniPwp, cha
             }
         }
     } while (trypw == PR_TRUE);
+
+    /* revert the option setting */
+    if (forceUnicode != pk12uForceUnicode) {
+        rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "PKCS12 decoding failed to set option");
+            pk12uErrno = PK12UERR_DECODEVERIFY;
+        }
+    }
 /* rv has been set at this point */
 
 done:
@@ -470,6 +493,8 @@ P12U_ImportPKCS12Object(char *in_file, P
 {
     SEC_PKCS12DecoderContext *p12dcx = NULL;
     SECItem uniPwitem = { 0 };
+    PRBool forceUnicode = pk12uForceUnicode;
+    PRBool trypw;
     SECStatus rv = SECFailure;
 
     rv = P12U_InitSlot(slot, slotPw);
@@ -480,31 +505,62 @@ P12U_ImportPKCS12Object(char *in_file, P
         return rv;
     }
 
-    rv = SECFailure;
-    p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
+    do {
+        trypw = PR_FALSE; /* normally we do this once */
+        rv = SECFailure;
+        p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
 
-    if (p12dcx == NULL) {
-        goto loser;
-    }
+        if (p12dcx == NULL) {
+            goto loser;
+        }
 
-    /* make sure the bags are okey dokey -- nicknames correct, etc. */
-    rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
-    if (rv != SECSuccess) {
-        if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
-            pk12uErrno = PK12UERR_CERTALREADYEXISTS;
-        } else {
-            pk12uErrno = PK12UERR_DECODEVALIBAGS;
+        /* make sure the bags are okey dokey -- nicknames correct, etc. */
+        rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
+        if (rv != SECSuccess) {
+            if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
+                pk12uErrno = PK12UERR_CERTALREADYEXISTS;
+            } else {
+                pk12uErrno = PK12UERR_DECODEVALIBAGS;
+            }
+            SECU_PrintError(progName, "PKCS12 decode validate bags failed");
+            goto loser;
         }
-        SECU_PrintError(progName, "PKCS12 decode validate bags failed");
-        goto loser;
-    }
 
-    /* stuff 'em in */
-    rv = SEC_PKCS12DecoderImportBags(p12dcx);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "PKCS12 decode import bags failed");
-        pk12uErrno = PK12UERR_DECODEIMPTBAGS;
-        goto loser;
+        /* stuff 'em in */
+        if (forceUnicode != pk12uForceUnicode) {
+            rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
+                               forceUnicode);
+            if (rv != SECSuccess) {
+                SECU_PrintError(progName, "PKCS12 decode set option failed");
+                pk12uErrno = PK12UERR_DECODEIMPTBAGS;
+                goto loser;
+            }
+        }
+        rv = SEC_PKCS12DecoderImportBags(p12dcx);
+        if (rv != SECSuccess) {
+            if (PR_GetError() == SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY &&
+                forceUnicode == pk12uForceUnicode) {
+                /* try again with a different password encoding */
+                forceUnicode = !pk12uForceUnicode;
+                SEC_PKCS12DecoderFinish(p12dcx);
+                SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
+                trypw = PR_TRUE;
+            } else {
+                SECU_PrintError(progName, "PKCS12 decode import bags failed");
+                pk12uErrno = PK12UERR_DECODEIMPTBAGS;
+                goto loser;
+            }
+        }
+    } while (trypw);
+
+    /* revert the option setting */
+    if (forceUnicode != pk12uForceUnicode) {
+        rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "PKCS12 decode set option failed");
+            pk12uErrno = PK12UERR_DECODEIMPTBAGS;
+            goto loser;
+        }
     }
 
     fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
@@ -951,6 +1007,7 @@ main(int argc, char **argv)
     int keyLen = 0;
     int certKeyLen = 0;
     secuCommand pk12util;
+    PRInt32 forceUnicode;
 
 #ifdef _CRTDBG_MAP_ALLOC
     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
@@ -982,6 +1039,14 @@ main(int argc, char **argv)
         Usage(progName);
     }
 
+    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName,
+                        "Failed to get NSS_PKCS12_DECODE_FORCE_UNICODE option");
+        Usage(progName);
+    }
+    pk12uForceUnicode = forceUnicode;
+
     slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
 
     import_file = (pk12util.options[opt_List].activated) ? SECU_GetOptionArg(&pk12util, opt_List)
diff -up nss/lib/nss/nss.h.pk12util-force-unicode nss/lib/nss/nss.h
--- nss/lib/nss/nss.h.pk12util-force-unicode	2017-04-05 14:23:56.000000000 +0200
+++ nss/lib/nss/nss.h	2017-09-21 09:49:22.387039226 +0200
@@ -291,6 +291,15 @@ SECStatus NSS_UnregisterShutdown(NSS_Shu
 #define NSS_DTLS_VERSION_MIN_POLICY 0x00a
 #define NSS_DTLS_VERSION_MAX_POLICY 0x00b
 
+/* Until NSS 3.30, the PKCS#12 implementation used BMPString encoding
+ * for all passwords.  This changed to use UTF-8 for non-PKCS#12 PBEs
+ * in NSS 3.31.
+ *
+ * For backward compatibility, this option reverts the behavior to the
+ * old NSS versions.  This option might be removed in the future NSS
+ * releases; don't rely on it. */
+#define __NSS_PKCS12_DECODE_FORCE_UNICODE 0x00c
+
 /*
  * Set and get global options for the NSS library.
  */
diff -up nss/lib/nss/nssoptions.c.pk12util-force-unicode nss/lib/nss/nssoptions.c
--- nss/lib/nss/nssoptions.c.pk12util-force-unicode	2017-04-05 14:23:56.000000000 +0200
+++ nss/lib/nss/nssoptions.c	2017-09-21 09:49:22.387039226 +0200
@@ -23,6 +23,7 @@ struct nssOps {
     PRInt32 tlsVersionMaxPolicy;
     PRInt32 dtlsVersionMinPolicy;
     PRInt32 dtlsVersionMaxPolicy;
+    PRInt32 pkcs12DecodeForceUnicode;
 };
 
 static struct nssOps nss_ops = {
@@ -33,6 +34,7 @@ static struct nssOps nss_ops = {
     0xffff, /* set TLS max to more than the largest legal SSL value */
     1,
     0xffff,
+    PR_FALSE
 };
 
 SECStatus
@@ -62,6 +64,9 @@ NSS_OptionSet(PRInt32 which, PRInt32 val
         case NSS_DTLS_VERSION_MAX_POLICY:
             nss_ops.dtlsVersionMaxPolicy = value;
             break;
+        case __NSS_PKCS12_DECODE_FORCE_UNICODE:
+            nss_ops.pkcs12DecodeForceUnicode = value;
+            break;
         default:
             rv = SECFailure;
     }
@@ -96,6 +101,9 @@ NSS_OptionGet(PRInt32 which, PRInt32 *va
         case NSS_DTLS_VERSION_MAX_POLICY:
             *value = nss_ops.dtlsVersionMaxPolicy;
             break;
+        case __NSS_PKCS12_DECODE_FORCE_UNICODE:
+            *value = nss_ops.pkcs12DecodeForceUnicode;
+            break;
         default:
             rv = SECFailure;
     }
diff -up nss/lib/pkcs12/p12d.c.pk12util-force-unicode nss/lib/pkcs12/p12d.c
--- nss/lib/pkcs12/p12d.c.pk12util-force-unicode	2017-09-21 09:49:22.374039520 +0200
+++ nss/lib/pkcs12/p12d.c	2017-09-21 09:49:22.388039203 +0200
@@ -3,6 +3,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nssrenam.h"
+#include "nss.h"
 #include "p12t.h"
 #include "p12.h"
 #include "plarena.h"
@@ -126,6 +127,7 @@ struct SEC_PKCS12DecoderContextStr {
     SECKEYGetPasswordKey pwfn;
     void *pwfnarg;
     PRBool swapUnicodeBytes;
+    PRBool forceUnicode;
 
     /* import information */
     PRBool bagsVerified;
@@ -192,8 +194,18 @@ sec_pkcs12_decoder_get_decrypt_key(void
     }
 
     algorithm = SECOID_GetAlgorithmTag(algid);
-    if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm, p12dcx->pwitem))
-        return NULL;
+
+    if (p12dcx->forceUnicode) {
+        if (SECITEM_CopyItem(NULL, &pwitem, p12dcx->pwitem) != SECSuccess) {
+            PK11_FreeSlot(slot);
+            return NULL;
+        }
+    } else {
+        if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm, p12dcx->pwitem)) {
+            PK11_FreeSlot(slot);
+            return NULL;
+        }
+    }
 
     bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx);
     /* some tokens can't generate PBE keys on their own, generate the
@@ -1164,6 +1176,8 @@ SEC_PKCS12DecoderStart(SECItem *pwitem,
 {
     SEC_PKCS12DecoderContext *p12dcx;
     PLArenaPool *arena;
+    PRInt32 forceUnicode = PR_FALSE;
+    SECStatus rv;
 
     arena = PORT_NewArena(2048); /* different size? */
     if (!arena) {
@@ -1196,6 +1210,11 @@ SEC_PKCS12DecoderStart(SECItem *pwitem,
 #else
     p12dcx->swapUnicodeBytes = PR_FALSE;
 #endif
+    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    p12dcx->forceUnicode = forceUnicode;
     p12dcx->errorValue = 0;
     p12dcx->error = PR_FALSE;
 
@@ -2428,7 +2447,7 @@ sec_pkcs12_get_public_value_and_type(SEC
 static SECStatus
 sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey,
                    unsigned int keyUsage,
-                   SECItem *nickName, void *wincx)
+                   SECItem *nickName, PRBool forceUnicode, void *wincx)
 {
     SECStatus rv;
     SECItem *publicValue = NULL;
@@ -2466,9 +2485,21 @@ sec_pkcs12_add_key(sec_PKCS12SafeBag *ke
                 &key->safeBagContent.pkcs8ShroudedKeyBag->algorithm;
             SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
 
-            if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm,
-                                            key->pwitem))
-                return SECFailure;
+            if (forceUnicode) {
+                if (SECITEM_CopyItem(NULL, &pwitem, key->pwitem) != SECSuccess) {
+                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
+                    key->problem = PR_TRUE;
+                    return SECFailure;
+                }
+            } else {
+                if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm,
+                                                key->pwitem)) {
+                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
+                    key->problem = PR_TRUE;
+                    return SECFailure;
+                }
+            }
+
             rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
                                                     key->safeBagContent.pkcs8ShroudedKeyBag,
                                                     &pwitem, nickName, publicValue,
@@ -2923,7 +2954,8 @@ sec_pkcs12_get_public_value_and_type(SEC
  * two passes in sec_pkcs12_validate_bags.
  */
 static SECStatus
-sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, void *wincx)
+sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, PRBool forceUnicode,
+                        void *wincx)
 {
     sec_PKCS12SafeBag **keyList;
     int i;
@@ -2976,7 +3008,8 @@ sec_pkcs12_install_bags(sec_PKCS12SafeBa
                 key->problem = PR_TRUE;
                 rv = SECFailure;
             } else {
-                rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName, wincx);
+                rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName,
+                                        forceUnicode, wincx);
             }
             if (pubKey) {
                 SECKEY_DestroyPublicKey(pubKey);
@@ -3053,6 +3086,9 @@ sec_pkcs12_install_bags(sec_PKCS12SafeBa
 SECStatus
 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
 {
+    PRBool forceUnicode = PR_FALSE;
+    SECStatus rv;
+
     if (!p12dcx || p12dcx->error) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
@@ -3062,7 +3098,16 @@ SEC_PKCS12DecoderImportBags(SEC_PKCS12De
         return SECFailure;
     }
 
-    return sec_pkcs12_install_bags(p12dcx->safeBags, p12dcx->wincx);
+    /* We need to check the option here as well as in
+     * SEC_PKCS12DecoderStart, because different PBE's could be used
+     * for PKCS #7 and PKCS #8 */
+    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    return sec_pkcs12_install_bags(p12dcx->safeBags, forceUnicode,
+                                   p12dcx->wincx);
 }
 
 PRBool
diff -up nss/tests/tools/tools.sh.pk12util-force-unicode nss/tests/tools/tools.sh
--- nss/tests/tools/tools.sh.pk12util-force-unicode	2017-09-21 09:49:22.373039542 +0200
+++ nss/tests/tools/tools.sh	2017-09-21 09:50:06.593062871 +0200
@@ -106,6 +106,8 @@ tools_init()
   cp ${ALICEDIR}/* ${SIGNDIR}/
   mkdir -p ${TOOLSDIR}/html
   cp ${QADIR}/tools/sign*.html ${TOOLSDIR}/html
+  mkdir -p ${TOOLSDIR}/data
+  cp ${QADIR}/tools/TestOldCA.p12 ${TOOLSDIR}/data
 
   cd ${TOOLSDIR}
 }
@@ -398,6 +400,16 @@ tools_p12_export_list_import_with_defaul
   fi
 }
 
+tools_p12_import_old_files()
+{
+  echo "$SCRIPTNAME: Importing CA cert & key created with NSS 3.21 --------------"
+  echo "pk12util -i TestOldCA.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_PWFILE}"
+  ${BINDIR}/pk12util -i ${TOOLSDIR}/data/TestOldCA.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_PWFILE} 2>&1
+  ret=$?
+  html_msg $ret 0 "Importing CA cert & key created with NSS 3.21"
+  check_tmpfile
+}
+
 ############################## tools_p12 ###############################
 # local shell function to test basic functionality of pk12util
 ########################################################################
@@ -408,6 +420,7 @@ tools_p12()
   tools_p12_export_list_import_all_pkcs5pbe_ciphers
   tools_p12_export_list_import_all_pkcs12v2pbe_ciphers
   tools_p12_export_with_null_ciphers
+  tools_p12_import_old_files
 }
 
 ############################## tools_sign ##############################