Blame SOURCES/nss-pk12util-force-unicode.patch

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