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