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