# HG changeset patch # User Daiki Ueno # Date 1481829086 -3600 # Thu Dec 15 20:11:26 2016 +0100 # Node ID 6d66c2c24e4d9d1ad12a7065c55ef1c9fe143057 # Parent 35ecce23718136f99ca9537007481b4774c57e68 Bug 1268143 - pk12util can't import PKCS#12 files with SHA-256 MAC, r=rrelyea diff --git a/lib/pk11wrap/pk11mech.c b/lib/pk11wrap/pk11mech.c --- a/lib/pk11wrap/pk11mech.c +++ b/lib/pk11wrap/pk11mech.c @@ -612,6 +612,10 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN: case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN: case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN: + case CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN: + case CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN: + case CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN: + case CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: diff --git a/lib/pkcs12/p12d.c b/lib/pkcs12/p12d.c --- a/lib/pkcs12/p12d.c +++ b/lib/pkcs12/p12d.c @@ -1335,11 +1335,23 @@ sec_pkcs12_decoder_verify_mac(SEC_PKCS12 case SEC_OID_MD2: integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break; + case SEC_OID_SHA224: + integrityMech = CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN; + break; + case SEC_OID_SHA256: + integrityMech = CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN; + break; + case SEC_OID_SHA384: + integrityMech = CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN; + break; + case SEC_OID_SHA512: + integrityMech = CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN; + break; default: goto loser; } - symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL); + symKey = PK11_KeyGen(NULL, integrityMech, params, 0, NULL); PK11_DestroyPBEParams(params); params = NULL; if (!symKey) diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c --- a/lib/softoken/lowpbe.c +++ b/lib/softoken/lowpbe.c @@ -408,7 +408,6 @@ loser: return result; } -#define HMAC_BUFFER 64 #define NSSPBE_ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y)) #define NSSPBE_MIN(x, y) ((x) < (y) ? (x) : (y)) /* @@ -430,6 +429,7 @@ nsspkcs5_PKCS12PBE(const SECHashObject * int iter; unsigned char *iterBuf; void *hash = NULL; + unsigned int bufferLength; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { @@ -439,8 +439,11 @@ nsspkcs5_PKCS12PBE(const SECHashObject * /* how many hash object lengths are needed */ c = (bytesNeeded + (hashLength - 1)) / hashLength; + /* 64 if 0 < hashLength <= 32, 128 if 32 < hashLength <= 64 */ + bufferLength = NSSPBE_ROUNDUP(hashLength * 2, 64); + /* initialize our buffers */ - D.len = HMAC_BUFFER; + D.len = bufferLength; /* B and D are the same length, use one alloc go get both */ D.data = (unsigned char *)PORT_ArenaZAlloc(arena, D.len * 2); B.len = D.len; @@ -452,8 +455,8 @@ nsspkcs5_PKCS12PBE(const SECHashObject * goto loser; } - SLen = NSSPBE_ROUNDUP(salt->len, HMAC_BUFFER); - PLen = NSSPBE_ROUNDUP(pwitem->len, HMAC_BUFFER); + SLen = NSSPBE_ROUNDUP(salt->len, bufferLength); + PLen = NSSPBE_ROUNDUP(pwitem->len, bufferLength); I.len = SLen + PLen; I.data = (unsigned char *)PORT_ArenaZAlloc(arena, I.len); if (I.data == NULL) { # HG changeset patch # User Daiki Ueno # Date 1485768835 -3600 # Mon Jan 30 10:33:55 2017 +0100 # Node ID 09d1a0757431fa52ae025138da654c698141971b # Parent 806c3106536feea0827ec54729a52b5cbac8a496 Bug 1268141 - pk12util can't import PKCS#12 files encrypted with AES-128-CBC, r=rrelyea diff --git a/cmd/pk12util/pk12util.c b/cmd/pk12util/pk12util.c --- a/cmd/pk12util/pk12util.c +++ b/cmd/pk12util/pk12util.c @@ -861,6 +861,9 @@ p12u_EnableAllCiphers() SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); + SEC_PKCS12EnableCipher(PKCS12_AES_CBC_128, 1); + SEC_PKCS12EnableCipher(PKCS12_AES_CBC_192, 1); + SEC_PKCS12EnableCipher(PKCS12_AES_CBC_256, 1); SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); } diff --git a/lib/pk11wrap/pk11pbe.c b/lib/pk11wrap/pk11pbe.c --- a/lib/pk11wrap/pk11pbe.c +++ b/lib/pk11wrap/pk11pbe.c @@ -4,6 +4,7 @@ #include "plarena.h" +#include "blapit.h" #include "seccomon.h" #include "secitem.h" #include "secport.h" @@ -301,17 +302,49 @@ SEC_PKCS5GetPBEAlgorithm(SECOidTag algTa return SEC_OID_UNKNOWN; } +static PRBool +sec_pkcs5_is_algorithm_v2_aes_algorithm(SECOidTag algorithm) +{ + switch (algorithm) { + case SEC_OID_AES_128_CBC: + case SEC_OID_AES_192_CBC: + case SEC_OID_AES_256_CBC: + return PR_TRUE; + default: + return PR_FALSE; + } +} + +static int +sec_pkcs5v2_aes_key_length(SECOidTag algorithm) +{ + switch (algorithm) { + /* The key length for the AES-CBC-Pad algorithms are + * determined from the undelying cipher algorithm. */ + case SEC_OID_AES_128_CBC: + return AES_128_KEY_LENGTH; + case SEC_OID_AES_192_CBC: + return AES_192_KEY_LENGTH; + case SEC_OID_AES_256_CBC: + return AES_256_KEY_LENGTH; + default: + break; + } + return 0; +} + /* * get the key length in bytes from a PKCS5 PBE */ -int -sec_pkcs5v2_key_length(SECAlgorithmID *algid) +static int +sec_pkcs5v2_key_length(SECAlgorithmID *algid, SECAlgorithmID *cipherAlgId) { SECOidTag algorithm; PLArenaPool *arena = NULL; SEC_PKCS5PBEParameter p5_param; SECStatus rv; int length = -1; + SECOidTag cipherAlg = SEC_OID_UNKNOWN; algorithm = SECOID_GetAlgorithmTag(algid); /* sanity check, they should all be PBKDF2 here */ @@ -330,7 +363,12 @@ sec_pkcs5v2_key_length(SECAlgorithmID *a goto loser; } - if (p5_param.keyLength.data != NULL) { + if (cipherAlgId) + cipherAlg = SECOID_GetAlgorithmTag(cipherAlgId); + + if (sec_pkcs5_is_algorithm_v2_aes_algorithm(cipherAlg)) { + length = sec_pkcs5v2_aes_key_length(cipherAlg); + } else if (p5_param.keyLength.data != NULL) { length = DER_GetInteger(&p5_param.keyLength); } @@ -375,14 +413,15 @@ SEC_PKCS5GetKeyLength(SECAlgorithmID *al case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: return 16; case SEC_OID_PKCS5_PBKDF2: - return sec_pkcs5v2_key_length(algid); + return sec_pkcs5v2_key_length(algid, NULL); case SEC_OID_PKCS5_PBES2: case SEC_OID_PKCS5_PBMAC1: { sec_pkcs5V2Parameter *pbeV2_param; int length = -1; pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid); if (pbeV2_param != NULL) { - length = sec_pkcs5v2_key_length(&pbeV2_param->pbeAlgId); + length = sec_pkcs5v2_key_length(&pbeV2_param->pbeAlgId, + &pbeV2_param->cipherAlgId); sec_pkcs5_v2_destroy_v2_param(pbeV2_param); } return length; @@ -614,6 +653,8 @@ sec_pkcs5CreateAlgorithmID(SECOidTag alg SECOidTag hashAlg = HASH_GetHashOidTagByHMACOidTag(cipherAlgorithm); if (hashAlg != SEC_OID_UNKNOWN) { keyLength = HASH_ResultLenByOidTag(hashAlg); + } else if (sec_pkcs5_is_algorithm_v2_aes_algorithm(cipherAlgorithm)) { + keyLength = sec_pkcs5v2_aes_key_length(cipherAlgorithm); } else { CK_MECHANISM_TYPE cryptoMech; cryptoMech = PK11_AlgtagToMechanism(cipherAlgorithm); diff --git a/lib/pkcs12/p12d.c b/lib/pkcs12/p12d.c --- a/lib/pkcs12/p12d.c +++ b/lib/pkcs12/p12d.c @@ -177,6 +177,9 @@ sec_pkcs12_decoder_get_decrypt_key(void SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg; PK11SlotInfo *slot; PK11SymKey *bulkKey; + SECItem *pwitem; + SECItem decodedPwitem = { 0 }; + SECOidTag algorithm; if (!p12dcx) { return NULL; @@ -189,7 +192,24 @@ sec_pkcs12_decoder_get_decrypt_key(void slot = PK11_GetInternalKeySlot(); } - bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, + algorithm = SECOID_GetAlgorithmTag(algid); + pwitem = p12dcx->pwitem; + + /* here we assume that the password is already encoded into + * BMPString by the caller. if the encryption scheme is not the + * one defined in PKCS #12, decode the password back into + * UTF-8. */ + if (!sec_pkcs12_is_pkcs12_pbe_algorithm(algorithm)) { + if (!sec_pkcs12_convert_item_to_unicode(NULL, &decodedPwitem, + p12dcx->pwitem, + PR_TRUE, PR_FALSE, PR_FALSE)) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + pwitem = &decodedPwitem; + } + + bulkKey = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, p12dcx->wincx); /* some tokens can't generate PBE keys on their own, generate the * key in the internal slot, and let the Import code deal with it, @@ -198,7 +218,7 @@ sec_pkcs12_decoder_get_decrypt_key(void if (!bulkKey && !PK11_IsInternal(slot)) { PK11_FreeSlot(slot); slot = PK11_GetInternalKeySlot(); - bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, + bulkKey = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, p12dcx->wincx); } PK11_FreeSlot(slot); @@ -208,6 +228,10 @@ sec_pkcs12_decoder_get_decrypt_key(void PK11_SetSymKeyUserData(bulkKey, p12dcx->pwitem, NULL); } + if (decodedPwitem.data) { + SECITEM_ZfreeItem(&decodedPwitem, PR_FALSE); + } + return bulkKey; } diff --git a/lib/pkcs12/p12e.c b/lib/pkcs12/p12e.c --- a/lib/pkcs12/p12e.c +++ b/lib/pkcs12/p12e.c @@ -10,6 +10,7 @@ #include "seccomon.h" #include "secport.h" #include "cert.h" +#include "secpkcs5.h" #include "secpkcs7.h" #include "secasn1.h" #include "secerr.h" @@ -378,19 +379,36 @@ SEC_PKCS12CreatePasswordPrivSafe(SEC_PKC safeInfo->itemCount = 0; /* create the encrypted safe */ - safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn, - p12ctxt->pwfnarg); + if (!SEC_PKCS5IsAlgorithmPBEAlgTag(privAlg) && + PK11_AlgtagToMechanism(privAlg) == CKM_AES_CBC) { + safeInfo->cinfo = SEC_PKCS7CreateEncryptedDataWithPBEV2(SEC_OID_PKCS5_PBES2, + privAlg, + SEC_OID_UNKNOWN, + 0, + p12ctxt->pwfn, + p12ctxt->pwfnarg); + } else { + safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn, + p12ctxt->pwfnarg); + } if (!safeInfo->cinfo) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } safeInfo->arena = p12ctxt->arena; - /* convert the password to unicode */ - if (!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem, - PR_TRUE, PR_TRUE, PR_TRUE)) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; + if (sec_pkcs12_is_pkcs12_pbe_algorithm(privAlg)) { + /* convert the password to unicode */ + if (!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem, + PR_TRUE, PR_TRUE, PR_TRUE)) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto loser; + } + } else { + if (SECITEM_CopyItem(NULL, &uniPwitem, pwitem) != SECSuccess) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto loser; + } } if (SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) { PORT_SetError(SEC_ERROR_NO_MEMORY); diff --git a/lib/pkcs12/p12local.c b/lib/pkcs12/p12local.c --- a/lib/pkcs12/p12local.c +++ b/lib/pkcs12/p12local.c @@ -949,6 +949,33 @@ sec_pkcs12_convert_item_to_unicode(PLAre return PR_TRUE; } +PRBool +sec_pkcs12_is_pkcs12_pbe_algorithm(SECOidTag algorithm) +{ + switch (algorithm) { + case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: + case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: + case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC: + case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: + case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: + case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: + case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: + case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4: + case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4: + case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: + case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: + /* those are actually PKCS #5 v1.5 PBEs, but we + * historically treat them in the same way as PKCS #12 + * PBEs */ + case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC: + case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC: + case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC: + return PR_TRUE; + default: + return PR_FALSE; + } +} + /* pkcs 12 templates */ static const SEC_ASN1TemplateChooserPtr sec_pkcs12_shroud_chooser = sec_pkcs12_choose_shroud_type; diff --git a/lib/pkcs12/p12local.h b/lib/pkcs12/p12local.h --- a/lib/pkcs12/p12local.h +++ b/lib/pkcs12/p12local.h @@ -55,4 +55,6 @@ sec_PKCS12ConvertOldSafeToNew(PLArenaPoo void *wincx, SEC_PKCS12SafeContents *safe, SEC_PKCS12Baggage *baggage); +extern PRBool sec_pkcs12_is_pkcs12_pbe_algorithm(SECOidTag algorithm); + #endif diff --git a/lib/pkcs12/p12plcy.c b/lib/pkcs12/p12plcy.c --- a/lib/pkcs12/p12plcy.c +++ b/lib/pkcs12/p12plcy.c @@ -24,6 +24,9 @@ static pkcs12SuiteMap pkcs12SuiteMaps[] { SEC_OID_RC2_CBC, 128, PKCS12_RC2_CBC_128, PR_FALSE, PR_FALSE }, { SEC_OID_DES_CBC, 64, PKCS12_DES_56, PR_FALSE, PR_FALSE }, { SEC_OID_DES_EDE3_CBC, 192, PKCS12_DES_EDE3_168, PR_FALSE, PR_FALSE }, + { SEC_OID_AES_128_CBC, 128, PKCS12_AES_CBC_128, PR_FALSE, PR_FALSE }, + { SEC_OID_AES_192_CBC, 192, PKCS12_AES_CBC_192, PR_FALSE, PR_FALSE }, + { SEC_OID_AES_256_CBC, 256, PKCS12_AES_CBC_256, PR_FALSE, PR_FALSE }, { SEC_OID_UNKNOWN, 0, PKCS12_NULL, PR_FALSE, PR_FALSE }, { SEC_OID_UNKNOWN, 0, 0L, PR_FALSE, PR_FALSE } }; diff --git a/lib/pkcs7/p7create.c b/lib/pkcs7/p7create.c --- a/lib/pkcs7/p7create.c +++ b/lib/pkcs7/p7create.c @@ -1245,3 +1245,56 @@ SEC_PKCS7CreateEncryptedData(SECOidTag a return cinfo; } + +SEC_PKCS7ContentInfo * +SEC_PKCS7CreateEncryptedDataWithPBEV2(SECOidTag pbe_algorithm, + SECOidTag cipher_algorithm, + SECOidTag prf_algorithm, + int keysize, + SECKEYGetPasswordKey pwfn, void *pwfn_arg) +{ + SEC_PKCS7ContentInfo *cinfo; + SECAlgorithmID *algid; + SEC_PKCS7EncryptedData *enc_data; + SECStatus rv; + + PORT_Assert(SEC_PKCS5IsAlgorithmPBEAlgTag(pbe_algorithm)); + + cinfo = sec_pkcs7_create_content_info(SEC_OID_PKCS7_ENCRYPTED_DATA, + PR_FALSE, pwfn, pwfn_arg); + if (cinfo == NULL) + return NULL; + + enc_data = cinfo->content.encryptedData; + algid = &(enc_data->encContentInfo.contentEncAlg); + + SECAlgorithmID *pbe_algid; + pbe_algid = PK11_CreatePBEV2AlgorithmID(pbe_algorithm, + cipher_algorithm, + prf_algorithm, + keysize, + NSS_PBE_DEFAULT_ITERATION_COUNT, + NULL); + if (pbe_algid == NULL) { + rv = SECFailure; + } else { + rv = SECOID_CopyAlgorithmID(cinfo->poolp, algid, pbe_algid); + SECOID_DestroyAlgorithmID(pbe_algid, PR_TRUE); + } + + if (rv != SECSuccess) { + SEC_PKCS7DestroyContentInfo(cinfo); + return NULL; + } + + rv = sec_pkcs7_init_encrypted_content_info(&(enc_data->encContentInfo), + cinfo->poolp, + SEC_OID_PKCS7_DATA, PR_FALSE, + cipher_algorithm, keysize); + if (rv != SECSuccess) { + SEC_PKCS7DestroyContentInfo(cinfo); + return NULL; + } + + return cinfo; +} diff --git a/lib/pkcs7/secpkcs7.h b/lib/pkcs7/secpkcs7.h --- a/lib/pkcs7/secpkcs7.h +++ b/lib/pkcs7/secpkcs7.h @@ -287,6 +287,26 @@ SEC_PKCS7CreateEncryptedData(SECOidTag a SECKEYGetPasswordKey pwfn, void *pwfn_arg); /* + * Create an empty PKCS7 encrypted content info. + * + * Similar to SEC_PKCS7CreateEncryptedData(), but this is capable of + * creating encrypted content for PKCS #5 v2 algorithms. + * + * "pbe_algorithm" specifies the PBE algorithm to use. + * "cipher_algorithm" specifies the bulk encryption algorithm to use. + * "prf_algorithm" specifies the PRF algorithm which pbe_algorithm uses. + * + * An error results in a return value of NULL and an error set. + * (Retrieve specific errors via PORT_GetError()/XP_GetError().) + */ +extern SEC_PKCS7ContentInfo * +SEC_PKCS7CreateEncryptedDataWithPBEV2(SECOidTag pbe_algorithm, + SECOidTag cipher_algorithm, + SECOidTag prf_algorithm, + int keysize, + SECKEYGetPasswordKey pwfn, void *pwfn_arg); + +/* * All of the following things return SECStatus to signal success or failure. * Failure should have a more specific error status available via * PORT_GetError()/XP_GetError(). diff --git a/tests/tools/tools.sh b/tests/tools/tools.sh --- a/tests/tools/tools.sh +++ b/tests/tools/tools.sh @@ -273,12 +273,9 @@ tools_p12_export_list_import_all_pkcs5v2 CAMELLIA-256-CBC; do #--------------------------------------------------------------- -# Bug 452464 - pk12util -o fails when -C option specifies AES or +# Bug 452464 - pk12util -o fails when -C option specifies # Camellia ciphers # FIXME Restore these to the list -# AES-128-CBC, \ -# AES-192-CBC, \ -# AES-256-CBC, \ # CAMELLIA-128-CBC, \ # CAMELLIA-192-CBC, \ # CAMELLIA-256-CBC, \ @@ -287,6 +284,9 @@ tools_p12_export_list_import_all_pkcs5v2 for cert_cipher in \ RC2-CBC \ DES-EDE3-CBC \ + AES-128-CBC \ + AES-192-CBC \ + AES-256-CBC \ null; do export_list_import ${key_cipher} ${cert_cipher} done # HG changeset patch # User Daiki Ueno # Date 1491303138 -7200 # Tue Apr 04 12:52:18 2017 +0200 # Node ID ef11922df67881332f1fa200c7ae21b9c30cec76 # Parent 7228445b43ac095ebc0eee330d6a351b898ebbdd Bug 1353325, pkcs12: don't encode password if non-PKCS12 PBEs is used, r=rrelyea diff --git a/lib/pkcs12/p12d.c b/lib/pkcs12/p12d.c --- a/lib/pkcs12/p12d.c +++ b/lib/pkcs12/p12d.c @@ -177,8 +177,7 @@ sec_pkcs12_decoder_get_decrypt_key(void SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg; PK11SlotInfo *slot; PK11SymKey *bulkKey; - SECItem *pwitem; - SECItem decodedPwitem = { 0 }; + SECItem pwitem = { 0 }; SECOidTag algorithm; if (!p12dcx) { @@ -193,24 +192,10 @@ sec_pkcs12_decoder_get_decrypt_key(void } algorithm = SECOID_GetAlgorithmTag(algid); - pwitem = p12dcx->pwitem; - - /* here we assume that the password is already encoded into - * BMPString by the caller. if the encryption scheme is not the - * one defined in PKCS #12, decode the password back into - * UTF-8. */ - if (!sec_pkcs12_is_pkcs12_pbe_algorithm(algorithm)) { - if (!sec_pkcs12_convert_item_to_unicode(NULL, &decodedPwitem, - p12dcx->pwitem, - PR_TRUE, PR_FALSE, PR_FALSE)) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - pwitem = &decodedPwitem; - } - - bulkKey = PK11_PBEKeyGen(slot, algid, pwitem, - PR_FALSE, p12dcx->wincx); + if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm, p12dcx->pwitem)) + return NULL; + + bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx); /* some tokens can't generate PBE keys on their own, generate the * key in the internal slot, and let the Import code deal with it, * (if the slot can't generate PBEs, then we need to use the internal @@ -218,8 +203,7 @@ sec_pkcs12_decoder_get_decrypt_key(void if (!bulkKey && !PK11_IsInternal(slot)) { PK11_FreeSlot(slot); slot = PK11_GetInternalKeySlot(); - bulkKey = PK11_PBEKeyGen(slot, algid, pwitem, - PR_FALSE, p12dcx->wincx); + bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx); } PK11_FreeSlot(slot); @@ -228,8 +212,8 @@ sec_pkcs12_decoder_get_decrypt_key(void PK11_SetSymKeyUserData(bulkKey, p12dcx->pwitem, NULL); } - if (decodedPwitem.data) { - SECITEM_ZfreeItem(&decodedPwitem, PR_FALSE); + if (pwitem.data) { + SECITEM_ZfreeItem(&pwitem, PR_FALSE); } return bulkKey; @@ -2476,13 +2460,25 @@ sec_pkcs12_add_key(sec_PKCS12SafeBag *ke nickName, publicValue, PR_TRUE, PR_TRUE, keyUsage, wincx); break; - case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: + case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: { + SECItem pwitem = { 0 }; + SECAlgorithmID *algid = + &key->safeBagContent.pkcs8ShroudedKeyBag->algorithm; + SECOidTag algorithm = SECOID_GetAlgorithmTag(algid); + + if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm, + key->pwitem)) + return SECFailure; rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot, key->safeBagContent.pkcs8ShroudedKeyBag, - key->pwitem, nickName, publicValue, + &pwitem, nickName, publicValue, PR_TRUE, PR_TRUE, keyType, keyUsage, wincx); + if (pwitem.data) { + SECITEM_ZfreeItem(&pwitem, PR_FALSE); + } break; + } default: key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION; key->problem = PR_TRUE; diff --git a/lib/pkcs12/p12e.c b/lib/pkcs12/p12e.c --- a/lib/pkcs12/p12e.c +++ b/lib/pkcs12/p12e.c @@ -397,18 +397,9 @@ SEC_PKCS12CreatePasswordPrivSafe(SEC_PKC } safeInfo->arena = p12ctxt->arena; - if (sec_pkcs12_is_pkcs12_pbe_algorithm(privAlg)) { - /* convert the password to unicode */ - if (!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem, - PR_TRUE, PR_TRUE, PR_TRUE)) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - } else { - if (SECITEM_CopyItem(NULL, &uniPwitem, pwitem) != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } + if (!sec_pkcs12_encode_password(NULL, &uniPwitem, privAlg, pwitem)) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto loser; } if (SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) { PORT_SetError(SEC_ERROR_NO_MEMORY); @@ -1221,8 +1212,8 @@ SEC_PKCS12AddKeyForCert(SEC_PKCS12Export SECKEYEncryptedPrivateKeyInfo *epki = NULL; PK11SlotInfo *slot = NULL; - if (!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, &uniPwitem, - pwitem, PR_TRUE, PR_TRUE, PR_TRUE)) { + if (!sec_pkcs12_encode_password(p12ctxt->arena, &uniPwitem, algorithm, + pwitem)) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } diff --git a/lib/pkcs12/p12local.c b/lib/pkcs12/p12local.c --- a/lib/pkcs12/p12local.c +++ b/lib/pkcs12/p12local.c @@ -976,6 +976,46 @@ sec_pkcs12_is_pkcs12_pbe_algorithm(SECOi } } +/* this function decodes a password from Unicode if necessary, + * according to the PBE algorithm. + * + * we assume that the pwitem is already encoded in Unicode by the + * caller. if the encryption scheme is not the one defined in PKCS + * #12, decode the pwitem back into UTF-8. */ +PRBool +sec_pkcs12_decode_password(PLArenaPool *arena, + SECItem *result, + SECOidTag algorithm, + const SECItem *pwitem) +{ + if (!sec_pkcs12_is_pkcs12_pbe_algorithm(algorithm)) + return sec_pkcs12_convert_item_to_unicode(arena, result, + (SECItem *)pwitem, + PR_TRUE, PR_FALSE, PR_FALSE); + + return SECITEM_CopyItem(arena, result, pwitem) == SECSuccess; +} + +/* this function encodes a password into Unicode if necessary, + * according to the PBE algorithm. + * + * we assume that the pwitem holds a raw password. if the encryption + * scheme is the one defined in PKCS #12, encode the password into + * BMPString. */ +PRBool +sec_pkcs12_encode_password(PLArenaPool *arena, + SECItem *result, + SECOidTag algorithm, + const SECItem *pwitem) +{ + if (sec_pkcs12_is_pkcs12_pbe_algorithm(algorithm)) + return sec_pkcs12_convert_item_to_unicode(arena, result, + (SECItem *)pwitem, + PR_TRUE, PR_TRUE, PR_TRUE); + + return SECITEM_CopyItem(arena, result, pwitem) == SECSuccess; +} + /* pkcs 12 templates */ static const SEC_ASN1TemplateChooserPtr sec_pkcs12_shroud_chooser = sec_pkcs12_choose_shroud_type; diff --git a/lib/pkcs12/p12local.h b/lib/pkcs12/p12local.h --- a/lib/pkcs12/p12local.h +++ b/lib/pkcs12/p12local.h @@ -57,4 +57,13 @@ sec_PKCS12ConvertOldSafeToNew(PLArenaPoo extern PRBool sec_pkcs12_is_pkcs12_pbe_algorithm(SECOidTag algorithm); +extern PRBool sec_pkcs12_decode_password(PLArenaPool *arena, + SECItem *result, + SECOidTag algorithm, + const SECItem *pwitem); +extern PRBool sec_pkcs12_encode_password(PLArenaPool *arena, + SECItem *result, + SECOidTag algorithm, + const SECItem *pwitem); + #endif # HG changeset patch # User Daiki Ueno # Date 1491397923 -7200 # Wed Apr 05 15:12:03 2017 +0200 # Node ID c9af3144ac8cd7e2203817a334a9f814649e86b0 # Parent 769f9ae07b103494af809620478e60256a344adc fix key length calculation for PKCS#5 DES-EDE3-CBC-Pad diff --git a/lib/pk11wrap/pk11pbe.c b/lib/pk11wrap/pk11pbe.c --- a/lib/pk11wrap/pk11pbe.c +++ b/lib/pk11wrap/pk11pbe.c @@ -370,6 +370,13 @@ sec_pkcs5v2_key_length(SECAlgorithmID *a length = sec_pkcs5v2_aes_key_length(cipherAlg); } else if (p5_param.keyLength.data != NULL) { length = DER_GetInteger(&p5_param.keyLength); + } else { + CK_MECHANISM_TYPE cipherMech; + cipherMech = PK11_AlgtagToMechanism(cipherAlg); + if (cipherMech == CKM_INVALID_MECHANISM) { + goto loser; + } + length = PK11_GetMaxKeyLength(cipherMech); } loser: diff --git a/lib/pk11wrap/pk11priv.h b/lib/pk11wrap/pk11priv.h --- a/lib/pk11wrap/pk11priv.h +++ b/lib/pk11wrap/pk11priv.h @@ -106,6 +106,7 @@ CK_OBJECT_HANDLE PK11_FindObjectForCert( void *wincx, PK11SlotInfo **pSlot); PK11SymKey *pk11_CopyToSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey); +unsigned int pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType); /********************************************************************** * Certs diff --git a/lib/pk11wrap/pk11slot.c b/lib/pk11wrap/pk11slot.c --- a/lib/pk11wrap/pk11slot.c +++ b/lib/pk11wrap/pk11slot.c @@ -2291,6 +2291,14 @@ PK11_GetMaxKeyLength(CK_MECHANISM_TYPE m } } } + + /* fallback to pk11_GetPredefinedKeyLength for fixed key size algorithms */ + if (keyLength == 0) { + CK_KEY_TYPE keyType; + keyType = PK11_GetKeyType(mechanism, 0); + keyLength = pk11_GetPredefinedKeyLength(keyType); + } + if (le) PK11_FreeSlotListElement(list, le); if (freeit)