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 ##############################